Blame SOURCES/0066-AD-read-trusted-domains-from-local-domain-as-well.patch

44f86b
From 2519d5ea3757862bebc17d73d74c7e5c57bdc815 Mon Sep 17 00:00:00 2001
44f86b
From: Sumit Bose <sbose@redhat.com>
44f86b
Date: Tue, 16 Feb 2021 14:30:55 +0100
44f86b
Subject: [PATCH 66/66] AD: read trusted domains from local domain as well
44f86b
MIME-Version: 1.0
44f86b
Content-Type: text/plain; charset=UTF-8
44f86b
Content-Transfer-Encoding: 8bit
44f86b
44f86b
Currently SSSD only uses information stored in a domain controller of
44f86b
the forest root domain to get the names of other trusted domains in the
44f86b
forest. Depending on how the forest was created the forest root might
44f86b
not have LDAP objects for all domains in the forest. It looks like a
44f86b
typical case are child domains of other domains in the forest.
44f86b
44f86b
As a start SSSD can now include trusted domains stored in the LDAP tree
44f86b
of a local domain controller as well. In a long run it would make sense
44f86b
to allow SSSD to explicitly search for domain by looking up DNS entries
44f86b
and checking a potential domain controller with a CLDAP ping.
44f86b
44f86b
Resolves: https://github.com/SSSD/sssd/issues/5528
44f86b
44f86b
:feature: Besides trusted domains known by the forest root, trusted
44f86b
          domains known by the local domain are used as well.
44f86b
44f86b
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
44f86b
(cherry picked from commit 95adf488f94f5968f6cfba9e3bef74c07c02ccff)
44f86b
44f86b
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
44f86b
---
44f86b
 src/providers/ad/ad_subdomains.c | 105 +++++++++++++++++++++++++------
44f86b
 1 file changed, 86 insertions(+), 19 deletions(-)
44f86b
44f86b
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
44f86b
index ba4efe975..16aecbc64 100644
44f86b
--- a/src/providers/ad/ad_subdomains.c
44f86b
+++ b/src/providers/ad/ad_subdomains.c
44f86b
@@ -45,6 +45,7 @@
44f86b
 #define AD_AT_TRUST_TYPE    "trustType"
44f86b
 #define AD_AT_TRUST_PARTNER "trustPartner"
44f86b
 #define AD_AT_TRUST_ATTRS   "trustAttributes"
44f86b
+#define AD_AT_DOMAIN_NAME   "cn"
44f86b
 
44f86b
 /* trustType=2 denotes uplevel (NT5 and later) trusted domains. See
44f86b
  * http://msdn.microsoft.com/en-us/library/windows/desktop/ms680342%28v=vs.85%29.aspx
44f86b
@@ -56,7 +57,6 @@
44f86b
  */
44f86b
 #define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))"
44f86b
 #define SLAVE_DOMAIN_FILTER      "(&"SLAVE_DOMAIN_FILTER_BASE")"
44f86b
-#define FOREST_ROOT_FILTER_FMT   "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))"
44f86b
 
44f86b
 /* Attributes of schema objects. See e.g.
44f86b
  * https://docs.microsoft.com/en-us/windows/desktop/AD/characteristics-of-attributes
44f86b
@@ -646,6 +646,10 @@ done:
44f86b
     return ret;
44f86b
 }
44f86b
 
44f86b
+/* How many times we keep a domain not found during searches before it will be
44f86b
+ * removed. */
44f86b
+#define MAX_NOT_FOUND 6
44f86b
+
44f86b
 static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
44f86b
                                      struct sdap_idmap_ctx *idmap_ctx,
44f86b
                                      struct sdap_options *opts,
44f86b
@@ -706,6 +710,25 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
44f86b
         }
44f86b
 
44f86b
         if (c >= num_subdomains) {
44f86b
+            DEBUG(SSSDBG_CONF_SETTINGS, "Domain [%s] not in current list.\n",
44f86b
+                                        dom->name);
44f86b
+            /* Since the forest root might not have trustedDomain objects for
44f86b
+             * each domain in the forest, especially e.g. for child-domains of
44f86b
+             * child-domains, we cannot reliable say if a domain is still
44f86b
+             * present or not.
44f86b
+             * Maybe it would work to check the crossRef objects in
44f86b
+             * CN=Partitions,CN=Configuration as well to understand if a
44f86b
+             * domain is still known in the forest or not.
44f86b
+             * For the time being we use a counter, if a domain was not found
44f86b
+             * after multiple attempts it will be deleted. */
44f86b
+
44f86b
+            if (dom->not_found_counter++ < MAX_NOT_FOUND) {
44f86b
+                DEBUG(SSSDBG_TRACE_ALL,
44f86b
+                      "Domain [%s] was not found [%zu] times.\n", dom->name,
44f86b
+                      dom->not_found_counter);
44f86b
+                continue;
44f86b
+            }
44f86b
+
44f86b
             /* ok this subdomain does not exist anymore, let's clean up */
44f86b
             sss_domain_set_state(dom, DOM_DISABLED);
44f86b
 
44f86b
@@ -743,6 +766,7 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
44f86b
             /* terminate all requests for this subdomain so we can free it */
44f86b
             dp_terminate_domain_requests(be_ctx->provider, dom->name);
44f86b
             talloc_zfree(sdom);
44f86b
+
44f86b
         } else {
44f86b
             /* ok let's try to update it */
44f86b
             ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
44f86b
@@ -750,6 +774,7 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
44f86b
                 goto done;
44f86b
             }
44f86b
 
44f86b
+            dom->not_found_counter = 0;
44f86b
             ret = ad_subdom_store(be_ctx->cdb, idmap_ctx, domain,
44f86b
                                   subdomains[c], enumerate);
44f86b
             if (ret) {
44f86b
@@ -1310,10 +1335,9 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
44f86b
     struct tevent_req *req;
44f86b
     struct sdap_options *opts;
44f86b
     errno_t ret;
44f86b
-    const char *filter;
44f86b
     const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
44f86b
                             AD_AT_SID, AD_AT_TRUST_TYPE,
44f86b
-                            AD_AT_TRUST_ATTRS, NULL };
44f86b
+                            AD_AT_TRUST_ATTRS, AD_AT_DOMAIN_NAME, NULL };
44f86b
 
44f86b
     req = tevent_req_create(mem_ctx, &state, struct ad_get_root_domain_state);
44f86b
     if (req == NULL) {
44f86b
@@ -1338,15 +1362,10 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
44f86b
     state->domain = domain;
44f86b
     state->forest = forest;
44f86b
 
44f86b
-    filter = talloc_asprintf(state, FOREST_ROOT_FILTER_FMT, forest);
44f86b
-    if (filter == NULL) {
44f86b
-        ret = ENOMEM;
44f86b
-        goto immediately;
44f86b
-    }
44f86b
-
44f86b
     subreq = sdap_search_bases_return_first_send(state, ev, opts, sh,
44f86b
                                                  opts->sdom->search_bases,
44f86b
-                                                 NULL, false, 0, filter, attrs,
44f86b
+                                                 NULL, false, 0,
44f86b
+                                                 SLAVE_DOMAIN_FILTER, attrs,
44f86b
                                                  NULL);
44f86b
     if (subreq == NULL) {
44f86b
         ret = ENOMEM;
44f86b
@@ -1368,11 +1387,33 @@ immediately:
44f86b
     return req;
44f86b
 }
44f86b
 
44f86b
+static struct sysdb_attrs *find_domain(size_t count, struct sysdb_attrs **reply,
44f86b
+                                       const char *dom_name)
44f86b
+{
44f86b
+    size_t c;
44f86b
+    const char *name;
44f86b
+    int ret;
44f86b
+
44f86b
+    for (c = 0; c < count; c++) {
44f86b
+        ret = sysdb_attrs_get_string(reply[c], AD_AT_DOMAIN_NAME, &name);
44f86b
+        if (ret != EOK) {
44f86b
+            DEBUG(SSSDBG_OP_FAILURE, "Failed to find domain name, skipping");
44f86b
+            continue;
44f86b
+        }
44f86b
+        if (strcasecmp(name, dom_name) == 0) {
44f86b
+            return reply[c];
44f86b
+        }
44f86b
+    }
44f86b
+
44f86b
+    return NULL;
44f86b
+}
44f86b
+
44f86b
 static void ad_get_root_domain_done(struct tevent_req *subreq)
44f86b
 {
44f86b
     struct tevent_req *req;
44f86b
     struct ad_get_root_domain_state *state;
44f86b
     errno_t ret;
44f86b
+    bool has_changes = false;
44f86b
 
44f86b
     req = tevent_req_callback_data(subreq, struct tevent_req);
44f86b
     state = tevent_req_data(req, struct ad_get_root_domain_state);
44f86b
@@ -1387,7 +1428,37 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
44f86b
         goto done;
44f86b
     }
44f86b
 
44f86b
-    if (state->reply_count == 0) {
44f86b
+    find_domain(state->reply_count, state->reply, state->forest);
44f86b
+
44f86b
+    if (state->reply_count == 0
44f86b
+            || find_domain(state->reply_count, state->reply,
44f86b
+                           state->forest) == NULL) {
44f86b
+
44f86b
+        if (state->reply_count > 0) {
44f86b
+            /* refresh the other domains we have found before checking forest
44f86b
+             * root */
44f86b
+            ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx,
44f86b
+                                        state->opts,
44f86b
+                                        state->reply, state->reply_count, false,
44f86b
+                                        &state->sd_ctx->last_refreshed,
44f86b
+                                        &has_changes);
44f86b
+            if (ret != EOK) {
44f86b
+                DEBUG(SSSDBG_OP_FAILURE,
44f86b
+                      "ad_subdomains_refresh failed [%d]: %s\n",
44f86b
+                      ret, sss_strerror(ret));
44f86b
+                goto done;
44f86b
+            }
44f86b
+
44f86b
+            if (has_changes) {
44f86b
+                ret = ad_subdom_reinit(state->sd_ctx);
44f86b
+                if (ret != EOK) {
44f86b
+                    DEBUG(SSSDBG_OP_FAILURE,
44f86b
+                          "Could not reinitialize subdomains\n");
44f86b
+                    goto done;
44f86b
+                }
44f86b
+            }
44f86b
+        }
44f86b
+
44f86b
         DEBUG(SSSDBG_OP_FAILURE,
44f86b
               "No information provided for root domain, trying directly.\n");
44f86b
         subreq = ad_check_domain_send(state, state->ev, state->be_ctx,
44f86b
@@ -1400,11 +1471,6 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
44f86b
         }
44f86b
         tevent_req_set_callback(subreq, ad_check_root_domain_done, req);
44f86b
         return;
44f86b
-    } else if (state->reply_count > 1) {
44f86b
-        DEBUG(SSSDBG_CRIT_FAILURE, "Multiple results for root domain search, "
44f86b
-              "domain list might be incomplete!\n");
44f86b
-        ret = ERR_MALFORMED_ENTRY;
44f86b
-        goto done;
44f86b
     }
44f86b
 
44f86b
     ret = ad_get_root_domain_refresh(state);
44f86b
@@ -1522,7 +1588,7 @@ ad_get_root_domain_refresh(struct ad_get_root_domain_state *state)
44f86b
     errno_t ret;
44f86b
 
44f86b
     ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
44f86b
-                                state->reply, state->reply_count, true,
44f86b
+                                state->reply, state->reply_count, false,
44f86b
                                 &state->sd_ctx->last_refreshed,
44f86b
                                 &has_changes);
44f86b
     if (ret != EOK) {
44f86b
@@ -1539,8 +1605,9 @@ ad_get_root_domain_refresh(struct ad_get_root_domain_state *state)
44f86b
         }
44f86b
     }
44f86b
 
44f86b
-    state->root_domain_attrs = state->reply[0];
44f86b
-    root_domain = ads_get_root_domain(state->be_ctx, state->reply[0]);
44f86b
+    state->root_domain_attrs = find_domain(state->reply_count, state->reply,
44f86b
+                                           state->forest);
44f86b
+    root_domain = ads_get_root_domain(state->be_ctx, state->root_domain_attrs);
44f86b
     if (root_domain == NULL) {
44f86b
         DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
44f86b
         ret = EFAULT;
44f86b
-- 
44f86b
2.26.3
44f86b