/* * Build a tree given a set of profile values retrieved by * walk_rtree_capath_vals(). */ static krb5_error_code rtree_capath_tree( krb5_context context, const krb5_data *client, const krb5_data *server, char **vals, krb5_principal **rettree) { krb5_error_code retval = 0; unsigned int nvals, nlinks, nprincs, i; krb5_data srcrealm, dstrealm; krb5_principal *tree, *pprinc; *rettree = NULL; tree = pprinc = NULL; for (nvals = 0; vals[nvals] != NULL; nvals++) ; if (vals[0] != NULL && *vals[0] == '.') { nlinks = 0; } else { nlinks = nvals; } nprincs = nlinks + 2; tree = calloc(nprincs + 1, sizeof(krb5_principal)); if (tree == NULL) { retval = ENOMEM; goto error; } for (i = 0; i < nprincs + 1; i++) tree[i] = NULL; /* Invariant: PPRINC points one past end of list. */ pprinc = &tree[0]; /* Local TGS name */ retval = krb5_tgtname(context, client, client, pprinc++); if (retval) goto error; srcrealm = *client; for (i = 0; i < nlinks; i++) { dstrealm.data = vals[i]; dstrealm.length = strcspn(vals[i], "\t "); retval = krb5_tgtname(context, &dstrealm, &srcrealm, pprinc++); if (retval) goto error; srcrealm = dstrealm; } retval = krb5_tgtname(context, server, &srcrealm, pprinc++); if (retval) goto error; *rettree = tree; error: profile_free_list(vals); if (retval) { while (pprinc != NULL && pprinc > &tree[0]) { /* krb5_free_principal() correctly handles null input */ krb5_free_principal(context, *--pprinc); *pprinc = NULL; } free(tree); } return retval; }
/* * kdc_mcred() * * Return MCREDS for use as a match criterion. * * Resulting credential has CLIENT as the client principal, and * krbtgt/remote_realm(NXT_KDC)@local_realm(CUR_KDC) as the server * principal. Zeroes MCREDS first, does not allocate MCREDS, and * cleans MCREDS on failure. */ 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; }
/* * tgt_mcred() * * Return MCREDS for use as a match criterion. * * Resulting credential has CLIENT as the client principal, and * krbtgt/realm_of(DST)@realm_of(SRC) as the server principal. Zeroes * MCREDS first, does not allocate MCREDS, and cleans MCREDS on * failure. The peculiar ordering of DST and SRC args is for * consistency with krb5_tgtname(). */ 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 fast_armor_ap_request (krb5_context context, struct krb5int_fast_request_state *state, krb5_ccache ccache, krb5_data *target_realm) { krb5_error_code retval = 0; krb5_creds creds, *out_creds = NULL; krb5_auth_context authcontext = NULL; krb5_data encoded_authenticator; krb5_fast_armor *armor = NULL; krb5_keyblock *subkey = NULL, *armor_key = NULL; encoded_authenticator.data = NULL; memset(&creds, 0, sizeof(creds)); retval = krb5_tgtname(context, target_realm, target_realm, &creds.server); if (retval ==0) retval = krb5_cc_get_principal(context, ccache, &creds.client); if (retval == 0) retval = krb5_get_credentials(context, 0, ccache, &creds, &out_creds); if (retval == 0) retval = krb5_mk_req_extended(context, &authcontext, AP_OPTS_USE_SUBKEY, NULL /*data*/, out_creds, &encoded_authenticator); if (retval == 0) retval = krb5_auth_con_getsendsubkey(context, authcontext, &subkey); if (retval == 0) retval = krb5_c_fx_cf2_simple(context, subkey, "subkeyarmor", &out_creds->keyblock, "ticketarmor", &armor_key); if (retval == 0) { armor = calloc(1, sizeof(krb5_fast_armor)); if (armor == NULL) retval = ENOMEM; } if (retval == 0) { armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST; armor->armor_value = encoded_authenticator; encoded_authenticator.data = NULL; encoded_authenticator.length = 0; state->armor = armor; armor = NULL; state->armor_key = armor_key; armor_key = NULL; } krb5_free_keyblock(context, armor_key); krb5_free_keyblock(context, subkey); if (out_creds) krb5_free_creds(context, out_creds); krb5_free_cred_contents(context, &creds); if (encoded_authenticator.data) krb5_free_data_contents(context, &encoded_authenticator); krb5_auth_con_free(context, authcontext); return retval; }
/* * Build tree by hierarchical traversal. */ static krb5_error_code rtree_hier_tree( krb5_context context, const krb5_data *client, const krb5_data *server, krb5_principal **rettree, int sep) { krb5_error_code retval; krb5_data *realms; const krb5_data *dstrealm, *srcrealm; krb5_principal *tree, *pprinc; size_t nrealms, nprincs, i; *rettree = NULL; retval = rtree_hier_realms(context, client, server, &realms, &nrealms, sep); if (retval) return retval; nprincs = nrealms; pprinc = tree = calloc(nprincs + 1, sizeof(krb5_principal)); if (tree == NULL) { retval = ENOMEM; goto error; } for (i = 0; i < nrealms; i++) tree[i] = NULL; srcrealm = client; for (i = 0; i < nrealms; i++) { dstrealm = &realms[i]; retval = krb5_tgtname(context, dstrealm, srcrealm, pprinc++); if (retval) goto error; srcrealm = dstrealm; } *rettree = tree; free_realmlist(context, realms, nrealms); return 0; error: while (pprinc != NULL && pprinc > tree) { krb5_free_principal(context, *--pprinc); *pprinc = NULL; } free_realmlist(context, realms, nrealms); free(tree); return retval; }
/* * chase_offpath() * * Chase off-path TGT referrals. * * If we are traversing a trusted path (either hierarchically derived * or explicit capath) and get a TGT pointing to a realm off this * path, query the realm referenced by that off-path TGT. Repeat * until we get to the destination realm or encounter an error. * * CUR_TGT is always either pointing into REFTGTS or is an alias for * TS->OFFPATH_TGT. */ static krb5_error_code chase_offpath(struct tr_state *ts, krb5_principal client, krb5_principal server) { krb5_error_code retval; krb5_creds mcred; krb5_creds *cur_tgt, *nxt_tgt, *reftgts[KRB5_REFERRAL_MAXHOPS]; krb5_data *rsrc, *rdst, *r1; int rcount, i; rdst = krb5_princ_realm(ts->ctx, server); cur_tgt = ts->offpath_tgt; for (rcount = 0; rcount < KRB5_REFERRAL_MAXHOPS; rcount++) { nxt_tgt = NULL; memset(&mcred, 0, sizeof(mcred)); rsrc = krb5_princ_component(ts->ctx, cur_tgt->server, 1); retval = krb5_tgtname(ts->ctx, rdst, rsrc, &mcred.server); if (retval) goto cleanup; mcred.client = client; retval = krb5_get_cred_via_tkt(ts->ctx, cur_tgt, FLAGS2OPTS(cur_tgt->ticket_flags), cur_tgt->addresses, &mcred, &nxt_tgt); mcred.client = NULL; krb5_free_principal(ts->ctx, mcred.server); mcred.server = NULL; if (retval) goto cleanup; if (!IS_TGS_PRINC(ts->ctx, nxt_tgt->server)) { retval = KRB5_KDCREP_MODIFIED; goto cleanup; } r1 = krb5_princ_component(ts->ctx, nxt_tgt->server, 1); if (rdst->length == r1->length && !memcmp(rdst->data, r1->data, rdst->length)) { retval = 0; goto cleanup; } retval = offpath_loopchk(ts, nxt_tgt, reftgts, rcount); if (retval) goto cleanup; reftgts[rcount] = nxt_tgt; cur_tgt = nxt_tgt; nxt_tgt = NULL; } /* Max hop count exceeded. */ retval = KRB5_KDCREP_MODIFIED; cleanup: if (mcred.server != NULL) { krb5_free_principal(ts->ctx, mcred.server); } /* * Don't free TS->OFFPATH_TGT if it's in the list of cacheable * TGTs to be returned by do_traversal(). */ if (ts->offpath_tgt != ts->nxt_tgt) { krb5_free_creds(ts->ctx, ts->offpath_tgt); } ts->offpath_tgt = NULL; if (nxt_tgt != NULL) { if (retval) krb5_free_creds(ts->ctx, nxt_tgt); else ts->offpath_tgt = nxt_tgt; } for (i = 0; i < rcount; i++) { krb5_free_creds(ts->ctx, reftgts[i]); } 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_creds **ret_tgts = NULL; int ntgts = 0; krb5_creds tgt, tgtq, *tgtr = NULL; krb5_error_code retval; krb5_principal int_server = NULL; /* Intermediate server for request */ krb5_principal *tgs_list = NULL; krb5_principal *top_server = NULL; krb5_principal *next_server = NULL; unsigned int nservers = 0; krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes; /* in case we never get a TGT, zero the return */ *tgts = NULL; memset((char *)&tgtq, 0, sizeof(tgtq)); memset((char *)&tgt, 0, sizeof(tgt)); /* * we know that the desired credentials aren't in the cache yet. * * To get them, we first need a tgt for the realm of the server. * first, we see if we have such a TGT in cache. if not, then * we ask the kdc to give us one. if that doesn't work, then * we try to get a tgt for a realm that is closest to the target. * once we have that, then we ask that realm if it can give us * tgt for the target. if not, we do the process over with this * new tgt. */ /* * (the ticket may be issued by some other intermediate * realm's KDC; so we use KRB5_TC_MATCH_SRV_NAMEONLY) */ if ((retval = krb5_copy_principal(context, in_cred->client, &tgtq.client))) goto cleanup; /* get target tgt from cache */ if ((retval = krb5_tgtname(context, krb5_princ_realm(context, in_cred->server), krb5_princ_realm(context, in_cred->client), &int_server))) { goto cleanup; } if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) { goto cleanup; } /* set endtime to now so krb5_cc_retrieve_cred won't return an expired tik */ if ((retval = krb5_timeofday(context, &(tgtq.times.endtime))) != 0) { goto cleanup; } context->use_conf_ktypes = 1; if ((retval = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES | KRB5_TC_MATCH_TIMES, &tgtq, &tgt)) != 0) { if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) { goto cleanup; } /* * Note that we want to request a TGT from our local KDC, even * if we already have a TGT for some intermediate realm. The * reason is that our local KDC may have a shortcut to the * destination realm, and if it does we want to use the * shortcut because it will provide greater security. - bcn */ /* * didn't find it in the cache so it is time to get a local * tgt and walk the realms tree. */ krb5_free_principal(context, int_server); int_server = NULL; if ((retval = krb5_tgtname(context, krb5_princ_realm(context, in_cred->client), krb5_princ_realm(context, in_cred->client), &int_server))) { goto cleanup; } krb5_free_cred_contents(context, &tgtq); memset((char *)&tgtq, 0, sizeof(tgtq)); if ((retval = krb5_copy_principal(context, in_cred->client, &tgtq.client))) goto cleanup; if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) goto cleanup; if ((retval = krb5_timeofday(context, &(tgtq.times.endtime))) != 0) { goto cleanup; } if ((retval = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES | KRB5_TC_MATCH_TIMES, &tgtq, &tgt)) != 0) { goto cleanup; } /* get a list of realms to consult */ if ((retval = krb5_walk_realm_tree(context, krb5_princ_realm(context,in_cred->client), krb5_princ_realm(context,in_cred->server), &tgs_list, KRB5_REALM_BRANCH_CHAR))) { goto cleanup; } for (nservers = 0; tgs_list[nservers]; nservers++) ; /* allocate storage for TGT pointers. */ if (!(ret_tgts = (krb5_creds **) calloc(nservers+1, sizeof(krb5_creds)))) { retval = ENOMEM; goto cleanup; } *tgts = ret_tgts; /* * step one is to take the current tgt and see if there is a tgt for * krbtgt/realmof(target)@realmof(tgt). if not, try to get one with * the tgt. * * if we don't get a tgt for the target, then try to find a tgt as * close to the target realm as possible. at each step if there isn't * a tgt in the cache we have to try and get one with our latest tgt. * once we have a tgt for a closer realm, we go back to step one. * * once we have a tgt for the target, we go try and get credentials. */ for (top_server = tgs_list; top_server < tgs_list + nservers; top_server = next_server) { /* look in cache for a tgt for the destination */ krb5_free_cred_contents(context, &tgtq); memset(&tgtq, 0, sizeof(tgtq)); if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client))) goto cleanup; krb5_free_principal(context, int_server); int_server = NULL; if ((retval = krb5_tgtname(context, krb5_princ_realm(context, in_cred->server), krb5_princ_realm(context, *top_server), &int_server))) { goto cleanup; } if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) goto cleanup; if ((retval = krb5_timeofday(context, &(tgtq.times.endtime))) != 0) { goto cleanup; } if ((retval = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES | KRB5_TC_MATCH_TIMES, &tgtq, &tgt)) != 0) { if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) { goto cleanup; } /* didn't find it in the cache so try and get one */ /* with current tgt. */ if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { retval = KRB5_PROG_ETYPE_NOSUPP; goto cleanup; } krb5_free_cred_contents(context, &tgtq); memset(&tgtq, 0, sizeof(tgtq)); tgtq.times = tgt.times; if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client))) goto cleanup; if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) goto cleanup; tgtq.is_skey = FALSE; tgtq.ticket_flags = tgt.ticket_flags; retval = krb5_get_cred_via_tkt(context, &tgt, FLAGS2OPTS(tgtq.ticket_flags), tgt.addresses, &tgtq, &tgtr); if (retval) { /* * couldn't get one so now loop backwards through the realms * list and try and get a tgt for a realm as close to the * target as possible. the kdc should give us a tgt for the * closest one it knows about, but not all kdc's do this yet. */ for (next_server = tgs_list + nservers - 1; next_server > top_server; next_server--) { krb5_free_cred_contents(context, &tgtq); memset(&tgtq, 0, sizeof(tgtq)); if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client))) goto cleanup; krb5_free_principal(context, int_server); int_server = NULL; if ((retval = krb5_tgtname(context, krb5_princ_realm(context, *next_server), krb5_princ_realm(context, *top_server), &int_server))) { goto cleanup; } if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) goto cleanup; if ((retval = krb5_timeofday(context, &(tgtq.times.endtime))) != 0) { goto cleanup; } if ((retval = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES | KRB5_TC_MATCH_TIMES, &tgtq, &tgt)) != 0) { if (retval != KRB5_CC_NOTFOUND) { goto cleanup; } /* not in the cache so try and get one with our current tgt. */ if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { retval = KRB5_PROG_ETYPE_NOSUPP; goto cleanup; } krb5_free_cred_contents(context, &tgtq); memset(&tgtq, 0, sizeof(tgtq)); tgtq.times = tgt.times; if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client))) goto cleanup; if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) goto cleanup; tgtq.is_skey = FALSE; tgtq.ticket_flags = tgt.ticket_flags; retval = krb5_get_cred_via_tkt(context, &tgt, FLAGS2OPTS(tgtq.ticket_flags), tgt.addresses, &tgtq, &tgtr); if (retval) continue; /* save tgt in return array */ if ((retval = krb5_copy_creds(context, tgtr, &ret_tgts[ntgts]))) { goto cleanup; } krb5_free_creds(context, tgtr); tgtr = NULL; tgt = *ret_tgts[ntgts++]; } /* got one as close as possible, now start all over */ break; } if (next_server == top_server) { goto cleanup; } continue; } /* * Got a tgt. If it is for the target realm we can go try for the * credentials. If it is not for the target realm, then make sure it * is in the realms hierarchy and if so, save it and start the loop * over from there. Note that we only need to compare the instance * names since that is the target realm of the tgt. */ for (next_server = top_server; *next_server; next_server++) { krb5_data *realm_1 = krb5_princ_component(context, next_server[0], 1); krb5_data *realm_2 = krb5_princ_component(context, tgtr->server, 1); if (realm_1 != NULL && realm_2 != NULL && realm_1->length == realm_2->length && !memcmp(realm_1->data, realm_2->data, realm_1->length)) { break; } } if (!next_server) { retval = KRB5_KDCREP_MODIFIED; goto cleanup; } if ((retval = krb5_copy_creds(context, tgtr, &ret_tgts[ntgts]))) { goto cleanup; } krb5_free_creds(context, tgtr); tgtr = NULL; tgt = *ret_tgts[ntgts++]; /* we're done if it is the target */ if (!*next_server++) break; } } } /* got/finally have tgt! try for the creds */ if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) { retval = KRB5_PROG_ETYPE_NOSUPP; goto cleanup; } context->use_conf_ktypes = old_use_conf_ktypes; retval = krb5_get_cred_via_tkt(context, &tgt, FLAGS2OPTS(tgt.ticket_flags) | kdcopt | (in_cred->second_ticket.length ? KDC_OPT_ENC_TKT_IN_SKEY : 0), tgt.addresses, in_cred, out_cred); /* cleanup and return */ cleanup: if (tgtr) krb5_free_creds(context, tgtr); if(tgs_list) krb5_free_realm_tree(context, tgs_list); krb5_free_cred_contents(context, &tgtq); if (int_server) krb5_free_principal(context, int_server); if (ntgts == 0) { *tgts = NULL; if (ret_tgts) free(ret_tgts); krb5_free_cred_contents(context, &tgt); } context->use_conf_ktypes = old_use_conf_ktypes; return(retval); }
krb5_error_code krb5_walk_realm_tree(krb5_context context, const krb5_data *client, const krb5_data *server, krb5_principal **tree, int realm_branch_char) { krb5_error_code retval; krb5_principal *rettree; register char *ccp, *scp; register char *prevccp = 0, *prevscp = 0; char *com_sdot = 0, *com_cdot = 0; register int i, links = 0; int clen, slen = -1; krb5_data tmpcrealm, tmpsrealm; int nocommon = 1; #ifdef CONFIGURABLE_AUTHENTICATION_PATH const char *cap_names[4]; char *cap_client, *cap_server; char **cap_nodes; krb5_error_code cap_code; #endif #ifdef DEBUG_REFERRALS printf("krb5_walk_realm_tree starting\n"); printf(" client is %s\n",client->data); printf(" server is %s\n",server->data); #endif if (!(client->data && server->data)) { /* Solaris Kerberos - enhance error message */ if (!client->data && !server->data) { krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, dgettext(TEXT_DOMAIN, "Cannot find ticket for requested realm: unknown client and server")); } else { if (!client->data) { krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, dgettext(TEXT_DOMAIN, "Cannot find ticket for requested realm: unknown client")); } else { krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, dgettext(TEXT_DOMAIN, "Cannot find ticket for requested realm: unknown server")); } } return KRB5_NO_TKT_IN_RLM; } #ifdef CONFIGURABLE_AUTHENTICATION_PATH if ((cap_client = (char *)malloc(client->length + 1)) == NULL) return ENOMEM; strncpy(cap_client, client->data, client->length); cap_client[client->length] = '\0'; if ((cap_server = (char *)malloc(server->length + 1)) == NULL) { krb5_xfree(cap_client); return ENOMEM; } strncpy(cap_server, server->data, server->length); cap_server[server->length] = '\0'; cap_names[0] = "capaths"; cap_names[1] = cap_client; cap_names[2] = cap_server; cap_names[3] = 0; cap_code = profile_get_values(context->profile, cap_names, &cap_nodes); krb5_xfree(cap_client); /* done with client string */ cap_names[1] = 0; if (cap_code == 0) { /* found a path, so lets use it */ links = 0; if (*cap_nodes[0] != '.') { /* a link of . means direct */ while(cap_nodes[links]) { links++; } } if (cap_nodes[links] != NULL) krb5_xfree(cap_nodes[links]); cap_nodes[links] = cap_server; /* put server on end of list */ /* this simplifies the code later and make */ /* cleanup eaiser as well */ links++; /* count the null entry at end */ } else { /* no path use hierarchical method */ krb5_xfree(cap_server); /* failed, don't need server string */ cap_names[2] = 0; #endif clen = client->length; slen = server->length; for (com_cdot = ccp = client->data + clen - 1, com_sdot = scp = server->data + slen - 1; clen && slen && *ccp == *scp ; ccp--, scp--, clen--, slen--) { if (*ccp == realm_branch_char) { com_cdot = ccp; com_sdot = scp; nocommon = 0; } } /* ccp, scp point to common root. com_cdot, com_sdot point to common components. */ /* handle case of one ran out */ if (!clen) { /* construct path from client to server, down the tree */ if (!slen) { /* in the same realm--this means there is no ticket in this realm. */ krb5_set_error_message(context, KRB5_NO_TKT_IN_RLM, dgettext(TEXT_DOMAIN, "Cannot find ticket for requested realm: client is '%s', server is '%s'"), client->data, server->data); return KRB5_NO_TKT_IN_RLM; } if (*scp == realm_branch_char) { /* one is a subdomain of the other */ com_cdot = client->data; com_sdot = scp; nocommon = 0; } /* else normal case of two sharing parents */ } if (!slen) { /* construct path from client to server, up the tree */ if (*ccp == realm_branch_char) { /* one is a subdomain of the other */ com_sdot = server->data; com_cdot = ccp; nocommon = 0; } /* else normal case of two sharing parents */ } /* determine #links to/from common ancestor */ if (nocommon) links = 1; else links = 2; /* if no common ancestor, artificially set up common root at the last component, then join with special code */ for (ccp = client->data; ccp < com_cdot; ccp++) { if (*ccp == realm_branch_char) { links++; if (nocommon) prevccp = ccp; } } for (scp = server->data; scp < com_sdot; scp++) { if (*scp == realm_branch_char) { links++; if (nocommon) prevscp = scp; } } if (nocommon) { if (prevccp) com_cdot = prevccp; if (prevscp) com_sdot = prevscp; if(com_cdot == client->data + client->length -1) com_cdot = client->data - 1 ; if(com_sdot == server->data + server->length -1) com_sdot = server->data - 1 ; } #ifdef CONFIGURABLE_AUTHENTICATION_PATH } /* end of if use hierarchical method */ #endif if (!(rettree = (krb5_principal *)calloc(links+2, sizeof(krb5_principal)))) { return ENOMEM; } i = 1; if ((retval = krb5_tgtname(context, client, client, &rettree[0]))) { krb5_xfree(rettree); return retval; } #ifdef CONFIGURABLE_AUTHENTICATION_PATH links--; /* dont count the null entry on end */ if (cap_code == 0) { /* found a path above */ tmpcrealm.data = client->data; tmpcrealm.length = client->length; while( i-1 <= links) { tmpsrealm.data = cap_nodes[i-1]; /* don't count trailing whitespace from profile_get */ tmpsrealm.length = strcspn(cap_nodes[i-1],"\t "); if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i]))) { while (i) { krb5_free_principal(context, rettree[i-1]); i--; } krb5_xfree(rettree); /* cleanup the cap_nodes from profile_get */ for (i = 0; i<=links; i++) { krb5_xfree(cap_nodes[i]); } krb5_xfree((char *)cap_nodes); return retval; } tmpcrealm.data = tmpsrealm.data; tmpcrealm.length = tmpsrealm.length; i++; } /* cleanup the cap_nodes from profile_get last one has server */ for (i = 0; i<=links; i++) { krb5_xfree(cap_nodes[i]); } krb5_xfree((char *)cap_nodes); } else { /* if not cap then use hierarchical method */ #endif for (prevccp = ccp = client->data; ccp <= com_cdot; ccp++) { if (*ccp != realm_branch_char) continue; ++ccp; /* advance past dot */ tmpcrealm.data = prevccp; tmpcrealm.length = client->length - (prevccp - client->data); tmpsrealm.data = ccp; tmpsrealm.length = client->length - (ccp - client->data); if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i]))) { while (i) { krb5_free_principal(context, rettree[i-1]); i--; } krb5_xfree(rettree); return retval; } prevccp = ccp; i++; } if (nocommon) { tmpcrealm.data = com_cdot + 1; tmpcrealm.length = client->length - (com_cdot + 1 - client->data); tmpsrealm.data = com_sdot + 1; tmpsrealm.length = server->length - (com_sdot + 1 - server->data); if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i]))) { while (i) { krb5_free_principal(context, rettree[i-1]); i--; } krb5_xfree(rettree); return retval; } i++; } for (prevscp = com_sdot + 1, scp = com_sdot - 1; scp > server->data; scp--) { if (*scp != realm_branch_char) continue; if (scp - 1 < server->data) break; /* XXX only if . starts realm? */ tmpcrealm.data = prevscp; tmpcrealm.length = server->length - (prevscp - server->data); tmpsrealm.data = scp + 1; tmpsrealm.length = server->length - (scp + 1 - server->data); if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm, &rettree[i]))) { while (i) { krb5_free_principal(context, rettree[i-1]); i--; } krb5_xfree(rettree); return retval; } prevscp = scp + 1; i++; } if (slen && com_sdot >= server->data) { /* only necessary if building down tree from ancestor or client */ /* however, we can get here if we have only one component in the server realm name, hence we make sure we found a component separator there... */ tmpcrealm.data = prevscp; tmpcrealm.length = server->length - (prevscp - server->data); if ((retval = krb5_tgtname(context, server, &tmpcrealm, &rettree[i]))) { while (i) { krb5_free_principal(context, rettree[i-1]); i--; } krb5_xfree(rettree); return retval; } } #ifdef CONFIGURABLE_AUTHENTICATION_PATH } #endif *tree = rettree; #ifdef DEBUG_REFERRALS printf("krb5_walk_realm_tree ending; tree (length %d) is:\n",links); for(i=0;i<links+2;i++) { if ((*tree)[i]) krb5int_dbgref_dump_principal("krb5_walk_realm_tree tree",(*tree)[i]); else printf("tree element %i null\n"); } #endif return 0; }