From: Ken Raeburn Date: Fri, 27 Jul 2007 04:39:21 +0000 (+0000) Subject: Debugged version of patch worked up with Luke X-Git-Tag: krb5-1.7-alpha1~987 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=76fdc16a95093e399c43e8597275a5cc95ff4925;p=krb5.git Debugged version of patch worked up with Luke Adds a callback to krb5int_sendto to examine the response and indicate whether to quit the loop or not. For sendto_kdc, keep going if the returned error is "service unavailable". Updated all other callers to pass a null function pointer, which means to always break out of the loop on any response (the old behavior). ticket: 3334 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19738 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 197dc6367..2b9796078 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -216,6 +216,10 @@ typedef INT64_TYPE krb5_int64; /* 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 krb5_sendto_kdc (krb5_context, const krb5_data *, 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 * ); @@ -1874,7 +1880,9 @@ typedef struct _krb5int_access { 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, diff --git a/src/lib/krb4/send_to_kdc.c b/src/lib/krb4/send_to_kdc.c index a33ad2b03..95d9d9113 100644 --- a/src/lib/krb4/send_to_kdc.c +++ b/src/lib/krb4/send_to_kdc.c @@ -181,7 +181,7 @@ krb4int_send_to_kdc_addr( 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); diff --git a/src/lib/krb5/error_tables/krb5_err.et b/src/lib/krb5/error_tables/krb5_err.et index 92e45ad61..e16624287 100644 --- a/src/lib/krb5/error_tables/krb5_err.et +++ b/src/lib/krb5/error_tables/krb5_err.et @@ -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_PREAUTH_REQUIRED, "Additional pre-authentication required 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" diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c index a2bf8f0b3..816713dc4 100644 --- a/src/lib/krb5/os/changepw.c +++ b/src/lib/krb5/os/changepw.c @@ -247,6 +247,8 @@ krb5_change_set_password(krb5_context context, krb5_creds *creds, char *newpw, NULL, ss2sa(&remote_addr), &addrlen, + NULL, + NULL, NULL ))) { diff --git a/src/lib/krb5/os/send524.c b/src/lib/krb5/os/send524.c index f6e7a0b56..1792b4930 100644 --- a/src/lib/krb5/os/send524.c +++ b/src/lib/krb5/os/send524.c @@ -98,7 +98,7 @@ krb5int_524_sendto_kdc (context, message, realm, reply, addr, addrlen) 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 diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c index 3be46de9f..0c63b22ec 100644 --- a/src/lib/krb5/os/sendto_kdc.c +++ b/src/lib/krb5/os/sendto_kdc.c @@ -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 @@ -312,6 +312,30 @@ in_addrlist (struct addrinfo *thisaddr, struct addrlist *list) 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'. @@ -398,8 +422,10 @@ krb5_sendto_kdc (krb5_context context, const krb5_data *message, } if (addrs.naddrs > 0) { + krb5_error_code err = 0; + retval = krb5int_sendto (context, message, &addrs, 0, reply, 0, 0, - 0, 0, &addr_used); + 0, 0, &addr_used, check_for_svc_unavailable, &err); switch (retval) { case 0: /* @@ -423,9 +449,13 @@ krb5_sendto_kdc (krb5_context context, const krb5_data *message, break; /* Cases here are for constructing useful error messages. */ case KRB5_KDC_UNREACH: - krb5_set_error_message(context, retval, - "Cannot contact any KDC for realm '%.*s'", - realm->length, realm->data); + 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); @@ -1041,9 +1071,12 @@ service_udp_fd(struct conn_state *conn, struct select_state *selstate, } 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; @@ -1087,9 +1120,22 @@ service_fds (struct select_state *selstate, 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; + } } } } @@ -1129,7 +1175,10 @@ krb5int_sendto (krb5_context context, const krb5_data *message, 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; @@ -1216,8 +1265,8 @@ krb5int_sendto (krb5_context context, const krb5_data *message, 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) @@ -1237,7 +1286,8 @@ krb5int_sendto (krb5_context context, const krb5_data *message, 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)