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.
217 lines
6.7 KiB
217 lines
6.7 KiB
7 years ago
|
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;
|
||
|
}
|