#include "k5-int.h"
#include <stdio.h>
#include "int-proto.h"
struct tr_state;
#define NCC_TGTS 2
struct cc_tgts {
krb5_creds cred[NCC_TGTS];
int dirty[NCC_TGTS];
unsigned int cur, nxt;
};
#define NXT_TGT_IS_CACHED(ts) \
((ts)->nxt_tgt == (ts)->cur_cc_tgt)
#define MARK_CUR_CC_TGT_CLEAN(ts) \
do { \
(ts)->cc_tgts.dirty[(ts)->cc_tgts.cur] = 0; \
} while (0)
static void init_cc_tgts(struct tr_state *);
static void shift_cc_tgts(struct tr_state *);
static void clean_cc_tgts(struct tr_state *);
struct tr_state {
krb5_context ctx;
krb5_ccache ccache;
krb5_principal *kdc_list;
unsigned int nkdcs;
krb5_principal *cur_kdc;
krb5_principal *nxt_kdc;
krb5_principal *lst_kdc;
krb5_creds *cur_tgt;
krb5_creds *nxt_tgt;
krb5_creds **kdc_tgts;
struct cc_tgts cc_tgts;
krb5_creds *cur_cc_tgt;
krb5_creds *nxt_cc_tgt;
unsigned int ntgts;
};
#ifdef DEBUG_GC_FRM_KDC
#define TR_DBG(ts, prog) tr_dbg(ts, prog)
#define TR_DBG_RET(ts, prog, ret) tr_dbg_ret(ts, prog, ret)
#define TR_DBG_RTREE(ts, prog, princ) tr_dbg_rtree(ts, prog, princ)
static void tr_dbg(struct tr_state *, const char *);
static void tr_dbg_ret(struct tr_state *, const char *, krb5_error_code);
static void tr_dbg_rtree(struct tr_state *, const char *, krb5_principal);
#else
#define TR_DBG(ts, prog)
#define TR_DBG_RET(ts, prog, ret)
#define TR_DBG_RTREE(ts, prog, princ)
#endif
#ifdef DEBUG_REFERRALS
#define DPRINTF(x) printf x
#define DFPRINTF(x) fprintf x
#define DUMP_PRINC(x, y) krb5int_dbgref_dump_principal((x), (y))
#else
#define DPRINTF(x)
#define DFPRINTF(x)
#define DUMP_PRINC(x, y)
#endif
#define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK)
#define HARD_CC_ERR(r) ((r) && (r) != KRB5_CC_NOTFOUND && \
(r) != KRB5_CC_NOT_KTYPE)
#define IS_TGS_PRINC(c, p) \
((krb5_princ_size((c), (p)) == 2) && \
(krb5_princ_component((c), (p), 0)->length == \
KRB5_TGS_NAME_SIZE) && \
(!memcmp(krb5_princ_component((c), (p), 0)->data, \
KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE)))
#define RETR_FLAGS (KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES)
static krb5_error_code tgt_mcred(krb5_context, krb5_principal,
krb5_principal, krb5_principal, krb5_creds *);
static krb5_error_code retr_local_tgt(struct tr_state *, krb5_principal);
static krb5_error_code try_ccache(struct tr_state *, krb5_creds *);
static krb5_error_code find_nxt_kdc(struct tr_state *);
static krb5_error_code try_kdc(struct tr_state *, krb5_creds *);
static krb5_error_code kdc_mcred(struct tr_state *, krb5_principal,
krb5_creds *mcreds);
static krb5_error_code next_closest_tgt(struct tr_state *, krb5_principal);
static krb5_error_code init_rtree(struct tr_state *,
krb5_principal, krb5_principal);
static krb5_error_code do_traversal(krb5_context ctx, krb5_ccache,
krb5_principal client, krb5_principal server,
krb5_creds *out_cc_tgt, krb5_creds **out_tgt,
krb5_creds ***out_kdc_tgts);
static krb5_error_code krb5_get_cred_from_kdc_opt(krb5_context, krb5_ccache,
krb5_creds *, krb5_creds **, krb5_creds ***, int);
static void
init_cc_tgts(struct tr_state *ts)
{
ts->cc_tgts.cur = 0;
ts->cc_tgts.nxt = 1;
ts->cur_cc_tgt = &ts->cc_tgts.cred[0];
ts->nxt_cc_tgt = &ts->cc_tgts.cred[1];
}
static void
shift_cc_tgts(struct tr_state *ts)
{
unsigned int i;
struct cc_tgts *rb;
rb = &ts->cc_tgts;
i = rb->cur = rb->nxt;
rb->dirty[i] = 1;
ts->cur_cc_tgt = ts->nxt_cc_tgt;
i = (i + 1) % NCC_TGTS;
rb->nxt = i;
ts->nxt_cc_tgt = &rb->cred[i];
if (rb->dirty[i]) {
krb5_free_cred_contents(ts->ctx, &rb->cred[i]);
rb->dirty[i] = 0;
}
}
static void
clean_cc_tgts(struct tr_state *ts)
{
unsigned int i;
struct cc_tgts *rb;
rb = &ts->cc_tgts;
for (i = 0; i < NCC_TGTS; i++) {
if (rb->dirty[i]) {
krb5_free_cred_contents(ts->ctx, &rb->cred[i]);
rb->dirty[i] = 0;
}
}
}
#ifdef DEBUG_GC_FRM_KDC
static void
tr_dbg(struct tr_state *ts, const char *prog)
{
krb5_error_code retval;
char *cur_tgt_str, *cur_kdc_str, *nxt_kdc_str;
cur_tgt_str = cur_kdc_str = nxt_kdc_str = NULL;
retval = krb5_unparse_name(ts->ctx, ts->cur_tgt->server, &cur_tgt_str);
if (retval) goto cleanup;
retval = krb5_unparse_name(ts->ctx, *ts->cur_kdc, &cur_kdc_str);
if (retval) goto cleanup;
retval = krb5_unparse_name(ts->ctx, *ts->nxt_kdc, &nxt_kdc_str);
if (retval) goto cleanup;
fprintf(stderr, "%s: cur_tgt %s\n", prog, cur_tgt_str);
fprintf(stderr, "%s: cur_kdc %s\n", prog, cur_kdc_str);
fprintf(stderr, "%s: nxt_kdc %s\n", prog, nxt_kdc_str);
cleanup:
if (cur_tgt_str)
krb5_free_unparsed_name(ts->ctx, cur_tgt_str);
if (cur_kdc_str)
krb5_free_unparsed_name(ts->ctx, cur_kdc_str);
if (nxt_kdc_str)
krb5_free_unparsed_name(ts->ctx, nxt_kdc_str);
}
static void
tr_dbg_ret(struct tr_state *ts, const char *prog, krb5_error_code ret)
{
fprintf(stderr, "%s: return %d (%s)\n", prog, (int)ret,
error_message(ret));
}
static void
tr_dbg_rtree(struct tr_state *ts, const char *prog, krb5_principal princ)
{
char *str;
if (krb5_unparse_name(ts->ctx, princ, &str))
return;
fprintf(stderr, "%s: %s\n", prog, str);
krb5_free_unparsed_name(ts->ctx, str);
}
#endif
static krb5_error_code
tgt_mcred(krb5_context ctx, krb5_principal client,
krb5_principal dst, krb5_principal src,
krb5_creds *mcreds)
{
krb5_error_code retval;
retval = 0;
memset(mcreds, 0, sizeof(*mcreds));
retval = krb5_copy_principal(ctx, client, &mcreds->client);
if (retval)
goto cleanup;
retval = krb5_tgtname(ctx, krb5_princ_realm(ctx, dst),
krb5_princ_realm(ctx, src), &mcreds->server);
if (retval)
goto cleanup;
cleanup:
if (retval)
krb5_free_cred_contents(ctx, mcreds);
return retval;
}
static krb5_error_code
init_rtree(struct tr_state *ts,
krb5_principal client, krb5_principal server)
{
krb5_error_code retval;
ts->kdc_list = NULL;
retval = krb5_walk_realm_tree(ts->ctx, krb5_princ_realm(ts->ctx, client),
krb5_princ_realm(ts->ctx, server),
&ts->kdc_list, KRB5_REALM_BRANCH_CHAR);
if (retval)
return retval;
for (ts->nkdcs = 0; ts->kdc_list[ts->nkdcs]; ts->nkdcs++) {
assert(krb5_princ_size(ts->ctx, ts->kdc_list[ts->nkdcs]) == 2);
TR_DBG_RTREE(ts, "init_rtree", ts->kdc_list[ts->nkdcs]);
}
assert(ts->nkdcs > 1);
ts->lst_kdc = ts->kdc_list + ts->nkdcs - 1;
ts->kdc_tgts = calloc(ts->nkdcs + 1, sizeof(krb5_creds));
if (ts->kdc_tgts == NULL)
return ENOMEM;
return 0;
}
static krb5_error_code
retr_local_tgt(struct tr_state *ts, krb5_principal client)
{
krb5_error_code retval;
krb5_creds tgtq;
memset(&tgtq, 0, sizeof(tgtq));
retval = tgt_mcred(ts->ctx, client, client, client, &tgtq);
if (retval)
return retval;
retval = krb5_cc_retrieve_cred(ts->ctx, ts->ccache,
KRB5_TC_SUPPORTED_KTYPES,
&tgtq, ts->nxt_cc_tgt);
krb5_free_cred_contents(ts->ctx, &tgtq);
if (!retval) {
shift_cc_tgts(ts);
ts->nxt_tgt = ts->cur_tgt = ts->cur_cc_tgt;
}
return retval;
}
static krb5_error_code
try_ccache(struct tr_state *ts, krb5_creds *tgtq)
{
krb5_error_code retval;
TR_DBG(ts, "try_ccache");
retval = krb5_cc_retrieve_cred(ts->ctx, ts->ccache, RETR_FLAGS,
tgtq, ts->nxt_cc_tgt);
if (!retval) {
shift_cc_tgts(ts);
ts->nxt_tgt = ts->cur_cc_tgt;
}
TR_DBG_RET(ts, "try_ccache", retval);
return retval;
}
static krb5_error_code
find_nxt_kdc(struct tr_state *ts)
{
krb5_data *r1, *r2;
krb5_principal *kdcptr;
TR_DBG(ts, "find_nxt_kdc");
assert(ts->nxt_tgt == ts->kdc_tgts[ts->ntgts-1]);
if (krb5_princ_size(ts->ctx, ts->nxt_tgt->server) != 2)
return KRB5_KDCREP_MODIFIED;
r1 = krb5_princ_component(ts->ctx, ts->nxt_tgt->server, 1);
for (kdcptr = ts->cur_kdc + 1; *kdcptr != NULL; kdcptr++) {
r2 = krb5_princ_component(ts->ctx, *kdcptr, 1);
if (r1 != NULL && r2 != NULL &&
r1->length == r2->length &&
!memcmp(r1->data, r2->data, r1->length)) {
break;
}
}
if (*kdcptr == NULL) {
if (ts->ntgts > 0) {
krb5_free_creds(ts->ctx, ts->kdc_tgts[--ts->ntgts]);
ts->kdc_tgts[ts->ntgts] = NULL;
}
TR_DBG_RET(ts, "find_nxt_kdc", KRB5_KDCREP_MODIFIED);
return KRB5_KDCREP_MODIFIED;
}
ts->nxt_kdc = kdcptr;
TR_DBG_RET(ts, "find_nxt_kdc", 0);
return 0;
}
static krb5_error_code
try_kdc(struct tr_state *ts, krb5_creds *tgtq)
{
krb5_error_code retval;
krb5_creds ltgtq;
TR_DBG(ts, "try_kdc");
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;
retval = krb5_get_cred_via_tkt(ts->ctx, ts->cur_tgt,
FLAGS2OPTS(ltgtq.ticket_flags),
ts->cur_tgt->addresses,
<gtq, &ts->kdc_tgts[ts->ntgts++]);
if (retval) {
ts->ntgts--;
ts->nxt_tgt = ts->cur_tgt;
TR_DBG_RET(ts, "try_kdc", retval);
return retval;
}
ts->nxt_tgt = ts->kdc_tgts[ts->ntgts-1];
retval = find_nxt_kdc(ts);
TR_DBG_RET(ts, "try_kdc", retval);
return retval;
}
static krb5_error_code
kdc_mcred(struct tr_state *ts, krb5_principal client, krb5_creds *mcreds)
{
krb5_error_code retval;
krb5_data *rdst, *rsrc;
retval = 0;
memset(mcreds, 0, sizeof(*mcreds));
rdst = krb5_princ_component(ts->ctx, *ts->nxt_kdc, 1);
rsrc = krb5_princ_component(ts->ctx, *ts->cur_kdc, 1);
retval = krb5_copy_principal(ts->ctx, client, &mcreds->client);
if (retval)
goto cleanup;
retval = krb5_tgtname(ts->ctx, rdst, rsrc, &mcreds->server);
if (retval)
goto cleanup;
cleanup:
if (retval)
krb5_free_cred_contents(ts->ctx, mcreds);
return retval;
}
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;
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;
}
retval = try_kdc(ts, &tgtq);
if (!retval) {
break;
}
}
cleanup:
krb5_free_cred_contents(ts->ctx, &tgtq);
return retval;
}
static krb5_error_code
do_traversal(krb5_context ctx,
krb5_ccache ccache,
krb5_principal client,
krb5_principal server,
krb5_creds *out_cc_tgt,
krb5_creds **out_tgt,
krb5_creds ***out_kdc_tgts)
{
krb5_error_code retval;
struct tr_state state, *ts;
*out_tgt = NULL;
*out_kdc_tgts = NULL;
ts = &state;
memset(ts, 0, sizeof(*ts));
ts->ctx = ctx;
ts->ccache = ccache;
init_cc_tgts(ts);
retval = init_rtree(ts, client, server);
if (retval)
goto cleanup;
retval = retr_local_tgt(ts, client);
if (retval)
goto cleanup;
for (ts->cur_kdc = ts->kdc_list, ts->nxt_kdc = NULL;
ts->cur_kdc != NULL && ts->cur_kdc < ts->lst_kdc;
ts->cur_kdc = ts->nxt_kdc, ts->cur_tgt = ts->nxt_tgt) {
retval = next_closest_tgt(ts, client);
if (retval)
goto cleanup;
assert(ts->cur_kdc != ts->nxt_kdc);
}
if (NXT_TGT_IS_CACHED(ts)) {
*out_cc_tgt = *ts->cur_cc_tgt;
*out_tgt = out_cc_tgt;
MARK_CUR_CC_TGT_CLEAN(ts);
} else {
*out_tgt = ts->nxt_tgt;
}
cleanup:
clean_cc_tgts(ts);
if (ts->kdc_list != NULL)
krb5_free_realm_tree(ctx, ts->kdc_list);
if (ts->ntgts == 0) {
*out_kdc_tgts = NULL;
if (ts->kdc_tgts != NULL)
free(ts->kdc_tgts);
} else
*out_kdc_tgts = ts->kdc_tgts;
return retval;
}
static krb5_error_code
krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
krb5_creds *in_cred, krb5_creds **out_cred,
krb5_creds ***tgts, int kdcopt)
{
krb5_error_code retval, subretval;
krb5_principal client, server, supplied_server, out_supplied_server;
krb5_creds tgtq, cc_tgt, *tgtptr, *referral_tgts[KRB5_REFERRAL_MAXHOPS];
krb5_boolean old_use_conf_ktypes;
char **hrealms;
int referral_count, i;
client = in_cred->client;
if ((retval=krb5_copy_principal(context, in_cred->server, &server)))
return retval;
if ((retval = krb5_copy_principal(context, server,
&out_supplied_server)) != 0 ) {
krb5_free_principal(context, server);
return retval;
}
supplied_server = in_cred->server;
in_cred->server=server;
DUMP_PRINC("gc_from_kdc initial client", client);
DUMP_PRINC("gc_from_kdc initial server", server);
memset(&cc_tgt, 0, sizeof(cc_tgt));
memset(&tgtq, 0, sizeof(tgtq));
memset(&referral_tgts, 0, sizeof(referral_tgts));
tgtptr = NULL;
*tgts = NULL;
*out_cred=NULL;
old_use_conf_ktypes = context->use_conf_ktypes;
if (krb5_is_referral_realm(&server->realm)) {
DPRINTF(("gc_from_kdc: no server realm supplied, "
"using client realm.\n"));
krb5_free_data_contents(context, &server->realm);
if (!( server->realm.data = (char *)malloc(client->realm.length+1)))
return ENOMEM;
memcpy(server->realm.data, client->realm.data, client->realm.length);
server->realm.length = client->realm.length;
server->realm.data[server->realm.length] = 0;
}
retval = tgt_mcred(context, client, server, client, &tgtq);
if (retval)
goto cleanup;
context->use_conf_ktypes = 1;
retval = krb5_cc_retrieve_cred(context, ccache, RETR_FLAGS,
&tgtq, &cc_tgt);
if (!retval) {
tgtptr = &cc_tgt;
} else if (!HARD_CC_ERR(retval)) {
DPRINTF(("gc_from_kdc: starting do_traversal to find "
"initial TGT for referral\n"));
retval = do_traversal(context, ccache, client, server,
&cc_tgt, &tgtptr, tgts);
}
if (retval) {
DPRINTF(("gc_from_kdc: failed to find initial TGT for referral\n"));
goto cleanup;
}
DUMP_PRINC("gc_from_kdc: server as requested", supplied_server);
for (referral_count = 0;
referral_count < KRB5_REFERRAL_MAXHOPS;
referral_count++) {
#if 0
DUMP_PRINC("gc_from_kdc: referral loop: tgt in use", tgtptr->server);
DUMP_PRINC("gc_from_kdc: referral loop: request is for", server);
#endif
retval = krb5_get_cred_via_tkt(context, tgtptr,
KDC_OPT_CANONICALIZE |
FLAGS2OPTS(tgtptr->ticket_flags) |
kdcopt |
(in_cred->second_ticket.length ?
KDC_OPT_ENC_TKT_IN_SKEY : 0),
tgtptr->addresses, in_cred, out_cred);
if (retval) {
DPRINTF(("gc_from_kdc: referral TGS-REQ request failed: <%s>\n",
error_message(retval)));
if (referral_count==0) {
DPRINTF(("gc_from_kdc: initial referral failed; "
"punting to fallback.\n"));
break;
}
DPRINTF(("gc_from_kdc: referral #%d failed; "
"retrying without option.\n", referral_count + 1));
retval = krb5_get_cred_via_tkt(context, tgtptr,
FLAGS2OPTS(tgtptr->ticket_flags) |
kdcopt |
(in_cred->second_ticket.length ?
KDC_OPT_ENC_TKT_IN_SKEY : 0),
tgtptr->addresses,
in_cred, out_cred);
goto cleanup;
}
if (krb5_principal_compare(context, in_cred->server,
(*out_cred)->server)) {
DPRINTF(("gc_from_kdc: request generated ticket "
"for requested server principal\n"));
DUMP_PRINC("gc_from_kdc final referred reply",
in_cred->server);
if (old_use_conf_ktypes || context->tgs_ktype_count == 0)
goto cleanup;
for (i = 0; i < context->tgs_ktype_count; i++) {
if ((*out_cred)->keyblock.enctype == context->tgs_ktypes[i]) {
goto cleanup;
}
}
krb5_free_creds(context, *out_cred);
*out_cred = NULL;
context->use_conf_ktypes = old_use_conf_ktypes;
retval = krb5_get_cred_via_tkt(context, tgtptr,
KDC_OPT_CANONICALIZE |
FLAGS2OPTS(tgtptr->ticket_flags) |
kdcopt |
(in_cred->second_ticket.length ?
KDC_OPT_ENC_TKT_IN_SKEY : 0),
tgtptr->addresses,
in_cred, out_cred);
goto cleanup;
}
else if (IS_TGS_PRINC(context, (*out_cred)->server)) {
krb5_data *r1, *r2;
DPRINTF(("gc_from_kdc: request generated referral tgt\n"));
DUMP_PRINC("gc_from_kdc credential received",
(*out_cred)->server);
if (referral_count == 0)
r1 = &tgtptr->server->data[1];
else
r1 = &referral_tgts[referral_count-1]->server->data[1];
r2 = &(*out_cred)->server->data[1];
if (r1->length == r2->length &&
!memcmp(r1->data, r2->data, r1->length)) {
DPRINTF(("gc_from_kdc: referred back to "
"previous realm; fall back\n"));
krb5_free_creds(context, *out_cred);
*out_cred = NULL;
break;
}
for (i=0;i<referral_count;i++) {
#if 0
DUMP_PRINC("gc_from_kdc: loop compare #1",
(*out_cred)->server);
DUMP_PRINC("gc_from_kdc: loop compare #2",
referral_tgts[i]->server);
#endif
if (krb5_principal_compare(context,
(*out_cred)->server,
referral_tgts[i]->server)) {
DFPRINTF((stderr,
"krb5_get_cred_from_kdc_opt: "
"referral routing loop - "
"got referral back to hop #%d\n", i));
retval=KRB5_KDC_UNREACH;
goto cleanup;
}
}
if (tgtptr == &cc_tgt)
krb5_free_cred_contents(context, tgtptr);
tgtptr=*out_cred;
referral_tgts[referral_count]=*out_cred;
krb5_free_data_contents(context, &server->realm);
retval = krb5int_copy_data_contents(context,
&tgtptr->server->data[1],
&server->realm);
if (retval)
return retval;
} else {
krb5_free_creds(context, *out_cred);
*out_cred = NULL;
break;
}
}
DUMP_PRINC("gc_from_kdc client at fallback", client);
DUMP_PRINC("gc_from_kdc server at fallback", server);
if (krb5_is_referral_realm(&supplied_server->realm)) {
if (server->length >= 2) {
retval=krb5_get_fallback_host_realm(context, &server->data[1],
&hrealms);
if (retval) goto cleanup;
#if 0
DPRINTF(("gc_from_kdc: using fallback realm of %s\n",
hrealms[0]));
#endif
krb5_free_data_contents(context,&in_cred->server->realm);
server->realm.data=hrealms[0];
server->realm.length=strlen(hrealms[0]);
free(hrealms);
}
else {
DPRINTF(("gc_from_kdc: referral specified "
"but no fallback realm avaiable!\n"));
return KRB5_ERR_HOST_REALM_UNKNOWN;
}
}
DUMP_PRINC("gc_from_kdc server at fallback after fallback rewrite",
server);
krb5_free_cred_contents(context, &tgtq);
retval = tgt_mcred(context, client, server, client, &tgtq);
if (retval)
goto cleanup;
if (tgtptr == &cc_tgt)
krb5_free_cred_contents(context, tgtptr);
if (*tgts != NULL) {
for (i = 0; (*tgts)[i] != NULL; i++) {
krb5_free_creds(context, (*tgts)[i]);
}
free(*tgts);
*tgts = NULL;
}
context->use_conf_ktypes = 1;
retval = krb5_cc_retrieve_cred(context, ccache, RETR_FLAGS,
&tgtq, &cc_tgt);
if (!retval) {
tgtptr = &cc_tgt;
} else if (!HARD_CC_ERR(retval)) {
retval = do_traversal(context, ccache, client, server,
&cc_tgt, &tgtptr, tgts);
}
if (retval)
goto cleanup;
if (!krb5_c_valid_enctype(tgtptr->keyblock.enctype)) {
retval = KRB5_PROG_ETYPE_NOSUPP;
goto cleanup;
}
context->use_conf_ktypes = old_use_conf_ktypes;
retval = krb5_get_cred_via_tkt(context, tgtptr,
FLAGS2OPTS(tgtptr->ticket_flags) |
kdcopt |
(in_cred->second_ticket.length ?
KDC_OPT_ENC_TKT_IN_SKEY : 0),
tgtptr->addresses, in_cred, out_cred);
cleanup:
krb5_free_cred_contents(context, &tgtq);
if (tgtptr == &cc_tgt)
krb5_free_cred_contents(context, tgtptr);
context->use_conf_ktypes = old_use_conf_ktypes;
DUMP_PRINC("gc_from_kdc: final hacked server principal at cleanup",
server);
krb5_free_principal(context, server);
in_cred->server = supplied_server;
if (*out_cred && !retval) {
krb5_free_principal (context, (*out_cred)->server);
(*out_cred)->server= out_supplied_server;
}
else {
krb5_free_principal (context, out_supplied_server);
}
DUMP_PRINC("gc_from_kdc: final server after reversion", in_cred->server);
if (*tgts == NULL) {
if (referral_tgts[0]) {
#if 0
subretval=...?;
if (subretval) {
#endif
if (!(*tgts=calloc(sizeof (krb5_creds *), 2)))
return ENOMEM;
subretval=krb5_copy_creds(context, referral_tgts[0], &((*tgts)[0]));
if(subretval)
return subretval;
(*tgts)[1]=NULL;
DUMP_PRINC("gc_from_kdc: returning referral TGT for ccache",
(*tgts)[0]->server);
#if 0
}
#endif
}
}
for (i=0;i<KRB5_REFERRAL_MAXHOPS;i++) {
if(referral_tgts[i]) {
krb5_free_creds(context, referral_tgts[i]);
}
}
DPRINTF(("gc_from_kdc finishing with %s\n",
retval ? error_message(retval) : "no error"));
return retval;
}
krb5_error_code
krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache,
krb5_creds *in_cred, krb5_creds **out_cred,
krb5_creds ***tgts)
{
return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
0);
}
krb5_error_code
krb5_get_cred_from_kdc_validate(krb5_context context, krb5_ccache ccache,
krb5_creds *in_cred, krb5_creds **out_cred,
krb5_creds ***tgts)
{
return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
KDC_OPT_VALIDATE);
}
krb5_error_code
krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache,
krb5_creds *in_cred, krb5_creds **out_cred,
krb5_creds ***tgts)
{
return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
KDC_OPT_RENEW);
}