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

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