[prev in list] [next in list] [prev in thread] [next in thread] 

List:       sssd-devel
Subject:    =?utf-8?b?W1NTU0Rd?= [sssd PR#5532][synchronized] ldap: retry ldap_install_tls() when watchdog inter
From:       ikerexxe <sssd-github-notification () fedorahosted ! org>
Date:       2021-03-31 8:18:21
Message-ID: gh-SSSD/sssd-5532-2021-58aaf2d2-6ecc-442d-a2ef-0627bc6b7969 () sssd-github-notification ! fedorahosted ! org
[Download RAW message or body]

[Attachment #2 (unknown)]

   URL: https://github.com/SSSD/sssd/pull/5532
Author: ikerexxe
 Title: #5532: ldap: retry ldap_install_tls() when watchdog interruption
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/5532/head:pr5532
git checkout pr5532

["sssd-pr-5532.patch" (sssd-pr-5532.patch)]

From 41f59e1b90b331869b56d74414a347a8204c7f2b 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

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
---
 src/providers/backend.h                    |  6 +++-
 src/providers/data_provider_fo.c           | 32 +++++++++++++++++++++-
 src/providers/krb5/krb5_auth.c             | 15 ++++++----
 src/providers/ldap/sdap_async_connection.c | 32 ++++++++++++++--------
 src/util/sss_ldap.c                        | 12 ++++++++
 src/util/util.h                            |  1 +
 src/util/util_errors.c                     |  2 ++
 src/util/util_errors.h                     |  2 ++
 src/util/util_watchdog.c                   |  5 ++++
 9 files changed, 89 insertions(+), 18 deletions(-)

diff --git a/src/providers/backend.h b/src/providers/backend.h
index f8e8af9aa0..c5280c8ffb 100644
--- a/src/providers/backend.h
+++ b/src/providers/backend.h
@@ -60,6 +60,9 @@ struct be_svc_data {
 
     struct be_svc_callback *callbacks;
     struct fo_server *first_resolved;
+
+    struct fo_server *current_resolved;
+    int current_resolved_attempts;
 };
 
 struct be_failover_ctx {
@@ -189,7 +192,8 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct be_ctx *ctx,
                                           const char *service_name,
-                                          bool first_try);
+                                          bool first_try,
+                                          bool retry_same_server);
 int be_resolve_server_recv(struct tevent_req *req,
                            TALLOC_CTX *ref_ctx,
                            struct fo_server **srv);
diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index 0dfbb04b0f..91ea7e68c2 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -24,6 +24,8 @@
 #include "providers/backend.h"
 #include "resolv/async_resolv.h"
 
+#define MAX_RESOLVED_ATTEMPTS 2
+
 struct be_svc_callback {
     struct be_svc_callback *prev;
     struct be_svc_callback *next;
@@ -506,7 +508,8 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct be_ctx *ctx,
                                           const char *service_name,
-                                          bool first_try)
+                                          bool first_try,
+                                          bool retry_same_server)
 {
     struct tevent_req *req, *subreq;
     struct be_resolve_server_state *state;
@@ -529,6 +532,30 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
     state->attempts = 0;
     state->first_try = first_try;
 
+    if (retry_same_server &&
+        state->svc->current_resolved_attempts < MAX_RESOLVED_ATTEMPTS) {
+        state->srv = state->svc->current_resolved;
+        state->svc->current_resolved_attempts++;
+        DEBUG(SSSDBG_IMPORTANT_INFO, "Performing retry to %s:%d\n",
+              fo_get_server_str_name(state->srv),
+              fo_get_server_port(state->srv));
+        tevent_req_done(req);
+        tevent_req_post(req, ev);
+        return req;
+    } else if (retry_same_server &&
+               state->svc->current_resolved_attempts >= MAX_RESOLVED_ATTEMPTS) {
+        DEBUG(SSSDBG_IMPORTANT_INFO,
+              "Will not retry %s:%d, maximum number of attempts (%d) reached\n",
+              fo_get_server_str_name(state->svc->current_resolved),
+              fo_get_server_port(state->svc->current_resolved),
+              MAX_RESOLVED_ATTEMPTS);
+        be_fo_set_port_status(state->ctx, state->svc->name,
+                              state->svc->current_resolved,
+                              PORT_NOT_WORKING);
+    }
+
+    state->svc->current_resolved_attempts = 0;
+
     subreq = fo_resolve_service_send(state, ev,
                                      ctx->be_fo->be_res->resolv,
                                      ctx->be_fo->fo_ctx,
@@ -645,6 +672,9 @@ errno_t be_resolve_server_process(struct tevent_req *subreq,
         return ENOENT;
     }
 
+    state->svc->current_resolved = state->srv;
+    state->svc->current_resolved_attempts++;
+
     if (DEBUG_IS_SET(SSSDBG_FUNC_DATA) && fo_get_server_name(state->srv)) {
         struct resolv_hostent *srvaddr;
         char ipaddr[128];
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index 699c2467b8..95336f68d0 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -688,7 +688,8 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
     state->search_kpasswd = false;
     subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
                                     state->krb5_ctx->service->name,
-                                    state->kr->srv == NULL ? true : false);
+                                    state->kr->srv == NULL ? true : false,
+                                    false);
     if (!subreq) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolver request.\n");
         ret = EIO;
@@ -759,7 +760,8 @@ static void krb5_auth_resolve_done(struct tevent_req *subreq)
                 subreq = be_resolve_server_send(state,
                                     state->ev, state->be_ctx,
                                     state->krb5_ctx->kpasswd_service->name,
-                                    kr->kpasswd_srv == NULL ? true : false);
+                                    kr->kpasswd_srv == NULL ? true : false,
+                                    false);
                 if (subreq == NULL) {
                     DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
                     ret = EIO;
@@ -863,7 +865,8 @@ static void krb5_auth_done(struct tevent_req *subreq)
                               search_srv, PORT_NOT_WORKING);
         subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
                                         state->krb5_ctx->service->name,
-                                        search_srv == NULL ? true : false);
+                                        search_srv == NULL ? true : false,
+                                        false);
         if (subreq == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE, "Failed resolved request.\n");
             ret = ENOMEM;
@@ -965,7 +968,8 @@ static void krb5_auth_done(struct tevent_req *subreq)
             state->search_kpasswd = true;
             subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
                                 state->krb5_ctx->kpasswd_service->name,
-                                state->kr->kpasswd_srv == NULL ?  true : false);
+                                state->kr->kpasswd_srv == NULL ?  true : false,
+                                false);
             if (subreq == NULL) {
                 DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
                 ret = ENOMEM;
@@ -982,7 +986,8 @@ static void krb5_auth_done(struct tevent_req *subreq)
             state->search_kpasswd = false;
             subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
                                             state->krb5_ctx->service->name,
-                                            kr->srv == NULL ?  true : false);
+                                            kr->srv == NULL ?  true : false,
+                                            false);
             if (subreq == NULL) {
                 DEBUG(SSSDBG_CRIT_FAILURE, "Resolver request failed.\n");
                 ret = ENOMEM;
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index eead3f119a..5039c4a696 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -1172,7 +1172,8 @@ static struct tevent_req *sdap_kinit_next_kdc(struct tevent_req *req)
     next_req = be_resolve_server_send(state, state->ev,
                                       state->be,
                                       state->krb_service_name,
-                                      state->kdc_srv == NULL ? true : false);
+                                      state->kdc_srv == NULL ? true : false,
+                                      false);
     if (next_req == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "be_resolve_server_send failed.\n");
         return NULL;
@@ -1450,7 +1451,7 @@ struct sdap_cli_connect_state {
     bool use_tls;
 };
 
-static int sdap_cli_resolve_next(struct tevent_req *req);
+static int sdap_cli_resolve_next(struct tevent_req *req, bool retry_same_server);
 static void sdap_cli_resolve_done(struct tevent_req *subreq);
 static void sdap_cli_connect_done(struct tevent_req *subreq);
 static void sdap_cli_rootdse_step(struct tevent_req *req);
@@ -1521,7 +1522,7 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
     state->force_tls = force_tls;
     state->do_auth = !skip_auth;
 
-    ret = sdap_cli_resolve_next(req);
+    ret = sdap_cli_resolve_next(req, false);
     if (ret) {
         tevent_req_error(req, ret);
         tevent_req_post(req, ev);
@@ -1529,7 +1530,7 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
     return req;
 }
 
-static int sdap_cli_resolve_next(struct tevent_req *req)
+static int sdap_cli_resolve_next(struct tevent_req *req, bool retry_same_server)
 {
     struct sdap_cli_connect_state *state = tevent_req_data(req,
                                              struct sdap_cli_connect_state);
@@ -1542,7 +1543,8 @@ static int sdap_cli_resolve_next(struct tevent_req *req)
      * with a new valid server. Do not use service->uri before */
     subreq = be_resolve_server_send(state, state->ev,
                                     state->be, state->service->name,
-                                    state->srv == NULL ? true : false);
+                                    state->srv == NULL ? true : false,
+                                    retry_same_server);
     if (!subreq) {
         return ENOMEM;
     }
@@ -1596,15 +1598,23 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
                                              struct sdap_cli_connect_state);
     const char *sasl_mech;
     int ret;
+    bool retry_same_server;
 
     talloc_zfree(state->sh);
     ret = sdap_connect_recv(subreq, state, &state->sh);
     talloc_zfree(subreq);
     if (ret) {
-        /* 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 == ERR_TLS_HANDSHAKE_INTERRUPTED) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "TLS handshake was interruped, provider may retry\n");
+            retry_same_server = true;
+        } else {
+            retry_same_server = false;
+            /* retry another server */
+            be_fo_set_port_status(state->be, state->service->name,
+                                  state->srv, PORT_NOT_WORKING);
+        }
+        ret = sdap_cli_resolve_next(req, retry_same_server);
         if (ret != EOK) {
             tevent_req_error(req, ret);
         }
@@ -1678,7 +1688,7 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq)
         if (ret == ETIMEDOUT) { /* retry another server */
             be_fo_set_port_status(state->be, state->service->name,
                                   state->srv, PORT_NOT_WORKING);
-            ret = sdap_cli_resolve_next(req);
+            ret = sdap_cli_resolve_next(req, false);
             if (ret != EOK) {
                 tevent_req_error(req, ret);
             }
@@ -2040,7 +2050,7 @@ static void sdap_cli_rootdse_auth_done(struct tevent_req *subreq)
              * one */
             be_fo_set_port_status(state->be, state->service->name,
                                   state->srv, PORT_NOT_WORKING);
-            ret = sdap_cli_resolve_next(req);
+            ret = sdap_cli_resolve_next(req, false);
             if (ret != EOK) {
                 tevent_req_error(req, ret);
             }
diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
index 976d6208ee..3c68b85994 100644
--- a/src/util/sss_ldap.c
+++ b/src/util/sss_ldap.c
@@ -237,6 +237,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);
@@ -279,7 +281,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");
@@ -301,6 +305,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 aec53962b3..4546d8f123 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -750,6 +750,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 b5c7419a94..334fd9d508 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -143,6 +143,8 @@ struct err_string error_to_str[] = {
     { "Error while parsing configuration file" }, /* ERR_INI_PARSE_FAILED */
     { "Failed to add configuration snippets" }, /* ERR_INI_ADD_SNIPPETS_FAILED */
 
+    { "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 75c46286af..b6b96f3eea 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -164,6 +164,8 @@ enum sssd_errors {
     ERR_INI_PARSE_FAILED,
     ERR_INI_ADD_SNIPPETS_FAILED,
 
+    ERR_TLS_HANDSHAKE_INTERRUPTED,
+
     ERR_LAST            /* ALWAYS LAST */
 };
 
diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c
index 14bf98a9bc..b1534e499c 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);
+}

[Attachment #4 (text/plain)]

_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-leave@lists.fedorahosted.org
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org
Do not reply to spam on the list, report it: https://pagure.io/fedora-infrastructure


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic