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

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