Drop retransmits while processing requests
authorGreg Hudson <ghudson@mit.edu>
Sat, 15 Oct 2011 15:35:46 +0000 (15:35 +0000)
committerGreg Hudson <ghudson@mit.edu>
Sat, 15 Oct 2011 15:35:46 +0000 (15:35 +0000)
Supporting asynchronous preauth modules means that the KDC can receive
a retransmitted request before it finishes processing the initial
request.  Ignore those retransmits instead of processing them.

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

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

index 5f9c810e241107b967a9870dba0129535fbb652b..eeb95ff73799047f58a34f63ed07bd2d63787772 100644 (file)
@@ -54,6 +54,11 @@ finish_dispatch(void *arg, krb5_error_code code, krb5_data *response)
     oldrespond = state->respond;
     oldarg = state->arg;
 
+#ifndef NOCACHE
+    /* Remove our NULL cache entry to indicate request completion. */
+    kdc_remove_lookaside(kdc_context, state->request);
+#endif
+
     if (state->is_tcp == 0 && response &&
         response->length > max_dgram_reply_size) {
         krb5_free_data(kdc_context, response);
@@ -67,7 +72,7 @@ finish_dispatch(void *arg, krb5_error_code code, krb5_data *response)
 
 #ifndef NOCACHE
     /* put the response into the lookaside buffer */
-    else if (!code)
+    else if (!code && response)
         kdc_insert_lookaside(state->request, response);
 #endif
 
@@ -104,20 +109,30 @@ 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) {
+        if (!response || 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);
+            if (response)
+                krb5_klog_syslog(LOG_INFO,
+                                 "DISPATCH: repeated (retransmitted?) request "
+                                 "from %s, resending previous response", name);
+            else
+                krb5_klog_syslog(LOG_INFO,
+                                 "DISPATCH: repeated (retransmitted?) request "
+                                 "from %s during request processing, dropping "
+                                 "repeated request", name);
         }
 
-        finish_dispatch(state, 0, response);
+        finish_dispatch(state, response ? 0 : KRB5KDC_ERR_DISCARD, response);
         return;
     }
+
+    /* Insert a NULL entry into the lookaside to indicate that this request
+     * is currently being processed. */
+    kdc_insert_lookaside(pkt, NULL);
 #endif
 
     retval = krb5_crypto_us_timeofday(&now, &now_usec);
index a31eec568dd7762d9d3ae1a1a5320f7c576b0e1a..bdeaa5f7db4b77bdf9b4b7b589489aacf46e431d 100644 (file)
@@ -236,6 +236,7 @@ handle_authdata (krb5_context context,
 /* replay.c */
 krb5_boolean kdc_check_lookaside (krb5_data *, krb5_data **);
 void kdc_insert_lookaside (krb5_data *, krb5_data *);
+void kdc_remove_lookaside (krb5_context kcontext, krb5_data *);
 void kdc_free_lookaside(krb5_context);
 
 /* kdc_util.c */
index 96c84807e083b87351cf71ccdb777d0e66159c4a..63ff95ee2cdea53cc3c2bc34ed69f6b470263924 100644 (file)
@@ -55,6 +55,29 @@ static int num_entries = 0;
    Todo:  quench the size of the queue...
 */
 
+/* Removes the most recent cache entry for a given packet. */
+void
+kdc_remove_lookaside(krb5_context kcontext, krb5_data *inpkt)
+{
+    register krb5_kdc_replay_ent *eptr, *last;
+
+    if (!root_ptr.next)
+        return;
+
+    for (last = &root_ptr, eptr = root_ptr.next;
+         eptr;
+         last = eptr, eptr = eptr->next) {
+        if (!MATCH(eptr))
+            continue;
+
+        last->next = eptr->next;
+        krb5_free_data(kcontext, eptr->req_packet);
+        krb5_free_data(kcontext, eptr->reply_packet);
+        free(eptr);
+        return;
+    }
+}
+
 /* return TRUE if outpkt is filled in with a packet to reply with,
    FALSE if the caller should do the work */