/* * try_kdc() * * Using CUR_TGT, attempt to get desired NXT_TGT. Update NXT_KDC if * successful. */ static krb5_error_code try_kdc(struct tr_state *ts, krb5_creds *tgtq) { krb5_error_code retval; krb5_creds ltgtq; krb5_creds *tmp_out_cred; TR_DBG(ts, "try_kdc"); /* This check should probably be in gc_via_tkt. */ if (!krb5_c_valid_enctype(ts->cur_tgt->keyblock.enctype)) return KRB5_PROG_ETYPE_NOSUPP; ltgtq = *tgtq; ltgtq.is_skey = FALSE; ltgtq.ticket_flags = ts->cur_tgt->ticket_flags; /* * Solaris Kerberos: * Store credential in a temporary ticket as we may not * want to add it to ts->kdc_tgts if it is already in * the cache. */ retval = krb5_get_cred_via_tkt(ts->ctx, ts->cur_tgt, FLAGS2OPTS(ltgtq.ticket_flags), ts->cur_tgt->addresses, <gtq, &tmp_out_cred); if (retval) { ts->ntgts--; ts->nxt_tgt = ts->cur_tgt; TR_DBG_RET(ts, "try_kdc", retval); return retval; } /* * Solaris Kerberos: * See if the returned creds are different to the requested creds. * This can happen when the server returns a TGT "closer" to the * desired realm. */ if (!(krb5_principal_compare(ts->ctx, tgtq->server, tmp_out_cred->server))) { /* Not equal, ticket may already be in the cache */ retval = try_ccache(ts, tmp_out_cred); if (!retval) { krb5_free_creds(ts->ctx, tmp_out_cred); retval = find_nxt_kdc(ts); return retval; } } ts->kdc_tgts[ts->ntgts++] = tmp_out_cred; ts->nxt_tgt = ts->kdc_tgts[ts->ntgts-1]; retval = find_nxt_kdc(ts); TR_DBG_RET(ts, "try_kdc", retval); return retval; }
/* * next_closest_tgt() * * Using CUR_TGT, attempt to get the cross-realm TGT having its remote * realm closest to the target principal's. Update NXT_TGT, NXT_KDC * accordingly. */ static krb5_error_code next_closest_tgt(struct tr_state *ts, krb5_principal client) { krb5_error_code retval; krb5_creds tgtq; retval = 0; memset(&tgtq, 0, sizeof(tgtq)); for (ts->nxt_kdc = ts->lst_kdc; ts->nxt_kdc > ts->cur_kdc; ts->nxt_kdc--) { krb5_free_cred_contents(ts->ctx, &tgtq); retval = kdc_mcred(ts, client, &tgtq); if (retval) goto cleanup; /* Don't waste time retrying ccache for direct path. */ if (ts->cur_kdc != ts->kdc_list || ts->nxt_kdc != ts->lst_kdc) { retval = try_ccache(ts, &tgtq); if (!retval) break; if (HARD_CC_ERR(retval)) goto cleanup; } /* Not in the ccache, so talk to a KDC. */ retval = try_kdc(ts, &tgtq); if (!retval) { break; } /* * Because try_kdc() validates referral TGTs, it can return an * error indicating a bogus referral. The loop continues when * it gets a bogus referral, which is arguably the right * thing. (Previous implementation unconditionally failed.) */ } /* * If we have a non-zero retval, we either have a hard error or we * failed to find a closer TGT. */ cleanup: krb5_free_cred_contents(ts->ctx, &tgtq); return retval; }
/* * next_closest_tgt() * * Using CUR_TGT, attempt to get the cross-realm TGT having its remote * realm closest to the target principal's. Update NXT_TGT, NXT_KDC * accordingly. */ static krb5_error_code next_closest_tgt(struct tr_state *ts, krb5_principal client) { krb5_error_code retval; krb5_creds tgtq; retval = 0; memset(&tgtq, 0, sizeof(tgtq)); for (ts->nxt_kdc = ts->lst_kdc; ts->nxt_kdc > ts->cur_kdc; ts->nxt_kdc--) { krb5_free_cred_contents(ts->ctx, &tgtq); retval = kdc_mcred(ts, client, &tgtq); if (retval) goto cleanup; /* Don't waste time retrying ccache for direct path. */ if (ts->cur_kdc != ts->kdc_list || ts->nxt_kdc != ts->lst_kdc) { retval = try_ccache(ts, &tgtq); if (!retval) break; if (HARD_CC_ERR(retval)) goto cleanup; } /* Not in the ccache, so talk to a KDC. */ retval = try_kdc(ts, &tgtq); if (!retval) { break; } /* * In case of errors in try_kdc() or find_nxt_kdc(), continue * looping through the KDC list. */ } /* * If we have a non-zero retval, we either have a hard error or we * failed to find a closer TGT. */ cleanup: krb5_free_cred_contents(ts->ctx, &tgtq); return retval; }