Make do_as_req() respond via a callback
authorGreg Hudson <ghudson@mit.edu>
Mon, 3 Oct 2011 19:13:57 +0000 (19:13 +0000)
committerGreg Hudson <ghudson@mit.edu>
Mon, 3 Oct 2011 19:13:57 +0000 (19:13 +0000)
From npmccallum@redhat.com with changes.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25292 dc483132-0cff-0310-8789-dd5450dbe970

src/kdc/dispatch.c
src/kdc/do_as_req.c
src/kdc/kdc_util.h

index cb09c62ff9b5ba490214b21196c9d61e0a528401..5f9c810e241107b967a9870dba0129535fbb652b 100644 (file)
@@ -36,6 +36,45 @@ static krb5_int32 last_usec = 0, last_os_random = 0;
 
 static krb5_error_code make_too_big_error (krb5_data **out);
 
+struct dispatch_state {
+    loop_respond_fn respond;
+    void *arg;
+    krb5_data *request;
+    int is_tcp;
+};
+
+static void
+finish_dispatch(void *arg, krb5_error_code code, krb5_data *response)
+{
+    struct dispatch_state *state = arg;
+    loop_respond_fn oldrespond;
+    void *oldarg;
+
+    assert(state);
+    oldrespond = state->respond;
+    oldarg = state->arg;
+
+    if (state->is_tcp == 0 && response &&
+        response->length > max_dgram_reply_size) {
+        krb5_free_data(kdc_context, response);
+        response = NULL;
+        code = make_too_big_error(&response);
+        if (code)
+            krb5_klog_syslog(LOG_ERR, "error constructing "
+                             "KRB_ERR_RESPONSE_TOO_BIG error: %s",
+                             error_message(code));
+    }
+
+#ifndef NOCACHE
+    /* put the response into the lookaside buffer */
+    else if (!code)
+        kdc_insert_lookaside(state->request, response);
+#endif
+
+    free(state);
+    (*oldrespond)(oldarg, code, response);
+}
+
 void
 dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
          krb5_data *pkt, int is_tcp, loop_respond_fn respond, void *arg)
@@ -43,7 +82,18 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
     krb5_error_code retval;
     krb5_kdc_req *as_req;
     krb5_int32 now, now_usec;
-    krb5_data *response;
+    krb5_data *response = NULL;
+    struct dispatch_state *state;
+
+    state = malloc(sizeof(*state));
+    if (!state) {
+        (*respond)(arg, ENOMEM, NULL);
+        return;
+    }
+    state->respond = respond;
+    state->arg = arg;
+    state->request = pkt;
+    state->is_tcp = is_tcp;
 
     /* decode incoming packet, and dispatch */
 
@@ -54,20 +104,22 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
         const char *name = 0;
         char buf[46];
 
-        if (is_tcp == 0 && response->length > max_dgram_reply_size)
-            goto too_big_for_udp;
-
-        name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype),
-                          from->address->contents, buf, sizeof (buf));
-        if (name == 0)
-            name = "[unknown address type]";
-        krb5_klog_syslog(LOG_INFO,
-                         "DISPATCH: repeated (retransmitted?) request from %s, resending previous response",
-                         name);
-        (*respond)(arg, 0, response);
+        if (is_tcp != 0 || response->length <= max_dgram_reply_size) {
+            name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype),
+                              from->address->contents, buf, sizeof (buf));
+            if (name == 0)
+                name = "[unknown address type]";
+            krb5_klog_syslog(LOG_INFO,
+                             "DISPATCH: repeated (retransmitted?) request "
+                             "from %s, resending previous response",
+                             name);
+        }
+
+        finish_dispatch(state, 0, response);
         return;
     }
 #endif
+
     retval = krb5_crypto_us_timeofday(&now, &now_usec);
     if (retval == 0) {
         krb5_int32 usec_difference = now_usec-last_usec;
@@ -99,32 +151,16 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
              * process_as_req frees the request if it is called
              */
             if (!(retval = setup_server_realm(as_req->server))) {
-                retval = process_as_req(as_req, pkt, from, &response);
+                process_as_req(as_req, pkt, from, finish_dispatch, state);
+                return;
             }
-            else            krb5_free_kdc_req(kdc_context, as_req);
+            else
+                krb5_free_kdc_req(kdc_context, as_req);
         }
-    }
-    else
+    } else
         retval = KRB5KRB_AP_ERR_MSG_TYPE;
-#ifndef NOCACHE
-    /* put the response into the lookaside buffer */
-    if (!retval)
-        kdc_insert_lookaside(pkt, response);
-#endif
-
-    if (is_tcp == 0 && response != NULL &&
-        response->length > max_dgram_reply_size) {
-    too_big_for_udp:
-        krb5_free_data(kdc_context, response);
-        retval = make_too_big_error(&response);
-        if (retval) {
-            krb5_klog_syslog(LOG_ERR,
-                             "error constructing KRB_ERR_RESPONSE_TOO_BIG error: %s",
-                             error_message(retval));
-        }
-    }
 
-    (*respond)(arg, retval, retval == 0 ? response : NULL);
+    finish_dispatch(state, retval, response);
 }
 
 static krb5_error_code
index 87bccdb59ff1d4a9dbed7e87fe6f44b8bc962dcd..3351fdf34208cbd4cbd9368a7b81c13016708b09 100644 (file)
@@ -99,9 +99,9 @@ get_key_exp(krb5_db_entry *entry)
 }
 
 /*ARGSUSED*/
-krb5_error_code
+void
 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
-               const krb5_fulladdr *from, krb5_data **response)
+               const krb5_fulladdr *from, loop_respond_fn respond, void *arg)
 {
     krb5_db_entry *client = NULL, *server = NULL;
     krb5_kdc_rep reply;
@@ -127,6 +127,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     struct kdc_request_state *state = NULL;
     krb5_data encoded_req_body;
     krb5_keyblock *as_encrypting_key = NULL;
+    krb5_data *response;
 
 
 #if APPLE_PKINIT
@@ -593,7 +594,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     }
 
     errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart,
-                                  0, as_encrypting_key,  &reply, response);
+                                  0, as_encrypting_key,  &reply, &response);
     reply.enc_part.kvno = client_key->key_data_kvno;
     if (errcode) {
         status = "ENCODE_KDC_REP";
@@ -639,11 +640,12 @@ egress:
 
         errcode = prepare_error_as(state, request, errcode, &e_data,
                                    (client != NULL) ? client->princ : NULL,
-                                   response, status);
+                                   &response, status);
         status = 0;
     }
 
-discard: if (emsg)
+discard:
+    if (emsg)
         krb5_free_error_message(kdc_context, emsg);
     if (enc_tkt_reply.authorization_data != NULL)
         krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
@@ -676,7 +678,7 @@ discard: if (emsg)
     krb5_free_kdc_req(kdc_context, request);
     assert(did_log != 0);
 
-    return errcode;
+    (*respond)(arg, errcode, response);
 }
 
 /*
index af6c32cfc023ce1fc78e3c51d9f335c46838a688..368f0806afd95f5a131a9afc4f2fb71dbf0adf1c 100644 (file)
@@ -118,10 +118,10 @@ void
 rep_etypes2str(char *s, size_t len, krb5_kdc_rep *rep);
 
 /* do_as_req.c */
-krb5_error_code
+void
 process_as_req (krb5_kdc_req *, krb5_data *,
                 const krb5_fulladdr *,
-                krb5_data ** );
+                loop_respond_fn, void *);
 
 /* do_tgs_req.c */
 krb5_error_code