diff options
Diffstat (limited to 'proxy/src')
-rw-r--r-- | proxy/src/client/gpm_acquire_cred.c | 33 | ||||
-rw-r--r-- | proxy/src/client/gssapi_gpm.h | 2 | ||||
-rw-r--r-- | proxy/src/gp_common.h | 3 | ||||
-rw-r--r-- | proxy/src/gp_creds.c | 84 | ||||
-rw-r--r-- | proxy/src/gp_rpc_accept_sec_context.c | 2 | ||||
-rw-r--r-- | proxy/src/gp_rpc_acquire_cred.c | 9 | ||||
-rw-r--r-- | proxy/src/gp_rpc_creds.h | 8 | ||||
-rw-r--r-- | proxy/src/gp_rpc_init_sec_context.c | 2 | ||||
-rw-r--r-- | proxy/src/mechglue/gpp_acquire_cred.c | 130 | ||||
-rw-r--r-- | proxy/src/mechglue/gpp_creds.c | 4 | ||||
-rw-r--r-- | proxy/src/mechglue/gss_plugin.h | 10 |
11 files changed, 261 insertions, 26 deletions
diff --git a/proxy/src/client/gpm_acquire_cred.c b/proxy/src/client/gpm_acquire_cred.c index c0b16cb..a2ac068 100644 --- a/proxy/src/client/gpm_acquire_cred.c +++ b/proxy/src/client/gpm_acquire_cred.c @@ -45,10 +45,12 @@ static int gpmint_cred_to_actual_mechs(gssx_cred *c, gss_OID_set *a) } OM_uint32 gpm_acquire_cred(OM_uint32 *minor_status, + gssx_cred *in_cred_handle, gssx_name *desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, + bool impersonate, gssx_cred **output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec) @@ -72,6 +74,7 @@ OM_uint32 gpm_acquire_cred(OM_uint32 *minor_status, /* ignore call_ctx for now */ + arg->input_cred_handle = in_cred_handle; arg->desired_name = desired_name; if (desired_mechs) { @@ -85,6 +88,33 @@ OM_uint32 gpm_acquire_cred(OM_uint32 *minor_status, arg->time_req = time_req; arg->cred_usage = gp_conv_cred_usage_to_gssx(cred_usage); + /* impersonate calls use input cred and a special option */ + if (impersonate) { + gssx_option *opt; + arg->options.options_val = calloc(1, sizeof(gssx_option)); + if (!arg->options.options_val) { + ret_maj = GSS_S_FAILURE; + ret_min = ENOMEM; + goto done; + } + arg->options.options_len = 1; + opt = &arg->options.options_val[0]; + opt->option.octet_string_val = strdup(ACQUIRE_TYPE_OPTION); + if (!opt->option.octet_string_val) { + ret_maj = GSS_S_FAILURE; + ret_min = ENOMEM; + goto done; + } + opt->option.octet_string_len = sizeof(ACQUIRE_TYPE_OPTION); + opt->value.octet_string_val = strdup(ACQUIRE_IMPERSONATE_NAME); + if (!opt->value.octet_string_val) { + ret_maj = GSS_S_FAILURE; + ret_min = ENOMEM; + goto done; + } + opt->value.octet_string_len = sizeof(ACQUIRE_IMPERSONATE_NAME); + } + /* execute proxy request */ ret = gpm_make_call(GSSX_ACQUIRE_CRED, &uarg, &ures); if (ret) { @@ -133,8 +163,9 @@ OM_uint32 gpm_acquire_cred(OM_uint32 *minor_status, ret_min = 0; done: - /* desired_name is passed in, don't let gpm_free_xdrs free it */ + /* don't let gpm_free_xdrs free variables passed in */ arg->desired_name = NULL; + arg->input_cred_handle = NULL; gpm_free_xdrs(GSSX_ACQUIRE_CRED, &uarg, &ures); *minor_status = ret_min; return ret_maj; diff --git a/proxy/src/client/gssapi_gpm.h b/proxy/src/client/gssapi_gpm.h index b0a75d0..667b0e0 100644 --- a/proxy/src/client/gssapi_gpm.h +++ b/proxy/src/client/gssapi_gpm.h @@ -53,10 +53,12 @@ OM_uint32 gpm_delete_sec_context(OM_uint32 *minor_status, gss_buffer_t output_token); OM_uint32 gpm_acquire_cred(OM_uint32 *minor_status, + gssx_cred *imp_cred_handle, gssx_name *desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, + bool impersonate, gssx_cred **output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec); diff --git a/proxy/src/gp_common.h b/proxy/src/gp_common.h index 25a89b7..5b9b9b2 100644 --- a/proxy/src/gp_common.h +++ b/proxy/src/gp_common.h @@ -114,4 +114,7 @@ do { \ } \ } while(0) +#define ACQUIRE_TYPE_OPTION "acquire_type" +#define ACQUIRE_IMPERSONATE_NAME "impersonate_name" + #endif /* _GP_COMMON_H_ */ diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c index 2a747a6..c28c10a 100644 --- a/proxy/src/gp_creds.c +++ b/proxy/src/gp_creds.c @@ -192,9 +192,31 @@ static void free_cred_store_elements(gss_key_value_set_desc *cs) safefree(cs->elements); } +int gp_get_acquire_type(struct gssx_arg_acquire_cred *arg) +{ + struct gssx_option *val = NULL; + + gp_options_find(val, arg->options, + ACQUIRE_TYPE_OPTION, sizeof(ACQUIRE_TYPE_OPTION)); + if (val) { + if (gp_option_value_match(val, ACQUIRE_IMPERSONATE_NAME, + sizeof(ACQUIRE_IMPERSONATE_NAME))) { + return ACQ_IMPNAME; + } else { + return -1; + } + } + + return ACQ_NORMAL; +} + static bool try_impersonate(struct gp_service *svc, - gss_cred_usage_t cred_usage) + gss_cred_usage_t cred_usage, + enum gp_aqcuire_cred_type acquire_type) { + if (acquire_type == ACQ_IMPNAME) { + return true; + } if (!svc->impersonate) { return false; } @@ -276,7 +298,7 @@ static int gp_get_cred_environment(struct gp_call_ctx *gpcall, /* impersonation case (only for initiation) */ if (user_requested) { - if (try_impersonate(svc, *cred_usage)) { + if (try_impersonate(svc, *cred_usage, ACQ_NORMAL)) { /* When impersonating we want to use the service keytab to * acquire initial credential ... */ use_service_keytab = true; @@ -394,6 +416,7 @@ done: uint32_t gp_add_krb5_creds(uint32_t *min, struct gp_call_ctx *gpcall, + enum gp_aqcuire_cred_type acquire_type, gss_cred_id_t in_cred, gssx_name *desired_name, gss_cred_usage_t cred_usage, @@ -409,7 +432,7 @@ uint32_t gp_add_krb5_creds(uint32_t *min, uint32_t discard; gss_name_t req_name = GSS_C_NO_NAME; gss_OID_set_desc desired_mechs = { 1, &gp_mech_krb5 }; - gss_key_value_set_desc cred_store; + gss_key_value_set_desc cred_store = { 0 }; gss_cred_id_t impersonator_cred = GSS_C_NO_CREDENTIAL; gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT; @@ -417,6 +440,7 @@ uint32_t gp_add_krb5_creds(uint32_t *min, gss_name_t target_name = GSS_C_NO_NAME; gss_buffer_desc init_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc accept_token = GSS_C_EMPTY_BUFFER; + gss_cred_id_t input_cred; if (!min || !output_cred_handle) { return GSS_S_CALL_INACCESSIBLE_WRITE; @@ -428,7 +452,7 @@ uint32_t gp_add_krb5_creds(uint32_t *min, *actual_mechs = GSS_C_NO_OID_SET; } - if (in_cred != GSS_C_NO_CREDENTIAL) { + if (in_cred != GSS_C_NO_CREDENTIAL && acquire_type != ACQ_IMPNAME) { /* we can't yet handle adding to an existing credential due to * the way gss_krb5_import_cred works. This limitation should * be removed by adding a gssapi extension that superceedes this @@ -436,14 +460,18 @@ uint32_t gp_add_krb5_creds(uint32_t *min, return GSS_S_CRED_UNAVAIL; } - ret_min = gp_get_cred_environment(gpcall, desired_name, &req_name, - &cred_usage, &cred_store); + if (acquire_type == ACQ_NORMAL) { + ret_min = gp_get_cred_environment(gpcall, desired_name, &req_name, + &cred_usage, &cred_store); + } else if (desired_name) { + ret_maj = gp_conv_gssx_to_name(&ret_min, desired_name, &req_name); + } if (ret_min) { ret_maj = GSS_S_CRED_UNAVAIL; goto done; } - if (!try_impersonate(gpcall->service, cred_usage)) { + if (!try_impersonate(gpcall->service, cred_usage, acquire_type)) { ret_maj = gss_acquire_cred_from(&ret_min, req_name, GSS_C_INDEFINITE, &desired_mechs, cred_usage, &cred_store, output_cred_handle, @@ -452,22 +480,35 @@ uint32_t gp_add_krb5_creds(uint32_t *min, goto done; } } else { /* impersonation */ - ret_maj = gss_acquire_cred_from(&ret_min, GSS_C_NO_NAME, - GSS_C_INDEFINITE, - &desired_mechs, GSS_C_BOTH, - &cred_store, &impersonator_cred, - NULL, NULL); - if (ret_maj) { + switch (acquire_type) { + case ACQ_NORMAL: + ret_maj = gss_acquire_cred_from(&ret_min, GSS_C_NO_NAME, + GSS_C_INDEFINITE, + &desired_mechs, GSS_C_BOTH, + &cred_store, &impersonator_cred, + NULL, NULL); + if (ret_maj) { + goto done; + } + input_cred = impersonator_cred; + break; + case ACQ_IMPNAME: + input_cred = in_cred; + break; + default: + ret_maj = GSS_S_FAILURE; + ret_min = EFAULT; goto done; } - ret_maj = gss_inquire_cred(&ret_min, impersonator_cred, + + ret_maj = gss_inquire_cred(&ret_min, input_cred, &target_name, NULL, NULL, NULL); if (ret_maj) { goto done; } ret_maj = gss_acquire_cred_impersonate_name(&ret_min, - impersonator_cred, + input_cred, req_name, GSS_C_INDEFINITE, &desired_mechs, @@ -477,6 +518,14 @@ uint32_t gp_add_krb5_creds(uint32_t *min, if (ret_maj) { goto done; } + + if (acquire_type == ACQ_IMPNAME) { + /* we are done here */ + *output_cred_handle = user_cred; + user_cred = GSS_C_NO_CREDENTIAL; + goto done; + } + /* now acquire credentials for impersonated user to self */ ret_maj = gss_init_sec_context(&ret_min, user_cred, &initiator_context, target_name, &gp_mech_krb5, @@ -488,9 +537,9 @@ uint32_t gp_add_krb5_creds(uint32_t *min, if (ret_maj) { goto done; } - /* accept context to be able to store delgated credentials */ + /* accept context to be able to store delegated credentials */ ret_maj = gss_accept_sec_context(&ret_min, &acceptor_context, - impersonator_cred, &init_token, + input_cred, &init_token, GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL, &accept_token, NULL, NULL, output_cred_handle); @@ -530,6 +579,7 @@ done: gss_delete_sec_context(&discard, &initiator_context, NULL); gss_release_buffer(&discard, &init_token); gss_release_buffer(&discard, &accept_token); + gss_release_name(&discard, &req_name); *min = ret_min; return ret_maj; diff --git a/proxy/src/gp_rpc_accept_sec_context.c b/proxy/src/gp_rpc_accept_sec_context.c index 7b9d5df..4bb892b 100644 --- a/proxy/src/gp_rpc_accept_sec_context.c +++ b/proxy/src/gp_rpc_accept_sec_context.c @@ -56,7 +56,7 @@ int gp_accept_sec_context(struct gp_call_ctx *gpcall, if (ach == GSS_C_NO_CREDENTIAL) { ret_maj = gp_add_krb5_creds(&ret_min, gpcall, - NULL, NULL, + ACQ_NORMAL, NULL, NULL, GSS_C_ACCEPT, 0, 0, &ach, diff --git a/proxy/src/gp_rpc_acquire_cred.c b/proxy/src/gp_rpc_acquire_cred.c index e9deabf..7f40c64 100644 --- a/proxy/src/gp_rpc_acquire_cred.c +++ b/proxy/src/gp_rpc_acquire_cred.c @@ -18,6 +18,7 @@ int gp_acquire_cred(struct gp_call_ctx *gpcall, gss_cred_usage_t cred_usage; gss_cred_id_t out_cred = GSS_C_NO_CREDENTIAL; gss_cred_id_t *add_out_cred = NULL; + int acquire_type = ACQ_NORMAL; int ret; int i; @@ -32,6 +33,13 @@ int gp_acquire_cred(struct gp_call_ctx *gpcall, if (ret_maj) { goto done; } + + acquire_type = gp_get_acquire_type(aca); + if (acquire_type == -1) { + ret_maj = GSS_S_FAILURE; + ret_min = EINVAL; + goto done; + } } if (aca->add_cred_to_input_handle) { @@ -93,6 +101,7 @@ int gp_acquire_cred(struct gp_call_ctx *gpcall, if (gss_oid_equal(desired_mech, gss_mech_krb5)) { ret_maj = gp_add_krb5_creds(&ret_min, gpcall, + acquire_type, in_cred, aca->desired_name, cred_usage, diff --git a/proxy/src/gp_rpc_creds.h b/proxy/src/gp_rpc_creds.h index 98f2eaf..ead6afc 100644 --- a/proxy/src/gp_rpc_creds.h +++ b/proxy/src/gp_rpc_creds.h @@ -12,8 +12,16 @@ struct gp_call_ctx; bool gp_creds_allowed_mech(struct gp_call_ctx *gpcall, gss_OID desired_mech); uint32_t gp_get_supported_mechs(uint32_t *min, gss_OID_set *set); +struct gssx_arg_acquire_cred; +enum gp_aqcuire_cred_type { + ACQ_NORMAL = 0, + ACQ_IMPNAME = 1, +}; +int gp_get_acquire_type(struct gssx_arg_acquire_cred *arg); + uint32_t gp_add_krb5_creds(uint32_t *min, struct gp_call_ctx *gpcall, + enum gp_aqcuire_cred_type acquire_type, gss_cred_id_t in_cred, gssx_name *desired_name, gss_cred_usage_t cred_usage, diff --git a/proxy/src/gp_rpc_init_sec_context.c b/proxy/src/gp_rpc_init_sec_context.c index 563275d..d607b07 100644 --- a/proxy/src/gp_rpc_init_sec_context.c +++ b/proxy/src/gp_rpc_init_sec_context.c @@ -84,7 +84,7 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall, if (!isca->cred_handle) { if (gss_oid_equal(mech_type, gss_mech_krb5)) { ret_maj = gp_add_krb5_creds(&ret_min, gpcall, - NULL, NULL, + ACQ_NORMAL, NULL, NULL, GSS_C_INITIATE, time_req, 0, &ich, NULL, NULL, NULL); diff --git a/proxy/src/mechglue/gpp_acquire_cred.c b/proxy/src/mechglue/gpp_acquire_cred.c index 3591e8a..faf5914 100644 --- a/proxy/src/mechglue/gpp_acquire_cred.c +++ b/proxy/src/mechglue/gpp_acquire_cred.c @@ -3,6 +3,7 @@ #include "gss_plugin.h" static OM_uint32 acquire_local(OM_uint32 *minor_status, + struct gpp_cred_handle *imp_cred_handle, struct gpp_name_handle *name, OM_uint32 time_req, const gss_OID_set desired_mechs, @@ -29,6 +30,19 @@ static OM_uint32 acquire_local(OM_uint32 *minor_status, } } + if (imp_cred_handle) { + maj = gss_acquire_cred_impersonate_name(&min, + imp_cred_handle->local, + name ? name->local : NULL, + time_req, + special_mechs, + cred_usage, + &out_cred_handle->local, + actual_mechs, + time_rec); + goto done; + } + maj = gss_acquire_cred(&min, name ? name->local : NULL, time_req, @@ -82,7 +96,8 @@ OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, /* See if we should try local first */ if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { - maj = acquire_local(&min, name, time_req, desired_mechs, cred_usage, + maj = acquire_local(&min, NULL, name, + time_req, desired_mechs, cred_usage, out_cred_handle, actual_mechs, time_rec); if (maj == GSS_S_COMPLETE || behavior == GPP_LOCAL_ONLY) { @@ -102,11 +117,11 @@ OM_uint32 gssi_acquire_cred(OM_uint32 *minor_status, } } - maj = gpm_acquire_cred(&min, + maj = gpm_acquire_cred(&min, NULL, name ? name->remote : NULL, time_req, desired_mechs, - cred_usage, + cred_usage, false, &out_cred_handle->remote, actual_mechs, time_rec); @@ -116,7 +131,8 @@ 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, name, time_req, desired_mechs, cred_usage, + maj = acquire_local(&min, NULL, name, + time_req, desired_mechs, cred_usage, out_cred_handle, actual_mechs, time_rec); } @@ -310,3 +326,109 @@ done: (void)gss_release_oid_set(&min, &special_mechs); return maj; } + +OM_uint32 gssi_acquire_cred_impersonate_name(OM_uint32 *minor_status, + gss_cred_id_t *imp_cred_handle, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + 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 *impersonator_cred_handle = NULL; + struct gpp_cred_handle *out_cred_handle = NULL; + OM_uint32 maj, min; + OM_uint32 tmaj, tmin; + + GSSI_TRACE(); + + if (!imp_cred_handle) { + *minor_status = gpp_map_error(EINVAL); + return GSS_S_NO_CRED; + } + + impersonator_cred_handle = (struct gpp_cred_handle *)imp_cred_handle; + + if (!output_cred_handle) { + *minor_status = gpp_map_error(EINVAL); + return GSS_S_FAILURE; + } + + tmaj = GSS_S_COMPLETE; + tmin = 0; + + out_cred_handle = calloc(1, sizeof(struct gpp_cred_handle)); + if (!out_cred_handle) { + maj = GSS_S_FAILURE; + min = ENOMEM; + goto done; + } + + name = (struct gpp_name_handle *)desired_name; + behavior = gpp_get_behavior(); + + /* See if we should try local first */ + if (behavior == GPP_LOCAL_ONLY || behavior == GPP_LOCAL_FIRST) { + + maj = acquire_local(&min, impersonator_cred_handle, name, + time_req, desired_mechs, cred_usage, + out_cred_handle, actual_mechs, time_rec); + + if (maj == GSS_S_COMPLETE || behavior == GPP_LOCAL_ONLY) { + goto done; + } + + /* not successful, save actual local error if remote fallback fails */ + tmaj = maj; + tmin = min; + } + + /* Then try with remote */ + if (name && name->local && !name->remote) { + maj = gpp_local_to_name(&min, name->local, &name->remote); + if (maj) { + goto done; + } + } + + maj = gpm_acquire_cred(&min, + impersonator_cred_handle->remote, + name ? name->remote : NULL, + time_req, + desired_mechs, + cred_usage, + true, + &out_cred_handle->remote, + actual_mechs, + time_rec); + if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) { + goto done; + } + + 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, + out_cred_handle, actual_mechs, time_rec); + } + +done: + if (maj != GSS_S_COMPLETE && + maj != GSS_S_CONTINUE_NEEDED && + tmaj != GSS_S_COMPLETE) { + maj = tmaj; + min = tmin; + } + if (maj == GSS_S_COMPLETE) { + *output_cred_handle = (gss_cred_id_t)out_cred_handle; + } else { + free(out_cred_handle); + } + *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 fab987a..dcfc896 100644 --- a/proxy/src/mechglue/gpp_creds.c +++ b/proxy/src/mechglue/gpp_creds.c @@ -67,8 +67,8 @@ OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, /* Then try with remote */ if (behavior == GPP_REMOTE_ONLY || behavior == GPP_REMOTE_FIRST) { - maj = gpm_acquire_cred(&min, - NULL, 0, NULL, cred_usage, + maj = gpm_acquire_cred(&min, NULL, + NULL, 0, NULL, cred_usage, false, &cred->remote, NULL, NULL); if (maj == GSS_S_COMPLETE || behavior == GPP_REMOTE_ONLY) { diff --git a/proxy/src/mechglue/gss_plugin.h b/proxy/src/mechglue/gss_plugin.h index cc5f01b..6df4c6a 100644 --- a/proxy/src/mechglue/gss_plugin.h +++ b/proxy/src/mechglue/gss_plugin.h @@ -102,6 +102,16 @@ OM_uint32 gssi_acquire_cred_with_password(OM_uint32 *minor_status, gss_OID_set *actual_mechs, OM_uint32 *time_rec); +OM_uint32 gssi_acquire_cred_impersonate_name(OM_uint32 *minor_status, + gss_cred_id_t *imp_cred_handle, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + OM_uint32 gppint_get_def_creds(OM_uint32 *minor_status, enum gpp_behavior behavior, struct gpp_name_handle *name, |