/* Possibly try a non-referral request after a referral request failure. * Expects ctx->reply_code to be set to the error from a referral request. */ static krb5_error_code try_fallback(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; char **hrealms; /* Only fall back if our error was from the first referral request. */ if (ctx->referral_count > 1) return ctx->reply_code; /* If the request used a specified realm, make a non-referral request to * that realm (in case it's a KDC which rejects KDC_OPT_CANONICALIZE). */ if (!krb5_is_referral_realm(&ctx->req_server->realm)) return begin_non_referral(context, ctx); if (ctx->server->length < 2) { /* We need a type/host format principal to find a fallback realm. */ return KRB5_ERR_HOST_REALM_UNKNOWN; } /* We expect this to give exactly one answer (XXX clean up interface). */ code = krb5_get_fallback_host_realm(context, &ctx->server->data[1], &hrealms); if (code != 0) return code; /* If the fallback realm isn't any different, use the existing TGT. */ if (data_eq_string(ctx->server->realm, hrealms[0])) { krb5_free_host_realm(context, hrealms); return begin_non_referral(context, ctx); } /* Rewrite server->realm to be the fallback realm. */ krb5_free_data_contents(context, &ctx->server->realm); ctx->server->realm = string2data(hrealms[0]); free(hrealms); TRACE_TKT_CREDS_FALLBACK(context, &ctx->server->realm); /* Obtain a TGT for the new service realm. */ ctx->getting_tgt_for = STATE_NON_REFERRAL; return begin_get_tgt(context, ctx); }
/* Decide where to begin the acquisition process. */ static krb5_error_code begin(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; code = check_cache(context, ctx); if (code != 0 || ctx->state == STATE_COMPLETE) return code; /* If the server realm is unspecified, start with the client realm. */ if (krb5_is_referral_realm(&ctx->server->realm)) { krb5_free_data_contents(context, &ctx->server->realm); code = krb5int_copy_data_contents(context, &ctx->client->realm, &ctx->server->realm); TRACE_TKT_CREDS_REFERRAL_REALM(context, ctx->server); if (code != 0) return code; } /* Obtain a TGT for the service realm. */ ctx->getting_tgt_for = STATE_REFERRALS; return begin_get_tgt(context, ctx); }