/* Make a non-referrals request for the desired service ticket. */ static krb5_error_code begin_non_referral(krb5_context context, krb5_tkt_creds_context ctx) { ctx->state = STATE_NON_REFERRAL; return make_request_for_service(context, ctx, FALSE); }
/* Advance the referral request loop. */ static krb5_error_code step_referrals(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; const krb5_data *referral_realm; /* Possibly try a non-referral fallback request on error. */ if (ctx->reply_code != 0) return try_fallback(context, ctx); if (krb5_principal_compare(context, ctx->reply_creds->server, ctx->server)) { /* We got the ticket we asked for... but we didn't necessarily ask for * it with the right enctypes. Try a non-referral request if so. */ if (wrong_enctype(context, ctx->reply_creds->keyblock.enctype)) { TRACE_TKT_CREDS_WRONG_ENCTYPE(context); return begin_non_referral(context, ctx); } return complete(context, ctx); } /* Old versions of Active Directory can rewrite the server name instead of * returning a referral. Try a non-referral query if we see this. */ if (!IS_TGS_PRINC(context, ctx->reply_creds->server)) { TRACE_TKT_CREDS_NON_TGT(context, ctx->reply_creds->server); return begin_non_referral(context, ctx); } /* Active Directory may return a TGT to the local realm. Try a * non-referral query if we see this. */ referral_realm = &ctx->reply_creds->server->data[1]; if (data_eq(*referral_realm, ctx->cur_tgt->server->data[1])) { TRACE_TKT_CREDS_SAME_REALM_TGT(context, referral_realm); return begin_non_referral(context, ctx); } if (ctx->referral_count == 1) { /* Cache the referral TGT only if it's from the local realm. * Make sure to note the associated authdata, if any. */ code = krb5_copy_authdata(context, ctx->authdata, &ctx->reply_creds->authdata); if (code != 0) return code; (void) krb5_cc_store_cred(context, ctx->ccache, ctx->reply_creds); /* The authdata in this TGT will be copied into subsequent TGTs or the * final credentials, so we don't need to request it again. */ krb5_free_authdata(context, ctx->in_creds->authdata); ctx->in_creds->authdata = NULL; } /* Give up if we've gotten too many referral TGTs. */ if (ctx->referral_count++ >= KRB5_REFERRAL_MAXHOPS) return KRB5_KDC_UNREACH; /* Check for referral loops. */ if (seen_realm_before(context, ctx, referral_realm)) return KRB5_KDC_UNREACH; code = remember_realm(context, ctx, referral_realm); if (code != 0) return code; /* Use the referral TGT for the next request. */ krb5_free_creds(context, ctx->cur_tgt); ctx->cur_tgt = ctx->reply_creds; ctx->reply_creds = NULL; TRACE_TKT_CREDS_REFERRAL(context, ctx->cur_tgt->server); /* Rewrite the server realm to be the referral realm. */ krb5_free_data_contents(context, &ctx->server->realm); code = krb5int_copy_data_contents(context, referral_realm, &ctx->server->realm); if (code != 0) return code; /* Generate the next referral request. */ return make_request_for_service(context, ctx, TRUE); }