/* * init_rtree() * * Populate KDC_LIST with the output of krb5_walk_realm_tree(). */ 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; }
int main(int argc, char **argv) { krb5_data client, server; char realm_branch_char = '.'; krb5_principal *tree, *p; char *name; krb5_error_code retval; krb5_context context; krb5_init_context(&context); if (argc < 3 || argc > 4) { fprintf(stderr, "Usage: %s client-realm server-realm [sep_char]\n", argv[0]); exit(99); } client.data = argv[1]; client.length = strlen(client.data); server.data = argv[2]; server.length = strlen(server.data); if (argc == 4) realm_branch_char = argv[3][0]; retval = krb5_walk_realm_tree(context, &client, &server, &tree, realm_branch_char); if (retval) { com_err("krb5_walk_realm_tree", retval, " "); exit(1); } for (p = tree; *p; p++) { retval = krb5_unparse_name(context, *p, &name); if (retval) { com_err("krb5_unprase_name", retval, " "); exit(2); } printf("%s\n", name); free(name); } krb5_free_realm_tree(context, tree); krb5_free_context(context); exit(0); }
krb5_error_code krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in, const krb5_data *crealm, const krb5_data *srealm) { krb5_data trans; struct check_data cdata; krb5_error_code r; const krb5_data *anonymous; trans.length = trans_in->length; trans.data = (char *) trans_in->data; if (trans.length && (trans.data[trans.length-1] == '\0')) trans.length--; Tprintf (("krb5_check_transited_list(trans=\"%.*s\", crealm=\"%.*s\", srealm=\"%.*s\")\n", (int) trans.length, trans.data, (int) crealm->length, crealm->data, (int) srealm->length, srealm->data)); if (trans.length == 0) return 0; anonymous = krb5_anonymous_realm(); if (crealm->length == anonymous->length && (memcmp(crealm->data, anonymous->data, anonymous->length) == 0)) return 0; /* Nothing to check for anonymous */ r = krb5_walk_realm_tree (ctx, crealm, srealm, &cdata.tgs, KRB5_REALM_BRANCH_CHAR); if (r) { Tprintf (("error %ld\n", (long) r)); return r; } #ifdef DEBUG /* avoid compiler warning about 'd' unused */ { int i; Tprintf (("tgs list = {\n")); for (i = 0; cdata.tgs[i]; i++) { char *name; r = krb5_unparse_name (ctx, cdata.tgs[i], &name); Tprintf (("\t'%s'\n", name)); free (name); } Tprintf (("}\n")); } #endif cdata.ctx = ctx; r = foreach_realm (check_realm_in_list, &cdata, crealm, srealm, &trans); krb5_free_realm_tree (ctx, cdata.tgs); return r; }
/* * The request seems to be for a ticket-granting service somewhere else, * but we don't have a ticket for the final TGS. Try to give the requestor * some intermediate realm. */ static krb5_error_code find_alternate_tgs(kdc_realm_t *kdc_active_realm, krb5_principal princ, krb5_db_entry **server_ptr, const char **status) { krb5_error_code retval; krb5_principal *plist = NULL, *pl2; krb5_data tmp; krb5_db_entry *server = NULL; *server_ptr = NULL; assert(is_cross_tgs_principal(princ)); if ((retval = krb5_walk_realm_tree(kdc_context, krb5_princ_realm(kdc_context, princ), krb5_princ_component(kdc_context, princ, 1), &plist, KRB5_REALM_BRANCH_CHAR))) { goto cleanup; } /* move to the end */ for (pl2 = plist; *pl2; pl2++); /* the first entry in this array is for krbtgt/local@local, so we ignore it */ while (--pl2 > plist) { tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, princ)); retval = db_get_svc_princ(kdc_context, *pl2, 0, &server, status); krb5_princ_set_realm(kdc_context, *pl2, &tmp); if (retval == KRB5_KDB_NOENTRY) continue; else if (retval) goto cleanup; log_tgs_alt_tgt(kdc_context, server->princ); *server_ptr = server; server = NULL; goto cleanup; } cleanup: if (retval == 0 && *server_ptr == NULL) retval = KRB5_KDB_NOENTRY; if (retval != 0) *status = "UNKNOWN_SERVER"; krb5_free_realm_tree(kdc_context, plist); krb5_db_free_principal(kdc_context, server); return retval; }
/* Initialize the realm path fields for getting a TGT for * ctx->server->realm. */ static krb5_error_code init_realm_path(krb5_context context, krb5_tkt_creds_context ctx) { krb5_error_code code; krb5_principal *tgt_princ_list = NULL; krb5_data *realm_path; size_t nrealms, i; /* Construct a list of TGT principals from client to server. We will throw * this away after grabbing the remote realms from each principal. */ code = krb5_walk_realm_tree(context, &ctx->client->realm, &ctx->server->realm, &tgt_princ_list, KRB5_REALM_BRANCH_CHAR); if (code != 0) return code; /* Count the number of principals and allocate the realm path. */ for (nrealms = 0; tgt_princ_list[nrealms]; nrealms++); assert(nrealms > 1); realm_path = k5alloc((nrealms + 1) * sizeof(*realm_path), &code); if (realm_path == NULL) goto cleanup; /* Steal the remote realm field from each TGT principal. */ for (i = 0; i < nrealms; i++) { assert(tgt_princ_list[i]->length == 2); realm_path[i] = tgt_princ_list[i]->data[1]; tgt_princ_list[i]->data[1].data = NULL; } realm_path[nrealms] = empty_data(); /* Initialize the realm path fields in ctx. */ krb5int_free_data_list(context, ctx->realm_path); ctx->realm_path = realm_path; ctx->last_realm = realm_path + nrealms - 1; ctx->cur_realm = realm_path; ctx->next_realm = ctx->last_realm; realm_path = NULL; cleanup: krb5_free_realm_tree(context, tgt_princ_list); return 0; }
/* * The request seems to be for a ticket-granting service somewhere else, * but we don't have a ticket for the final TGS. Try to give the requestor * some intermediate realm. */ static void find_alternate_tgs(krb5_kdc_req *request, krb5_db_entry *server, krb5_boolean *more, int *nprincs) { krb5_error_code retval; krb5_principal *plist, *pl2; krb5_data tmp; *nprincs = 0; *more = FALSE; /* * Call to krb5_princ_component is normally not safe but is so * here only because find_alternate_tgs() is only called from * somewhere that has already checked the number of components in * the principal. */ if ((retval = krb5_walk_realm_tree(kdc_context, krb5_princ_realm(kdc_context, request->server), krb5_princ_component(kdc_context, request->server, 1), &plist, KRB5_REALM_BRANCH_CHAR))) return; /* move to the end */ for (pl2 = plist; *pl2; pl2++); /* the first entry in this array is for krbtgt/local@local, so we ignore it */ while (--pl2 > plist) { *nprincs = 1; tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, tgs_server)); retval = get_principal(kdc_context, *pl2, server, nprincs, more); krb5_princ_set_realm(kdc_context, *pl2, &tmp); if (retval) { *nprincs = 0; *more = FALSE; krb5_free_realm_tree(kdc_context, plist); return; } if (*more) { krb5_db_free_principal(kdc_context, server, *nprincs); continue; } else if (*nprincs == 1) { /* Found it! */ krb5_principal tmpprinc; tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, tgs_server)); if ((retval = krb5_copy_principal(kdc_context, *pl2, &tmpprinc))) { krb5_db_free_principal(kdc_context, server, *nprincs); krb5_princ_set_realm(kdc_context, *pl2, &tmp); continue; } krb5_princ_set_realm(kdc_context, *pl2, &tmp); krb5_free_principal(kdc_context, request->server); request->server = tmpprinc; log_tgs_alt_tgt(request->server); krb5_free_realm_tree(kdc_context, plist); return; } krb5_db_free_principal(kdc_context, server, *nprincs); continue; } *nprincs = 0; *more = FALSE; krb5_free_realm_tree(kdc_context, plist); return; }
/* * The request seems to be for a ticket-granting service somewhere else, * but we don't have a ticket for the final TGS. Try to give the requestor * some intermediate realm. */ static krb5_error_code find_alternate_tgs(krb5_kdc_req *request, krb5_db_entry **server_ptr) { krb5_error_code retval; krb5_principal *plist = NULL, *pl2, tmpprinc; krb5_data tmp; krb5_db_entry *server = NULL; *server_ptr = NULL; /* * Call to krb5_princ_component is normally not safe but is so * here only because find_alternate_tgs() is only called from * somewhere that has already checked the number of components in * the principal. */ if ((retval = krb5_walk_realm_tree(kdc_context, krb5_princ_realm(kdc_context, request->server), krb5_princ_component(kdc_context, request->server, 1), &plist, KRB5_REALM_BRANCH_CHAR))) return retval; /* move to the end */ for (pl2 = plist; *pl2; pl2++); /* the first entry in this array is for krbtgt/local@local, so we ignore it */ while (--pl2 > plist) { tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, tgs_server)); retval = krb5_db_get_principal(kdc_context, *pl2, 0, &server); krb5_princ_set_realm(kdc_context, *pl2, &tmp); if (retval == KRB5_KDB_NOENTRY) continue; else if (retval) goto cleanup; /* Found it. */ tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, tgs_server)); retval = krb5_copy_principal(kdc_context, *pl2, &tmpprinc); if (retval) goto cleanup; krb5_princ_set_realm(kdc_context, *pl2, &tmp); krb5_free_principal(kdc_context, request->server); request->server = tmpprinc; log_tgs_alt_tgt(request->server); *server_ptr = server; server = NULL; goto cleanup; } retval = KRB5_KDB_NOENTRY; cleanup: krb5_free_realm_tree(kdc_context, plist); krb5_db_free_principal(kdc_context, server); 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); }
/* * The request seems to be for a ticket-granting service somewhere else, * but we don't have a ticket for the final TGS. Try to give the requestor * some intermediate realm. */ static void find_alternate_tgs(krb5_kdc_req *request, krb5_db_entry *server, krb5_boolean *more, int *nprincs, const krb5_fulladdr *from, char *cname) { krb5_error_code retval; krb5_principal *plist, *pl2; krb5_data tmp; *nprincs = 0; *more = FALSE; /* * Call to krb5_princ_component is normally not safe but is so * here only because find_alternate_tgs() is only called from * somewhere that has already checked the number of components in * the principal. */ if ((retval = krb5_walk_realm_tree(kdc_context, krb5_princ_realm(kdc_context, request->server), krb5_princ_component(kdc_context, request->server, 1), &plist, KRB5_REALM_BRANCH_CHAR))) return; /* move to the end */ for (pl2 = plist; *pl2; pl2++); /* the first entry in this array is for krbtgt/local@local, so we ignore it */ while (--pl2 > plist) { *nprincs = 1; tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, tgs_server)); retval = krb5_db_get_principal(kdc_context, *pl2, server, nprincs, more); krb5_princ_set_realm(kdc_context, *pl2, &tmp); if (retval) { *nprincs = 0; *more = FALSE; krb5_free_realm_tree(kdc_context, plist); return; } if (*more) { krb5_db_free_principal(kdc_context, server, *nprincs); continue; } else if (*nprincs == 1) { /* Found it! */ krb5_principal tmpprinc; char *sname; tmp = *krb5_princ_realm(kdc_context, *pl2); krb5_princ_set_realm(kdc_context, *pl2, krb5_princ_realm(kdc_context, tgs_server)); if ((retval = krb5_copy_principal(kdc_context, *pl2, &tmpprinc))) { krb5_db_free_principal(kdc_context, server, *nprincs); krb5_princ_set_realm(kdc_context, *pl2, &tmp); continue; } krb5_princ_set_realm(kdc_context, *pl2, &tmp); krb5_free_principal(kdc_context, request->server); request->server = tmpprinc; if (krb5_unparse_name(kdc_context, request->server, &sname)) { audit_krb5kdc_tgs_req_alt_tgt( (struct in_addr *)from->address->contents, (in_port_t)from->port, 0, cname, "<unparseable>", 0); krb5_klog_syslog(LOG_INFO, "TGS_REQ: issuing alternate <un-unparseable> TGT"); } else { limit_string(sname); audit_krb5kdc_tgs_req_alt_tgt( (struct in_addr *)from->address->contents, (in_port_t)from->port, 0, cname, sname, 0); krb5_klog_syslog(LOG_INFO, "TGS_REQ: issuing TGT %s", sname); free(sname); } return; } krb5_db_free_principal(kdc_context, server, *nprincs); continue; } *nprincs = 0; *more = FALSE; krb5_free_realm_tree(kdc_context, plist); return; }