URL: https://github.com/SSSD/sssd/pull/5529
Author: sumit-bose
 Title: #5529: AD: read trusted domains from local domain as well
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/5529/head:pr5529
git checkout pr5529
From 041a96415a063b7eccf30bccbdda2f9f41c66bf3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 14 Apr 2021 17:22:06 +0200
Subject: [PATCH 1/2] sss_domain_info: add not_found_counter

This new counter should be used to track how often a domain could not be
found while discovering the environment so that it can be deleted after
a number of failed attempts.

Resolves: https://github.com/SSSD/sssd/issues/5528
---
 src/confdb/confdb.c       | 1 +
 src/confdb/confdb.h       | 4 ++++
 src/db/sysdb_subdomains.c | 2 ++
 3 files changed, 7 insertions(+)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index cca76159bc..c554edda0f 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -1620,6 +1620,7 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
     domain->view_name = NULL;
 
     domain->state = DOM_ACTIVE;
+    domain->not_found_counter = 0;
 
     *_domain = domain;
     ret = EOK;
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 81b68a0f15..c6c2514f83 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -441,6 +441,10 @@ struct sss_domain_info {
     char *gssapi_check_upn; /* true | false | NULL */
     /* List of indicators associated with the specific PAM service */
     char **gssapi_indicators_map;
+
+    /* Counts how often the domain was not found during a refresh of the
+     * domain list */
+    size_t not_found_counter;
 };
 
 /**
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index e2381c8afa..348f242d08 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -193,6 +193,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
     dom->gssapi_services = parent->gssapi_services;
     dom->gssapi_indicators_map = parent->gssapi_indicators_map;
 
+    dom->not_found_counter = 0;
+
     if (parent->sysdb == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Missing sysdb context in parent domain.\n");
         goto fail;

From c15c5f4fcc1e3660bf1352ac1146926321b73c0f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Tue, 16 Feb 2021 14:30:55 +0100
Subject: [PATCH 2/2] AD: read trusted domains from local domain as well

Currently SSSD only uses information stored in a domain controller of
the forest root domain to get the names of other trusted domains in the
forest. Depending on how the forest was created the forest root might
not have LDAP objects for all domains in the forest. It looks like a
typical case are child domains of other domains in the forest.

As a start SSSD can now include trusted domains stored in the LDAP tree
of a local domain controller as well. In a long run it would make sense
to allow SSSD to explicitly search for domain by looking up DNS entries
and checking a potential domain controller with a CLDAP ping.

Resolves: https://github.com/SSSD/sssd/issues/5528

:feature: Besides trusted domains known by the forest root, trusted
          domains known by the local domain are used as well.
---
 src/providers/ad/ad_subdomains.c | 105 +++++++++++++++++++++++++------
 1 file changed, 86 insertions(+), 19 deletions(-)

diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index f5b0be6c21..3eb49c93f2 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -45,6 +45,7 @@
 #define AD_AT_TRUST_TYPE    "trustType"
 #define AD_AT_TRUST_PARTNER "trustPartner"
 #define AD_AT_TRUST_ATTRS   "trustAttributes"
+#define AD_AT_DOMAIN_NAME   "cn"
 
 /* trustType=2 denotes uplevel (NT5 and later) trusted domains. See
  * http://msdn.microsoft.com/en-us/library/windows/desktop/ms680342%28v=vs.85%29.aspx
@@ -56,7 +57,6 @@
  */
 #define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))"
 #define SLAVE_DOMAIN_FILTER      "(&"SLAVE_DOMAIN_FILTER_BASE")"
-#define FOREST_ROOT_FILTER_FMT   "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))"
 
 /* Attributes of schema objects. See e.g.
  * https://docs.microsoft.com/en-us/windows/desktop/AD/characteristics-of-attributes
@@ -646,6 +646,10 @@ ad_subdom_store(struct confdb_ctx *cdb,
     return ret;
 }
 
+/* How many times we keep a domain not found during searches before it will be
+ * removed. */
+#define MAX_NOT_FOUND 6
+
 static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
                                      struct sdap_idmap_ctx *idmap_ctx,
                                      struct sdap_options *opts,
@@ -706,6 +710,25 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
         }
 
         if (c >= num_subdomains) {
+            DEBUG(SSSDBG_CONF_SETTINGS, "Domain [%s] not in current list.\n",
+                                        dom->name);
+            /* Since the forest root might not have trustedDomain objects for
+             * each domain in the forest, especially e.g. for child-domains of
+             * child-domains, we cannot reliable say if a domain is still
+             * present or not.
+             * Maybe it would work to check the crossRef objects in
+             * CN=Partitions,CN=Configuration as well to understand if a
+             * domain is still known in the forest or not.
+             * For the time being we use a counter, if a domain was not found
+             * after multiple attempts it will be deleted. */
+
+            if (dom->not_found_counter++ < MAX_NOT_FOUND) {
+                DEBUG(SSSDBG_TRACE_ALL,
+                      "Domain [%s] was not found [%zu] times.\n", dom->name,
+                      dom->not_found_counter);
+                continue;
+            }
+
             /* ok this subdomain does not exist anymore, let's clean up */
             sss_domain_set_state(dom, DOM_DISABLED);
 
@@ -740,6 +763,7 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
             /* terminate all requests for this subdomain so we can free it */
             dp_terminate_domain_requests(be_ctx->provider, dom->name);
             talloc_zfree(sdom);
+
         } else {
             /* ok let's try to update it */
             ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
@@ -747,6 +771,7 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
                 goto done;
             }
 
+            dom->not_found_counter = 0;
             ret = ad_subdom_store(be_ctx->cdb, idmap_ctx, domain,
                                   subdomains[c], enumerate);
             if (ret) {
@@ -1307,10 +1332,9 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
     struct tevent_req *req;
     struct sdap_options *opts;
     errno_t ret;
-    const char *filter;
     const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
                             AD_AT_SID, AD_AT_TRUST_TYPE,
-                            AD_AT_TRUST_ATTRS, NULL };
+                            AD_AT_TRUST_ATTRS, AD_AT_DOMAIN_NAME, NULL };
 
     req = tevent_req_create(mem_ctx, &state, struct ad_get_root_domain_state);
     if (req == NULL) {
@@ -1335,15 +1359,10 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
     state->domain = domain;
     state->forest = forest;
 
-    filter = talloc_asprintf(state, FOREST_ROOT_FILTER_FMT, forest);
-    if (filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
     subreq = sdap_search_bases_return_first_send(state, ev, opts, sh,
                                                  opts->sdom->search_bases,
-                                                 NULL, false, 0, filter, attrs,
+                                                 NULL, false, 0,
+                                                 SLAVE_DOMAIN_FILTER, attrs,
                                                  NULL);
     if (subreq == NULL) {
         ret = ENOMEM;
@@ -1365,11 +1384,33 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
     return req;
 }
 
+static struct sysdb_attrs *find_domain(size_t count, struct sysdb_attrs **reply,
+                                       const char *dom_name)
+{
+    size_t c;
+    const char *name;
+    int ret;
+
+    for (c = 0; c < count; c++) {
+        ret = sysdb_attrs_get_string(reply[c], AD_AT_DOMAIN_NAME, &name);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "Failed to find domain name, skipping");
+            continue;
+        }
+        if (strcasecmp(name, dom_name) == 0) {
+            return reply[c];
+        }
+    }
+
+    return NULL;
+}
+
 static void ad_get_root_domain_done(struct tevent_req *subreq)
 {
     struct tevent_req *req;
     struct ad_get_root_domain_state *state;
     errno_t ret;
+    bool has_changes = false;
 
     req = tevent_req_callback_data(subreq, struct tevent_req);
     state = tevent_req_data(req, struct ad_get_root_domain_state);
@@ -1384,7 +1425,37 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
         goto done;
     }
 
-    if (state->reply_count == 0) {
+    find_domain(state->reply_count, state->reply, state->forest);
+
+    if (state->reply_count == 0
+            || find_domain(state->reply_count, state->reply,
+                           state->forest) == NULL) {
+
+        if (state->reply_count > 0) {
+            /* refresh the other domains we have found before checking forest
+             * root */
+            ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx,
+                                        state->opts,
+                                        state->reply, state->reply_count, false,
+                                        &state->sd_ctx->last_refreshed,
+                                        &has_changes);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "ad_subdomains_refresh failed [%d]: %s\n",
+                      ret, sss_strerror(ret));
+                goto done;
+            }
+
+            if (has_changes) {
+                ret = ad_subdom_reinit(state->sd_ctx);
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_OP_FAILURE,
+                          "Could not reinitialize subdomains\n");
+                    goto done;
+                }
+            }
+        }
+
         DEBUG(SSSDBG_OP_FAILURE,
               "No information provided for root domain, trying directly.\n");
         subreq = ad_check_domain_send(state, state->ev, state->be_ctx,
@@ -1397,11 +1468,6 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
         }
         tevent_req_set_callback(subreq, ad_check_root_domain_done, req);
         return;
-    } else if (state->reply_count > 1) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Multiple results for root domain search, "
-              "domain list might be incomplete!\n");
-        ret = ERR_MALFORMED_ENTRY;
-        goto done;
     }
 
     ret = ad_get_root_domain_refresh(state);
@@ -1519,7 +1585,7 @@ ad_get_root_domain_refresh(struct ad_get_root_domain_state *state)
     errno_t ret;
 
     ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
-                                state->reply, state->reply_count, true,
+                                state->reply, state->reply_count, false,
                                 &state->sd_ctx->last_refreshed,
                                 &has_changes);
     if (ret != EOK) {
@@ -1536,8 +1602,9 @@ ad_get_root_domain_refresh(struct ad_get_root_domain_state *state)
         }
     }
 
-    state->root_domain_attrs = state->reply[0];
-    root_domain = ads_get_root_domain(state->be_ctx, state->reply[0]);
+    state->root_domain_attrs = find_domain(state->reply_count, state->reply,
+                                           state->forest);
+    root_domain = ads_get_root_domain(state->be_ctx, state->root_domain_attrs);
     if (root_domain == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
         ret = EFAULT;
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to