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,