From 5cbecfed4a45fc8f500d240bb969733972299541 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Dec 02 2016 16:13:38 +0000 Subject: [PATCH 1/4] Add cred_store support for local calls. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c index faf5914..dade19c 100644 --- a/proxy/src/mechglue/gpp_acquire_cred.c +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -8,6 +8,7 @@ static OM_uint32 acquire_local(OM_uint32 *minor_status, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, struct gpp_cred_handle *out_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec) @@ -43,14 +44,15 @@ static OM_uint32 acquire_local(OM_uint32 *minor_status, goto done; } - maj = gss_acquire_cred(&min, - name ? name->local : NULL, - time_req, - special_mechs, - cred_usage, - &out_cred_handle->local, - actual_mechs, - time_rec); + maj = gss_acquire_cred_from(&min, + name ? name->local : NULL, + time_req, + special_mechs, + cred_usage, + cred_store, + &out_cred_handle->local, + actual_mechs, + time_rec); done: *minor_status = min; @@ -67,6 +69,21 @@ OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { + return gssi_acquire_cred_from(minor_status, desired_name, time_req, + desired_mechs, cred_usage, NULL, + output_cred_handle, actual_mechs, time_rec); +} + +OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ enum gpp_behavior behavior; struct gpp_name_handle *name; struct gpp_cred_handle *out_cred_handle = NULL; @@ -97,7 +114,7 @@ OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { maj = acquire_local(&min, NULL, name, - time_req, desired_mechs, cred_usage, + time_req, desired_mechs, cred_usage, cred_store, out_cred_handle, actual_mechs, time_rec); if (maj == GSS_S_COMPLETE || behavior == GPP_LOCAL_ONLY) { @@ -132,7 +149,7 @@ OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, if (behavior == GPP_REMOTE_FIRST) { /* So remote failed, but we can fallback to local, try that */ maj = acquire_local(&min, NULL, name, - time_req, desired_mechs, cred_usage, + time_req, desired_mechs, cred_usage, cred_store, out_cred_handle, actual_mechs, time_rec); } @@ -164,6 +181,26 @@ OM_uint32 gssi_add_cred(OM_uint32 *minor_status, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { + return gssi_add_cred_from(minor_status, input_cred_handle, desired_name, + desired_mech, cred_usage, initiator_time_req, + acceptor_time_req, NULL, output_cred_handle, + actual_mechs, initiator_time_rec, + acceptor_time_rec); +} + +OM_uint32 gssi_add_cred_from(OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + const gss_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ gss_OID_set desired_mechs = GSS_C_NO_OID_SET; OM_uint32 time_req, time_rec; OM_uint32 maj, min; @@ -206,14 +243,9 @@ OM_uint32 gssi_add_cred(OM_uint32 *minor_status, time_req = 0; } - maj = gssi_acquire_cred(minor_status, - desired_name, - time_req, - desired_mechs, - cred_usage, - output_cred_handle, - actual_mechs, - &time_rec); + maj = gssi_acquire_cred_from(minor_status, desired_name, time_req, + desired_mechs, cred_usage, NULL, + output_cred_handle, actual_mechs, &time_rec); if (maj == GSS_S_COMPLETE) { if (acceptor_time_rec && (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)) { @@ -375,7 +407,7 @@ OM_uint32 gssi_acquire_cred_impersonate_name(OM_uint32 *minor_status, if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { maj = acquire_local(&min, impersonator_cred_handle, name, - time_req, desired_mechs, cred_usage, + time_req, desired_mechs, cred_usage, NULL, out_cred_handle, actual_mechs, time_rec); if (maj == GSS_S_COMPLETE || behavior == GPP_LOCAL_ONLY) { @@ -412,7 +444,7 @@ OM_uint32 gssi_acquire_cred_impersonate_name(OM_uint32 *minor_status, if (behavior == GPP_REMOTE_FIRST) { /* So remote failed, but we can fallback to local, try that */ maj = acquire_local(&min, impersonator_cred_handle, name, - time_req, desired_mechs, cred_usage, + time_req, desired_mechs, cred_usage, NULL, out_cred_handle, actual_mechs, time_rec); } @@ -431,4 +463,3 @@ done: *minor_status = gpp_map_error(min); return maj; } - diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index 31ad9d4..a0f28c2 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -6,7 +6,9 @@ #define GPKRB_SRV_NAME "Encrypted/Credentials/v1@X-GSSPROXY:" #define GPKRB_MAX_CRED_SIZE 1024 * 512 -uint32_t gpp_store_remote_creds(uint32_t *min, gssx_cred *creds) +uint32_t gpp_store_remote_creds(uint32_t *min, + gss_const_key_value_set_t cred_store, + gssx_cred *creds) { krb5_context ctx = NULL; krb5_ccache ccache = NULL; @@ -24,8 +26,20 @@ uint32_t gpp_store_remote_creds(uint32_t *min, gssx_cred *creds) ret = krb5_init_context(&ctx); if (ret) return ret; - ret = krb5_cc_default(ctx, &ccache); - if (ret) goto done; + if (cred_store) { + for (unsigned i = 0; i < cred_store->count; i++) { + if (strcmp(cred_store->elements[i].key, "ccache") == 0) { + ret = krb5_cc_resolve(ctx, cred_store->elements[i].value, + &ccache); + if (ret) goto done; + break; + } + } + } + if (!ccache) { + ret = krb5_cc_default(ctx, &ccache); + if (ret) goto done; + } ret = krb5_parse_name(ctx, creds->desired_name.display_name.octet_string_val, @@ -497,6 +511,21 @@ OM_uint32 gssi_store_cred(OM_uint32 *minor_status, gss_OID_set *elements_stored, gss_cred_usage_t *cred_usage_stored) { + return gssi_store_cred_into(minor_status, input_cred_handle, input_usage, + desired_mech, overwrite_cred, default_cred, + NULL, elements_stored, cred_usage_stored); +} + +OM_uint32 gssi_store_cred_into(OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ struct gpp_cred_handle *cred = NULL; OM_uint32 maj, min; @@ -509,14 +538,14 @@ OM_uint32 gssi_store_cred(OM_uint32 *minor_status, cred = (struct gpp_cred_handle *)input_cred_handle; if (cred->remote) { - maj = gpp_store_remote_creds(&min, cred->remote); + maj = gpp_store_remote_creds(&min, cred_store, cred->remote); goto done; } - maj = gss_store_cred(&min, cred->local, input_usage, - gpp_special_mech(desired_mech), - overwrite_cred, default_cred, - elements_stored, cred_usage_stored); + maj = gss_store_cred_into(&min, cred->local, input_usage, + gpp_special_mech(desired_mech), + overwrite_cred, default_cred, cred_store, + elements_stored, cred_usage_stored); done: *minor_status = gpp_map_error(min); return maj; diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index d7ab0b4..ac491e6 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -81,6 +81,16 @@ OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, gss_OID_set *actual_mechs, OM_uint32 *time_rec); +OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + OM_uint32 gssi_add_cred(OM_uint32 *minor_status, const gss_cred_id_t input_cred_handle, const gss_name_t desired_name, @@ -93,6 +103,19 @@ OM_uint32 gssi_add_cred(OM_uint32 *minor_status, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec); +OM_uint32 gssi_add_cred_from(OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + const gss_name_t desired_name, + const gss_OID desired_mech, + gss_cred_usage_t cred_usage, + OM_uint32 initiator_time_req, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec); + OM_uint32 gssi_acquire_cred_with_password(OM_uint32 *minor_status, const gss_name_t desired_name, const gss_buffer_t password, @@ -153,6 +176,16 @@ OM_uint32 gssi_store_cred(OM_uint32 *minor_status, gss_OID_set *elements_stored, gss_cred_usage_t *cred_usage_stored); +OM_uint32 gssi_store_cred_into(OM_uint32 *minor_status, + const gss_cred_id_t input_cred_handle, + gss_cred_usage_t input_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored); + OM_uint32 gssi_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle); From 126bd3a24dbae8a29fbf5dc2fcf2b431356e4870 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Dec 02 2016 16:13:38 +0000 Subject: [PATCH 2/4] Make sure to pass on request for delegated creds Signed-off-by: Simo Sorce --- diff --git a/proxy/src/client/gpm_accept_sec_context.c b/proxy/src/client/gpm_accept_sec_context.c index 375ee17..ef5e79c 100644 --- a/proxy/src/client/gpm_accept_sec_context.c +++ b/proxy/src/client/gpm_accept_sec_context.c @@ -50,6 +50,11 @@ OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status, } } + /* check if we want delegated creds */ + if (delegated_cred_handle) { + arg->ret_deleg_cred = true; + } + /* execute proxy request */ ret = gpm_make_call(GSSX_ACCEPT_SEC_CONTEXT, &uarg, &ures); if (ret) { From 45257233b76f75a2e55a231510428c0ecab80ca2 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Dec 05 2016 21:03:50 +0000 Subject: [PATCH 3/4] In acquire_cred_from, probe for remote creds If the calling application is passing in a cred_store, it's either one of two cases: - The application previously stored credentials in a ccache and now wants to use them. - The application has access to specific keys and wants to acquire a local credential. In the first case we can only work with a remote call as a local mechanism wouldn't know what to do with remote creds. In the latter calling the remote code would make no sense as we have local credentials. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c index dade19c..1444728 100644 --- a/proxy/src/mechglue/gpp_acquire_cred.c +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -87,6 +87,7 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, enum gpp_behavior behavior; struct gpp_name_handle *name; struct gpp_cred_handle *out_cred_handle = NULL; + struct gssx_cred *in_cred_remote = NULL; OM_uint32 maj, min; OM_uint32 tmaj, tmin; @@ -110,6 +111,33 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, name = (struct gpp_name_handle *)desired_name; behavior = gpp_get_behavior(); + /* if a cred_store option is passed in, check if it references + * valid credentials, if so switch behavior appropriately */ + if (cred_store) { + for (unsigned i = 0; i < cred_store->count; i++) { + if (strcmp(cred_store->elements[i].key, "ccache") == 0) { + gssx_cred remote = {0}; + maj = gppint_retrieve_remote_creds(&min, + cred_store->elements[i].value, NULL, &remote); + if (maj == GSS_S_COMPLETE) { + in_cred_remote = malloc(sizeof(gssx_cred)); + if (!in_cred_remote) { + maj = GSS_S_FAILURE; + min = ENOMEM; + goto done; + } + *in_cred_remote = remote; + break; + } + } + } + if (in_cred_remote) { + behavior = GPP_REMOTE_ONLY; + } else { + behavior = GPP_LOCAL_ONLY; + } + } + /* See if we should try local first */ if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { @@ -134,7 +162,7 @@ OM_uint32 gssi_acquire_cred_from(OM_uint32 *minor_status, } } - maj = gpm_acquire_cred(&min, NULL, + maj = gpm_acquire_cred(&min, in_cred_remote, name ? name->remote : NULL, time_req, desired_mechs, @@ -160,6 +188,10 @@ done: maj = tmaj; min = tmin; } + if (in_cred_remote) { + xdr_free((xdrproc_t)xdr_gssx_cred, (char *)in_cred_remote); + free(in_cred_remote); + } if (maj == GSS_S_COMPLETE) { *output_cred_handle = (gss_cred_id_t)out_cred_handle; } else { diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index a0f28c2..c1241bb 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -79,8 +79,8 @@ done: return ret ? GSS_S_FAILURE : GSS_S_COMPLETE; } -static uint32_t retrieve_remote_creds(uint32_t *min, gssx_name *name, - gssx_cred *creds) +OM_uint32 gppint_retrieve_remote_creds(uint32_t *min, const char *ccache_name, + gssx_name *name, gssx_cred *creds) { krb5_context ctx = NULL; krb5_ccache ccache = NULL; @@ -96,7 +96,11 @@ static uint32_t retrieve_remote_creds(uint32_t *min, gssx_name *name, ret = krb5_init_context(&ctx); if (ret) goto done; - ret = krb5_cc_default(ctx, &ccache); + if (ccache_name) { + ret = krb5_cc_resolve(ctx, ccache_name, &ccache); + } else { + ret = krb5_cc_default(ctx, &ccache); + } if (ret) goto done; if (name) { @@ -203,7 +207,9 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, memset(&remote, 0, sizeof(gssx_cred)); /* We intentionally ignore failures as finding creds is optional */ - maj = retrieve_remote_creds(&min, name ? name->remote : NULL, &remote); + maj = gppint_retrieve_remote_creds(&min, NULL, + name ? name->remote : NULL, + &remote); if (maj == GSS_S_COMPLETE) { premote = &remote; } diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index ac491e6..d32f2bc 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -136,6 +136,9 @@ OM_uint32 gssi_acquire_cred_impersonate_name(OM_uint32 *minor_status, gss_OID_set *actual_mechs, OM_uint32 *time_rec); +OM_uint32 gppint_retrieve_remote_creds(uint32_t *min, const char *ccache_name, + gssx_name *name, gssx_cred *creds); + OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, enum gpp_behavior behavior, struct gpp_name_handle *name, From 7f3ab1c72cb5c2bdcd0f2de7c644d4fec3d29d57 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Dec 05 2016 23:33:02 +0000 Subject: [PATCH 4/4] Always initialize ccache when storing. If we do not initialize the ccache additional entries will pile up and the code that retrieves the encrypted credentials will end up sourcing old, expired creds instead of the latest ones. Plues storage size may grow indefinitely. Signed-off-by: Simo Sorce --- diff --git a/proxy/src/mechglue/gpp_creds.c b/proxy/src/mechglue/gpp_creds.c index c1241bb..c1506e6 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -58,14 +58,10 @@ uint32_t gpp_store_remote_creds(uint32_t *min, } cred.ticket.length = xdr_getpos(&xdrctx); - ret = krb5_cc_store_cred(ctx, ccache, &cred); - - if (ret == KRB5_FCC_NOFILE) { - /* If a ccache does not exit, try to create one */ - ret = krb5_cc_initialize(ctx, ccache, cred.client); - if (ret) goto done; - - /* and try again to store the cred */ + /* Always initialize and destroy any existing contents to avoid pileup of + * entries */ + ret = krb5_cc_initialize(ctx, ccache, cred.client); + if (ret == 0) { ret = krb5_cc_store_cred(ctx, ccache, &cred); }