diff options
Diffstat (limited to 'src/lib/gssapi/krb5')
-rw-r--r-- | src/lib/gssapi/krb5/acquire_cred.c | 117 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/gssapiP_krb5.h | 4 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/iakerb.c | 20 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/init_sec_context.c | 37 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/inq_cred.c | 49 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/s4u_gss_glue.c | 5 |
6 files changed, 149 insertions, 83 deletions
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c index 50c8ef4ad2..c815b3590a 100644 --- a/src/lib/gssapi/krb5/acquire_cred.c +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -368,12 +368,25 @@ prep_ccache(krb5_context context, krb5_gss_cred_id_rec *cred, krb5_error_code code; krb5_principal ccache_princ; krb5_data password_data = make_data(password->value, password->length); + krb5_boolean eq; + const char *cctype; + krb5_ccache newcache = NULL; /* Check the ccache principal or initialize a new cache. */ code = krb5_cc_get_principal(context, ccache, &ccache_princ); if (code == 0) { - if (!krb5_principal_compare(context, ccache_princ, desired_princ)) - return KG_CCACHE_NOMATCH; + eq = krb5_principal_compare(context, ccache_princ, desired_princ); + krb5_free_principal(context, ccache_princ); + if (!eq) { + cctype = krb5_cc_get_type(context, ccache); + if (krb5_cc_support_switch(context, cctype)) { + /* Make a new ccache within the collection. */ + code = krb5_cc_new_unique(context, cctype, NULL, &newcache); + if (code) + return code; + } else + return KG_CCACHE_NOMATCH; + } } else if (code == KRB5_FCC_NOFILE) { /* Cache file does not exist; create and initialize one. */ code = krb5_cc_initialize(context, ccache, desired_princ); @@ -396,7 +409,11 @@ prep_ccache(krb5_context context, krb5_gss_cred_id_rec *cred, if (code) return code; - cred->ccache = ccache; + if (newcache) { + krb5_cc_close(context, ccache); + cred->ccache = newcache; + } else + cred->ccache = ccache; return 0; } @@ -523,7 +540,13 @@ acquire_init_cred(krb5_context context, #elif defined(USE_LEASH) code = get_ccache_leash(context, desired_princ, &ccache); #else - code = 0; + code = krb5_cc_cache_match(context, desired_princ, &ccache); + if (code == KRB5_CC_NOTFOUND && password != GSS_C_NO_BUFFER) { + /* Grab the default ccache for now; if it's not empty, prep_ccache + * will create a new one of the default type or error out. */ + krb5_clear_error_message(context); + code = krb5_cc_default(context, &ccache); + } #endif } else code = 0; @@ -531,25 +554,26 @@ acquire_init_cred(krb5_context context, *minor_status = code; return GSS_S_CRED_UNAVAIL; } - if (ccache == NULL) { - code = krb5int_cc_default(context, &ccache); + + if (ccache != NULL) { + if (password != GSS_C_NO_BUFFER && desired_princ != NULL) + code = prep_ccache(context, cred, ccache, desired_princ, password); + else + code = scan_ccache(context, cred, ccache, desired_princ); if (code != 0) { + krb5_cc_close(context, ccache); *minor_status = code; return GSS_S_CRED_UNAVAIL; } + cred->ccache = ccache; } - if (password != GSS_C_NO_BUFFER && desired_princ != NULL) - code = prep_ccache(context, cred, ccache, desired_princ, password); - else - code = scan_ccache(context, cred, ccache, desired_princ); - if (code != 0) { - krb5_cc_close(context, ccache); - *minor_status = code; - return GSS_S_CRED_UNAVAIL; - } + /* + * If the caller specified no ccache and no desired principal, leave + * cred->ccache and cred->name NULL. They will be resolved later by + * kg_cred_resolve(), possibly using the target principal name. + */ - cred->ccache = ccache; *minor_status = 0; return GSS_S_COMPLETE; } @@ -692,6 +716,67 @@ error_out: return ret; } +/* + * Resolve the name and ccache for an initiator credential if it has not yet + * been done. If specified, use the target name to pick an appropriate ccache + * within the collection. Validates cred_handle and leaves it locked on + * success. + */ +OM_uint32 +kg_cred_resolve(OM_uint32 *minor_status, krb5_context context, + gss_cred_id_t cred_handle, gss_name_t target_name) +{ + OM_uint32 maj; + krb5_error_code code; + krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)cred_handle; + krb5_gss_name_t tname = (krb5_gss_name_t)target_name; + krb5_ccache ccache = NULL; + krb5_principal client_princ = NULL; + + *minor_status = 0; + + maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context); + if (maj != 0) + return maj; + k5_mutex_assert_locked(&cred->lock); + + if (cred->ccache != NULL || cred->usage == GSS_C_ACCEPT) + return GSS_S_COMPLETE; + + /* Pick a credential cache. */ + if (tname != NULL) { + code = krb5_cc_select(context, tname->princ, &ccache, &client_princ); + if (code && code != KRB5_CC_NOTFOUND) + goto kerr; + } + if (ccache == NULL) { + /* + * Ideally we would get credentials for client_princ if it is set. At + * the moment, we just get the default ccache (obtaining credentials if + * the platform supports it) and check it against client_princ below. + */ + code = krb5int_cc_default(context, &ccache); + if (code) + goto kerr; + } + + code = scan_ccache(context, cred, ccache, client_princ); + if (code) { + krb5_cc_close(context, ccache); + goto kerr; + } + + krb5_free_principal(context, client_princ); + return GSS_S_COMPLETE; + +kerr: + krb5_free_principal(context, client_princ); + k5_mutex_unlock(&cred->lock); + save_error_info(code, context); + *minor_status = code; + return GSS_S_CRED_UNAVAIL; +} + OM_uint32 gss_krb5int_set_cred_rcache(OM_uint32 *minor_status, gss_cred_id_t *cred_handle, diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index f7aab88b82..08155e820f 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -478,6 +478,10 @@ krb5_to_gss_cred(krb5_context context, krb5_creds *creds, krb5_gss_cred_id_t *out_cred); +OM_uint32 +kg_cred_resolve(OM_uint32 *minor_status, krb5_context context, + gss_cred_id_t cred_handle, gss_name_t target_name); + /** declarations of internal name mechanism functions **/ OM_uint32 KRB5_CALLCONV krb5_gss_acquire_cred diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c index e0aede9fb2..84a96ac1bf 100644 --- a/src/lib/gssapi/krb5/iakerb.c +++ b/src/lib/gssapi/krb5/iakerb.c @@ -914,16 +914,7 @@ iakerb_gss_init_sec_context(OM_uint32 *minor_status, kname = (krb5_gss_name_t)target_name; - if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { - major_status = krb5_gss_validate_cred_1(minor_status, - claimant_cred_handle, - ctx->k5c); - if (GSS_ERROR(major_status)) - goto cleanup; - - cred_locked = TRUE; - kcred = (krb5_gss_cred_id_t)claimant_cred_handle; - } else { + if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { major_status = krb5_gss_acquire_cred(minor_status, NULL, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, @@ -931,9 +922,16 @@ iakerb_gss_init_sec_context(OM_uint32 *minor_status, &defcred, NULL, NULL); if (GSS_ERROR(major_status)) goto cleanup; - kcred = (krb5_gss_cred_id_t)defcred; + claimant_cred_handle = defcred; } + major_status = kg_cred_resolve(minor_status, ctx->k5c, + claimant_cred_handle, target_name); + if (GSS_ERROR(major_status)) + goto cleanup; + cred_locked = TRUE; + kcred = (krb5_gss_cred_id_t)claimant_cred_handle; + major_status = GSS_S_FAILURE; if (initialContextToken) { diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 0133bf084b..d62822e2d4 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -930,6 +930,7 @@ krb5_gss_init_sec_context_ext( krb5_gss_ctx_ext_t exts) { krb5_context context; + gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL; krb5_gss_cred_id_t cred; krb5_error_code kerr; OM_uint32 major_status; @@ -961,30 +962,25 @@ krb5_gss_init_sec_context_ext( /* verify the credential, or use the default */ /*SUPPRESS 29*/ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { - major_status = kg_get_defcred(minor_status, (gss_cred_id_t *)&cred); + major_status = kg_get_defcred(minor_status, &defcred); if (major_status && GSS_ERROR(major_status)) { if (*context_handle == GSS_C_NO_CONTEXT) krb5_free_context(context); return(major_status); } - } else { - major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle); - if (GSS_ERROR(major_status)) { - save_error_info(*minor_status, context); - if (*context_handle == GSS_C_NO_CONTEXT) - krb5_free_context(context); - return(major_status); - } - cred = (krb5_gss_cred_id_t) claimant_cred_handle; + claimant_cred_handle = defcred; } - kerr = k5_mutex_lock(&cred->lock); - if (kerr) { - if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) - krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred); - krb5_free_context(context); - *minor_status = kerr; - return GSS_S_FAILURE; + + major_status = kg_cred_resolve(minor_status, context, claimant_cred_handle, + target_name); + if (GSS_ERROR(major_status)) { + save_error_info(*minor_status, context); + krb5_gss_release_cred(&tmp_min_stat, &defcred); + if (*context_handle == GSS_C_NO_CONTEXT) + krb5_free_context(context); + return(major_status); } + cred = (krb5_gss_cred_id_t)claimant_cred_handle; /* verify the mech_type */ @@ -998,8 +994,7 @@ krb5_gss_init_sec_context_ext( mech_type = (gss_OID) gss_mech_iakerb; } else { k5_mutex_unlock(&cred->lock); - if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) - krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred); + krb5_gss_release_cred(minor_status, &defcred); *minor_status = 0; if (*context_handle == GSS_C_NO_CONTEXT) krb5_free_context(context); @@ -1036,9 +1031,7 @@ krb5_gss_init_sec_context_ext( too. */ } - if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) - krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t *)&cred); - + krb5_gss_release_cred(&tmp_min_stat, &defcred); return(major_status); } diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c index cc24e7a903..f523a545cf 100644 --- a/src/lib/gssapi/krb5/inq_cred.c +++ b/src/lib/gssapi/krb5/inq_cred.c @@ -83,14 +83,14 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, gss_OID_set *mechanisms; { krb5_context context; - krb5_gss_cred_id_t cred; + krb5_gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL, cred; krb5_error_code code; krb5_timestamp now; krb5_deltat lifetime; krb5_gss_name_t ret_name; krb5_principal princ; gss_OID_set mechs; - OM_uint32 ret; + OM_uint32 major, tmpmin, ret; ret = GSS_S_FAILURE; ret_name = NULL; @@ -104,39 +104,31 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, if (name) *name = NULL; if (mechanisms) *mechanisms = NULL; + if ((code = krb5_timeofday(context, &now))) { + *minor_status = code; + ret = GSS_S_FAILURE; + goto fail; + } + /* check for default credential */ /*SUPPRESS 29*/ if (cred_handle == GSS_C_NO_CREDENTIAL) { - OM_uint32 major; - - if ((major = kg_get_defcred(minor_status, (gss_cred_id_t *)&cred)) && - GSS_ERROR(major)) { - krb5_free_context(context); - return(major); - } - } else { - OM_uint32 major; - - major = krb5_gss_validate_cred(minor_status, cred_handle); + major = kg_get_defcred(minor_status, &defcred); if (GSS_ERROR(major)) { krb5_free_context(context); return(major); } - cred = (krb5_gss_cred_id_t) cred_handle; + cred_handle = defcred; } - if ((code = krb5_timeofday(context, &now))) { - *minor_status = code; - ret = GSS_S_FAILURE; - goto fail; + major = krb5_gss_validate_cred(minor_status, cred_handle); + if (GSS_ERROR(major)) { + krb5_gss_release_cred(minor_status, &defcred); + krb5_free_context(context); + return(major); } + cred = (krb5_gss_cred_id_t)cred_handle; - code = k5_mutex_lock(&cred->lock); - if (code != 0) { - *minor_status = code; - ret = GSS_S_FAILURE; - goto fail; - } if (cred->tgt_expire > 0) { if ((lifetime = cred->tgt_expire - now) < 0) lifetime = 0; @@ -161,7 +153,6 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, code = 0; } if (code) { - k5_mutex_unlock(&cred->lock); *minor_status = code; save_error_info(*minor_status, context); ret = GSS_S_FAILURE; @@ -178,7 +169,6 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status, gss_mech_krb5, &mechs))) { - k5_mutex_unlock(&cred->lock); if (ret_name) kg_release_name(context, &ret_name); /* *minor_status set above */ @@ -210,11 +200,8 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, *minor_status = 0; return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE); fail: - if (cred_handle == GSS_C_NO_CREDENTIAL) { - OM_uint32 tmp_min_stat; - - krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t *)&cred); - } + k5_mutex_unlock(&cred->lock); + krb5_gss_release_cred(&tmpmin, &defcred); krb5_free_context(context); return ret; } diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c index 70fbfbce6a..4ac2ce3015 100644 --- a/src/lib/gssapi/krb5/s4u_gss_glue.c +++ b/src/lib/gssapi/krb5/s4u_gss_glue.c @@ -144,9 +144,8 @@ krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status, return GSS_S_FAILURE; } - major_status = krb5_gss_validate_cred_1(minor_status, - impersonator_cred_handle, - context); + major_status = kg_cred_resolve(minor_status, context, + impersonator_cred_handle, NULL); if (GSS_ERROR(major_status)) { krb5_free_context(context); return major_status; |