Blame SOURCES/0076-ad-filter-trusted-domains.patch

73eb8e
From 87aaf96ab7bd39698c41625d56602ca3de943b87 Mon Sep 17 00:00:00 2001
73eb8e
From: Sumit Bose <sbose@redhat.com>
73eb8e
Date: Wed, 6 Oct 2021 13:03:27 +0200
73eb8e
Subject: [PATCH] ad: filter trusted domains
73eb8e
MIME-Version: 1.0
73eb8e
Content-Type: text/plain; charset=UTF-8
73eb8e
Content-Transfer-Encoding: 8bit
73eb8e
73eb8e
The fix for https://github.com/SSSD/sssd/issues/5528 might discover
73eb8e
domains which are not trusted (one-way trust) or are from a different
73eb8e
forest (direct trust). Both should be ignored because they are not
73eb8e
trusted or can currently not be handled properly. This patch filters out
73eb8e
those domains.
73eb8e
73eb8e
Resolves: https://github.com/SSSD/sssd/issues/5819
73eb8e
73eb8e
Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
73eb8e
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
73eb8e
(cherry picked from commit 4c48c4a7792961cf8a228c76975ac370d32904e1)
73eb8e
---
73eb8e
 src/providers/ad/ad_subdomains.c | 104 +++++++++++++++++++++++++++++--
73eb8e
 1 file changed, 99 insertions(+), 5 deletions(-)
73eb8e
73eb8e
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
73eb8e
index 9b32196b7..6b98cdf1d 100644
73eb8e
--- a/src/providers/ad/ad_subdomains.c
73eb8e
+++ b/src/providers/ad/ad_subdomains.c
73eb8e
@@ -46,6 +46,7 @@
73eb8e
 #define AD_AT_TRUST_PARTNER "trustPartner"
73eb8e
 #define AD_AT_TRUST_ATTRS   "trustAttributes"
73eb8e
 #define AD_AT_DOMAIN_NAME   "cn"
73eb8e
+#define AD_AT_TRUST_DIRECTION   "trustDirection"
73eb8e
 
73eb8e
 /* trustType=2 denotes uplevel (NT5 and later) trusted domains. See
73eb8e
  * http://msdn.microsoft.com/en-us/library/windows/desktop/ms680342%28v=vs.85%29.aspx
73eb8e
@@ -69,6 +70,12 @@
73eb8e
 /* do not refresh more often than every 5 seconds for now */
73eb8e
 #define AD_SUBDOMAIN_REFRESH_LIMIT 5
73eb8e
 
73eb8e
+/* Flags of trustAttributes attribute, see MS-ADTS 6.1.6.7.9 for details */
73eb8e
+#define TRUST_ATTRIBUTE_WITHIN_FOREST 0x00000020
73eb8e
+
73eb8e
+/* Flags for trustDirection attribute, see MS-ADTS 6.1.6.7.12 for details */
73eb8e
+#define TRUST_DIRECTION_OUTBOUND 0x00000002
73eb8e
+
73eb8e
 static void
73eb8e
 ad_disable_gc(struct ad_options *ad_options)
73eb8e
 {
73eb8e
@@ -646,6 +653,85 @@ done:
73eb8e
     return ret;
73eb8e
 }
73eb8e
 
73eb8e
+/* When reading trusted domains from the local DC we are basically interested
73eb8e
+ * in domains from the local forest we are trusting, i.e. users from this
73eb8e
+ * domain can connect to us. To not unnecessarily bloat the list of domains
73eb8e
+ * and make multi-domain searches slow we filter domains from other forest and
73eb8e
+ * domains we do not trust.
73eb8e
+ * In future we might add config options to broaden the scope and allow more
73eb8e
+ * domains.
73eb8e
+ * If ad_filter_domains() returns successfully with EOK in input array is not
73eb8e
+ * valid anymore and should be freed by the caller. */
73eb8e
+static errno_t ad_filter_domains(TALLOC_CTX *mem_ctx,
73eb8e
+                                 struct sysdb_attrs **subdomains,
73eb8e
+                                 size_t num_subdomains,
73eb8e
+                                 struct sysdb_attrs ***_sd_out,
73eb8e
+                                 size_t *_num_sd_out)
73eb8e
+{
73eb8e
+    int ret;
73eb8e
+    size_t c;
73eb8e
+    uint32_t tmp_uint32_t;
73eb8e
+    const char *value;
73eb8e
+    struct sysdb_attrs **sd_out;
73eb8e
+    size_t num_sd_out = 0;
73eb8e
+
73eb8e
+    sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *,
73eb8e
+                               num_subdomains + 1);
73eb8e
+    if (sd_out == NULL) {
73eb8e
+        DEBUG(SSSDBG_OP_FAILURE,
73eb8e
+              "Failed to allocate memory for sub-domain list.\n");
73eb8e
+        return ENOMEM;
73eb8e
+    }
73eb8e
+
73eb8e
+    for (c = 0; c < num_subdomains; c++) {
73eb8e
+        ret = sysdb_attrs_get_string(subdomains[c], AD_AT_TRUST_PARTNER,
73eb8e
+                                     &value);
73eb8e
+        if (ret != EOK) {
73eb8e
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
73eb8e
+            talloc_free(sd_out);
73eb8e
+            return ret;
73eb8e
+        }
73eb8e
+
73eb8e
+        /* Ignore direct trusts to domains from other forests
73eb8e
+         * (TRUST_ATTRIBUTE_WITHIN_FOREST is not set) or domains we do not
73eb8e
+         * trust (TRUST_DIRECTION_OUTBOUND is not set) */
73eb8e
+
73eb8e
+        tmp_uint32_t = 0;
73eb8e
+        ret = sysdb_attrs_get_uint32_t(subdomains[c], AD_AT_TRUST_ATTRS,
73eb8e
+                                       &tmp_uint32_t);
73eb8e
+        if (ret != EOK
73eb8e
+                || (tmp_uint32_t & TRUST_ATTRIBUTE_WITHIN_FOREST) == 0) {
73eb8e
+            DEBUG(SSSDBG_FUNC_DATA,
73eb8e
+                  "TRUST_ATTRIBUTE_WITHIN_FOREST not set for [%s].\n",
73eb8e
+                  value);
73eb8e
+            continue;
73eb8e
+        }
73eb8e
+
73eb8e
+        tmp_uint32_t = 0;
73eb8e
+        ret = sysdb_attrs_get_uint32_t(subdomains[c], AD_AT_TRUST_DIRECTION,
73eb8e
+                                       &tmp_uint32_t);
73eb8e
+        if (ret != EOK
73eb8e
+                || (tmp_uint32_t & TRUST_DIRECTION_OUTBOUND) == 0) {
73eb8e
+            DEBUG(SSSDBG_FUNC_DATA,
73eb8e
+                  "TRUST_DIRECTION_OUTBOUND not set for [%s].\n",
73eb8e
+                  value);
73eb8e
+            continue;
73eb8e
+        }
73eb8e
+
73eb8e
+        sd_out[num_sd_out] = subdomains[c];
73eb8e
+        num_sd_out++;
73eb8e
+    }
73eb8e
+
73eb8e
+    for (c = 0; c < num_sd_out; c++) {
73eb8e
+        sd_out[c] = talloc_steal(sd_out, sd_out[c]);
73eb8e
+    }
73eb8e
+
73eb8e
+    *_sd_out = sd_out;
73eb8e
+    *_num_sd_out = num_sd_out;
73eb8e
+
73eb8e
+    return EOK;
73eb8e
+}
73eb8e
+
73eb8e
 /* How many times we keep a domain not found during searches before it will be
73eb8e
  * removed. */
73eb8e
 #define MAX_NOT_FOUND 6
73eb8e
@@ -1128,7 +1214,7 @@ static void ad_get_slave_domain_connect_done(struct tevent_req *subreq)
73eb8e
     errno_t ret;
73eb8e
     const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
73eb8e
                             AD_AT_SID, AD_AT_TRUST_TYPE,
73eb8e
-                            AD_AT_TRUST_ATTRS, NULL };
73eb8e
+                            AD_AT_TRUST_ATTRS, AD_AT_TRUST_DIRECTION, NULL };
73eb8e
 
73eb8e
     req = tevent_req_callback_data(subreq, struct tevent_req);
73eb8e
     state = tevent_req_data(req, struct ad_get_slave_domain_state);
73eb8e
@@ -1336,7 +1422,7 @@ ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
73eb8e
     struct sdap_options *opts;
73eb8e
     errno_t ret;
73eb8e
     const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
73eb8e
-                            AD_AT_SID, AD_AT_TRUST_TYPE,
73eb8e
+                            AD_AT_SID, AD_AT_TRUST_TYPE, AD_AT_TRUST_DIRECTION,
73eb8e
                             AD_AT_TRUST_ATTRS, AD_AT_DOMAIN_NAME, NULL };
73eb8e
 
73eb8e
     req = tevent_req_create(mem_ctx, &state, struct ad_get_root_domain_state);
73eb8e
@@ -1414,13 +1500,15 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
73eb8e
     struct ad_get_root_domain_state *state;
73eb8e
     errno_t ret;
73eb8e
     bool has_changes = false;
73eb8e
+    struct sysdb_attrs **unfiltered_reply;
73eb8e
+    size_t unfiltered_reply_count;
73eb8e
 
73eb8e
     req = tevent_req_callback_data(subreq, struct tevent_req);
73eb8e
     state = tevent_req_data(req, struct ad_get_root_domain_state);
73eb8e
 
73eb8e
     ret = sdap_search_bases_return_first_recv(subreq, state,
73eb8e
-                                              &state->reply_count,
73eb8e
-                                              &state->reply);
73eb8e
+                                              &unfiltered_reply_count,
73eb8e
+                                              &unfiltered_reply);
73eb8e
     talloc_zfree(subreq);
73eb8e
     if (ret != EOK) {
73eb8e
         DEBUG(SSSDBG_OP_FAILURE, "Unable to lookup forest root information "
73eb8e
@@ -1428,7 +1516,13 @@ static void ad_get_root_domain_done(struct tevent_req *subreq)
73eb8e
         goto done;
73eb8e
     }
73eb8e
 
73eb8e
-    find_domain(state->reply_count, state->reply, state->forest);
73eb8e
+    ret = ad_filter_domains(state, unfiltered_reply, unfiltered_reply_count,
73eb8e
+                            &state->reply, &state->reply_count);
73eb8e
+    if (ret != EOK) {
73eb8e
+        DEBUG(SSSDBG_OP_FAILURE,
73eb8e
+              "Failed to filter list of returned domains.\n");
73eb8e
+        goto done;
73eb8e
+    }
73eb8e
 
73eb8e
     if (state->reply_count == 0
73eb8e
             || find_domain(state->reply_count, state->reply,
73eb8e
-- 
73eb8e
2.26.3
73eb8e