From c37f1b3e4f8793b24582bfd0aac3a5a1e36841e1 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 11 Mar 2015 15:32:05 -0500 Subject: [PATCH] krb5: Don't cache/reuse referral TGTs Prior to this change _krb5_get_cred_kdc_any() would include TGTs obtained via KDC referrals in the "*ret_tgts" array returned to the caller. The caller typically stores these TGTs in the active credential cache. However, referrals TGTs must not be cached or reused for any request beyond the one it was issued for. The referral is for a specific service principal and the resulting TGT could include service specific AuthData. The referral might also direct the client along a transitive path that is specific to this service and not applicable in the general case. This change removes the *ret_tgts parameter from get_cred_kdc_referral() so that the obtained TGTs are never returned to its caller. This also prevents these TGTs from being used by any subsequent call to get_cred_kdc_capath(). Change-Id: Iacc76c5b1639af3cf6bf277966cfd1535dd1e84d --- lib/krb5/get_cred.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/krb5/get_cred.c b/lib/krb5/get_cred.c index 57a940b12..8338c4b58 100644 --- a/lib/krb5/get_cred.c +++ b/lib/krb5/get_cred.c @@ -919,6 +919,13 @@ get_cred_kdc_capath(krb5_context context, return ret; } +/* + * Get a service ticket from a KDC by chasing referrals from a start realm. + * + * All referral TGTs produced in the process are thrown away when we're done. + * We don't store them, and we don't allow other search mechanisms (capaths) to + * use referral TGTs produced here. + */ static krb5_error_code get_cred_kdc_referral(krb5_context context, krb5_kdc_flags flags, @@ -926,14 +933,15 @@ get_cred_kdc_referral(krb5_context context, krb5_creds *in_creds, krb5_principal impersonate_principal, Ticket *second_ticket, - krb5_creds **out_creds, - krb5_creds ***ret_tgts) + krb5_creds **out_creds) { krb5_const_realm client_realm; krb5_error_code ret; krb5_creds tgt, referral, ticket; + krb5_creds **referral_tgts = NULL; /* used for loop detection */ int loop = 0; int ok_as_delegate = 1; + size_t i; if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) { krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED, @@ -962,7 +970,7 @@ get_cred_kdc_referral(krb5_context context, if(ret) return ret; - ret = find_cred(context, ccache, tgtname, *ret_tgts, &tgt); + ret = find_cred(context, ccache, tgtname, NULL, &tgt); krb5_free_principal(context, tgtname); if (ret) return ret; @@ -1021,7 +1029,7 @@ get_cred_kdc_referral(krb5_context context, referral_realm = ticket.server->name.name_string.val[1]; /* check that there are no referrals loops */ - tickets = *ret_tgts; + tickets = referral_tgts; krb5_cc_clear_mcred(&mcreds); mcreds.server = ticket.server; @@ -1053,7 +1061,7 @@ get_cred_kdc_referral(krb5_context context, ticket.flags.b.ok_as_delegate = 0; } - ret = add_cred(context, &ticket, ret_tgts); + ret = add_cred(context, &ticket, &referral_tgts); if (ret) goto out; @@ -1071,6 +1079,9 @@ get_cred_kdc_referral(krb5_context context, ret = krb5_copy_creds(context, &ticket, out_creds); out: + for (i = 0; referral_tgts && referral_tgts[i]; i++) + krb5_free_creds(context, referral_tgts[i]); + free(referral_tgts); krb5_free_principal(context, referral.server); krb5_free_cred_contents(context, &tgt); krb5_free_cred_contents(context, &ticket); @@ -1102,16 +1113,19 @@ _krb5_get_cred_kdc_any(krb5_context context, context->kdc_usec_offset = 0; } + /* Try referrals */ ret = get_cred_kdc_referral(context, flags, ccache, in_creds, impersonate_principal, second_ticket, - out_creds, - ret_tgts); + out_creds); + if (ret == 0 || flags.b.canonicalize) return ret; + + /* Try capaths */ return get_cred_kdc_capath(context, flags, ccache,