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