139 lines
4.8 KiB
Diff
139 lines
4.8 KiB
Diff
|
From 0bf66d2018db92c95d3bab54a62f6a3265ceb158 Mon Sep 17 00:00:00 2001
|
||
|
From: Greg Hudson <ghudson@mit.edu>
|
||
|
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
|
||
|
|