Debugged version of patch worked up with Luke
authorKen Raeburn <raeburn@mit.edu>
Fri, 27 Jul 2007 04:39:21 +0000 (04:39 +0000)
committerKen Raeburn <raeburn@mit.edu>
Fri, 27 Jul 2007 04:39:21 +0000 (04:39 +0000)
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

src/include/k5-int.h
src/lib/krb4/send_to_kdc.c
src/lib/krb5/error_tables/krb5_err.et
src/lib/krb5/os/changepw.c
src/lib/krb5/os/send524.c
src/lib/krb5/os/sendto_kdc.c

index 197dc6367ae2ef85c7eb92bc7d6919127db14c27..2b9796078d2196203425b8780a93258c2b896ccd 100644 (file)
@@ -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,
index a33ad2b037d1f6c454f9733eec5245e2276349e3..95d9d91136f41b293207c63caec353841d2004b9 100644 (file)
@@ -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);
index 92e45ad61645dcd8730d69f399a3d92497ea19b5..e166242875e790b537e845afaffefde0dd3e8487 100644 (file)
@@ -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"
index a2bf8f0b38f32dc286185a87ff6f883ffbcef501..816713dc44185272b7840ce705ab8947e061fb80 100644 (file)
@@ -247,6 +247,8 @@ krb5_change_set_password(krb5_context context, krb5_creds *creds, char *newpw,
                                   NULL,
                                   ss2sa(&remote_addr),
                                    &addrlen,
+                                  NULL,
+                                  NULL,
                                   NULL
                 ))) {
 
index f6e7a0b568669695d3cda1ead8fc0676b0374df6..1792b4930ea4f092b99271a677f6cc5237dd43f6 100644 (file)
@@ -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
index 3be46de9fde5212d809272206fd6805ae49bd205..0c63b22ecab1fbb1c27ad15b6fa03747b9194be5 100644 (file)
@@ -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)