commit 9dc75551cb8cc4c03f7e0fe5e8a705ed678079f4 Author: ghudson Date: Wed Dec 7 19:38:13 2011 +0000 ticket: 7046 subject: Allow S4U2Proxy delegated credentials to be saved The initial implementation of client-side S4U2Proxy support did not allow delegated proxy credentials to be stored (gss_store_cred would error out, and gss_krb5_copy_ccache would generate a non-working cache). To make this work, we save the impersonator name in a cache config variable and in a cred structure field (replacing the proxy_cred flag), and make the default principal of the proxy cache the subject principal as the caller would expect for a regular delegated cred. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25529 dc483132-0cff-0310-8789-dd5450dbe970 diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 514e2ea..b25c159 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -273,7 +273,10 @@ typedef INT64_TYPE krb5_int64; #define KRB5_CONF_V4_INSTANCE_CONVERT "v4_instance_convert" #define KRB5_CONF_V4_REALM "v4_realm" #define KRB5_CONF_ASTERISK "*" + +/* Cache configuration variables */ #define KRB5_CONF_FAST_AVAIL "fast_avail" +#define KRB5_CONF_PROXY_IMPERSONATOR "proxy_impersonator" /* Error codes used in KRB_ERROR protocol messages. Return values of library routines are based on a different error table diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c index c815b35..c08e059 100644 --- a/src/lib/gssapi/krb5/acquire_cred.c +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -417,6 +417,34 @@ prep_ccache(krb5_context context, krb5_gss_cred_id_rec *cred, return 0; } +/* If an impersonator config entry exists in ccache, set *impersonator_out to + * the parsed principal. Otherwise set *impersonator_out to NULL. */ +static krb5_error_code +get_impersonator(krb5_context context, krb5_ccache ccache, + krb5_principal *impersonator_out) +{ + krb5_error_code code; + krb5_data data = empty_data(), data0 = empty_data(); + + *impersonator_out = NULL; + + code = krb5_cc_get_config(context, ccache, NULL, + KRB5_CONF_PROXY_IMPERSONATOR, &data); + if (code) + return (code == KRB5_CC_NOTFOUND) ? 0 : code; + + code = krb5int_copy_data_contents_add0(context, &data, &data0); + if (code) + goto cleanup; + + code = krb5_parse_name(context, data0.data, impersonator_out); + +cleanup: + krb5_free_data_contents(context, &data); + krb5_free_data_contents(context, &data0); + return code; +} + /* Check ccache and scan it for its expiry time. On success, cred takes * ownership of ccache. */ static krb5_error_code @@ -493,6 +521,10 @@ scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred, goto cleanup; } + code = get_impersonator(context, ccache, &cred->impersonator); + if (code) + goto cleanup; + (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); cred->ccache = ccache; @@ -622,6 +654,7 @@ acquire_cred(OM_uint32 *minor_status, cred->usage = args->cred_usage; cred->name = NULL; + cred->impersonator = NULL; cred->iakerb_mech = args->iakerb; cred->default_identity = (name == NULL); #ifndef LEAN_CLIENT diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index 016a2e6..6b7d530 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -172,7 +172,7 @@ typedef struct _krb5_gss_cred_id_rec { /* name/type of credential */ gss_cred_usage_t usage; krb5_gss_name_t name; - unsigned int proxy_cred : 1; + krb5_principal impersonator; unsigned int default_identity : 1; unsigned int iakerb_mech : 1; unsigned int destroy_ccache : 1; diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 1b8120c..d7b9ffa 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -129,7 +129,6 @@ static krb5_error_code get_credentials(context, cred, server, now, krb5_error_code code; krb5_creds in_creds, evidence_creds, *result_creds = NULL; krb5_flags flags = 0; - krb5_principal cc_princ = NULL; *out_creds = NULL; @@ -140,16 +139,13 @@ static krb5_error_code get_credentials(context, cred, server, now, assert(cred->name != NULL); - if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ))) - goto cleanup; - /* * Do constrained delegation if we have proxy credentials and * we're not trying to get a ticket to ourselves (in which case * we can just use the S4U2Self or evidence ticket directly). */ - if (cred->proxy_cred && - !krb5_principal_compare(context, cc_princ, server->princ)) { + if (cred->impersonator && + !krb5_principal_compare(context, cred->impersonator, server->princ)) { krb5_creds mcreds; flags |= KRB5_GC_CANONICALIZE | @@ -159,20 +155,18 @@ static krb5_error_code get_credentials(context, cred, server, now, memset(&mcreds, 0, sizeof(mcreds)); mcreds.magic = KV5M_CREDS; - mcreds.times.endtime = cred->tgt_expire; - mcreds.server = cc_princ; + mcreds.server = cred->impersonator; mcreds.client = cred->name->princ; code = krb5_cc_retrieve_cred(context, cred->ccache, - KRB5_TC_MATCH_TIMES | KRB5_TC_MATCH_AUTHDATA, - &mcreds, + KRB5_TC_MATCH_AUTHDATA, &mcreds, &evidence_creds); if (code) goto cleanup; assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE); - in_creds.client = cc_princ; + in_creds.client = cred->impersonator; in_creds.second_ticket = evidence_creds.ticket; } else { in_creds.client = cred->name->princ; @@ -255,7 +249,6 @@ static krb5_error_code get_credentials(context, cred, server, now, cleanup: krb5_free_authdata(context, in_creds.authdata); - krb5_free_principal(context, cc_princ); krb5_free_cred_contents(context, &evidence_creds); krb5_free_creds(context, result_creds); diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c index 5b2ea2f..4fd3694 100644 --- a/src/lib/gssapi/krb5/rel_cred.c +++ b/src/lib/gssapi/krb5/rel_cred.c @@ -71,6 +71,8 @@ krb5_gss_release_cred(minor_status, cred_handle) if (cred->name) kg_release_name(context, &cred->name); + krb5_free_principal(context, cred->impersonator); + if (cred->req_enctypes) free(cred->req_enctypes); diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c index 4ac2ce3..4b37c5a 100644 --- a/src/lib/gssapi/krb5/s4u_gss_glue.c +++ b/src/lib/gssapi/krb5/s4u_gss_glue.c @@ -169,6 +169,39 @@ krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status, } +/* + * Set up cred to be an S4U2Proxy credential by copying in the impersonator's + * creds, setting a cache config variable with the impersonator principal name, + * and saving the impersonator principal name in the cred structure. + */ +static krb5_error_code +make_proxy_cred(krb5_context context, krb5_gss_cred_id_t cred, + krb5_gss_cred_id_t impersonator_cred) +{ + krb5_error_code code; + krb5_data data; + char *str; + + code = krb5_cc_copy_creds(context, impersonator_cred->ccache, + cred->ccache); + if (code) + return code; + + code = krb5_unparse_name(context, impersonator_cred->name->princ, &str); + if (code) + return code; + + data = string2data(str); + code = krb5_cc_set_config(context, cred->ccache, NULL, + KRB5_CONF_PROXY_IMPERSONATOR, &data); + krb5_free_unparsed_name(context, str); + if (code) + return code; + + return krb5_copy_principal(context, impersonator_cred->name->princ, + &cred->impersonator); +} + OM_uint32 kg_compose_deleg_cred(OM_uint32 *minor_status, krb5_gss_cred_id_t impersonator_cred, @@ -187,7 +220,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, if (!kg_is_initiator_cred(impersonator_cred) || impersonator_cred->name == NULL || - impersonator_cred->proxy_cred) { + impersonator_cred->impersonator != NULL) { code = G_BAD_USAGE; goto cleanup; } @@ -208,14 +241,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, if (code != 0) goto cleanup; - /* - * Only return a "proxy" credential for use with constrained - * delegation if the subject credentials are forwardable. - * Submitting non-forwardable credentials to the KDC for use - * with constrained delegation will only return an error. - */ cred->usage = GSS_C_INITIATE; - cred->proxy_cred = !!(subject_creds->ticket_flags & TKT_FLG_FORWARDABLE); cred->tgt_expire = subject_creds->times.endtime; @@ -229,16 +255,18 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, goto cleanup; cred->destroy_ccache = 1; - code = krb5_cc_initialize(context, cred->ccache, - cred->proxy_cred ? impersonator_cred->name->princ : - subject_creds->client); + code = krb5_cc_initialize(context, cred->ccache, subject_creds->client); if (code != 0) goto cleanup; - if (cred->proxy_cred) { - /* Impersonator's TGT will be necessary for S4U2Proxy */ - code = krb5_cc_copy_creds(context, impersonator_cred->ccache, - cred->ccache); + /* + * Only return a "proxy" credential for use with constrained + * delegation if the subject credentials are forwardable. + * Submitting non-forwardable credentials to the KDC for use + * with constrained delegation will only return an error. + */ + if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) { + code = make_proxy_cred(context, cred, impersonator_cred); if (code != 0) goto cleanup; } diff --git a/src/lib/gssapi/krb5/store_cred.c b/src/lib/gssapi/krb5/store_cred.c index bff3cde..d587589 100644 --- a/src/lib/gssapi/krb5/store_cred.c +++ b/src/lib/gssapi/krb5/store_cred.c @@ -91,7 +91,7 @@ copy_initiator_creds(OM_uint32 *minor_status, kcred = (krb5_gss_cred_id_t)input_cred_handle; - if (kcred->ccache == NULL || kcred->proxy_cred) { + if (kcred->ccache == NULL) { *minor_status = KG_CCACHE_NOMATCH; major_status = GSS_S_DEFECTIVE_CREDENTIAL; goto cleanup; diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c index e87f249..46a9ae1 100644 --- a/src/lib/gssapi/krb5/val_cred.c +++ b/src/lib/gssapi/krb5/val_cred.c @@ -50,8 +50,7 @@ krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle, *minor_status = code; return(GSS_S_DEFECTIVE_CREDENTIAL); } - if (!cred->proxy_cred && - !krb5_principal_compare(context, princ, cred->name->princ)) { + if (!krb5_principal_compare(context, princ, cred->name->princ)) { k5_mutex_unlock(&cred->lock); *minor_status = KG_CCACHE_NOMATCH; return(GSS_S_DEFECTIVE_CREDENTIAL);