From ee16c609497f29731c5a590821d27d0db0ffc91f Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedrosa@redhat.com>
Date: Wed, 3 Mar 2021 15:34:49 +0100
Subject: [PATCH] ldap: retry ldap_install_tls() when watchdog interruption
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When the call to ldap_install_tls() fails because the watchdog
interrupted it, retry it. The watchdog interruption is detected by
checking the value of the ticks before and after the call to
ldap_install_tls().
Resolves: https://github.com/SSSD/sssd/issues/5531
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
---
src/providers/ldap/sdap_async_connection.c | 27 +++++++++++++++++++++-
src/util/sss_ldap.c | 12 ++++++++++
src/util/util.h | 1 +
src/util/util_errors.c | 3 +++
src/util/util_errors.h | 3 +++
src/util/util_watchdog.c | 5 ++++
6 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index afa31ea0f..db963044e 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -30,6 +30,8 @@
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/ldap_common.h"
+#define MAX_RETRY_ATTEMPTS 1
+
/* ==Connect-to-LDAP-Server=============================================== */
struct sdap_rebind_proc_params {
@@ -1447,6 +1449,8 @@ struct sdap_cli_connect_state {
enum connect_tls force_tls;
bool do_auth;
bool use_tls;
+
+ int retry_attempts;
};
static int sdap_cli_resolve_next(struct tevent_req *req);
@@ -1599,16 +1603,37 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
talloc_zfree(state->sh);
ret = sdap_connect_recv(subreq, state, &state->sh);
talloc_zfree(subreq);
- if (ret) {
+ if (ret == ERR_TLS_HANDSHAKE_INTERRUPTED &&
+ state->retry_attempts < MAX_RETRY_ATTEMPTS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "TLS handshake was interruped, provider will retry\n");
+ state->retry_attempts++;
+ subreq = sdap_connect_send(state, state->ev, state->opts,
+ state->service->uri,
+ state->service->sockaddr,
+ state->use_tls);
+
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ tevent_req_set_callback(subreq, sdap_cli_connect_done, req);
+ return;
+ } else if (ret != EOK) {
+ state->retry_attempts = 0;
/* retry another server */
be_fo_set_port_status(state->be, state->service->name,
state->srv, PORT_NOT_WORKING);
+
ret = sdap_cli_resolve_next(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
+
return;
}
+ state->retry_attempts = 0;
if (state->use_rootdse) {
/* fetch the rootDSE this time */
diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
index 9d1e95217..652b08ea7 100644
--- a/src/util/sss_ldap.c
+++ b/src/util/sss_ldap.c
@@ -234,6 +234,8 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
int ret;
int lret;
int optret;
+ int ticks_before_install;
+ int ticks_after_install;
ret = sssd_async_socket_init_recv(subreq, &state->sd);
talloc_zfree(subreq);
@@ -261,7 +263,9 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
}
if (ldap_is_ldaps_url(state->uri)) {
+ ticks_before_install = get_watchdog_ticks();
lret = ldap_install_tls(state->ldap);
+ ticks_after_install = get_watchdog_ticks();
if (lret != LDAP_SUCCESS) {
if (lret == LDAP_LOCAL_ERROR) {
DEBUG(SSSDBG_FUNC_DATA, "TLS/SSL already in place.\n");
@@ -283,6 +287,14 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
"Check for certificate issues.");
}
+ if (ticks_after_install > ticks_before_install) {
+ ret = ERR_TLS_HANDSHAKE_INTERRUPTED;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Assuming %s\n",
+ sss_ldap_err2string(ret));
+ goto fail;
+ }
+
ret = EIO;
goto fail;
}
diff --git a/src/util/util.h b/src/util/util.h
index 486394448..94c2e6e3b 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -737,6 +737,7 @@ int sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl);
/* from util_watchdog.c */
int setup_watchdog(struct tevent_context *ev, int interval);
void teardown_watchdog(void);
+int get_watchdog_ticks(void);
/* from files.c */
int sss_remove_tree(const char *root);
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
index c35a99a54..0eeaa346c 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -121,6 +121,9 @@ struct err_string error_to_str[] = {
{ "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */
{ "ID is outside the allowed range" }, /* ERR_ID_OUTSIDE_RANGE */
{ "Group ID is duplicated" }, /* ERR_GID_DUPLICATED */
+
+ { "TLS handshake was interrupted"}, /* ERR_TLS_HANDSHAKE_INTERRUPTED */
+
{ "ERR_LAST" } /* ERR_LAST */
};
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
index 470f62f9e..366b75650 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -143,6 +143,9 @@ enum sssd_errors {
ERR_GET_ACCT_DOM_CACHED,
ERR_ID_OUTSIDE_RANGE,
ERR_GID_DUPLICATED,
+
+ ERR_TLS_HANDSHAKE_INTERRUPTED,
+
ERR_LAST /* ALWAYS LAST */
};
diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c
index 69160fbdf..7642bfd53 100644
--- a/src/util/util_watchdog.c
+++ b/src/util/util_watchdog.c
@@ -259,3 +259,8 @@ void teardown_watchdog(void)
/* and kill the watchdog event */
talloc_free(watchdog_ctx.te);
}
+
+int get_watchdog_ticks(void)
+{
+ return __sync_add_and_fetch(&watchdog_ctx.ticks, 0);
+}
--
2.26.3