krb5 commit: Wait indefinitely on KDC TCP connections

ghudson at mit.edu ghudson at mit.edu
Mon Oct 30 22:02:27 EDT 2023


https://github.com/krb5/krb5/commit/6436a3808061da787a43c6810f5f0370cdfb6e36
commit 6436a3808061da787a43c6810f5f0370cdfb6e36
Author: Greg Hudson <ghudson at mit.edu>
Date:   Thu Oct 26 16:26:42 2023 -0400

    Wait indefinitely on KDC TCP connections
    
    When making a KDC or password change request, wait indefinitely
    (limited only by request_timeout if set) once a KDC has accepted a TCP
    connection.
    
    ticket: 9105 (new)

 doc/admin/conf_files/krb5_conf.rst |  2 +-
 src/lib/krb5/os/sendto_kdc.c       | 50 ++++++++++++++++++++------------------
 2 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index fb9c8b7ab..1b92170da 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -363,7 +363,7 @@ The libdefaults section may contain any of the following relations:
     for initial ticket requests.  The default value is 0.
 
 **request_timeout**
-    (:ref:`duration` string.)  Sets the maximum total time for KDC or
+    (:ref:`duration` string.)  Sets the maximum total time for KDC and
     password change requests.  This timeout does not affect the
     intervals between requests, so setting a low timeout may result in
     fewer requests being attempted and/or some servers not being
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index d1254d28e..0ffc04bd5 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -134,7 +134,6 @@ struct conn_state {
     krb5_data callback_buffer;
     size_t server_index;
     struct conn_state *next;
-    time_ms endtime;
     krb5_boolean defer;
     struct {
         const char *uri_path;
@@ -344,15 +343,19 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
                   struct select_state *out, int *sret)
 {
 #ifndef USE_POLL
-    struct timeval tv;
+    struct timeval tv, *tvp;
 #endif
     krb5_error_code retval;
     time_ms curtime, interval;
 
-    retval = get_curtime_ms(&curtime);
-    if (retval != 0)
-        return retval;
-    interval = (curtime < endtime) ? endtime - curtime : 0;
+    if (endtime != 0) {
+        retval = get_curtime_ms(&curtime);
+        if (retval != 0)
+            return retval;
+        interval = (curtime < endtime) ? endtime - curtime : 0;
+    } else {
+        interval = -1;
+    }
 
     /* We don't need a separate copy of the selstate for poll, but use one for
      * consistency with how we use select. */
@@ -361,9 +364,14 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
 #ifdef USE_POLL
     *sret = poll(out->fds, out->nfds, interval);
 #else
-    tv.tv_sec = interval / 1000;
-    tv.tv_usec = interval % 1000 * 1000;
-    *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv);
+    if (interval != -1) {
+        tv.tv_sec = interval / 1000;
+        tv.tv_usec = interval % 1000 * 1000;
+        tvp = &tv;
+    } else {
+        tvp = NULL;
+    }
+    *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, tvp);
 #endif
 
     return (*sret < 0) ? SOCKET_ERRNO : 0;
@@ -1101,11 +1109,6 @@ service_tcp_connect(krb5_context context, const krb5_data *realm,
     }
 
     conn->state = WRITING;
-
-    /* Record this connection's timeout for service_fds. */
-    if (get_curtime_ms(&conn->endtime) == 0)
-        conn->endtime += 10000;
-
     return conn->service_write(context, realm, conn, selstate);
 }
 
@@ -1380,19 +1383,18 @@ kill_conn:
     return FALSE;
 }
 
-/* Return the maximum of endtime and the endtime fields of all currently active
- * TCP connections. */
-static time_ms
-get_endtime(time_ms endtime, struct conn_state *conns)
+/* Return true if conns contains any states with connected TCP sockets. */
+static krb5_boolean
+any_tcp_connections(struct conn_state *conns)
 {
     struct conn_state *state;
 
     for (state = conns; state != NULL; state = state->next) {
-        if ((state->state == READING || state->state == WRITING) &&
-            state->endtime > endtime)
-            endtime = state->endtime;
+        if (state->addr.transport != UDP &&
+            (state->state == READING || state->state == WRITING))
+            return TRUE;
     }
-    return endtime;
+    return FALSE;
 }
 
 static krb5_boolean
@@ -1415,9 +1417,9 @@ service_fds(krb5_context context, struct select_state *selstate,
 
     e = 0;
     while (selstate->nfds > 0) {
-        endtime = get_endtime(interval_end, conns);
+        endtime = any_tcp_connections(conns) ? 0 : interval_end;
         /* Don't wait longer than the whole request should last. */
-        if (timeout && endtime > timeout)
+        if (timeout && (!endtime || endtime > timeout))
             endtime = timeout;
         e = cm_select_or_poll(selstate, endtime, seltemp, &selret);
         if (e == EINTR)


More information about the cvs-krb5 mailing list