Blame SOURCES/Change-impersonator-check-code.patch

31d59b
From 37d1667ad0cc91f46a493281e62775cc8bbe3b5b Mon Sep 17 00:00:00 2001
31d59b
From: Simo Sorce <simo@redhat.com>
31d59b
Date: Tue, 14 Mar 2017 10:20:08 -0400
31d59b
Subject: [PATCH] Change impersonator check code
31d59b
31d59b
In MIT 1.15 we now have a native way to check for an impersonator,
31d59b
implement the use of that function but still keep the fallback for
31d59b
earlier krb5 versions that do not support this method for now.
31d59b
31d59b
Signed-off-by: Simo Sorce <simo@redhat.com>
31d59b
Reviewed-by: Robbie Harwood <rharwood@redhat.com>
31d59b
Merges: #172
31d59b
(cherry picked from commit 73b50c0b2799f0aed53337a6516b8e1a27279ebf)
31d59b
---
68bf20
 proxy/configure.ac   |   3 +
68bf20
 proxy/src/gp_creds.c | 147 ++++++++++++++++++++++++++++++++-----------
31d59b
 2 files changed, 112 insertions(+), 38 deletions(-)
31d59b
31d59b
diff --git a/proxy/configure.ac b/proxy/configure.ac
31d59b
index 63c0edf..c52dbb6 100644
31d59b
--- a/proxy/configure.ac
31d59b
+++ b/proxy/configure.ac
31d59b
@@ -131,6 +131,9 @@ AC_CHECK_LIB(gssapi_krb5, gss_export_cred,,
31d59b
              [AC_MSG_ERROR([GSSAPI library does not support gss_export_cred])],
31d59b
              [$GSSAPI_LIBS])
31d59b
 
31d59b
+AC_CHECK_DECLS([GSS_KRB5_GET_CRED_IMPERSONATOR], [], [],
31d59b
+               [[#include <gssapi/gssapi_krb5.h>]])
31d59b
+
31d59b
 AC_SUBST([KRB5_CFLAGS])
31d59b
 AC_SUBST([KRB5_LIBS])
31d59b
 AC_SUBST([GSSAPI_CFLAGS])
31d59b
diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c
31d59b
index 171a724..95a1c48 100644
31d59b
--- a/proxy/src/gp_creds.c
31d59b
+++ b/proxy/src/gp_creds.c
31d59b
@@ -773,9 +773,9 @@ void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags)
31d59b
     *flags &= ~gpcall->service->filter_flags;
31d59b
 }
31d59b
 
31d59b
-uint32_t gp_cred_allowed(uint32_t *min,
31d59b
-                         struct gp_call_ctx *gpcall,
31d59b
-                         gss_cred_id_t cred)
31d59b
+
31d59b
+static uint32_t get_impersonator_fallback(uint32_t *min, gss_cred_id_t cred,
31d59b
+                                          char **impersonator)
31d59b
 {
31d59b
     uint32_t ret_maj = 0;
31d59b
     uint32_t ret_min = 0;
31d59b
@@ -785,22 +785,6 @@ uint32_t gp_cred_allowed(uint32_t *min,
31d59b
     krb5_data config;
31d59b
     int err;
31d59b
 
31d59b
-    if (cred == GSS_C_NO_CREDENTIAL) {
31d59b
-        return GSS_S_CRED_UNAVAIL;
31d59b
-    }
31d59b
-
31d59b
-    if (gpcall->service->trusted ||
31d59b
-        gpcall->service->impersonate ||
31d59b
-        gpcall->service->allow_const_deleg) {
31d59b
-
31d59b
-        GPDEBUGN(2, "Credentials allowed by configuration\n");
31d59b
-        *min = 0;
31d59b
-        return GSS_S_COMPLETE;
31d59b
-    }
31d59b
-
31d59b
-    /* FIXME: krb5 specific code, should get an oid registerd to query the
31d59b
-     * cred with gss_inquire_cred_by_oid() or similar instead */
31d59b
-
31d59b
     err = krb5_init_context(&context);
31d59b
     if (err) {
31d59b
         ret_min = err;
31d59b
@@ -835,21 +819,116 @@ uint32_t gp_cred_allowed(uint32_t *min,
31d59b
         goto done;
31d59b
     }
31d59b
 
31d59b
+    err = krb5_cc_get_config(context, ccache, NULL, "proxy_impersonator",
31d59b
+                             &config);
31d59b
+    if (err == 0) {
31d59b
+        *impersonator = strndup(config.data, config.length);
31d59b
+        if (!*impersonator) {
31d59b
+            ret_min = ENOMEM;
31d59b
+            ret_maj = GSS_S_FAILURE;
31d59b
+        } else {
31d59b
+            ret_min = 0;
31d59b
+            ret_maj = GSS_S_COMPLETE;
31d59b
+        }
31d59b
+        krb5_free_data_contents(context, &config);
31d59b
+    } else {
31d59b
+        ret_min = err;
31d59b
+        ret_maj = GSS_S_FAILURE;
31d59b
+    }
31d59b
+
31d59b
+done:
31d59b
+    if (context) {
31d59b
+        if (ccache) {
31d59b
+            krb5_cc_destroy(context, ccache);
31d59b
+        }
31d59b
+        krb5_free_context(context);
31d59b
+    }
31d59b
+    free(memcache);
31d59b
+
31d59b
+    *min = ret_min;
31d59b
+    return ret_maj;
31d59b
+}
31d59b
+
31d59b
+#if !HAVE_DECL_GSS_KRB5_GET_CRED_IMPERSONATOR
31d59b
+gss_OID_desc impersonator_oid = {
31d59b
+    11, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e")
31d59b
+};
31d59b
+const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR = &impersonator_oid;
31d59b
+#endif
31d59b
+
31d59b
+static uint32_t get_impersonator_name(uint32_t *min, gss_cred_id_t cred,
31d59b
+                                      char **impersonator)
31d59b
+{
31d59b
+    gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
31d59b
+    uint32_t ret_maj = 0;
31d59b
+    uint32_t ret_min = 0;
31d59b
+    uint32_t discard;
31d59b
+
31d59b
+    *impersonator = NULL;
31d59b
+
31d59b
+    ret_maj = gss_inquire_cred_by_oid(&ret_min, cred,
31d59b
+                                      GSS_KRB5_GET_CRED_IMPERSONATOR,
31d59b
+                                      &bufset);
31d59b
+    if (ret_maj == GSS_S_COMPLETE) {
31d59b
+        if (bufset->count == 0) {
31d59b
+            ret_min = ENOENT;
31d59b
+            ret_maj = GSS_S_COMPLETE;
31d59b
+            goto done;
31d59b
+        }
31d59b
+        *impersonator = strndup(bufset->elements[0].value,
31d59b
+                                bufset->elements[0].length);
31d59b
+        if (!*impersonator) {
31d59b
+            ret_min = ENOMEM;
31d59b
+            ret_maj = GSS_S_FAILURE;
31d59b
+        }
31d59b
+    } else if (ret_maj == GSS_S_UNAVAILABLE) {
31d59b
+        /* Not supported by krb5 library yet, fallback to raw krb5 calls */
31d59b
+        /* TODO: Remove once we set a required dependency on MIT 1.15+ */
31d59b
+        ret_maj = get_impersonator_fallback(&ret_min, cred, impersonator);
31d59b
+        if (ret_maj == GSS_S_FAILURE) {
31d59b
+            if (ret_min == KRB5_CC_NOTFOUND) {
31d59b
+                ret_min = ENOENT;
31d59b
+                ret_maj = GSS_S_COMPLETE;
31d59b
+            }
31d59b
+        }
31d59b
+    }
31d59b
+
31d59b
+done:
31d59b
+    (void)gss_release_buffer_set(&discard, &bufset);
31d59b
+    *min = ret_min;
31d59b
+    return ret_maj;
31d59b
+}
31d59b
+
31d59b
+uint32_t gp_cred_allowed(uint32_t *min,
31d59b
+                         struct gp_call_ctx *gpcall,
31d59b
+                         gss_cred_id_t cred)
31d59b
+{
31d59b
+    char *impersonator = NULL;
31d59b
+    uint32_t ret_maj = 0;
31d59b
+    uint32_t ret_min = 0;
31d59b
+
31d59b
+    if (cred == GSS_C_NO_CREDENTIAL) {
31d59b
+        return GSS_S_CRED_UNAVAIL;
31d59b
+    }
31d59b
+
31d59b
+    if (gpcall->service->trusted ||
31d59b
+        gpcall->service->impersonate ||
31d59b
+        gpcall->service->allow_const_deleg) {
31d59b
+
31d59b
+        GPDEBUGN(2, "Credentials allowed by configuration\n");
31d59b
+        *min = 0;
31d59b
+        return GSS_S_COMPLETE;
31d59b
+    }
31d59b
+
31d59b
+    ret_maj = get_impersonator_name(&ret_min, cred, &impersonator);
31d59b
+    if (ret_maj) goto done;
31d59b
+
31d59b
     /* if we find an impersonator entry we bail as that is not authorized,
31d59b
      * if it were then gpcall->service->allow_const_deleg would have caused
31d59b
      * the ealier check to return GSS_S_COMPLETE already */
31d59b
-    err = krb5_cc_get_config(context, ccache, NULL, "proxy_impersonator",
31d59b
-                             &config);
31d59b
-    if (!err) {
31d59b
-        krb5_free_data_contents(context, &config);
31d59b
+    if (impersonator != NULL) {
31d59b
         ret_min = 0;
31d59b
         ret_maj = GSS_S_UNAUTHORIZED;
31d59b
-    } else if (err != KRB5_CC_NOTFOUND) {
31d59b
-        ret_min = err;
31d59b
-        ret_maj = GSS_S_FAILURE;
31d59b
-    } else {
31d59b
-        ret_min = 0;
31d59b
-        ret_maj = GSS_S_COMPLETE;
31d59b
     }
31d59b
 
31d59b
 done:
31d59b
@@ -864,15 +943,7 @@ done:
31d59b
         GPDEBUG("Failure while checking credentials\n");
31d59b
         break;
31d59b
     }
31d59b
-    if (context) {
31d59b
-        /* NOTE: destroy only if we created a MEMORY ccache */
31d59b
-        if (ccache) {
31d59b
-            if (memcache) krb5_cc_destroy(context, ccache);
31d59b
-            else krb5_cc_close(context, ccache);
31d59b
-        }
31d59b
-        krb5_free_context(context);
31d59b
-    }
31d59b
-    free(memcache);
31d59b
+    free(impersonator);
31d59b
     *min = ret_min;
31d59b
     return ret_maj;
31d59b
 }