Blame SOURCES/0073-cldap.patch

f9c044
From db644a3a24c123a964129d41934365d8eb2174c7 Mon Sep 17 00:00:00 2001
f9c044
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
f9c044
Date: Thu, 30 Jul 2020 12:59:01 +0200
f9c044
Subject: [PATCH 1/7] ldap: add support for cldap and udp connections
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
(cherry picked from commit 414593cca65ed09fe4659e2786370a4553664cd0)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 src/util/sss_ldap.c    | 28 ++++++++++++++++++++-----
f9c044
 src/util/sss_sockets.c | 47 ++++++++++++++++++++++++++++--------------
f9c044
 src/util/sss_sockets.h |  1 +
f9c044
 3 files changed, 56 insertions(+), 20 deletions(-)
f9c044
f9c044
diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
f9c044
index 652b08ea7..71fa21f4a 100644
f9c044
--- a/src/util/sss_ldap.c
f9c044
+++ b/src/util/sss_ldap.c
f9c044
@@ -116,6 +116,7 @@ struct sss_ldap_init_state {
f9c044
     LDAP *ldap;
f9c044
     int sd;
f9c044
     const char *uri;
f9c044
+    bool use_udp;
f9c044
 };
f9c044
 
f9c044
 static int sss_ldap_init_state_destructor(void *data)
f9c044
@@ -159,11 +160,13 @@ struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
f9c044
     state->ldap = NULL;
f9c044
     state->sd = -1;
f9c044
     state->uri = uri;
f9c044
+    state->use_udp = strncmp(uri, "cldap", 5) == 0 ? true : false;
f9c044
 
f9c044
 #ifdef HAVE_LDAP_INIT_FD
f9c044
     struct tevent_req *subreq;
f9c044
 
f9c044
-    subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout);
f9c044
+    subreq = sssd_async_socket_init_send(state, ev, state->use_udp, addr,
f9c044
+                                         addr_len, timeout);
f9c044
     if (subreq == NULL) {
f9c044
         ret = ENOMEM;
f9c044
         DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n");
f9c044
@@ -246,14 +249,29 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
f9c044
         goto fail;
f9c044
     }
f9c044
 
f9c044
-    ret = unset_fcntl_flags(state->sd, O_NONBLOCK);
f9c044
-    if (ret != EOK) {
f9c044
-        goto fail;
f9c044
+    /* openldap < 2.5 does not correctly handle O_NONBLOCK during starttls for
f9c044
+     * ldaps, so we need to remove the flag here. This is fine since I/O events
f9c044
+     * are handled via tevent so we only read when there is data available.
f9c044
+     *
f9c044
+     * We need to keep O_NONBLOCK due to a bug in openldap to correctly perform
f9c044
+     * a parallel CLDAP pings without timeout. See:
f9c044
+     * https://bugs.openldap.org/show_bug.cgi?id=9328
f9c044
+     *
f9c044
+     * @todo remove this when the bug is fixed and we can put a hard requirement
f9c044
+     * on newer openldap.
f9c044
+     */
f9c044
+    if (!state->use_udp) {
f9c044
+        ret = unset_fcntl_flags(state->sd, O_NONBLOCK);
f9c044
+        if (ret != EOK) {
f9c044
+            goto fail;
f9c044
+        }
f9c044
     }
f9c044
 
f9c044
     /* Initialize LDAP handler */
f9c044
 
f9c044
-    lret = ldap_init_fd(state->sd, LDAP_PROTO_TCP, state->uri, &state->ldap);
f9c044
+    lret = ldap_init_fd(state->sd,
f9c044
+                        state->use_udp ? LDAP_PROTO_UDP : LDAP_PROTO_TCP,
f9c044
+                        state->uri, &state->ldap);
f9c044
     if (lret != LDAP_SUCCESS) {
f9c044
         DEBUG(SSSDBG_CRIT_FAILURE,
f9c044
               "ldap_init_fd failed: %s. [%d][%s]\n",
f9c044
diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
f9c044
index 6f2b71bc8..733360f3b 100644
f9c044
--- a/src/util/sss_sockets.c
f9c044
+++ b/src/util/sss_sockets.c
f9c044
@@ -80,6 +80,18 @@ static errno_t set_fd_common_opts(int fd, int timeout)
f9c044
     int ret;
f9c044
     struct timeval tv;
f9c044
     unsigned int milli;
f9c044
+    int type;
f9c044
+    socklen_t optlen = sizeof(int);
f9c044
+
f9c044
+    /* Get protocol type. */
f9c044
+    ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
f9c044
+    if (ret != 0) {
f9c044
+        ret = errno;
f9c044
+        DEBUG(SSSDBG_FUNC_DATA, "Unable to get socket type [%d]: %s.\n",
f9c044
+              ret, strerror(ret));
f9c044
+        /* Assume TCP. */
f9c044
+        type = SOCK_STREAM;
f9c044
+    }
f9c044
 
f9c044
     /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
f9c044
      * failures are ignored.*/
f9c044
@@ -91,12 +103,14 @@ static errno_t set_fd_common_opts(int fd, int timeout)
f9c044
                   strerror(ret));
f9c044
     }
f9c044
 
f9c044
-    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
f9c044
-    if (ret != 0) {
f9c044
-        ret = errno;
f9c044
-        DEBUG(SSSDBG_FUNC_DATA,
f9c044
-              "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
f9c044
-                  strerror(ret));
f9c044
+    if (type == SOCK_STREAM) {
f9c044
+        ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
f9c044
+        if (ret != 0) {
f9c044
+            ret = errno;
f9c044
+            DEBUG(SSSDBG_FUNC_DATA,
f9c044
+                "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
f9c044
+                    strerror(ret));
f9c044
+        }
f9c044
     }
f9c044
 
f9c044
     if (timeout > 0) {
f9c044
@@ -119,14 +133,16 @@ static errno_t set_fd_common_opts(int fd, int timeout)
f9c044
                   strerror(ret));
f9c044
         }
f9c044
 
f9c044
-        milli = timeout * 1000; /* timeout in milliseconds */
f9c044
-        ret = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &milli,
f9c044
-                         sizeof(milli));
f9c044
-        if (ret != 0) {
f9c044
-            ret = errno;
f9c044
-            DEBUG(SSSDBG_FUNC_DATA,
f9c044
-                  "setsockopt TCP_USER_TIMEOUT failed.[%d][%s].\n", ret,
f9c044
-                  strerror(ret));
f9c044
+        if (type == SOCK_STREAM) {
f9c044
+            milli = timeout * 1000; /* timeout in milliseconds */
f9c044
+            ret = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &milli,
f9c044
+                            sizeof(milli));
f9c044
+            if (ret != 0) {
f9c044
+                ret = errno;
f9c044
+                DEBUG(SSSDBG_FUNC_DATA,
f9c044
+                    "setsockopt TCP_USER_TIMEOUT failed.[%d][%s].\n", ret,
f9c044
+                    strerror(ret));
f9c044
+            }
f9c044
         }
f9c044
     }
f9c044
 
f9c044
@@ -271,6 +287,7 @@ static void sssd_async_socket_init_done(struct tevent_req *subreq);
f9c044
 
f9c044
 struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
f9c044
                                                struct tevent_context *ev,
f9c044
+                                               bool use_udp,
f9c044
                                                struct sockaddr_storage *addr,
f9c044
                                                socklen_t addr_len, int timeout)
f9c044
 {
f9c044
@@ -289,7 +306,7 @@ struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
f9c044
     talloc_set_destructor((TALLOC_CTX *)state,
f9c044
                           sssd_async_socket_state_destructor);
f9c044
 
f9c044
-    state->sd = socket(addr->ss_family, SOCK_STREAM, 0);
f9c044
+    state->sd = socket(addr->ss_family, use_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
f9c044
     if (state->sd == -1) {
f9c044
         ret = errno;
f9c044
         DEBUG(SSSDBG_CRIT_FAILURE,
f9c044
diff --git a/src/util/sss_sockets.h b/src/util/sss_sockets.h
f9c044
index ccb05cb84..2758e6ed1 100644
f9c044
--- a/src/util/sss_sockets.h
f9c044
+++ b/src/util/sss_sockets.h
f9c044
@@ -32,6 +32,7 @@ int sssd_async_connect_recv(struct tevent_req *req);
f9c044
 
f9c044
 struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
f9c044
                                                struct tevent_context *ev,
f9c044
+                                               bool use_udp,
f9c044
                                                struct sockaddr_storage *addr,
f9c044
                                                socklen_t addr_len, int timeout);
f9c044
 int sssd_async_socket_init_recv(struct tevent_req *req, int *sd);
f9c044
-- 
f9c044
2.26.3
f9c044
f9c044
f9c044
From 3efae1df18f4bfe7782025a14bcfbb5965496b32 Mon Sep 17 00:00:00 2001
f9c044
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
f9c044
Date: Thu, 30 Jul 2020 13:30:50 +0200
f9c044
Subject: [PATCH 2/7] ad: use cldap for site and forrest discover (perform
f9c044
 CLDAP ping)
f9c044
f9c044
All Windows clients uses CLDAP (UDP) for LDAP ping. Even though AD
f9c044
also supports LDAP ping over TCP IPA does not therefore it is crusial
f9c044
for us to perform the ping over CLDAP protocol.
f9c044
f9c044
Resolves:
f9c044
https://github.com/SSSD/sssd/issues/5215
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
(cherry picked from commit 8265674a055e5cdb57acebad72d935356408540a)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 src/providers/ad/ad_init.c                | 6 +-----
f9c044
 src/providers/ad/ad_srv.c                 | 9 +++------
f9c044
 src/providers/ad/ad_srv.h                 | 3 +--
f9c044
 src/providers/ad/ad_subdomains.c          | 2 +-
f9c044
 src/providers/ipa/ipa_subdomains_server.c | 2 +-
f9c044
 5 files changed, 7 insertions(+), 15 deletions(-)
f9c044
f9c044
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
f9c044
index fb24a28e1..5abd28b7c 100644
f9c044
--- a/src/providers/ad/ad_init.c
f9c044
+++ b/src/providers/ad/ad_init.c
f9c044
@@ -187,14 +187,11 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx,
f9c044
     const char *ad_site_override;
f9c044
     bool sites_enabled;
f9c044
     errno_t ret;
f9c044
-    bool ad_use_ldaps;
f9c044
 
f9c044
     hostname = dp_opt_get_string(ad_options->basic, AD_HOSTNAME);
f9c044
     ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN);
f9c044
     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
f9c044
     sites_enabled = dp_opt_get_bool(ad_options->basic, AD_ENABLE_DNS_SITES);
f9c044
-    ad_use_ldaps = dp_opt_get_bool(ad_options->basic, AD_USE_LDAPS);
f9c044
-
f9c044
 
f9c044
     if (!sites_enabled) {
f9c044
         ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, hostname);
f9c044
@@ -210,8 +207,7 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx,
f9c044
     srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res,
f9c044
                                      default_host_dbs, ad_options->id,
f9c044
                                      hostname, ad_domain,
f9c044
-                                     ad_site_override,
f9c044
-                                     ad_use_ldaps);
f9c044
+                                     ad_site_override);
f9c044
     if (srv_ctx == NULL) {
f9c044
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
f9c044
         return ENOMEM;
f9c044
diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
f9c044
index ca15d3715..55e8f63f7 100644
f9c044
--- a/src/providers/ad/ad_srv.c
f9c044
+++ b/src/providers/ad/ad_srv.c
f9c044
@@ -335,9 +335,9 @@ static errno_t ad_get_client_site_next_dc(struct tevent_req *req)
f9c044
                                     state->be_res->resolv,
f9c044
                                     state->be_res->family_order,
f9c044
                                     state->host_db,
f9c044
-                                    state->ad_use_ldaps ? "ldaps" : "ldap",
f9c044
+                                    "cldap",
f9c044
                                     state->dc.host,
f9c044
-                                    state->ad_use_ldaps ? 636 : state->dc.port,
f9c044
+                                    state->dc.port,
f9c044
                                     false);
f9c044
     if (subreq == NULL) {
f9c044
         ret = ENOMEM;
f9c044
@@ -497,7 +497,6 @@ struct ad_srv_plugin_ctx {
f9c044
     const char *ad_domain;
f9c044
     const char *ad_site_override;
f9c044
     const char *current_site;
f9c044
-    bool ad_use_ldaps;
f9c044
 };
f9c044
 
f9c044
 struct ad_srv_plugin_ctx *
f9c044
@@ -508,8 +507,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
                        struct sdap_options *opts,
f9c044
                        const char *hostname,
f9c044
                        const char *ad_domain,
f9c044
-                       const char *ad_site_override,
f9c044
-                       bool ad_use_ldaps)
f9c044
+                       const char *ad_site_override)
f9c044
 {
f9c044
     struct ad_srv_plugin_ctx *ctx = NULL;
f9c044
     errno_t ret;
f9c044
@@ -523,7 +521,6 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
     ctx->be_res = be_res;
f9c044
     ctx->host_dbs = host_dbs;
f9c044
     ctx->opts = opts;
f9c044
-    ctx->ad_use_ldaps = ad_use_ldaps;
f9c044
 
f9c044
     ctx->hostname = talloc_strdup(ctx, hostname);
f9c044
     if (ctx->hostname == NULL) {
f9c044
diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h
f9c044
index 8e410ec26..e553d594d 100644
f9c044
--- a/src/providers/ad/ad_srv.h
f9c044
+++ b/src/providers/ad/ad_srv.h
f9c044
@@ -31,8 +31,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
                        struct sdap_options *opts,
f9c044
                        const char *hostname,
f9c044
                        const char *ad_domain,
f9c044
-                       const char *ad_site_override,
f9c044
-                       bool ad_use_ldaps);
f9c044
+                       const char *ad_site_override);
f9c044
 
f9c044
 struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
f9c044
                                        struct tevent_context *ev,
f9c044
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
f9c044
index 16aecbc64..9b32196b7 100644
f9c044
--- a/src/providers/ad/ad_subdomains.c
f9c044
+++ b/src/providers/ad/ad_subdomains.c
f9c044
@@ -411,7 +411,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
f9c044
                                      ad_id_ctx->ad_options->id,
f9c044
                                      hostname,
f9c044
                                      ad_domain,
f9c044
-                                     ad_site_override, ad_use_ldaps);
f9c044
+                                     ad_site_override);
f9c044
     if (srv_ctx == NULL) {
f9c044
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
f9c044
         return ENOMEM;
f9c044
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
f9c044
index e2037b59d..f0d8a6a20 100644
f9c044
--- a/src/providers/ipa/ipa_subdomains_server.c
f9c044
+++ b/src/providers/ipa/ipa_subdomains_server.c
f9c044
@@ -344,7 +344,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
f9c044
                                      ad_id_ctx->ad_options->id,
f9c044
                                      id_ctx->server_mode->hostname,
f9c044
                                      ad_domain,
f9c044
-                                     ad_site_override, false);
f9c044
+                                     ad_site_override);
f9c044
     if (srv_ctx == NULL) {
f9c044
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
f9c044
         return ENOMEM;
f9c044
-- 
f9c044
2.26.3
f9c044
f9c044
f9c044
From 7e856adefeaa377a50b40d397684e48ba82aa055 Mon Sep 17 00:00:00 2001
f9c044
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
f9c044
Date: Tue, 11 Aug 2020 13:27:42 +0200
f9c044
Subject: [PATCH 3/7] ad: connect to the first available server for cldap ping
f9c044
f9c044
Resolves:
f9c044
https://github.com/SSSD/sssd/issues/3743
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
(cherry picked from commit 1889ca60a9c642f0cca60b20a5b94de7a66924f6)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 Makefile.am                      |   5 +-
f9c044
 src/providers/ad/ad_cldap_ping.c | 586 +++++++++++++++++++++++++++++++
f9c044
 src/providers/ad/ad_srv.c        | 434 +----------------------
f9c044
 src/providers/ad/ad_srv.h        |  14 +
f9c044
 4 files changed, 613 insertions(+), 426 deletions(-)
f9c044
 create mode 100644 src/providers/ad/ad_cldap_ping.c
f9c044
f9c044
diff --git a/Makefile.am b/Makefile.am
f9c044
index b9ca9a7c6..17e20f1cb 100644
f9c044
--- a/Makefile.am
f9c044
+++ b/Makefile.am
f9c044
@@ -4202,7 +4202,9 @@ libsss_ipa_la_SOURCES = \
f9c044
     src/providers/ad/ad_pac.c \
f9c044
     src/providers/ad/ad_pac_common.c \
f9c044
     src/providers/ad/ad_srv.c \
f9c044
-    src/providers/ad/ad_domain_info.c
f9c044
+    src/providers/ad/ad_domain_info.c \
f9c044
+    src/providers/ad/ad_cldap_ping.c \
f9c044
+    $(NULL)
f9c044
 libsss_ipa_la_CFLAGS = \
f9c044
     $(AM_CFLAGS) \
f9c044
     $(OPENLDAP_CFLAGS) \
f9c044
@@ -4269,6 +4271,7 @@ libsss_ad_la_SOURCES = \
f9c044
     src/providers/ad/ad_subdomains.c \
f9c044
     src/providers/ad/ad_domain_info.c \
f9c044
     src/providers/ad/ad_refresh.c \
f9c044
+    src/providers/ad/ad_cldap_ping.c \
f9c044
     $(NULL)
f9c044
 
f9c044
 
f9c044
diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c
f9c044
new file mode 100644
f9c044
index 000000000..5fc1a4d20
f9c044
--- /dev/null
f9c044
+++ b/src/providers/ad/ad_cldap_ping.c
f9c044
@@ -0,0 +1,586 @@
f9c044
+/*
f9c044
+    Authors:
f9c044
+        Pavel Březina <pbrezina@redhat.com>
f9c044
+
f9c044
+    Copyright (C) 2020 Red Hat
f9c044
+
f9c044
+    This program is free software; you can redistribute it and/or modify
f9c044
+    it under the terms of the GNU General Public License as published by
f9c044
+    the Free Software Foundation; either version 3 of the License, or
f9c044
+    (at your option) any later version.
f9c044
+
f9c044
+    This program is distributed in the hope that it will be useful,
f9c044
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
f9c044
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
f9c044
+    GNU General Public License for more details.
f9c044
+
f9c044
+    You should have received a copy of the GNU General Public License
f9c044
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
f9c044
+*/
f9c044
+
f9c044
+#include <string.h>
f9c044
+#include <talloc.h>
f9c044
+#include <tevent.h>
f9c044
+#include <ndr.h>
f9c044
+#include <ndr/ndr_nbt.h>
f9c044
+
f9c044
+#include "util/util.h"
f9c044
+#include "util/sss_ldap.h"
f9c044
+#include "resolv/async_resolv.h"
f9c044
+#include "providers/backend.h"
f9c044
+#include "providers/ad/ad_srv.h"
f9c044
+#include "providers/ad/ad_common.h"
f9c044
+#include "providers/fail_over.h"
f9c044
+#include "providers/fail_over_srv.h"
f9c044
+#include "providers/ldap/sdap.h"
f9c044
+#include "providers/ldap/sdap_async.h"
f9c044
+#include "db/sysdb.h"
f9c044
+
f9c044
+struct ad_cldap_ping_dc_state {
f9c044
+    struct tevent_context *ev;
f9c044
+    struct sdap_options *opts;
f9c044
+    struct fo_server_info *dc;
f9c044
+    struct sdap_handle *sh;
f9c044
+    const char *ad_domain;
f9c044
+
f9c044
+    char *site;
f9c044
+    char *forest;
f9c044
+};
f9c044
+
f9c044
+static void ad_cldap_ping_dc_connect_done(struct tevent_req *subreq);
f9c044
+static void ad_cldap_ping_dc_done(struct tevent_req *subreq);
f9c044
+
f9c044
+static struct tevent_req *ad_cldap_ping_dc_send(TALLOC_CTX *mem_ctx,
f9c044
+                                                struct tevent_context *ev,
f9c044
+                                                struct sdap_options *opts,
f9c044
+                                                struct be_resolv_ctx *be_res,
f9c044
+                                                enum host_database *host_db,
f9c044
+                                                struct fo_server_info *dc,
f9c044
+                                                const char *ad_domain)
f9c044
+{
f9c044
+    struct ad_cldap_ping_dc_state *state;
f9c044
+    struct tevent_req *subreq;
f9c044
+    struct tevent_req *req;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_create(mem_ctx, &state,
f9c044
+                            struct ad_cldap_ping_dc_state);
f9c044
+    if (req == NULL) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
+        return NULL;
f9c044
+    }
f9c044
+
f9c044
+    state->ev = ev;
f9c044
+    state->opts = opts;
f9c044
+    state->dc = dc;
f9c044
+    state->ad_domain = ad_domain;
f9c044
+
f9c044
+    subreq = sdap_connect_host_send(state, ev, opts, be_res->resolv,
f9c044
+                                    be_res->family_order, host_db, "cldap",
f9c044
+                                    dc->host, dc->port, false);
f9c044
+    if (subreq == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_dc_connect_done, req);
f9c044
+
f9c044
+    return req;
f9c044
+
f9c044
+done:
f9c044
+    tevent_req_error(req, ret);
f9c044
+    tevent_req_post(req, ev);
f9c044
+
f9c044
+    return req;
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_dc_connect_done(struct tevent_req *subreq)
f9c044
+{
f9c044
+    static const char *attrs[] = {AD_AT_NETLOGON, NULL};
f9c044
+    struct ad_cldap_ping_dc_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    char *ntver;
f9c044
+    char *filter;
f9c044
+    int timeout;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_dc_state);
f9c044
+
f9c044
+    ret = sdap_connect_host_recv(state, subreq, &state->sh);
f9c044
+    talloc_zfree(subreq);
f9c044
+    if (ret != EOK) {
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX |
f9c044
+                                       NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
f9c044
+    if (ntver == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))", AD_AT_DNS_DOMAIN,
f9c044
+                             state->ad_domain, AD_AT_NT_VERSION, ntver);
f9c044
+    if (filter == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
f9c044
+    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, "",
f9c044
+                                   LDAP_SCOPE_BASE, filter, attrs, NULL,
f9c044
+                                   0, timeout, false);
f9c044
+    if (subreq == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_dc_done, req);
f9c044
+
f9c044
+    ret = EOK;
f9c044
+
f9c044
+done:
f9c044
+    if (ret != EOK) {
f9c044
+        tevent_req_error(req, ret);
f9c044
+    }
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_dc_done(struct tevent_req *subreq)
f9c044
+{
f9c044
+    struct ad_cldap_ping_dc_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    struct sysdb_attrs **reply;
f9c044
+    size_t reply_count;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_dc_state);
f9c044
+
f9c044
+    ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
f9c044
+
f9c044
+    talloc_zfree(subreq);
f9c044
+    talloc_zfree(state->sh);
f9c044
+
f9c044
+    if (ret != EOK) {
f9c044
+        DEBUG(SSSDBG_OP_FAILURE, "%s:%d: unable to get netlogon information\n",
f9c044
+              state->dc->host, state->dc->port);
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    if (reply_count == 0) {
f9c044
+        DEBUG(SSSDBG_OP_FAILURE, "%s:%d: no netlogon information available\n",
f9c044
+              state->dc->host, state->dc->port);
f9c044
+        ret = ENOENT;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    ret = netlogon_get_domain_info(state, reply[0], true, NULL, &state->site,
f9c044
+                                   &state->forest);
f9c044
+    if (ret != EOK) {
f9c044
+        DEBUG(SSSDBG_OP_FAILURE,
f9c044
+              "%s:%d: unable to retrieve site name [%d]: %s\n",
f9c044
+              state->dc->host, state->dc->port, ret, sss_strerror(ret));
f9c044
+        ret = ENOENT;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    DEBUG(SSSDBG_TRACE_FUNC, "%s:%d: found site (%s) and forest (%s)\n",
f9c044
+          state->dc->host, state->dc->port, state->site, state->forest);
f9c044
+
f9c044
+    ret = EOK;
f9c044
+
f9c044
+done:
f9c044
+    if (ret != EOK) {
f9c044
+        tevent_req_error(req, ret);
f9c044
+        return;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_done(req);
f9c044
+}
f9c044
+
f9c044
+static errno_t ad_cldap_ping_dc_recv(TALLOC_CTX *mem_ctx,
f9c044
+                                     struct tevent_req *req,
f9c044
+                                     const char **_site,
f9c044
+                                     const char **_forest)
f9c044
+{
f9c044
+    struct ad_cldap_ping_dc_state *state = NULL;
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_dc_state);
f9c044
+
f9c044
+    TEVENT_REQ_RETURN_ON_ERROR(req);
f9c044
+
f9c044
+    *_site = talloc_steal(mem_ctx, state->site);
f9c044
+    *_forest = talloc_steal(mem_ctx, state->forest);
f9c044
+
f9c044
+    return EOK;
f9c044
+}
f9c044
+
f9c044
+struct ad_cldap_ping_parallel_state {
f9c044
+    struct tevent_context *ev;
f9c044
+    struct sdap_options *opts;
f9c044
+    struct be_resolv_ctx *be_res;
f9c044
+    enum host_database *host_db;
f9c044
+    const char *ad_domain;
f9c044
+    struct fo_server_info *dc_list;
f9c044
+    size_t dc_count;
f9c044
+
f9c044
+    TALLOC_CTX *reqs_ctx;
f9c044
+    struct tevent_timer *te;
f9c044
+    int active_requests;
f9c044
+    size_t next_dc;
f9c044
+    int batch;
f9c044
+
f9c044
+    const char *site;
f9c044
+    const char *forest;
f9c044
+};
f9c044
+
f9c044
+static void ad_cldap_ping_parallel_batch(struct tevent_context *ev,
f9c044
+                                         struct tevent_timer *te,
f9c044
+                                         struct timeval tv,
f9c044
+                                         void *data);
f9c044
+static void ad_cldap_ping_parallel_done(struct tevent_req *subreq);
f9c044
+
f9c044
+static struct tevent_req *
f9c044
+ad_cldap_ping_parallel_send(TALLOC_CTX *mem_ctx,
f9c044
+                            struct tevent_context *ev,
f9c044
+                            struct sdap_options *opts,
f9c044
+                            struct be_resolv_ctx *be_res,
f9c044
+                            enum host_database *host_db,
f9c044
+                            struct fo_server_info *dc_list,
f9c044
+                            size_t dc_count,
f9c044
+                            const char *ad_domain)
f9c044
+{
f9c044
+    struct ad_cldap_ping_parallel_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    struct timeval tv = {0, 0};
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_create(mem_ctx, &state,
f9c044
+                            struct ad_cldap_ping_parallel_state);
f9c044
+    if (req == NULL) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
+        return NULL;
f9c044
+    }
f9c044
+
f9c044
+    state->ev = ev;
f9c044
+    state->opts = opts;
f9c044
+    state->be_res = be_res;
f9c044
+    state->host_db = host_db;
f9c044
+    state->ad_domain = ad_domain;
f9c044
+    state->dc_list = dc_list;
f9c044
+    state->dc_count = dc_count;
f9c044
+
f9c044
+    state->reqs_ctx = talloc_new(state);
f9c044
+    if (state->reqs_ctx == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    state->next_dc = 0;
f9c044
+    state->batch = 1;
f9c044
+    ad_cldap_ping_parallel_batch(ev, NULL, tv, req);
f9c044
+
f9c044
+    return req;
f9c044
+
f9c044
+done:
f9c044
+    tevent_req_error(req, ret);
f9c044
+    tevent_req_post(req, ev);
f9c044
+
f9c044
+    return req;
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_parallel_batch(struct tevent_context *ev,
f9c044
+                                         struct tevent_timer *te,
f9c044
+                                         struct timeval tv,
f9c044
+                                         void *data)
f9c044
+{
f9c044
+    struct ad_cldap_ping_parallel_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    struct tevent_req *subreq;
f9c044
+    uint32_t delay;
f9c044
+    size_t limit;
f9c044
+    size_t i;
f9c044
+
f9c044
+    req = talloc_get_type(data, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_parallel_state);
f9c044
+
f9c044
+    state->te = NULL;
f9c044
+
f9c044
+    /* Issue three batches in total to avoid pinging too many domain controllers
f9c044
+     * if not necessary. The first batch (5 pings) is issued immediately and we
f9c044
+     * will wait 400ms for it to finish. If we don't get a reply in time we
f9c044
+     * issue next batch (5 pings) and wait 200ms. If we still have no reply,
f9c044
+     * we contact remaining domain controllers.
f9c044
+     *
f9c044
+     * This follows algorithm described at section 5.4.5.3 of MS-DISO:
f9c044
+     * https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/WinArchive/%5bMS-DISO%5d.pdf
f9c044
+     */
f9c044
+    switch (state->batch) {
f9c044
+        case 1:
f9c044
+        case 2:
f9c044
+            limit = MIN(state->dc_count, 5 + state->next_dc);
f9c044
+            delay = 400000 / state->batch;
f9c044
+            break;
f9c044
+        default:
f9c044
+            limit = state->dc_count;
f9c044
+            delay = 0;
f9c044
+    }
f9c044
+
f9c044
+    for (i = state->next_dc; i < limit; i++) {
f9c044
+        DEBUG(SSSDBG_TRACE_ALL, "Batch %d: %s:%d\n", state->batch,
f9c044
+              state->dc_list[i].host, state->dc_list[i].port);
f9c044
+    }
f9c044
+
f9c044
+    for (; state->next_dc < limit; state->next_dc++) {
f9c044
+        subreq = ad_cldap_ping_dc_send(state->reqs_ctx, ev, state->opts,
f9c044
+                                       state->be_res, state->host_db,
f9c044
+                                       &state->dc_list[state->next_dc],
f9c044
+                                       state->ad_domain);
f9c044
+        if (subreq == NULL) {
f9c044
+            DEBUG(SSSDBG_OP_FAILURE, "Unable to create new ping request\n");
f9c044
+            goto fail;
f9c044
+        }
f9c044
+
f9c044
+        state->active_requests++;
f9c044
+        tevent_req_set_callback(subreq, ad_cldap_ping_parallel_done, req);
f9c044
+    }
f9c044
+
f9c044
+    state->batch++;
f9c044
+    if (delay > 0) {
f9c044
+        tv = tevent_timeval_current_ofs(0, delay);
f9c044
+        state->te = tevent_add_timer(ev, state->reqs_ctx, tv,
f9c044
+                                     ad_cldap_ping_parallel_batch, req);
f9c044
+        if (state->te == NULL) {
f9c044
+            DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule next batch!\n");
f9c044
+            goto fail;
f9c044
+        }
f9c044
+    }
f9c044
+
f9c044
+    return;
f9c044
+
f9c044
+fail:
f9c044
+    if (state->active_requests == 0) {
f9c044
+        tevent_req_error(req, ENOMEM);
f9c044
+        if (state->batch == 1) {
f9c044
+            tevent_req_post(req, ev);
f9c044
+        }
f9c044
+    }
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_parallel_done(struct tevent_req *subreq)
f9c044
+{
f9c044
+    struct ad_cldap_ping_parallel_state *state;
f9c044
+    struct timeval tv = {0, 0};
f9c044
+    struct tevent_req *req;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_parallel_state);
f9c044
+
f9c044
+    ret = ad_cldap_ping_dc_recv(state, subreq, &state->site, &state->forest);
f9c044
+    talloc_zfree(subreq);
f9c044
+    state->active_requests--;
f9c044
+
f9c044
+    if (ret == EOK) {
f9c044
+        /* We have the answer. Terminate other attempts and finish. */
f9c044
+        talloc_zfree(state->reqs_ctx);
f9c044
+        tevent_req_done(req);
f9c044
+    } else if (state->active_requests == 0) {
f9c044
+        /* There are still servers to try, don't wait for the timer. */
f9c044
+        if (state->next_dc < state->dc_count) {
f9c044
+            talloc_zfree(state->te);
f9c044
+            ad_cldap_ping_parallel_batch(state->ev, NULL, tv, req);
f9c044
+            return;
f9c044
+        }
f9c044
+        /* There is no available server. */
f9c044
+        tevent_req_error(req, ENOENT);
f9c044
+    }
f9c044
+
f9c044
+    /* Wait for another request to finish. */
f9c044
+}
f9c044
+
f9c044
+static errno_t ad_cldap_ping_parallel_recv(TALLOC_CTX *mem_ctx,
f9c044
+                                           struct tevent_req *req,
f9c044
+                                           const char **_site,
f9c044
+                                           const char **_forest)
f9c044
+{
f9c044
+    struct ad_cldap_ping_parallel_state *state = NULL;
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_parallel_state);
f9c044
+
f9c044
+    TEVENT_REQ_RETURN_ON_ERROR(req);
f9c044
+
f9c044
+    *_site = talloc_steal(mem_ctx, state->site);
f9c044
+    *_forest = talloc_steal(mem_ctx, state->forest);
f9c044
+
f9c044
+    return EOK;
f9c044
+}
f9c044
+
f9c044
+struct ad_cldap_ping_state {
f9c044
+    struct tevent_context *ev;
f9c044
+    struct sdap_options *opts;
f9c044
+    struct be_resolv_ctx *be_res;
f9c044
+    enum host_database *host_db;
f9c044
+    const char *ad_domain;
f9c044
+
f9c044
+    struct fo_server_info *dc_list;
f9c044
+    size_t dc_count;
f9c044
+    const char *site;
f9c044
+    const char *forest;
f9c044
+};
f9c044
+
f9c044
+static void ad_cldap_ping_discovery_done(struct tevent_req *subreq);
f9c044
+static void ad_cldap_ping_done(struct tevent_req *subreq);
f9c044
+
f9c044
+struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
+                                      struct tevent_context *ev,
f9c044
+                                      struct sdap_options *opts,
f9c044
+                                      struct be_resolv_ctx *be_res,
f9c044
+                                      enum host_database *host_db,
f9c044
+                                      const char *ad_domain,
f9c044
+                                      const char *discovery_domain,
f9c044
+                                      const char *current_site)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state;
f9c044
+    struct tevent_req *subreq;
f9c044
+    struct tevent_req *req;
f9c044
+    const char **domains;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_state);
f9c044
+    if (req == NULL) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
+        return NULL;
f9c044
+    }
f9c044
+
f9c044
+    state->ev = ev;
f9c044
+    state->opts = opts;
f9c044
+    state->be_res = be_res;
f9c044
+    state->host_db = host_db;
f9c044
+    state->ad_domain = ad_domain;
f9c044
+
f9c044
+    domains = talloc_zero_array(state, const char *, 3);
f9c044
+    if (domains == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    if (current_site == NULL) {
f9c044
+        domains[0] = discovery_domain;
f9c044
+        domains[1] = NULL;
f9c044
+    } else {
f9c044
+        domains[0] = ad_site_dns_discovery_domain(state, current_site,
f9c044
+                                                  discovery_domain);
f9c044
+        domains[1] = discovery_domain;
f9c044
+
f9c044
+        if (domains[0] == NULL) {
f9c044
+            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!");
f9c044
+            ret = ENOMEM;
f9c044
+            goto done;
f9c044
+        }
f9c044
+    }
f9c044
+
f9c044
+    /* Even though we use CLDAP (UDP) to perform the ping we need to discover
f9c044
+     * domain controllers in TCP namespace as they are not automatically
f9c044
+     * available under UDP. */
f9c044
+    subreq = fo_discover_srv_send(state, ev, be_res->resolv, "ldap",
f9c044
+                                  FO_PROTO_TCP, domains);
f9c044
+    if (subreq == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_discovery_done, req);
f9c044
+
f9c044
+    return req;
f9c044
+
f9c044
+done:
f9c044
+    tevent_req_error(req, ret);
f9c044
+    tevent_req_post(req, ev);
f9c044
+
f9c044
+    return req;
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_discovery_done(struct tevent_req *subreq)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    char *domain;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+
f9c044
+    ret = fo_discover_srv_recv(state, subreq, &domain, NULL, &state->dc_list,
f9c044
+                               &state->dc_count);
f9c044
+    talloc_zfree(subreq);
f9c044
+    if (ret != EOK) {
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    DEBUG(SSSDBG_TRACE_FUNC, "Found %zu domain controllers in domain %s\n",
f9c044
+          state->dc_count, domain);
f9c044
+
f9c044
+    subreq = ad_cldap_ping_parallel_send(state, state->ev, state->opts,
f9c044
+                                         state->be_res, state->host_db,
f9c044
+                                         state->dc_list, state->dc_count,
f9c044
+                                         state->ad_domain);
f9c044
+    if (subreq == NULL) {
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_done, req);
f9c044
+
f9c044
+done:
f9c044
+    if (ret != EOK) {
f9c044
+        tevent_req_error(req, ret);
f9c044
+        return;
f9c044
+    }
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_done(struct tevent_req *subreq)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+
f9c044
+    ret = ad_cldap_ping_parallel_recv(state, subreq, &state->site,
f9c044
+                                      &state->forest);
f9c044
+    talloc_zfree(subreq);
f9c044
+    if (ret != EOK) {
f9c044
+        DEBUG(SSSDBG_OP_FAILURE,
f9c044
+              "Unable to get site and forest information [%d]: %s\n",
f9c044
+              ret, sss_strerror(ret));
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
f9c044
+    DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest);
f9c044
+
f9c044
+done:
f9c044
+    if (ret != EOK) {
f9c044
+        tevent_req_error(req, ret);
f9c044
+        return;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_done(req);
f9c044
+}
f9c044
+
f9c044
+errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx,
f9c044
+                           struct tevent_req *req,
f9c044
+                           const char **_site,
f9c044
+                           const char **_forest)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state = NULL;
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+
f9c044
+    TEVENT_REQ_RETURN_ON_ERROR(req);
f9c044
+
f9c044
+    *_site = talloc_steal(mem_ctx, state->site);
f9c044
+    *_forest = talloc_steal(mem_ctx, state->forest);
f9c044
+
f9c044
+    return EOK;
f9c044
+}
f9c044
\ No newline at end of file
f9c044
diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
f9c044
index 55e8f63f7..d12f0971c 100644
f9c044
--- a/src/providers/ad/ad_srv.c
f9c044
+++ b/src/providers/ad/ad_srv.c
f9c044
@@ -116,378 +116,6 @@ static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx,
f9c044
     return EOK;
f9c044
 }
f9c044
 
f9c044
-struct ad_get_dc_servers_state {
f9c044
-    struct fo_server_info *servers;
f9c044
-    size_t num_servers;
f9c044
-};
f9c044
-
f9c044
-static void ad_get_dc_servers_done(struct tevent_req *subreq);
f9c044
-
f9c044
-static struct tevent_req *ad_get_dc_servers_send(TALLOC_CTX *mem_ctx,
f9c044
-                                                 struct tevent_context *ev,
f9c044
-                                                 struct resolv_ctx *resolv_ctx,
f9c044
-                                                 const char *discovery_domain,
f9c044
-                                                 const char *site)
f9c044
-{
f9c044
-    struct ad_get_dc_servers_state *state = NULL;
f9c044
-    struct tevent_req *req = NULL;
f9c044
-    struct tevent_req *subreq = NULL;
f9c044
-    const char **domains = NULL;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    req = tevent_req_create(mem_ctx, &state,
f9c044
-                            struct ad_get_dc_servers_state);
f9c044
-    if (req == NULL) {
f9c044
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
-        return NULL;
f9c044
-    }
f9c044
-
f9c044
-    domains = talloc_zero_array(state, const char *, 3);
f9c044
-    if (domains == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto immediately;
f9c044
-    }
f9c044
-
f9c044
-    if (site == NULL) {
f9c044
-        DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain "
f9c044
-              "%s\n", discovery_domain);
f9c044
-
f9c044
-        domains[0] = talloc_strdup(domains, discovery_domain);
f9c044
-        if (domains[0] == NULL) {
f9c044
-            ret = ENOMEM;
f9c044
-            goto immediately;
f9c044
-        }
f9c044
-    } else {
f9c044
-        DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain "
f9c044
-              "%s and site %s\n", discovery_domain, site);
f9c044
-
f9c044
-        domains[0] = ad_site_dns_discovery_domain(domains,
f9c044
-                                                  site, discovery_domain);
f9c044
-        if (domains[0] == NULL) {
f9c044
-            ret = ENOMEM;
f9c044
-            goto immediately;
f9c044
-        }
f9c044
-
f9c044
-        domains[1] = talloc_strdup(domains, discovery_domain);
f9c044
-        if (domains[1] == NULL) {
f9c044
-            ret = ENOMEM;
f9c044
-            goto immediately;
f9c044
-        }
f9c044
-    }
f9c044
-
f9c044
-    subreq = fo_discover_srv_send(state, ev, resolv_ctx,
f9c044
-                                  "ldap", FO_PROTO_TCP, domains);
f9c044
-    if (subreq == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto immediately;
f9c044
-    }
f9c044
-
f9c044
-    tevent_req_set_callback(subreq, ad_get_dc_servers_done, req);
f9c044
-
f9c044
-    return req;
f9c044
-
f9c044
-immediately:
f9c044
-    tevent_req_error(req, ret);
f9c044
-    tevent_req_post(req, ev);
f9c044
-
f9c044
-    return req;
f9c044
-}
f9c044
-
f9c044
-static void ad_get_dc_servers_done(struct tevent_req *subreq)
f9c044
-{
f9c044
-    struct ad_get_dc_servers_state *state = NULL;
f9c044
-    struct tevent_req *req = NULL;
f9c044
-    char *domain = NULL;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
-    state = tevent_req_data(req, struct ad_get_dc_servers_state);
f9c044
-
f9c044
-    ret = fo_discover_srv_recv(state, subreq, &domain, NULL,
f9c044
-                               &state->servers, &state->num_servers);
f9c044
-    talloc_zfree(subreq);
f9c044
-    if (ret != EOK) {
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "Found %zu domain controllers in domain %s\n",
f9c044
-                              state->num_servers, domain);
f9c044
-
f9c044
-done:
f9c044
-    if (ret != EOK) {
f9c044
-        tevent_req_error(req, ret);
f9c044
-        return;
f9c044
-    }
f9c044
-
f9c044
-    tevent_req_done(req);
f9c044
-}
f9c044
-
f9c044
-static int ad_get_dc_servers_recv(TALLOC_CTX *mem_ctx,
f9c044
-                                  struct tevent_req *req,
f9c044
-                                  struct fo_server_info **_dcs,
f9c044
-                                  size_t *_num_dcs)
f9c044
-{
f9c044
-    struct ad_get_dc_servers_state *state = NULL;
f9c044
-    state = tevent_req_data(req, struct ad_get_dc_servers_state);
f9c044
-
f9c044
-    TEVENT_REQ_RETURN_ON_ERROR(req);
f9c044
-
f9c044
-    *_dcs = talloc_steal(mem_ctx, state->servers);
f9c044
-    *_num_dcs = state->num_servers;
f9c044
-
f9c044
-    return EOK;
f9c044
-}
f9c044
-
f9c044
-struct ad_get_client_site_state {
f9c044
-    struct tevent_context *ev;
f9c044
-    struct be_resolv_ctx *be_res;
f9c044
-    enum host_database *host_db;
f9c044
-    struct sdap_options *opts;
f9c044
-    const char *ad_domain;
f9c044
-    bool ad_use_ldaps;
f9c044
-    struct fo_server_info *dcs;
f9c044
-    size_t num_dcs;
f9c044
-    size_t dc_index;
f9c044
-    struct fo_server_info dc;
f9c044
-
f9c044
-    struct sdap_handle *sh;
f9c044
-    char *site;
f9c044
-    char *forest;
f9c044
-};
f9c044
-
f9c044
-static errno_t ad_get_client_site_next_dc(struct tevent_req *req);
f9c044
-static void ad_get_client_site_connect_done(struct tevent_req *subreq);
f9c044
-static void ad_get_client_site_done(struct tevent_req *subreq);
f9c044
-
f9c044
-struct tevent_req *ad_get_client_site_send(TALLOC_CTX *mem_ctx,
f9c044
-                                           struct tevent_context *ev,
f9c044
-                                           struct be_resolv_ctx *be_res,
f9c044
-                                           enum host_database *host_db,
f9c044
-                                           struct sdap_options *opts,
f9c044
-                                           const char *ad_domain,
f9c044
-                                           bool ad_use_ldaps,
f9c044
-                                           struct fo_server_info *dcs,
f9c044
-                                           size_t num_dcs)
f9c044
-{
f9c044
-    struct ad_get_client_site_state *state = NULL;
f9c044
-    struct tevent_req *req = NULL;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    req = tevent_req_create(mem_ctx, &state,
f9c044
-                            struct ad_get_client_site_state);
f9c044
-    if (req == NULL) {
f9c044
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
-        return NULL;
f9c044
-    }
f9c044
-
f9c044
-    if (be_res == NULL || host_db == NULL || opts == NULL) {
f9c044
-        ret = EINVAL;
f9c044
-        goto immediately;
f9c044
-    }
f9c044
-
f9c044
-    state->ev = ev;
f9c044
-    state->be_res = be_res;
f9c044
-    state->host_db = host_db;
f9c044
-    state->opts = opts;
f9c044
-    state->ad_domain = ad_domain;
f9c044
-    state->ad_use_ldaps = ad_use_ldaps;
f9c044
-    state->dcs = dcs;
f9c044
-    state->num_dcs = num_dcs;
f9c044
-
f9c044
-    state->dc_index = 0;
f9c044
-    ret = ad_get_client_site_next_dc(req);
f9c044
-    if (ret == EOK) {
f9c044
-        ret = ENOENT;
f9c044
-        goto immediately;
f9c044
-    } else if (ret != EAGAIN) {
f9c044
-        goto immediately;
f9c044
-    }
f9c044
-
f9c044
-    return req;
f9c044
-
f9c044
-immediately:
f9c044
-    if (ret == EOK) {
f9c044
-        tevent_req_done(req);
f9c044
-    } else {
f9c044
-        tevent_req_error(req, ret);
f9c044
-    }
f9c044
-    tevent_req_post(req, ev);
f9c044
-
f9c044
-    return req;
f9c044
-}
f9c044
-
f9c044
-static errno_t ad_get_client_site_next_dc(struct tevent_req *req)
f9c044
-{
f9c044
-    struct ad_get_client_site_state *state = NULL;
f9c044
-    struct tevent_req *subreq = NULL;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    state = tevent_req_data(req, struct ad_get_client_site_state);
f9c044
-
f9c044
-    if (state->dc_index >= state->num_dcs) {
f9c044
-        ret = EOK;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    state->dc = state->dcs[state->dc_index];
f9c044
-
f9c044
-    subreq = sdap_connect_host_send(state, state->ev, state->opts,
f9c044
-                                    state->be_res->resolv,
f9c044
-                                    state->be_res->family_order,
f9c044
-                                    state->host_db,
f9c044
-                                    "cldap",
f9c044
-                                    state->dc.host,
f9c044
-                                    state->dc.port,
f9c044
-                                    false);
f9c044
-    if (subreq == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    tevent_req_set_callback(subreq, ad_get_client_site_connect_done, req);
f9c044
-
f9c044
-    state->dc_index++;
f9c044
-    ret = EAGAIN;
f9c044
-
f9c044
-done:
f9c044
-    return ret;
f9c044
-}
f9c044
-
f9c044
-static void ad_get_client_site_connect_done(struct tevent_req *subreq)
f9c044
-{
f9c044
-    struct ad_get_client_site_state *state = NULL;
f9c044
-    struct tevent_req *req = NULL;
f9c044
-    static const char *attrs[] = {AD_AT_NETLOGON, NULL};
f9c044
-    char *filter = NULL;
f9c044
-    char *ntver = NULL;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
-    state = tevent_req_data(req, struct ad_get_client_site_state);
f9c044
-
f9c044
-    ret = sdap_connect_host_recv(state, subreq, &state->sh);
f9c044
-    talloc_zfree(subreq);
f9c044
-    if (ret != EOK) {
f9c044
-        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to connect to domain controller "
f9c044
-              "[%s:%d]\n", state->dc.host, state->dc.port);
f9c044
-
f9c044
-        ret = ad_get_client_site_next_dc(req);
f9c044
-        if (ret == EOK) {
f9c044
-            ret = ENOENT;
f9c044
-        }
f9c044
-
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX |
f9c044
-                                       NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
f9c044
-    if (ntver == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
f9c044
-                             AD_AT_DNS_DOMAIN, state->ad_domain,
f9c044
-                             AD_AT_NT_VERSION, ntver);
f9c044
-    if (filter == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
f9c044
-                                   "", LDAP_SCOPE_BASE, filter,
f9c044
-                                   attrs, NULL, 0,
f9c044
-                                   dp_opt_get_int(state->opts->basic,
f9c044
-                                                  SDAP_SEARCH_TIMEOUT),
f9c044
-                                   false);
f9c044
-    if (subreq == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    tevent_req_set_callback(subreq, ad_get_client_site_done, req);
f9c044
-
f9c044
-    ret = EAGAIN;
f9c044
-
f9c044
-done:
f9c044
-    if (ret == EOK) {
f9c044
-        tevent_req_done(req);
f9c044
-    } else if (ret != EAGAIN) {
f9c044
-        tevent_req_error(req, ret);
f9c044
-    }
f9c044
-
f9c044
-    return;
f9c044
-}
f9c044
-
f9c044
-static void ad_get_client_site_done(struct tevent_req *subreq)
f9c044
-{
f9c044
-    struct ad_get_client_site_state *state = NULL;
f9c044
-    struct tevent_req *req = NULL;
f9c044
-    struct sysdb_attrs **reply = NULL;
f9c044
-    size_t reply_count;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
-    state = tevent_req_data(req, struct ad_get_client_site_state);
f9c044
-
f9c044
-    ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
f9c044
-    talloc_zfree(subreq);
f9c044
-
f9c044
-    /* we're done with this LDAP, close connection */
f9c044
-    talloc_zfree(state->sh);
f9c044
-    if (ret != EOK) {
f9c044
-        DEBUG(SSSDBG_OP_FAILURE, "Unable to get netlogon information\n");
f9c044
-
f9c044
-        ret = ad_get_client_site_next_dc(req);
f9c044
-        if (ret == EOK) {
f9c044
-            ret = ENOENT;
f9c044
-        }
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    if (reply_count == 0) {
f9c044
-        DEBUG(SSSDBG_OP_FAILURE, "No netlogon information retrieved\n");
f9c044
-        ret = ENOENT;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    ret = netlogon_get_domain_info(state, reply[0], true, NULL, &state->site,
f9c044
-                                   &state->forest);
f9c044
-    if (ret != EOK) {
f9c044
-        DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve site name [%d]: %s\n",
f9c044
-                                  ret, strerror(ret));
f9c044
-        ret = ENOENT;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest);
f9c044
-
f9c044
-done:
f9c044
-    if (ret != EOK) {
f9c044
-        tevent_req_error(req, ret);
f9c044
-        return;
f9c044
-    }
f9c044
-
f9c044
-    tevent_req_done(req);
f9c044
-}
f9c044
-
f9c044
-int ad_get_client_site_recv(TALLOC_CTX *mem_ctx,
f9c044
-                            struct tevent_req *req,
f9c044
-                            const char **_site,
f9c044
-                            const char **_forest)
f9c044
-{
f9c044
-    struct ad_get_client_site_state *state = NULL;
f9c044
-    state = tevent_req_data(req, struct ad_get_client_site_state);
f9c044
-
f9c044
-    TEVENT_REQ_RETURN_ON_ERROR(req);
f9c044
-
f9c044
-    *_site = talloc_steal(mem_ctx, state->site);
f9c044
-    *_forest = talloc_steal(mem_ctx, state->forest);
f9c044
-
f9c044
-    return EOK;
f9c044
-}
f9c044
-
f9c044
 struct ad_srv_plugin_ctx {
f9c044
     struct be_ctx *be_ctx;
f9c044
     struct be_resolv_ctx *be_res;
f9c044
@@ -610,8 +238,7 @@ struct ad_srv_plugin_state {
f9c044
     size_t num_backup_servers;
f9c044
 };
f9c044
 
f9c044
-static void ad_srv_plugin_dcs_done(struct tevent_req *subreq);
f9c044
-static void ad_srv_plugin_site_done(struct tevent_req *subreq);
f9c044
+static void ad_srv_plugin_ping_done(struct tevent_req *subreq);
f9c044
 static void ad_srv_plugin_servers_done(struct tevent_req *subreq);
f9c044
 
f9c044
 /* 1. Do a DNS lookup to find any DC in domain
f9c044
@@ -677,15 +304,16 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
f9c044
 
f9c044
     DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n");
f9c044
 
f9c044
-    subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv,
f9c044
-                                    state->discovery_domain,
f9c044
-                                    state->ctx->current_site);
f9c044
+    subreq = ad_cldap_ping_send(state, ev, ctx->opts, ctx->be_res,
f9c044
+                                ctx->host_dbs, ctx->ad_domain,
f9c044
+                                state->discovery_domain,
f9c044
+                                state->ctx->current_site);
f9c044
     if (subreq == NULL) {
f9c044
         ret = ENOMEM;
f9c044
         goto immediately;
f9c044
     }
f9c044
 
f9c044
-    tevent_req_set_callback(subreq, ad_srv_plugin_dcs_done, req);
f9c044
+    tevent_req_set_callback(subreq, ad_srv_plugin_ping_done, req);
f9c044
 
f9c044
     return req;
f9c044
 
f9c044
@@ -696,52 +324,7 @@ immediately:
f9c044
     return req;
f9c044
 }
f9c044
 
f9c044
-static void ad_srv_plugin_dcs_done(struct tevent_req *subreq)
f9c044
-{
f9c044
-    struct ad_srv_plugin_state *state = NULL;
f9c044
-    struct tevent_req *req = NULL;
f9c044
-    struct fo_server_info *dcs = NULL;
f9c044
-    size_t num_dcs = 0;
f9c044
-    errno_t ret;
f9c044
-
f9c044
-    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
-    state = tevent_req_data(req, struct ad_srv_plugin_state);
f9c044
-
f9c044
-    ret = ad_get_dc_servers_recv(state, subreq, &dcs, &num_dcs);
f9c044
-    talloc_zfree(subreq);
f9c044
-    if (ret != EOK) {
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "About to locate suitable site\n");
f9c044
-
f9c044
-    subreq = ad_get_client_site_send(state, state->ev,
f9c044
-                                     state->ctx->be_res,
f9c044
-                                     state->ctx->host_dbs,
f9c044
-                                     state->ctx->opts,
f9c044
-                                     state->discovery_domain,
f9c044
-                                     state->ctx->ad_use_ldaps,
f9c044
-                                     dcs, num_dcs);
f9c044
-    if (subreq == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    tevent_req_set_callback(subreq, ad_srv_plugin_site_done, req);
f9c044
-
f9c044
-    ret = EAGAIN;
f9c044
-
f9c044
-done:
f9c044
-    if (ret == EOK) {
f9c044
-        tevent_req_done(req);
f9c044
-    } else if (ret != EAGAIN) {
f9c044
-        tevent_req_error(req, ret);
f9c044
-    }
f9c044
-
f9c044
-    return;
f9c044
-}
f9c044
-
f9c044
-static void ad_srv_plugin_site_done(struct tevent_req *subreq)
f9c044
+static void ad_srv_plugin_ping_done(struct tevent_req *subreq)
f9c044
 {
f9c044
     struct ad_srv_plugin_state *state = NULL;
f9c044
     struct tevent_req *req = NULL;
f9c044
@@ -752,8 +335,9 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq)
f9c044
     req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
     state = tevent_req_data(req, struct ad_srv_plugin_state);
f9c044
 
f9c044
-    ret = ad_get_client_site_recv(state, subreq, &state->site, &state->forest);
f9c044
+    ret = ad_cldap_ping_recv(state, subreq, &state->site, &state->forest);
f9c044
     talloc_zfree(subreq);
f9c044
+
f9c044
     /* Ignore AD site found by dns discovery if specific site is set in
f9c044
      * configuration file. */
f9c044
     if (state->ctx->ad_site_override != NULL) {
f9c044
diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h
f9c044
index e553d594d..c03ac873f 100644
f9c044
--- a/src/providers/ad/ad_srv.h
f9c044
+++ b/src/providers/ad/ad_srv.h
f9c044
@@ -53,4 +53,18 @@ char *ad_site_dns_discovery_domain(TALLOC_CTX *mem_ctx,
f9c044
                                    const char *site,
f9c044
                                    const char *domain);
f9c044
 
f9c044
+struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
+                                      struct tevent_context *ev,
f9c044
+                                      struct sdap_options *opts,
f9c044
+                                      struct be_resolv_ctx *be_res,
f9c044
+                                      enum host_database *host_db,
f9c044
+                                      const char *ad_domain,
f9c044
+                                      const char *discovery_domain,
f9c044
+                                      const char *current_site);
f9c044
+
f9c044
+errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx,
f9c044
+                           struct tevent_req *req,
f9c044
+                           const char **_site,
f9c044
+                           const char **_forest);
f9c044
+
f9c044
 #endif /* __AD_SRV_H__ */
f9c044
-- 
f9c044
2.26.3
f9c044
f9c044
f9c044
From 27f394bb477aadb879c55df8e956fd37fa810109 Mon Sep 17 00:00:00 2001
f9c044
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
f9c044
Date: Tue, 25 Aug 2020 12:11:19 +0200
f9c044
Subject: [PATCH 4/7] ad: if all in-site dc are unreachable try off-site
f9c044
 controllers
f9c044
f9c044
Previous implementation would not fallback to the off-site domain
f9c044
controllers. This would cause problems if the site actually changed.
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
(cherry picked from commit fcfd834c9d80d7690f938582335d81231a5f6e60)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 src/providers/ad/ad_cldap_ping.c | 227 ++++++++++++++++++++++++-------
f9c044
 1 file changed, 181 insertions(+), 46 deletions(-)
f9c044
f9c044
diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c
f9c044
index 5fc1a4d20..7ecdcdbef 100644
f9c044
--- a/src/providers/ad/ad_cldap_ping.c
f9c044
+++ b/src/providers/ad/ad_cldap_ping.c
f9c044
@@ -415,7 +415,7 @@ static errno_t ad_cldap_ping_parallel_recv(TALLOC_CTX *mem_ctx,
f9c044
     return EOK;
f9c044
 }
f9c044
 
f9c044
-struct ad_cldap_ping_state {
f9c044
+struct ad_cldap_ping_domain_state {
f9c044
     struct tevent_context *ev;
f9c044
     struct sdap_options *opts;
f9c044
     struct be_resolv_ctx *be_res;
f9c044
@@ -428,25 +428,25 @@ struct ad_cldap_ping_state {
f9c044
     const char *forest;
f9c044
 };
f9c044
 
f9c044
-static void ad_cldap_ping_discovery_done(struct tevent_req *subreq);
f9c044
-static void ad_cldap_ping_done(struct tevent_req *subreq);
f9c044
+static void ad_cldap_ping_domain_discovery_done(struct tevent_req *subreq);
f9c044
+static void ad_cldap_ping_domain_done(struct tevent_req *subreq);
f9c044
 
f9c044
-struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
-                                      struct tevent_context *ev,
f9c044
-                                      struct sdap_options *opts,
f9c044
-                                      struct be_resolv_ctx *be_res,
f9c044
-                                      enum host_database *host_db,
f9c044
-                                      const char *ad_domain,
f9c044
-                                      const char *discovery_domain,
f9c044
-                                      const char *current_site)
f9c044
+static struct tevent_req *
f9c044
+ad_cldap_ping_domain_send(TALLOC_CTX *mem_ctx,
f9c044
+                          struct tevent_context *ev,
f9c044
+                          struct sdap_options *opts,
f9c044
+                          struct be_resolv_ctx *be_res,
f9c044
+                          enum host_database *host_db,
f9c044
+                          const char *ad_domain,
f9c044
+                          const char *discovery_domain)
f9c044
 {
f9c044
-    struct ad_cldap_ping_state *state;
f9c044
+    struct ad_cldap_ping_domain_state *state;
f9c044
     struct tevent_req *subreq;
f9c044
     struct tevent_req *req;
f9c044
     const char **domains;
f9c044
     errno_t ret;
f9c044
 
f9c044
-    req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_state);
f9c044
+    req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_domain_state);
f9c044
     if (req == NULL) {
f9c044
         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
         return NULL;
f9c044
@@ -458,25 +458,18 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
     state->host_db = host_db;
f9c044
     state->ad_domain = ad_domain;
f9c044
 
f9c044
-    domains = talloc_zero_array(state, const char *, 3);
f9c044
+    domains = talloc_zero_array(state, const char *, 2);
f9c044
     if (domains == NULL) {
f9c044
         ret = ENOMEM;
f9c044
         goto done;
f9c044
     }
f9c044
 
f9c044
-    if (current_site == NULL) {
f9c044
-        domains[0] = discovery_domain;
f9c044
-        domains[1] = NULL;
f9c044
-    } else {
f9c044
-        domains[0] = ad_site_dns_discovery_domain(state, current_site,
f9c044
-                                                  discovery_domain);
f9c044
-        domains[1] = discovery_domain;
f9c044
-
f9c044
-        if (domains[0] == NULL) {
f9c044
-            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!");
f9c044
-            ret = ENOMEM;
f9c044
-            goto done;
f9c044
-        }
f9c044
+    domains[0] = discovery_domain;
f9c044
+    domains[1] = NULL;
f9c044
+    if (domains[0] == NULL) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!");
f9c044
+        ret = ENOMEM;
f9c044
+        goto done;
f9c044
     }
f9c044
 
f9c044
     /* Even though we use CLDAP (UDP) to perform the ping we need to discover
f9c044
@@ -489,7 +482,7 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
         goto done;
f9c044
     }
f9c044
 
f9c044
-    tevent_req_set_callback(subreq, ad_cldap_ping_discovery_done, req);
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_domain_discovery_done, req);
f9c044
 
f9c044
     return req;
f9c044
 
f9c044
@@ -500,15 +493,15 @@ done:
f9c044
     return req;
f9c044
 }
f9c044
 
f9c044
-static void ad_cldap_ping_discovery_done(struct tevent_req *subreq)
f9c044
+static void ad_cldap_ping_domain_discovery_done(struct tevent_req *subreq)
f9c044
 {
f9c044
-    struct ad_cldap_ping_state *state;
f9c044
+    struct ad_cldap_ping_domain_state *state;
f9c044
     struct tevent_req *req;
f9c044
     char *domain;
f9c044
     errno_t ret;
f9c044
 
f9c044
     req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
-    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_domain_state);
f9c044
 
f9c044
     ret = fo_discover_srv_recv(state, subreq, &domain, NULL, &state->dc_list,
f9c044
                                &state->dc_count);
f9c044
@@ -529,7 +522,7 @@ static void ad_cldap_ping_discovery_done(struct tevent_req *subreq)
f9c044
         goto done;
f9c044
     }
f9c044
 
f9c044
-    tevent_req_set_callback(subreq, ad_cldap_ping_done, req);
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_domain_done, req);
f9c044
 
f9c044
 done:
f9c044
     if (ret != EOK) {
f9c044
@@ -538,41 +531,183 @@ done:
f9c044
     }
f9c044
 }
f9c044
 
f9c044
-static void ad_cldap_ping_done(struct tevent_req *subreq)
f9c044
+static void ad_cldap_ping_domain_done(struct tevent_req *subreq)
f9c044
 {
f9c044
-    struct ad_cldap_ping_state *state;
f9c044
+    struct ad_cldap_ping_domain_state *state;
f9c044
     struct tevent_req *req;
f9c044
     errno_t ret;
f9c044
 
f9c044
     req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
-    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_domain_state);
f9c044
 
f9c044
     ret = ad_cldap_ping_parallel_recv(state, subreq, &state->site,
f9c044
                                       &state->forest);
f9c044
     talloc_zfree(subreq);
f9c044
     if (ret != EOK) {
f9c044
-        DEBUG(SSSDBG_OP_FAILURE,
f9c044
-              "Unable to get site and forest information [%d]: %s\n",
f9c044
-              ret, sss_strerror(ret));
f9c044
+        tevent_req_error(req, ret);
f9c044
+        return;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_done(req);
f9c044
+}
f9c044
+
f9c044
+static errno_t ad_cldap_ping_domain_recv(TALLOC_CTX *mem_ctx,
f9c044
+                                         struct tevent_req *req,
f9c044
+                                         const char **_site,
f9c044
+                                         const char **_forest)
f9c044
+{
f9c044
+    struct ad_cldap_ping_domain_state *state = NULL;
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_domain_state);
f9c044
+
f9c044
+    TEVENT_REQ_RETURN_ON_ERROR(req);
f9c044
+
f9c044
+    *_site = talloc_steal(mem_ctx, state->site);
f9c044
+    *_forest = talloc_steal(mem_ctx, state->forest);
f9c044
+
f9c044
+    return EOK;
f9c044
+}
f9c044
+
f9c044
+struct ad_cldap_ping_state {
f9c044
+    struct tevent_context *ev;
f9c044
+    struct sdap_options *opts;
f9c044
+    struct be_resolv_ctx *be_res;
f9c044
+    enum host_database *host_db;
f9c044
+    const char *ad_domain;
f9c044
+    const char *discovery_domain;
f9c044
+    bool all_tried;
f9c044
+
f9c044
+    const char *site;
f9c044
+    const char *forest;
f9c044
+};
f9c044
+
f9c044
+static errno_t ad_cldap_ping_step(struct tevent_req *req,
f9c044
+                                  const char *domain);
f9c044
+static void ad_cldap_ping_done(struct tevent_req *subreq);
f9c044
+
f9c044
+struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
+                                      struct tevent_context *ev,
f9c044
+                                      struct sdap_options *opts,
f9c044
+                                      struct be_resolv_ctx *be_res,
f9c044
+                                      enum host_database *host_db,
f9c044
+                                      const char *ad_domain,
f9c044
+                                      const char *discovery_domain,
f9c044
+                                      const char *current_site)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    const char *domain;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_create(mem_ctx, &state, struct ad_cldap_ping_state);
f9c044
+    if (req == NULL) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f9c044
+        return NULL;
f9c044
+    }
f9c044
+
f9c044
+    state->ev = ev;
f9c044
+    state->opts = opts;
f9c044
+    state->be_res = be_res;
f9c044
+    state->host_db = host_db;
f9c044
+    state->ad_domain = ad_domain;
f9c044
+    state->discovery_domain = discovery_domain;
f9c044
+
f9c044
+    /* If possible, lookup the information in the current site first. */
f9c044
+    if (current_site != NULL) {
f9c044
+        state->all_tried = false;
f9c044
+        domain = ad_site_dns_discovery_domain(state, current_site,
f9c044
+                                              discovery_domain);
f9c044
+        if (domain == NULL) {
f9c044
+            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!");
f9c044
+            ret = ENOMEM;
f9c044
+            goto done;
f9c044
+        }
f9c044
+    } else {
f9c044
+        state->all_tried = true;
f9c044
+        domain = discovery_domain;
f9c044
+    }
f9c044
+
f9c044
+    ret = ad_cldap_ping_step(req, domain);
f9c044
+    if (ret != EOK) {
f9c044
         goto done;
f9c044
     }
f9c044
 
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest);
f9c044
+    return req;
f9c044
 
f9c044
 done:
f9c044
-    if (ret != EOK) {
f9c044
-        tevent_req_error(req, ret);
f9c044
+    tevent_req_error(req, ret);
f9c044
+    tevent_req_post(req, ev);
f9c044
+
f9c044
+    return req;
f9c044
+}
f9c044
+
f9c044
+static errno_t ad_cldap_ping_step(struct tevent_req *req,
f9c044
+                                  const char *domain)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state;
f9c044
+    struct tevent_req *subreq;
f9c044
+    struct timeval tv;
f9c044
+    int timeout;
f9c044
+
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+
f9c044
+    subreq = ad_cldap_ping_domain_send(state, state->ev, state->opts,
f9c044
+                                       state->be_res, state->host_db,
f9c044
+                                       state->ad_domain, domain);
f9c044
+    if (subreq == NULL) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!");
f9c044
+        return ENOMEM;
f9c044
+    }
f9c044
+
f9c044
+    tevent_req_set_callback(subreq, ad_cldap_ping_done, req);
f9c044
+
f9c044
+    timeout = dp_opt_get_int(state->be_res->opts,
f9c044
+                             DP_RES_OPT_RESOLVER_OP_TIMEOUT);
f9c044
+    if (timeout > 0) {
f9c044
+        tv = tevent_timeval_current_ofs(timeout, 0);
f9c044
+        tevent_req_set_endtime(subreq, state->ev, tv);
f9c044
+    }
f9c044
+
f9c044
+    return EOK;
f9c044
+}
f9c044
+
f9c044
+static void ad_cldap_ping_done(struct tevent_req *subreq)
f9c044
+{
f9c044
+    struct ad_cldap_ping_state *state;
f9c044
+    struct tevent_req *req;
f9c044
+    errno_t ret;
f9c044
+
f9c044
+    req = tevent_req_callback_data(subreq, struct tevent_req);
f9c044
+    state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
+
f9c044
+    ret = ad_cldap_ping_domain_recv(state, subreq, &state->site,
f9c044
+                                    &state->forest);
f9c044
+    talloc_zfree(subreq);
f9c044
+    if (ret == EOK) {
f9c044
+        DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
f9c044
+        DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest);
f9c044
+        tevent_req_done(req);
f9c044
         return;
f9c044
     }
f9c044
 
f9c044
-    tevent_req_done(req);
f9c044
+    if (!state->all_tried) {
f9c044
+        state->all_tried = true;
f9c044
+        ret = ad_cldap_ping_step(req, state->discovery_domain);
f9c044
+        if (ret == EOK) {
f9c044
+            return;
f9c044
+        }
f9c044
+    }
f9c044
+
f9c044
+    DEBUG(SSSDBG_OP_FAILURE,
f9c044
+          "Unable to get site and forest information [%d]: %s\n",
f9c044
+          ret, sss_strerror(ret));
f9c044
+
f9c044
+    tevent_req_error(req, ret);
f9c044
 }
f9c044
 
f9c044
 errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx,
f9c044
-                           struct tevent_req *req,
f9c044
-                           const char **_site,
f9c044
-                           const char **_forest)
f9c044
+                                  struct tevent_req *req,
f9c044
+                                  const char **_site,
f9c044
+                                  const char **_forest)
f9c044
 {
f9c044
     struct ad_cldap_ping_state *state = NULL;
f9c044
     state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
-- 
f9c044
2.26.3
f9c044
f9c044
f9c044
From 8249161d967a37847f42b62e0e6a384d063884af Mon Sep 17 00:00:00 2001
f9c044
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
f9c044
Date: Tue, 25 Aug 2020 13:43:32 +0200
f9c044
Subject: [PATCH 5/7] ad: renew site information only when SSSD was previously
f9c044
 offline
f9c044
f9c044
Site and forest information is stable not dynamic. To avoid spamming
f9c044
network with cldap pings all the time we will renew netlogon information
f9c044
only when SSSD starts and when we are recovering from an offline state
f9c044
to detect possible change (e.g. user moves to another location with laptop).
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
(cherry picked from commit 9fdf5cfacd1a425691d44db53897096887bb3e6f)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 src/providers/ad/ad_cldap_ping.c | 45 ++++++++++++++++----------
f9c044
 src/providers/ad/ad_srv.c        | 54 +++++++++++++++++++++-----------
f9c044
 src/providers/ad/ad_srv.h        | 22 ++++++++-----
f9c044
 3 files changed, 80 insertions(+), 41 deletions(-)
f9c044
f9c044
diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c
f9c044
index 7ecdcdbef..dc25f6670 100644
f9c044
--- a/src/providers/ad/ad_cldap_ping.c
f9c044
+++ b/src/providers/ad/ad_cldap_ping.c
f9c044
@@ -586,12 +586,8 @@ static void ad_cldap_ping_done(struct tevent_req *subreq);
f9c044
 
f9c044
 struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
                                       struct tevent_context *ev,
f9c044
-                                      struct sdap_options *opts,
f9c044
-                                      struct be_resolv_ctx *be_res,
f9c044
-                                      enum host_database *host_db,
f9c044
-                                      const char *ad_domain,
f9c044
-                                      const char *discovery_domain,
f9c044
-                                      const char *current_site)
f9c044
+                                      struct ad_srv_plugin_ctx *srv_ctx,
f9c044
+                                      const char *discovery_domain)
f9c044
 {
f9c044
     struct ad_cldap_ping_state *state;
f9c044
     struct tevent_req *req;
f9c044
@@ -604,17 +600,30 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
         return NULL;
f9c044
     }
f9c044
 
f9c044
+    if (!srv_ctx->renew_site) {
f9c044
+        state->site = srv_ctx->current_site;
f9c044
+        state->forest = srv_ctx->current_forest;
f9c044
+        DEBUG(SSSDBG_TRACE_FUNC,
f9c044
+              "CLDAP ping is not necessary, using site '%s' and forest '%s'\n",
f9c044
+              state->site != NULL ? state->site : "unknown",
f9c044
+              state->forest != NULL ? state->forest : "unknown");
f9c044
+        ret = EOK;
f9c044
+        goto done;
f9c044
+    }
f9c044
+
f9c044
+    DEBUG(SSSDBG_TRACE_FUNC, "Sending CLDAP ping\n");
f9c044
+
f9c044
     state->ev = ev;
f9c044
-    state->opts = opts;
f9c044
-    state->be_res = be_res;
f9c044
-    state->host_db = host_db;
f9c044
-    state->ad_domain = ad_domain;
f9c044
+    state->opts = srv_ctx->opts;
f9c044
+    state->be_res = srv_ctx->be_res;
f9c044
+    state->host_db = srv_ctx->host_dbs;
f9c044
+    state->ad_domain = srv_ctx->ad_domain;
f9c044
     state->discovery_domain = discovery_domain;
f9c044
 
f9c044
     /* If possible, lookup the information in the current site first. */
f9c044
-    if (current_site != NULL) {
f9c044
+    if (srv_ctx->current_site != NULL) {
f9c044
         state->all_tried = false;
f9c044
-        domain = ad_site_dns_discovery_domain(state, current_site,
f9c044
+        domain = ad_site_dns_discovery_domain(state, srv_ctx->current_site,
f9c044
                                               discovery_domain);
f9c044
         if (domain == NULL) {
f9c044
             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!");
f9c044
@@ -634,7 +643,11 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
     return req;
f9c044
 
f9c044
 done:
f9c044
-    tevent_req_error(req, ret);
f9c044
+    if (ret != EOK) {
f9c044
+        tevent_req_error(req, ret);
f9c044
+    } else {
f9c044
+        tevent_req_done(req);
f9c044
+    }
f9c044
     tevent_req_post(req, ev);
f9c044
 
f9c044
     return req;
f9c044
@@ -705,9 +718,9 @@ static void ad_cldap_ping_done(struct tevent_req *subreq)
f9c044
 }
f9c044
 
f9c044
 errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx,
f9c044
-                                  struct tevent_req *req,
f9c044
-                                  const char **_site,
f9c044
-                                  const char **_forest)
f9c044
+                           struct tevent_req *req,
f9c044
+                           const char **_site,
f9c044
+                           const char **_forest)
f9c044
 {
f9c044
     struct ad_cldap_ping_state *state = NULL;
f9c044
     state = tevent_req_data(req, struct ad_cldap_ping_state);
f9c044
diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
f9c044
index d12f0971c..e58c19aac 100644
f9c044
--- a/src/providers/ad/ad_srv.c
f9c044
+++ b/src/providers/ad/ad_srv.c
f9c044
@@ -116,16 +116,13 @@ static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx,
f9c044
     return EOK;
f9c044
 }
f9c044
 
f9c044
-struct ad_srv_plugin_ctx {
f9c044
-    struct be_ctx *be_ctx;
f9c044
-    struct be_resolv_ctx *be_res;
f9c044
-    enum host_database *host_dbs;
f9c044
-    struct sdap_options *opts;
f9c044
-    const char *hostname;
f9c044
-    const char *ad_domain;
f9c044
-    const char *ad_site_override;
f9c044
-    const char *current_site;
f9c044
-};
f9c044
+static void ad_srv_mark_renew_site(void *pvt)
f9c044
+{
f9c044
+    struct ad_srv_plugin_ctx *ctx;
f9c044
+
f9c044
+    ctx = talloc_get_type(pvt, struct ad_srv_plugin_ctx);
f9c044
+    ctx->renew_site = true;
f9c044
+}
f9c044
 
f9c044
 struct ad_srv_plugin_ctx *
f9c044
 ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
@@ -149,6 +146,7 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
     ctx->be_res = be_res;
f9c044
     ctx->host_dbs = host_dbs;
f9c044
     ctx->opts = opts;
f9c044
+    ctx->renew_site = true;
f9c044
 
f9c044
     ctx->hostname = talloc_strdup(ctx, hostname);
f9c044
     if (ctx->hostname == NULL) {
f9c044
@@ -181,6 +179,12 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
         }
f9c044
     }
f9c044
 
f9c044
+    ret = be_add_offline_cb(ctx, be_ctx, ad_srv_mark_renew_site, ctx, NULL);
f9c044
+    if (ret != EOK) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "be_add_offline_cb failed.\n");
f9c044
+        goto fail;
f9c044
+    }
f9c044
+
f9c044
     return ctx;
f9c044
 
f9c044
 fail:
f9c044
@@ -190,11 +194,26 @@ fail:
f9c044
 
f9c044
 static errno_t
f9c044
 ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx,
f9c044
-                              const char *new_site)
f9c044
+                              const char *new_site,
f9c044
+                              const char *new_forest)
f9c044
 {
f9c044
     const char *site;
f9c044
+    const char *forest;
f9c044
     errno_t ret;
f9c044
 
f9c044
+    /* Switch forest. */
f9c044
+    if (new_forest != NULL
f9c044
+        && (ctx->current_forest == NULL
f9c044
+            || strcmp(ctx->current_forest, new_forest) != 0)) {
f9c044
+        forest = talloc_strdup(ctx, new_forest);
f9c044
+        if (forest == NULL) {
f9c044
+            return ENOMEM;
f9c044
+        }
f9c044
+
f9c044
+        talloc_zfree(ctx->current_forest);
f9c044
+        ctx->current_forest = forest;
f9c044
+    }
f9c044
+
f9c044
     if (new_site == NULL) {
f9c044
         return EOK;
f9c044
     }
f9c044
@@ -302,12 +321,7 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
f9c044
         goto immediately;
f9c044
     }
f9c044
 
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n");
f9c044
-
f9c044
-    subreq = ad_cldap_ping_send(state, ev, ctx->opts, ctx->be_res,
f9c044
-                                ctx->host_dbs, ctx->ad_domain,
f9c044
-                                state->discovery_domain,
f9c044
-                                state->ctx->current_site);
f9c044
+    subreq = ad_cldap_ping_send(state, ev, state->ctx, state->discovery_domain);
f9c044
     if (subreq == NULL) {
f9c044
         ret = ENOMEM;
f9c044
         goto immediately;
f9c044
@@ -363,13 +377,17 @@ static void ad_srv_plugin_ping_done(struct tevent_req *subreq)
f9c044
         /* Remember current site so it can be used during next lookup so
f9c044
          * we can contact directory controllers within a known reachable
f9c044
          * site first. */
f9c044
-        ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site);
f9c044
+        ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site,
f9c044
+                                            state->forest);
f9c044
         if (ret != EOK) {
f9c044
             DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set site [%d]: %s\n",
f9c044
                   ret, sss_strerror(ret));
f9c044
             goto done;
f9c044
         }
f9c044
 
f9c044
+        /* Do not renew the site again unless we go offline. */
f9c044
+        state->ctx->renew_site = false;
f9c044
+
f9c044
         if (strcmp(state->service, "gc") == 0) {
f9c044
             if (state->forest != NULL) {
f9c044
                 if (state->site != NULL) {
f9c044
diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h
f9c044
index c03ac873f..3c6a779ea 100644
f9c044
--- a/src/providers/ad/ad_srv.h
f9c044
+++ b/src/providers/ad/ad_srv.h
f9c044
@@ -21,7 +21,19 @@
f9c044
 #ifndef __AD_SRV_H__
f9c044
 #define __AD_SRV_H__
f9c044
 
f9c044
-struct ad_srv_plugin_ctx;
f9c044
+struct ad_srv_plugin_ctx {
f9c044
+    struct be_ctx *be_ctx;
f9c044
+    struct be_resolv_ctx *be_res;
f9c044
+    enum host_database *host_dbs;
f9c044
+    struct sdap_options *opts;
f9c044
+    const char *hostname;
f9c044
+    const char *ad_domain;
f9c044
+    const char *ad_site_override;
f9c044
+    const char *current_site;
f9c044
+    const char *current_forest;
f9c044
+
f9c044
+    bool renew_site;
f9c044
+};
f9c044
 
f9c044
 struct ad_srv_plugin_ctx *
f9c044
 ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
f9c044
@@ -55,12 +67,8 @@ char *ad_site_dns_discovery_domain(TALLOC_CTX *mem_ctx,
f9c044
 
f9c044
 struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
                                       struct tevent_context *ev,
f9c044
-                                      struct sdap_options *opts,
f9c044
-                                      struct be_resolv_ctx *be_res,
f9c044
-                                      enum host_database *host_db,
f9c044
-                                      const char *ad_domain,
f9c044
-                                      const char *discovery_domain,
f9c044
-                                      const char *current_site);
f9c044
+                                      struct ad_srv_plugin_ctx *srv_ctx,
f9c044
+                                      const char *discovery_domain);
f9c044
 
f9c044
 errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx,
f9c044
                            struct tevent_req *req,
f9c044
-- 
f9c044
2.26.3
f9c044
f9c044
f9c044
From 08fde220baab823f53fd359746c7e75eaeb0580f Mon Sep 17 00:00:00 2001
f9c044
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
f9c044
Date: Wed, 30 Sep 2020 13:45:43 +0200
f9c044
Subject: [PATCH 6/7] tevent: correctly handle req timeout error
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
(cherry picked from commit f0d650799d4390f90890d17c56a4e395e931d8cb)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 src/util/util.h | 14 +++++++++-----
f9c044
 1 file changed, 9 insertions(+), 5 deletions(-)
f9c044
f9c044
diff --git a/src/util/util.h b/src/util/util.h
f9c044
index 94c2e6e3b..2cc7f98a3 100644
f9c044
--- a/src/util/util.h
f9c044
+++ b/src/util/util.h
f9c044
@@ -139,13 +139,17 @@ extern int dbus_activated;
f9c044
     \
f9c044
     if (tevent_req_is_error(req, &TRROEstate, &TRROEuint64)) { \
f9c044
         TRROEerr = (errno_t)TRROEuint64; \
f9c044
-        if (TRROEstate == TEVENT_REQ_USER_ERROR) { \
f9c044
-            if (TRROEerr == 0) { \
f9c044
+        switch (TRROEstate) { \
f9c044
+            case TEVENT_REQ_USER_ERROR:  \
f9c044
+                if (TRROEerr == 0) { \
f9c044
+                    return ERR_INTERNAL; \
f9c044
+                } \
f9c044
+                return TRROEerr; \
f9c044
+            case TEVENT_REQ_TIMED_OUT: \
f9c044
+                return ETIMEDOUT; \
f9c044
+            default: \
f9c044
                 return ERR_INTERNAL; \
f9c044
-            } \
f9c044
-            return TRROEerr; \
f9c044
         } \
f9c044
-        return ERR_INTERNAL; \
f9c044
     } \
f9c044
 } while (0)
f9c044
 
f9c044
-- 
f9c044
2.26.3
f9c044
f9c044
f9c044
From a431a977852dde6af194f9306291d7fcc2624cb6 Mon Sep 17 00:00:00 2001
f9c044
From: Sumit Bose <sbose@redhat.com>
f9c044
Date: Mon, 5 Oct 2020 10:58:49 +0200
f9c044
Subject: [PATCH 7/7] ad: fix handling of current site and forest in cldap ping
f9c044
MIME-Version: 1.0
f9c044
Content-Type: text/plain; charset=UTF-8
f9c044
Content-Transfer-Encoding: 8bit
f9c044
f9c044
The current site and forest are stored in a long living context and we
f9c044
have to make sure that they are not moved to a different talloc parent
f9c044
with a shorter lifetime. To achieve this the values are copied at the
f9c044
start of a new cldap ping although it is expected that the values won't
f9c044
change.
f9c044
f9c044
Resolves: https://github.com/SSSD/sssd/issues/3743
f9c044
f9c044
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
f9c044
(cherry picked from commit 37ba37a425453d8222584176ae5975a795422091)
f9c044
f9c044
Reviewed-by: Sumit Bose <sbose@redhat.com>
f9c044
---
f9c044
 src/providers/ad/ad_cldap_ping.c | 14 +++++++++++---
f9c044
 1 file changed, 11 insertions(+), 3 deletions(-)
f9c044
f9c044
diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c
f9c044
index dc25f6670..ab234f4d7 100644
f9c044
--- a/src/providers/ad/ad_cldap_ping.c
f9c044
+++ b/src/providers/ad/ad_cldap_ping.c
f9c044
@@ -601,8 +601,16 @@ struct tevent_req *ad_cldap_ping_send(TALLOC_CTX *mem_ctx,
f9c044
     }
f9c044
 
f9c044
     if (!srv_ctx->renew_site) {
f9c044
-        state->site = srv_ctx->current_site;
f9c044
-        state->forest = srv_ctx->current_forest;
f9c044
+        state->site = talloc_strdup(state, srv_ctx->current_site);
f9c044
+        state->forest = talloc_strdup(state, srv_ctx->current_forest);
f9c044
+        if ((srv_ctx->current_site != NULL && state->site == NULL)
f9c044
+                || (srv_ctx->current_forest != NULL && state->forest == NULL)) {
f9c044
+            DEBUG(SSSDBG_OP_FAILURE,
f9c044
+                  "Failed to copy current site or forest name.\n");
f9c044
+            ret = ENOMEM;
f9c044
+            goto done;
f9c044
+        }
f9c044
+
f9c044
         DEBUG(SSSDBG_TRACE_FUNC,
f9c044
               "CLDAP ping is not necessary, using site '%s' and forest '%s'\n",
f9c044
               state->site != NULL ? state->site : "unknown",
f9c044
@@ -731,4 +739,4 @@ errno_t ad_cldap_ping_recv(TALLOC_CTX *mem_ctx,
f9c044
     *_forest = talloc_steal(mem_ctx, state->forest);
f9c044
 
f9c044
     return EOK;
f9c044
-}
f9c044
\ No newline at end of file
f9c044
+}
f9c044
-- 
f9c044
2.26.3
f9c044