Blob Blame History Raw
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