diff options
author | Andrew Boardman <amb@mit.edu> | 2006-08-25 06:45:52 +0000 |
---|---|---|
committer | Andrew Boardman <amb@mit.edu> | 2006-08-25 06:45:52 +0000 |
commit | 736b0dc1b7c502d68c30df0eb679941297f3f867 (patch) | |
tree | 77c729c3a9406dd4b84695b340b07e9c74f67248 | |
parent | ca66b2b4b82aec99505539e013643da5b159fc79 (diff) | |
download | krb5-736b0dc1b7c502d68c30df0eb679941297f3f867.zip krb5-736b0dc1b7c502d68c30df0eb679941297f3f867.tar.gz krb5-736b0dc1b7c502d68c30df0eb679941297f3f867.tar.bz2 |
Rearrange and simplify logic to match decisions at 21 August meeting
git-svn-id: svn://anonsvn.mit.edu/krb5/users/amb/referrals@18535 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r-- | src/lib/krb5/krb/gc_frm_kdc.c | 184 |
1 files changed, 117 insertions, 67 deletions
diff --git a/src/lib/krb5/krb/gc_frm_kdc.c b/src/lib/krb5/krb/gc_frm_kdc.c index 0828c00..d702518 100644 --- a/src/lib/krb5/krb/gc_frm_kdc.c +++ b/src/lib/krb5/krb/gc_frm_kdc.c @@ -762,51 +762,37 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds ***tgts, int kdcopt) { krb5_error_code retval; - krb5_principal client, server; - krb5_creds tgtq, cc_tgt, *tgtptr, **kdc_tgts; + krb5_principal client, server, supplied_server; + krb5_creds tgtq, cc_tgt, *tgtptr, *referral_tgts[KRB5_REFERRAL_MAXHOPS]; krb5_boolean old_use_conf_ktypes; - char **hrealms, *supplied_server_realm; - int i; - - if(!(kdc_tgts=calloc(KRB5_REFERRAL_MAXHOPS, sizeof(krb5_creds)))) - return ENOMEM; - /* XXX: this is lazy. Allocate per use later on. */ + char **hrealms; + int referral_count; client = in_cred->client; server = in_cred->server; /* XXX hack for testing to force referral */ // /* XXX */ server->realm.data[0]=0; +#ifdef DEBUG_REFERRALS amb_dump_principal("krb5_get_cred_from_kdc_opt initial client", client); +#endif memset(&cc_tgt, 0, sizeof(cc_tgt)); memset(&tgtq, 0, sizeof(tgtq)); tgtptr = NULL; *tgts = NULL; old_use_conf_ktypes = context->use_conf_ktypes; - /* - * Get a TGT for the target realm. - */ - - /* Set initial realm. */ - supplied_server_realm=server->realm.data; - if (!strcmp(server->realm.data, KRB5_REFERRAL_REALM)) { + /* Copy initially specified principal, then copy client realm for server if no hint. */ + if ((retval=krb5_copy_principal(context, server, &supplied_server))) + return retval; + if (!strcmp(server->realm.data, KRB5_REFERRAL_REALM)) { // XXX a realm is not a string! /* Use the client realm. */ - if (!( server->realm.data = (char *)malloc(strlen(client->realm.data)+1))) - return ENOMEM; - strcpy(server->realm.data, client->realm.data); - } - else { - /* Make a copy of the oringinal supplied server realm. */ - if (!( server->realm.data = (char *)malloc(strlen(supplied_server_realm)+1))) + if (!( server->realm.data = (char *)malloc(client->realm.length))) return ENOMEM; - strcpy(server->realm.data, supplied_server_realm); + memcpy(server->realm.data, client->realm.data, client->realm.length); } - printf("Supplied realm <%s> stashed\n",supplied_server_realm); - - /* Make sure we have a starting TGT. */ - - /* Create minimal credential to match against ccache. */ - retval = tgt_mcred(context, client, server, client, &tgtq); + /* Retreive initial (local) TGT */ + /* retval = tgt_mcred(context, client, server, client, &tgtq);*/ + retval = tgt_mcred(context, client, client, client, &tgtq); if (retval) goto cleanup; @@ -816,19 +802,27 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, &tgtq, &cc_tgt); if (!retval) { tgtptr = &cc_tgt; - } else if (!HARD_CC_ERR(retval)) { - /* Not in ccache, so traverse the transit path. */ - /* XXX: this will not work if starting TGT needs referrals to be - obtained */ - retval = do_traversal(context, ccache, client, server, - &cc_tgt, &tgtptr, tgts); + } else { +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: couldn't find local tgt!\n"); +#endif + goto cleanup; } - if (retval) - goto cleanup; - for (i=0;i<KRB5_REFERRAL_MAXHOPS;i++) { - /* Main referral loop. Starting state: will have valid initial - realm set for server as well as a TGT for that realm. */ - amb_dump_principal("referral loop: requesting:", server); + +#ifdef DEBUG_REFERRALS + amb_dump_principal("gc_from_kdc: server as requested", supplied_server); +#endif + + /* + * Try requesting a service ticket from our local KDC with referrals + * turned on. If the first referral succeeds, follow a referral-only + * path, otherwise fall back to old-style assumptions. + */ + + for (referral_count=0;referral_count<KRB5_REFERRAL_MAXHOPS;referral_count++) { +#ifdef DEBUG_REFERRALS + amb_dump_principal("gc_from_kdc: referral loop requesting:", server); +#endif retval = krb5_get_cred_via_tkt(context, tgtptr, KDC_OPT_CANONICALIZE | FLAGS2OPTS(tgtptr->ticket_flags) | @@ -837,33 +831,55 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, KDC_OPT_ENC_TKT_IN_SKEY : 0), tgtptr->addresses, in_cred, out_cred); if (retval) { - /* Never exit here, no matter how bad the KDC error looks, just - punt to a non-referral request. */ - printf("referral tgs-req failed: <%s>\n",error_message(retval)); - //free (server->realm.data); - server->realm.data=supplied_server_realm; - break; +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: referral TGS-REQ request failed: <%s>\n",error_message(retval)); +#endif + /* If we haven't gone anywhere yet, fail through to the + non-referral case. */ + if (referral_count==0) { +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: initial referral failed; punting to fallback.\n"); +#endif + break; + } + /* Otherwise, try the same query without canonicalization + set, and fail hard if that doesn't work. */ +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: referral #%d failed; retrying without option.\n", + referral_count+1); +#endif + 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); + /* Whether or not that succeeded, we're done. */ + goto cleanup; } else { - /* Request succeeded; let's see what it is. */ + /* Referral request succeeded; let's see what it is. */ if (krb5_principal_compare(context, in_cred->server, out_cred[0]->server)) { - printf("referral generated ticket for requested server principal\n"); - amb_dump_principal("server reply",in_cred->server); - tgts=&kdc_tgts; - /* XXX clean up */ - return retval; +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: referral generated ticket for requested server principal\n"); + amb_dump_principal("gc_from_kdc final referred reply",in_cred->server); +#endif + // tgts=referral_tgts; + goto cleanup; } else { - printf("referral generated referral tgt\n"); - amb_dump_principal("credential got:", out_cred[0]->server); +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: referral generated referral tgt\n"); + amb_dump_principal("gc_from_kdc credential received:", out_cred[0]->server); +#endif /* need to: - 1) stash tgt in tgts + 1) stash tgt in referral_tgts 2) use this tgt for next referral 3) rewrite server principal per any padata */ - /* XXX verify referral TGT before use? */ tgtptr=out_cred[0]; /* save this credential in tgt sequence */ - kdc_tgts[i]=tgtptr=out_cred[0]; + referral_tgts[referral_count]=tgtptr=out_cred[0]; /* copy krbtgt realm to server principal */ free(server->realm.data); if(!(server->realm.data=malloc(tgtptr->server->data[1].length))) @@ -875,29 +891,46 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, } } - printf("referral failed; exiting.\n"),exit(1); - amb_dump_principal("krb5_get_cred_from_kdc_opt client at fallback", client); - amb_dump_principal("krb5_get_cred_from_kdc_opt server af fallback", server); +#ifdef DEBUG_REFERRALS + amb_dump_principal("gc_from_kdc client at fallback", client); + amb_dump_principal("gc_from_kdc server at fallback", server); + printf("gc_from_kdc: referral failed; exiting.\n"),exit(1); +#endif + + /* + * At this point referrals have been tried and have failed. Go back + * to the server principal as originally issued and try the conventional path. + */ + /* Free any referral TGTs accumulated. */ + // XXX: to be implemented + /* Referrals have failed. Look up fallback realm if not currently set. */ - if (!strcmp(server->realm.data, KRB5_REFERRAL_REALM)) { + if (!strcmp(server->realm.data, KRB5_REFERRAL_REALM)) { // XXX a realm is not a string! if (server->length >= 2) { retval=krb5_get_fallback_host_realm(context, server->data[1].data, &hrealms); if (retval) goto cleanup; - printf("using fallback realm of %s\n",hrealms[0]); +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: using fallback realm of %s\n",hrealms[0]); +#endif in_cred->server->realm.data=hrealms[0]; } else { - /* XXX specified for referral but apparently not in a + /* XXX realm tagged for referral but apparently not in a <type>/<host> format. Fall back in some intelligent way or just punt? */ - printf("referral specified but no fallback realm. wtf? exiting.\n"); +#ifdef DEBUG_REFERRALS + printf("gc_from_kdc: referral specified but no fallback realm. wtf? exiting.\n"); +#endif exit(1); } } + + /* + * Get a TGT for the target realm. + */ - /* Create minimal credential to match against ccache. */ retval = tgt_mcred(context, client, server, client, &tgtq); if (retval) goto cleanup; @@ -909,7 +942,6 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, if (!retval) { tgtptr = &cc_tgt; } else if (!HARD_CC_ERR(retval)) { - /* Not in ccache, so traverse the transit path. */ retval = do_traversal(context, ccache, client, server, &cc_tgt, &tgtptr, tgts); } @@ -939,6 +971,10 @@ cleanup: krb5_free_cred_contents(context, tgtptr); context->use_conf_ktypes = old_use_conf_ktypes; +#ifdef DEBUG_REFERRALS + amb_dump_principal("gc_from_kdc: final server",server); +#endif + return retval; } @@ -968,3 +1004,17 @@ krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache, return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts, KDC_OPT_RENEW); } + +#ifdef DEBUG_REFERRALS +void amb_dump_principal(char *d, krb5_principal p) +{ + int n; + + printf(" **%s (principal dump)\n",d); + printf(" principal realm: <%.*s>\n",p->realm.length,p->realm.data); + // printf(" principal length is %d\n",p->length); + for (n=0;n<p->length;n++) + printf(" principal data[%d]: %.*s\n",n,p->data[n].length,p->data[n].data); + // printf(" principal type is %d\n",p->type); +} +#endif |