1 From 37d1667ad0cc91f46a493281e62775cc8bbe3b5b Mon Sep 17 00:00:00 2001
2 From: Simo Sorce <simo@redhat.com>
3 Date: Tue, 14 Mar 2017 10:20:08 -0400
4 Subject: [PATCH] Change impersonator check code
6 In MIT 1.15 we now have a native way to check for an impersonator,
7 implement the use of that function but still keep the fallback for
8 earlier krb5 versions that do not support this method for now.
10 Signed-off-by: Simo Sorce <simo@redhat.com>
11 Reviewed-by: Robbie Harwood <rharwood@redhat.com>
13 (cherry picked from commit 73b50c0b2799f0aed53337a6516b8e1a27279ebf)
15 proxy/configure.ac | 3 +
16 proxy/src/gp_creds.c | 147 ++++++++++++++++++++++++++++++++-----------
17 2 files changed, 112 insertions(+), 38 deletions(-)
19 diff --git a/proxy/configure.ac b/proxy/configure.ac
20 index 63c0edf..c52dbb6 100644
21 --- a/proxy/configure.ac
22 +++ b/proxy/configure.ac
23 @@ -131,6 +131,9 @@ AC_CHECK_LIB(gssapi_krb5, gss_export_cred,,
24 [AC_MSG_ERROR([GSSAPI library does not support gss_export_cred])],
27 +AC_CHECK_DECLS([GSS_KRB5_GET_CRED_IMPERSONATOR], [], [],
28 + [[#include <gssapi/gssapi_krb5.h>]])
30 AC_SUBST([KRB5_CFLAGS])
32 AC_SUBST([GSSAPI_CFLAGS])
33 diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c
34 index 171a724..95a1c48 100644
35 --- a/proxy/src/gp_creds.c
36 +++ b/proxy/src/gp_creds.c
37 @@ -773,9 +773,9 @@ void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags)
38 *flags &= ~gpcall->service->filter_flags;
41 -uint32_t gp_cred_allowed(uint32_t *min,
42 - struct gp_call_ctx *gpcall,
45 +static uint32_t get_impersonator_fallback(uint32_t *min, gss_cred_id_t cred,
46 + char **impersonator)
50 @@ -785,22 +785,6 @@ uint32_t gp_cred_allowed(uint32_t *min,
54 - if (cred == GSS_C_NO_CREDENTIAL) {
55 - return GSS_S_CRED_UNAVAIL;
58 - if (gpcall->service->trusted ||
59 - gpcall->service->impersonate ||
60 - gpcall->service->allow_const_deleg) {
62 - GPDEBUGN(2, "Credentials allowed by configuration\n");
64 - return GSS_S_COMPLETE;
67 - /* FIXME: krb5 specific code, should get an oid registerd to query the
68 - * cred with gss_inquire_cred_by_oid() or similar instead */
70 err = krb5_init_context(&context);
73 @@ -835,21 +819,116 @@ uint32_t gp_cred_allowed(uint32_t *min,
77 + err = krb5_cc_get_config(context, ccache, NULL, "proxy_impersonator",
80 + *impersonator = strndup(config.data, config.length);
81 + if (!*impersonator) {
83 + ret_maj = GSS_S_FAILURE;
86 + ret_maj = GSS_S_COMPLETE;
88 + krb5_free_data_contents(context, &config);
91 + ret_maj = GSS_S_FAILURE;
97 + krb5_cc_destroy(context, ccache);
99 + krb5_free_context(context);
107 +#if !HAVE_DECL_GSS_KRB5_GET_CRED_IMPERSONATOR
108 +gss_OID_desc impersonator_oid = {
109 + 11, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e")
111 +const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR = &impersonator_oid;
114 +static uint32_t get_impersonator_name(uint32_t *min, gss_cred_id_t cred,
115 + char **impersonator)
117 + gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
118 + uint32_t ret_maj = 0;
119 + uint32_t ret_min = 0;
122 + *impersonator = NULL;
124 + ret_maj = gss_inquire_cred_by_oid(&ret_min, cred,
125 + GSS_KRB5_GET_CRED_IMPERSONATOR,
127 + if (ret_maj == GSS_S_COMPLETE) {
128 + if (bufset->count == 0) {
130 + ret_maj = GSS_S_COMPLETE;
133 + *impersonator = strndup(bufset->elements[0].value,
134 + bufset->elements[0].length);
135 + if (!*impersonator) {
137 + ret_maj = GSS_S_FAILURE;
139 + } else if (ret_maj == GSS_S_UNAVAILABLE) {
140 + /* Not supported by krb5 library yet, fallback to raw krb5 calls */
141 + /* TODO: Remove once we set a required dependency on MIT 1.15+ */
142 + ret_maj = get_impersonator_fallback(&ret_min, cred, impersonator);
143 + if (ret_maj == GSS_S_FAILURE) {
144 + if (ret_min == KRB5_CC_NOTFOUND) {
146 + ret_maj = GSS_S_COMPLETE;
152 + (void)gss_release_buffer_set(&discard, &bufset);
157 +uint32_t gp_cred_allowed(uint32_t *min,
158 + struct gp_call_ctx *gpcall,
159 + gss_cred_id_t cred)
161 + char *impersonator = NULL;
162 + uint32_t ret_maj = 0;
163 + uint32_t ret_min = 0;
165 + if (cred == GSS_C_NO_CREDENTIAL) {
166 + return GSS_S_CRED_UNAVAIL;
169 + if (gpcall->service->trusted ||
170 + gpcall->service->impersonate ||
171 + gpcall->service->allow_const_deleg) {
173 + GPDEBUGN(2, "Credentials allowed by configuration\n");
175 + return GSS_S_COMPLETE;
178 + ret_maj = get_impersonator_name(&ret_min, cred, &impersonator);
179 + if (ret_maj) goto done;
181 /* if we find an impersonator entry we bail as that is not authorized,
182 * if it were then gpcall->service->allow_const_deleg would have caused
183 * the ealier check to return GSS_S_COMPLETE already */
184 - err = krb5_cc_get_config(context, ccache, NULL, "proxy_impersonator",
187 - krb5_free_data_contents(context, &config);
188 + if (impersonator != NULL) {
190 ret_maj = GSS_S_UNAUTHORIZED;
191 - } else if (err != KRB5_CC_NOTFOUND) {
193 - ret_maj = GSS_S_FAILURE;
196 - ret_maj = GSS_S_COMPLETE;
200 @@ -864,15 +943,7 @@ done:
201 GPDEBUG("Failure while checking credentials\n");
205 - /* NOTE: destroy only if we created a MEMORY ccache */
207 - if (memcache) krb5_cc_destroy(context, ccache);
208 - else krb5_cc_close(context, ccache);
210 - krb5_free_context(context);
213 + free(impersonator);