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

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