From 0bf66d2018db92c95d3bab54a62f6a3265ceb158 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Thu, 26 Oct 2023 16:26:42 -0400 Subject: [PATCH] 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) (cherry picked from commit 6436a3808061da787a43c6810f5f0370cdfb6e36) --- 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 65fb592d98..b7284c47df 100644 --- a/doc/admin/conf_files/krb5_conf.rst +++ b/doc/admin/conf_files/krb5_conf.rst @@ -357,7 +357,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 98247a1089..924f5b2d26 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; @@ -1099,11 +1107,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); } @@ -1378,19 +1381,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 @@ -1413,9 +1415,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) -- 2.44.0