Index: src/include/k5-int.h =================================================================== --- src/include/k5-int.h (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/include/k5-int.h (.../branches/krb5-1-6) (Revision 19936) @@ -216,6 +216,10 @@ /* required */ #define KDC_ERR_SERVER_NOMATCH 26 /* Requested server and */ /* ticket don't match*/ +#define KDC_ERR_SVC_UNAVAILABLE 29 /* A service is not + * available that is + * required to process the + * request */ /* Application errors */ #define KRB_AP_ERR_BAD_INTEGRITY 31 /* Decrypt integrity check failed */ #define KRB_AP_ERR_TKT_EXPIRED 32 /* Ticket expired */ @@ -498,7 +502,9 @@ krb5_error_code krb5int_sendto (krb5_context context, const krb5_data *message, const struct addrlist *addrs, struct sendto_callback_info* callback_info, krb5_data *reply, struct sockaddr *localaddr, socklen_t *localaddrlen, - struct sockaddr *remoteaddr, socklen_t *remoteaddrlen, int *addr_used); + struct sockaddr *remoteaddr, socklen_t *remoteaddrlen, int *addr_used, + int (*msg_handler)(krb5_context, const krb5_data *, void *), + void *msg_handler_data); krb5_error_code krb5_get_krbhst (krb5_context, const krb5_data *, char *** ); krb5_error_code krb5_free_krbhst (krb5_context, char * const * ); @@ -1885,7 +1891,9 @@ krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg, const struct addrlist *, struct sendto_callback_info*, krb5_data *reply, struct sockaddr *, socklen_t *,struct sockaddr *, - socklen_t *, int *); + socklen_t *, int *, + int (*msg_handler)(krb5_context, const krb5_data *, void *), + void *msg_handler_data); krb5_error_code (*add_host_to_list)(struct addrlist *lp, const char *hostname, int port, int secport, Index: src/clients/kvno/kvno.M =================================================================== --- src/clients/kvno/kvno.M (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/clients/kvno/kvno.M (.../branches/krb5-1-6) (Revision 19936) @@ -55,6 +55,15 @@ specifies that Kerberos version 4 tickets should be acquired and described. This option is only available if Kerberos 4 support was enabled at compilation time. +.TP +.B \-S sname +specifies that krb5_sname_to_principal() will be used to build +principal names. If this flag is specified, the +.B service1 service2 ... +arguments are interpreted as hostnames (rather than principal names), +and +.B sname +is interpreted as the service name. .SH ENVIRONMENT .B Kvno uses the following environment variable: Index: src/clients/kvno/kvno.c =================================================================== --- src/clients/kvno/kvno.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/clients/kvno/kvno.c (.../branches/krb5-1-6) (Revision 19936) @@ -41,10 +41,10 @@ { #ifdef KRB5_KRB4_COMPAT fprintf(stderr, - "usage: %s [-4 | [-c ccache] [-e etype] [-k keytab]] service1 service2 ...\n", + "usage: %s [-4 | [-c ccache] [-e etype] [-k keytab] [-S sname]] service1 service2 ...\n", prog); #else - fprintf(stderr, "usage: %s [-c ccache] [-e etype] [-k keytab] service1 service2 ...\n", + fprintf(stderr, "usage: %s [-c ccache] [-e etype] [-k keytab] [-S sname] service1 service2 ...\n", prog); #endif exit(1); @@ -54,7 +54,8 @@ static void do_v4_kvno (int argc, char *argv[]); static void do_v5_kvno (int argc, char *argv[], - char *ccachestr, char *etypestr, char *keytab_name); + char *ccachestr, char *etypestr, char *keytab_name, + char *sname); #include static void extended_com_err_fn (const char *, errcode_t, const char *, @@ -64,6 +65,7 @@ { int option; char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL; + char *sname = NULL; int v4 = 0; set_com_err_hook (extended_com_err_fn); @@ -71,7 +73,7 @@ prog = strrchr(argv[0], '/'); prog = prog ? (prog + 1) : argv[0]; - while ((option = getopt(argc, argv, "c:e:hk:q4")) != -1) { + while ((option = getopt(argc, argv, "c:e:hk:q4S:")) != -1) { switch (option) { case 'c': ccachestr = optarg; @@ -91,6 +93,9 @@ case '4': v4 = 1; break; + case 'S': + sname = optarg; + break; default: xusage(); break; @@ -103,10 +108,14 @@ if ((ccachestr != NULL || etypestr != NULL || keytab_name != NULL) && v4) xusage(); + if (sname != NULL && v4) + xusage(); + if (v4) do_v4_kvno(argc - optind, argv + optind); else - do_v5_kvno(argc - optind, argv + optind, ccachestr, etypestr, keytab_name); + do_v5_kvno(argc - optind, argv + optind, + ccachestr, etypestr, keytab_name, sname); return 0; } @@ -172,7 +181,8 @@ } static void do_v5_kvno (int count, char *names[], - char * ccachestr, char *etypestr, char *keytab_name) + char * ccachestr, char *etypestr, char *keytab_name, + char *sname) { krb5_error_code ret; int i, errors; @@ -230,7 +240,13 @@ in_creds.client = me; - ret = krb5_parse_name(context, names[i], &in_creds.server); + if (sname != NULL) { + ret = krb5_sname_to_principal(context, names[i], + sname, KRB5_NT_SRV_HST, + &in_creds.server); + } else { + ret = krb5_parse_name(context, names[i], &in_creds.server); + } if (ret) { if (!quiet) com_err(prog, ret, "while parsing principal name %s", names[i]); Index: src/lib/crypto/prng.c =================================================================== --- src/lib/crypto/prng.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/crypto/prng.c (.../branches/krb5-1-6) (Revision 19936) @@ -162,7 +162,7 @@ krb5_data data; struct stat sb; int fd; - unsigned char buf[YARROW_SLOW_THRESH/8]; + unsigned char buf[YARROW_SLOW_THRESH/8], *bp; int left; fd = open (device, O_RDONLY); if (fd == -1) @@ -173,14 +173,16 @@ close(fd); return 0; } - for (left = sizeof (buf); left > 0;) { + + for (bp = &buf, left = sizeof (buf); left > 0;) { ssize_t count; - count = read (fd, &buf, (unsigned) left); + count = read (fd, bp, (unsigned) left); if (count <= 0) { close(fd); return 0; } left -= count; + bp += count; } close (fd); data.length = sizeof (buf); @@ -199,7 +201,7 @@ int unused; int *oursuccess = success?success:&unused; *oursuccess = 0; - /* If we are getting strong data then try that first. We aare + /* If we are getting strong data then try that first. We are guaranteed to cause a reseed of some kind if strong is true and we have both /dev/random and /dev/urandom. We want the strong data included in the reseed so we get it first.*/ Index: src/lib/gssapi/spnego/spnego_mech.c =================================================================== --- src/lib/gssapi/spnego/spnego_mech.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/gssapi/spnego/spnego_mech.c (.../branches/krb5-1-6) (Revision 19936) @@ -61,7 +61,7 @@ /* private routines for spnego_mechanism */ static spnego_token_t make_spnego_token(char *); static gss_buffer_desc make_err_msg(char *); -static int g_token_size(gss_OID_const, OM_uint32); +static int g_token_size(gss_OID_const, unsigned int); static int g_make_token_header(gss_OID_const, unsigned int, unsigned char **, unsigned int); static int g_verify_token_header(gss_OID_const, unsigned int *, @@ -835,6 +835,7 @@ ret = GSS_S_FAILURE; } } + gss_release_buffer(&tmpmin, &mechtok_out); if (ret == GSS_S_COMPLETE) { /* * Now, switch the output context to refer to the Index: src/lib/krb4/send_to_kdc.c =================================================================== --- src/lib/krb4/send_to_kdc.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb4/send_to_kdc.c (.../branches/krb5-1-6) (Revision 19936) @@ -181,7 +181,7 @@ message.length = pkt->length; message.data = (char *)pkt->dat; /* XXX yuck */ retval = internals.sendto_udp(NULL, &message, &al, NULL, &reply, addr, - addrlen, NULL, 0, NULL); + addrlen, NULL, 0, NULL, NULL, NULL); DEB(("sendto_udp returns %d\n", retval)); free_al: internals.free_addrlist(&al); Index: src/lib/krb5/os/sendto_kdc.c =================================================================== --- src/lib/krb5/os/sendto_kdc.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/os/sendto_kdc.c (.../branches/krb5-1-6) (Revision 19936) @@ -1,7 +1,7 @@ /* * lib/krb5/os/sendto_kdc.c * - * Copyright 1990,1991,2001,2002,2004,2005 by the Massachusetts Institute of Technology. + * Copyright 1990,1991,2001,2002,2004,2005,2007 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -295,6 +295,30 @@ return 0; } +static int +check_for_svc_unavailable (krb5_context context, + const krb5_data *reply, + void *msg_handler_data) +{ + krb5_error_code *retval = (krb5_error_code *)msg_handler_data; + + *retval = 0; + + if (krb5_is_krb_error(reply)) { + krb5_error *err_reply; + + if (decode_krb5_error(reply, &err_reply) == 0) { + *retval = err_reply->error; + krb5_free_error(context, err_reply); + + /* Returning 0 means continue to next KDC */ + return (*retval != KDC_ERR_SVC_UNAVAILABLE); + } + } + + return 1; +} + /* * send the formatted request 'message' to a KDC for realm 'realm' and * return the response (if any) in 'reply'. @@ -381,9 +405,12 @@ } if (addrs.naddrs > 0) { + krb5_error_code err = 0; + retval = krb5int_sendto (context, message, &addrs, 0, reply, 0, 0, - 0, 0, &addr_used); - if (retval == 0) { + 0, 0, &addr_used, check_for_svc_unavailable, &err); + switch (retval) { + case 0: /* * Set use_master to 1 if we ended up talking to a master when * we didn't explicitly request to @@ -401,7 +428,19 @@ } krb5int_free_addrlist (&addrs); return 0; - } + default: + break; + /* Cases here are for constructing useful error messages. */ + case KRB5_KDC_UNREACH: + if (err == KDC_ERR_SVC_UNAVAILABLE) { + retval = KRB5KDC_ERR_SVC_UNAVAILABLE; + } else { + krb5_set_error_message(context, retval, + "Cannot contact any KDC for realm '%.*s'", + realm->length, realm->data); + } + break; + } krb5int_free_addrlist (&addrs); } return retval; @@ -1015,9 +1054,12 @@ } static int -service_fds (struct select_state *selstate, +service_fds (krb5_context context, + struct select_state *selstate, struct conn_state *conns, size_t n_conns, int *winning_conn, - struct select_state *seltemp) + struct select_state *seltemp, + int (*msg_handler)(krb5_context, const krb5_data *, void *), + void *msg_handler_data) { int e, selret; @@ -1056,9 +1098,22 @@ state_strings[(int) conns[i].state]); if (conns[i].service (&conns[i], selstate, ssflags)) { - dprint("fd service routine says we're done\n"); - *winning_conn = i; - return 1; + int stop = 1; + + if (msg_handler != NULL) { + krb5_data reply; + + reply.data = conns[i].x.in.buf; + reply.length = conns[i].x.in.pos - conns[i].x.in.buf; + + stop = (msg_handler(context, &reply, msg_handler_data) != 0); + } + + if (stop) { + dprint("fd service routine says we're done\n"); + *winning_conn = i; + return 1; + } } } } @@ -1098,7 +1153,10 @@ struct sendto_callback_info* callback_info, krb5_data *reply, struct sockaddr *localaddr, socklen_t *localaddrlen, struct sockaddr *remoteaddr, socklen_t *remoteaddrlen, - int *addr_used) + int *addr_used, + /* return 0 -> keep going, 1 -> quit */ + int (*msg_handler)(krb5_context, const krb5_data *, void *), + void *msg_handler_data) { int i, pass; int delay_this_pass = 2; @@ -1185,8 +1243,8 @@ goto egress; sel_state->end_time = now; sel_state->end_time.tv_sec += 1; - e = service_fds(sel_state, conns, host+1, &winning_conn, - sel_state+1); + e = service_fds(context, sel_state, conns, host+1, &winning_conn, + sel_state+1, msg_handler, msg_handler_data); if (e) break; if (pass > 0 && sel_state->nfds == 0) @@ -1206,7 +1264,8 @@ call with the last one from the above loop, if the loop actually calls select. */ sel_state->end_time.tv_sec += delay_this_pass; - e = service_fds(sel_state, conns, host+1, &winning_conn, sel_state+1); + e = service_fds(context, sel_state, conns, host+1, &winning_conn, + sel_state+1, msg_handler, msg_handler_data); if (e) break; if (sel_state->nfds == 0) Index: src/lib/krb5/os/send524.c =================================================================== --- src/lib/krb5/os/send524.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/os/send524.c (.../branches/krb5-1-6) (Revision 19936) @@ -98,7 +98,7 @@ if (al.naddrs == 0) return KRB5_REALM_UNKNOWN; - retval = krb5int_sendto (context, message, &al, NULL, reply, addr, addrlen, NULL, 0, NULL); + retval = krb5int_sendto (context, message, &al, NULL, reply, addr, addrlen, NULL, 0, NULL, NULL, NULL); krb5int_free_addrlist (&al); return retval; #else Index: src/lib/krb5/os/changepw.c =================================================================== --- src/lib/krb5/os/changepw.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/os/changepw.c (.../branches/krb5-1-6) (Revision 19936) @@ -247,6 +247,8 @@ NULL, ss2sa(&remote_addr), &addrlen, + NULL, + NULL, NULL ))) { Index: src/lib/krb5/error_tables/krb5_err.et =================================================================== --- src/lib/krb5/error_tables/krb5_err.et (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/error_tables/krb5_err.et (.../branches/krb5-1-6) (Revision 19936) @@ -1,7 +1,7 @@ # # lib/krb5/error_tables/krb5_err.et # -# Copyright 1989,1990,1991 by the Massachusetts Institute of Technology. +# Copyright 1989,1990,1991,2007 by the Massachusetts Institute of Technology. # All Rights Reserved. # # Export of this software from the United States of America may @@ -68,7 +68,7 @@ error_code KRB5KDC_ERR_SERVER_NOMATCH, "Requested server and ticket don't match" error_code KRB5PLACEHOLD_27, "KRB5 error code 27" error_code KRB5PLACEHOLD_28, "KRB5 error code 28" -error_code KRB5PLACEHOLD_29, "KRB5 error code 29" +error_code KRB5KDC_ERR_SVC_UNAVAILABLE, "A service is not available that is required to process the request" error_code KRB5PLACEHOLD_30, "KRB5 error code 30" # vv 31 error_code KRB5KRB_AP_ERR_BAD_INTEGRITY, "Decrypt integrity check failed" Index: src/lib/krb5/ccache/t_cc.c =================================================================== --- src/lib/krb5/ccache/t_cc.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/ccache/t_cc.c (.../branches/krb5-1-6) (Revision 19936) @@ -123,6 +123,7 @@ krb5_cc_cursor cursor; const char *c_name; char newcache[300]; + char *save_type; init_test_cred(context); @@ -135,7 +136,9 @@ CHECK_STR(c_name, "get_name"); c_name = krb5_cc_get_type(context, id); - CHECK_STR(c_name, "get_prefix"); + CHECK_STR(c_name, "get_type"); + save_type=strdup(c_name); + CHECK_STR(save_type, "copying type"); kret = krb5_cc_store_cred(context, id, &test_creds); CHECK(kret, "store"); @@ -192,17 +195,22 @@ kret = krb5_cc_destroy(context, id); CHECK(kret, "destroy"); -#if 0 /* ----------------------------------------------------- */ /* Tests the generate new code */ - kret = krb5_cc_resolve(context, name, &id); - CHECK(kret, "resolve"); - kret = krb5_cc_gen_new(context, &id); - CHECK(kret, "gen_new"); - kret = krb5_cc_destroy(context, id); - CHECK(kret, "destroy"); -#endif + kret = krb5_cc_new_unique(context, save_type, + NULL, &id2); + CHECK(kret, "new_unique"); + + kret = krb5_cc_initialize(context, id2, test_creds.client); + CHECK(kret, "initialize"); + kret = krb5_cc_store_cred(context, id2, &test_creds); + CHECK(kret, "store"); + + kret = krb5_cc_destroy(context, id2); + CHECK(kret, "destroy id2"); + + free(save_type); free_test_cred(context); } Index: src/lib/krb5/ccache/cc_file.c =================================================================== --- src/lib/krb5/ccache/cc_file.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/ccache/cc_file.c (.../branches/krb5-1-6) (Revision 19936) @@ -1950,115 +1950,165 @@ { krb5_ccache lid; int ret; - krb5_error_code retcode = 0; + krb5_error_code kret = 0; char scratch[sizeof(TKT_ROOT)+6+1]; /* +6 for the scratch part, +1 for NUL */ krb5_fcc_data *data; + krb5_int16 fcc_fvno = htons(context->fcc_default_format); + krb5_int16 fcc_flen = 0; + int errsave, cnt; + struct fcc_set *setptr; - /* Allocate memory */ - lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); - if (lid == NULL) - return KRB5_CC_NOMEM; + /* Set master lock */ + kret = k5_mutex_lock(&krb5int_cc_file_mutex); + if (kret) + return kret; - lid->ops = &krb5_fcc_ops; - (void) strcpy(scratch, TKT_ROOT); (void) strcat(scratch, "XXXXXX"); #ifdef HAVE_MKSTEMP ret = mkstemp(scratch); if (ret == -1) { + k5_mutex_unlock(&krb5int_cc_file_mutex); return krb5_fcc_interpret(context, errno); - } else close(ret); + } #else /*HAVE_MKSTEMP*/ mktemp(scratch); + /* Make sure the file name is reserved */ + ret = THREEPARAMOPEN(scratch, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, 0); + if (ret == -1) { + return krb5_fcc_interpret(context, errno); + } #endif - lid->data = (krb5_pointer) malloc(sizeof(krb5_fcc_data)); - if (lid->data == NULL) { - krb5_xfree(lid); + /* Allocate memory */ + data = (krb5_pointer) malloc(sizeof(krb5_fcc_data)); + if (data == NULL) { + close(ret); + unlink(scratch); + k5_mutex_unlock(&krb5int_cc_file_mutex); return KRB5_CC_NOMEM; } - ((krb5_fcc_data *) lid->data)->filename = (char *) - malloc(strlen(scratch) + 1); - if (((krb5_fcc_data *) lid->data)->filename == NULL) { - krb5_xfree(((krb5_fcc_data *) lid->data)); - krb5_xfree(lid); + data->filename = strdup(scratch); + if (data->filename == NULL) { + k5_mutex_unlock(&krb5int_cc_file_mutex); + free(data); + close(ret); + unlink(scratch); + k5_mutex_unlock(&krb5int_cc_file_mutex); return KRB5_CC_NOMEM; } + kret = k5_mutex_init(&data->lock); + if (kret) { + k5_mutex_unlock(&krb5int_cc_file_mutex); + free(data->filename); + free(data); + close(ret); + unlink(scratch); + return kret; + } + kret = k5_mutex_lock(&data->lock); + if (kret) { + k5_mutex_unlock(&krb5int_cc_file_mutex); + k5_mutex_destroy(&data->lock); + free(data->filename); + free(data); + close(ret); + unlink(scratch); + return kret; + } + /* * The file is initially closed at the end of this call... */ - ((krb5_fcc_data *) lid->data)->flags = 0; - ((krb5_fcc_data *) lid->data)->file = -1; - ((krb5_fcc_data *) lid->data)->valid_bytes = 0; - data = (krb5_fcc_data *) lid->data; + data->flags = 0; + data->file = -1; + data->valid_bytes = 0; + /* data->version,mode filled in for real later */ + data->version = data->mode = 0; - retcode = k5_mutex_init(&data->lock); - if (retcode) - goto err_out; - /* Set up the filename */ - strcpy(((krb5_fcc_data *) lid->data)->filename, scratch); - - /* Make sure the file name is reserved */ - ret = THREEPARAMOPEN(((krb5_fcc_data *) lid->data)->filename, - O_CREAT | O_EXCL | O_WRONLY | O_BINARY, 0); - if (ret == -1) { - retcode = krb5_fcc_interpret(context, errno); - goto err_out; - } else { - krb5_int16 fcc_fvno = htons(context->fcc_default_format); - krb5_int16 fcc_flen = 0; - int errsave, cnt; - - /* Ignore user's umask, set mode = 0600 */ + /* Ignore user's umask, set mode = 0600 */ #ifndef HAVE_FCHMOD #ifdef HAVE_CHMOD - chmod(((krb5_fcc_data *) lid->data)->filename, S_IRUSR | S_IWUSR); + chmod(data->filename, S_IRUSR | S_IWUSR); #endif #else - fchmod(ret, S_IRUSR | S_IWUSR); + fchmod(ret, S_IRUSR | S_IWUSR); #endif - if ((cnt = write(ret, (char *)&fcc_fvno, sizeof(fcc_fvno))) - != sizeof(fcc_fvno)) { - errsave = errno; - (void) close(ret); - (void) unlink(((krb5_fcc_data *) lid->data)->filename); - retcode = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO; - goto err_out; + if ((cnt = write(ret, (char *)&fcc_fvno, sizeof(fcc_fvno))) + != sizeof(fcc_fvno)) { + errsave = errno; + (void) close(ret); + (void) unlink(data->filename); + kret = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO; + goto err_out; + } + /* For version 4 we save a length for the rest of the header */ + if (context->fcc_default_format == KRB5_FCC_FVNO_4) { + if ((cnt = write(ret, (char *)&fcc_flen, sizeof(fcc_flen))) + != sizeof(fcc_flen)) { + errsave = errno; + (void) close(ret); + (void) unlink(data->filename); + kret = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO; + goto err_out; } - /* For version 4 we save a length for the rest of the header */ - if (context->fcc_default_format == KRB5_FCC_FVNO_4) { - if ((cnt = write(ret, (char *)&fcc_flen, sizeof(fcc_flen))) - != sizeof(fcc_flen)) { - errsave = errno; - (void) close(ret); - (void) unlink(((krb5_fcc_data *) lid->data)->filename); - retcode = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO; - goto err_out; - } - } - if (close(ret) == -1) { - errsave = errno; - (void) unlink(((krb5_fcc_data *) lid->data)->filename); - retcode = krb5_fcc_interpret(context, errsave); - goto err_out; - } - *id = lid; - /* default to open/close on every trn - otherwise destroy - will get as to state confused */ - ((krb5_fcc_data *) lid->data)->flags = KRB5_TC_OPENCLOSE; - krb5_change_cache (); - return KRB5_OK; } + if (close(ret) == -1) { + errsave = errno; + (void) unlink(data->filename); + kret = krb5_fcc_interpret(context, errsave); + goto err_out; + } + + setptr = malloc(sizeof(struct fcc_set)); + if (setptr == NULL) { + k5_mutex_unlock(&krb5int_cc_file_mutex); + k5_mutex_destroy(&data->lock); + free(data->filename); + free(data); + (void) close(ret); + (void) unlink(scratch); + return KRB5_CC_NOMEM; + } + setptr->refcount = 1; + setptr->data = data; + setptr->next = fccs; + fccs = setptr; + k5_mutex_unlock(&krb5int_cc_file_mutex); + + k5_mutex_assert_locked(&data->lock); + k5_mutex_unlock(&data->lock); + lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); + if (lid == NULL) { + dereference(context, data); + return KRB5_CC_NOMEM; + } + + lid->ops = &krb5_fcc_ops; + lid->data = data; + lid->magic = KV5M_CCACHE; + + /* default to open/close on every trn - otherwise destroy + will get as to state confused */ + ((krb5_fcc_data *) lid->data)->flags = KRB5_TC_OPENCLOSE; + + *id = lid; + + + krb5_change_cache (); + return KRB5_OK; + err_out: - krb5_xfree(((krb5_fcc_data *) lid->data)->filename); - krb5_xfree(((krb5_fcc_data *) lid->data)); - krb5_xfree(lid); - return retcode; + k5_mutex_unlock(&krb5int_cc_file_mutex); + k5_mutex_destroy(&data->lock); + free(data->filename); + free(data); + return kret; } /* Index: src/lib/krb5/ccache/ccfns.c =================================================================== --- src/lib/krb5/ccache/ccfns.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/ccache/ccfns.c (.../branches/krb5-1-6) (Revision 19936) @@ -1,7 +1,7 @@ /* * lib/krb5/ccache/ccfns.c * - * Copyright 2000 by the Massachusetts Institute of Technology. + * Copyright 2000, 2007 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -65,7 +65,29 @@ krb5_cc_store_cred (krb5_context context, krb5_ccache cache, krb5_creds *creds) { - return cache->ops->store(context, cache, creds); + krb5_error_code ret; + krb5_ticket *tkt; + krb5_principal s1, s2; + + ret = cache->ops->store(context, cache, creds); + if (ret) return ret; + + /* + * If creds->server and the server in the decoded ticket differ, + * store both principals. + */ + s1 = creds->server; + ret = decode_krb5_ticket(&creds->ticket, &tkt); + /* Bail out on errors in case someone is storing a non-ticket. */ + if (ret) return 0; + s2 = tkt->server; + if (!krb5_principal_compare(context, s1, s2)) { + creds->server = s2; + ret = cache->ops->store(context, cache, creds); + creds->server = s1; + } + krb5_free_ticket(context, tkt); + return ret; } krb5_error_code KRB5_CALLCONV @@ -73,7 +95,23 @@ krb5_flags flags, krb5_creds *mcreds, krb5_creds *creds) { - return cache->ops->retrieve(context, cache, flags, mcreds, creds); + krb5_error_code ret; + krb5_data tmprealm; + + ret = cache->ops->retrieve(context, cache, flags, mcreds, creds); + if (ret != KRB5_CC_NOTFOUND) + return ret; + if (!krb5_is_referral_realm(&mcreds->server->realm)) + return ret; + + /* + * Retry using client's realm if service has referral realm. + */ + tmprealm = mcreds->server->realm; + mcreds->server->realm = mcreds->client->realm; + ret = cache->ops->retrieve(context, cache, flags, mcreds, creds); + mcreds->server->realm = tmprealm; + return ret; } krb5_error_code KRB5_CALLCONV Index: src/lib/krb5/krb/gc_frm_kdc.c =================================================================== --- src/lib/krb5/krb/gc_frm_kdc.c (.../tags/krb5-1-6-2-final) (Revision 19936) +++ src/lib/krb5/krb/gc_frm_kdc.c (.../branches/krb5-1-6) (Revision 19936) @@ -906,7 +906,6 @@ /* Whether or not that succeeded, we're done. */ goto cleanup; } - else { /* Referral request succeeded; let's see what it is. */ if (krb5_principal_compare(context, in_cred->server, (*out_cred)->server)) { @@ -914,8 +913,40 @@ "for requested server principal\n")); DUMP_PRINC("gc_from_kdc final referred reply", in_cred->server); + + /* + * Check if the return enctype is one that we requested if + * needed. + */ + 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]) { + /* Found an allowable etype, so we're done */ + goto cleanup; + } } + /* + * We need to try again, but this time use the + * tgs_ktypes in the context. At this point we should + * have all the tgts to succeed. + */ + + /* Free "wrong" credential */ + krb5_free_creds(context, *out_cred); + *out_cred = NULL; + /* Re-establish tgs etypes */ + 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; @@ -978,7 +1009,6 @@ krb5_free_creds(context, *out_cred); *out_cred = NULL; break; - } } }