Blame SOURCES/0151-SYSDB-Augment-sysdb_try_to_find_expected_dn-to-match.patch

45d81b
From a315e923a930e743de51c05183de383245f1c83e Mon Sep 17 00:00:00 2001
45d81b
From: Jakub Hrozek <jhrozek@redhat.com>
45d81b
Date: Mon, 31 Oct 2016 21:39:57 +0100
45d81b
Subject: [PATCH 151/151] SYSDB: Augment sysdb_try_to_find_expected_dn to match
45d81b
 search base as well
45d81b
45d81b
In cases where the domain name in sssd.conf does not match the AD
45d81b
domain, our previous matching process wouldn't match. This patch
45d81b
augments the matching as follows:
45d81b
    - the search base is known to sysdb_try_to_find_expected_dn and is
45d81b
      expected to be non-NULL
45d81b
    - the existing matching is ran first
45d81b
    - during the search base, matching, all the non-DC components are
45d81b
      stripped from the search base to 'canonicalize' the search base
45d81b
    - if only a single entry that matches with a non-DC DN component
45d81b
      (matching with a DC component would mean the DN comes from a
45d81b
      different domain) then this entry is a match and is returned
45d81b
45d81b
Resolves:
45d81b
https://fedorahosted.org/sssd/ticket/3199
45d81b
45d81b
Reviewed-by: Sumit Bose <sbose@redhat.com>
45d81b
(cherry picked from commit 24d8c85fae253f988165c112af208198cf48eef6)
45d81b
---
45d81b
 src/db/sysdb.h                             |  1 +
45d81b
 src/db/sysdb_subdomains.c                  | 99 ++++++++++++++++++++++++++++++
45d81b
 src/providers/ldap/sdap_async_initgroups.c |  8 ++-
45d81b
 src/tests/cmocka/test_sysdb_subdomains.c   | 43 +++++++++++--
45d81b
 4 files changed, 144 insertions(+), 7 deletions(-)
45d81b
45d81b
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
45d81b
index a0279fb249e1258c9cb73a4fcab55e4b242c61f3..6a1bbf089206970892590e85ae1f5c741a79f969 100644
45d81b
--- a/src/db/sysdb.h
45d81b
+++ b/src/db/sysdb.h
45d81b
@@ -1296,6 +1296,7 @@ errno_t sysdb_handle_original_uuid(const char *orig_name,
45d81b
 
45d81b
 errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
45d81b
                                       const char *domain_component_name,
45d81b
+                                      const char *ldap_search_base,
45d81b
                                       struct sysdb_attrs **usr_attrs,
45d81b
                                       size_t count,
45d81b
                                       struct sysdb_attrs **exp_usr);
45d81b
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
45d81b
index b011bad6c988db952622e7ddaabf015ec24e54ba..780140484f6f023bc6e8c12266e3b81ff016ec10 100644
45d81b
--- a/src/db/sysdb_subdomains.c
45d81b
+++ b/src/db/sysdb_subdomains.c
45d81b
@@ -1320,8 +1320,97 @@ static errno_t match_basedn(TALLOC_CTX *tmp_ctx,
45d81b
                              _result);
45d81b
 }
45d81b
 
45d81b
+static errno_t match_search_base(TALLOC_CTX *tmp_ctx,
45d81b
+                                 struct sss_domain_info *dom,
45d81b
+                                 const char *domain_component_name,
45d81b
+                                 const char *domain_search_base,
45d81b
+                                 struct sysdb_attrs **usr_attrs,
45d81b
+                                 size_t count,
45d81b
+                                 struct sysdb_attrs **_result)
45d81b
+{
45d81b
+    errno_t ret;
45d81b
+    bool ok;
45d81b
+    const char *search_base;
45d81b
+    struct ldb_context *ldb_ctx;
45d81b
+    struct sysdb_attrs *result = NULL;
45d81b
+    struct ldb_dn *ldb_search_base;
45d81b
+    int search_base_comp_num;
45d81b
+    int non_dc_comp_num;
45d81b
+    const char *component_name;
45d81b
+
45d81b
+    ldb_ctx = sysdb_ctx_get_ldb(dom->sysdb);
45d81b
+    if (ldb_ctx == NULL) {
45d81b
+        DEBUG(SSSDBG_OP_FAILURE, "Missing ldb context.\n");
45d81b
+        ret = EINVAL;
45d81b
+        goto done;
45d81b
+    }
45d81b
+
45d81b
+    ldb_search_base = ldb_dn_new(tmp_ctx, ldb_ctx, domain_search_base);
45d81b
+    if (ldb_search_base == NULL) {
45d81b
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
45d81b
+        ret = ENOMEM;
45d81b
+        goto done;
45d81b
+    }
45d81b
+
45d81b
+    /* strip non-DC components from the search base */
45d81b
+    search_base_comp_num = ldb_dn_get_comp_num(ldb_search_base);
45d81b
+    for (non_dc_comp_num = 0;
45d81b
+         non_dc_comp_num < search_base_comp_num;
45d81b
+         non_dc_comp_num++) {
45d81b
+
45d81b
+        component_name = ldb_dn_get_component_name(ldb_search_base,
45d81b
+                                                   non_dc_comp_num);
45d81b
+        if (strcasecmp(domain_component_name, component_name) == 0) {
45d81b
+            break;
45d81b
+        }
45d81b
+    }
45d81b
+
45d81b
+    if (non_dc_comp_num == search_base_comp_num) {
45d81b
+        /* The search base does not have any non-DC components, the search wouldn't
45d81b
+         * match anyway
45d81b
+         */
45d81b
+        ret = EOK;
45d81b
+        *_result = NULL;
45d81b
+        goto done;
45d81b
+    }
45d81b
+
45d81b
+    ok = ldb_dn_remove_child_components(ldb_search_base, non_dc_comp_num);
45d81b
+    if (!ok) {
45d81b
+        ret = EINVAL;
45d81b
+        goto done;
45d81b
+    }
45d81b
+
45d81b
+    search_base = ldb_dn_get_linearized(ldb_search_base);
45d81b
+    if (search_base == NULL) {
45d81b
+        ret = ENOMEM;
45d81b
+        goto done;
45d81b
+    }
45d81b
+
45d81b
+    ret = match_cn_users(tmp_ctx, usr_attrs, count, search_base, &result);
45d81b
+    if (ret != EOK) {
45d81b
+        goto done;
45d81b
+    }
45d81b
+
45d81b
+    if (result == NULL) {
45d81b
+        ret = match_non_dc_comp(tmp_ctx, dom,
45d81b
+                                usr_attrs, count,
45d81b
+                                ldb_search_base, search_base,
45d81b
+                                domain_component_name,
45d81b
+                                &result);
45d81b
+        if (ret != EOK) {
45d81b
+            goto done;
45d81b
+        }
45d81b
+    }
45d81b
+
45d81b
+    ret = EOK;
45d81b
+    *_result = result;
45d81b
+done:
45d81b
+    return ret;
45d81b
+}
45d81b
+
45d81b
 errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
45d81b
                                       const char *domain_component_name,
45d81b
+                                      const char *domain_search_base,
45d81b
                                       struct sysdb_attrs **usr_attrs,
45d81b
                                       size_t count,
45d81b
                                       struct sysdb_attrs **exp_usr)
45d81b
@@ -1332,6 +1421,7 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
45d81b
     struct sysdb_attrs *result = NULL;
45d81b
 
45d81b
     if (dom == NULL || domain_component_name == NULL
45d81b
+            || domain_search_base == NULL
45d81b
             || usr_attrs == NULL || count == 0) {
45d81b
         return EINVAL;
45d81b
     }
45d81b
@@ -1364,6 +1454,15 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
45d81b
     }
45d81b
 
45d81b
     if (result == NULL) {
45d81b
+        ret = match_search_base(tmp_ctx, dom, domain_component_name,
45d81b
+                                   domain_search_base, usr_attrs, count,
45d81b
+                                   &result);
45d81b
+        if (ret != EOK) {
45d81b
+            goto done;
45d81b
+        }
45d81b
+    }
45d81b
+
45d81b
+    if (result == NULL) {
45d81b
         DEBUG(SSSDBG_OP_FAILURE, "No matching DN found.\n");
45d81b
         ret = ENOENT;
45d81b
         goto done;
45d81b
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
45d81b
index 8eaba261c49082d086df9f19464ac0f40fae71fb..1173f4a875a1ea79990ff491ee7f2512f8435ac7 100644
45d81b
--- a/src/providers/ldap/sdap_async_initgroups.c
45d81b
+++ b/src/providers/ldap/sdap_async_initgroups.c
45d81b
@@ -2947,7 +2947,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
45d81b
         DEBUG(SSSDBG_OP_FAILURE,
45d81b
               "Expected one user entry and got %zu\n", count);
45d81b
 
45d81b
-        ret = sysdb_try_to_find_expected_dn(state->dom, "dc", usr_attrs, count,
45d81b
+        /* When matching against a search base, it's sufficient to pick only
45d81b
+         * the first search base because all bases in a single domain would
45d81b
+         * have the same DC= components
45d81b
+         */
45d81b
+        ret = sysdb_try_to_find_expected_dn(state->dom, "dc",
45d81b
+                                            state->sdom->search_bases[0]->basedn,
45d81b
+                                            usr_attrs, count,
45d81b
                                             &state->orig_user);
45d81b
         if (ret != EOK) {
45d81b
             DEBUG(SSSDBG_OP_FAILURE,
45d81b
diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
45d81b
index c9db56841e841472c81d00a79f475dbbd975ccb0..52056e0435d2793893f1a4e336f38acf7a70b2c0 100644
45d81b
--- a/src/tests/cmocka/test_sysdb_subdomains.c
45d81b
+++ b/src/tests/cmocka/test_sysdb_subdomains.c
45d81b
@@ -520,7 +520,9 @@ static void test_try_to_find_expected_dn(void **state)
45d81b
     int ret;
45d81b
     struct sysdb_attrs *result;
45d81b
     struct sysdb_attrs *usr_attrs[10] = { NULL };
45d81b
+    struct sysdb_attrs *dom_usr_attrs[10] = { NULL };
45d81b
     struct sss_domain_info *dom;
45d81b
+    char *dom_basedn;
45d81b
     struct subdom_test_ctx *test_ctx =
45d81b
         talloc_get_type(*state, struct subdom_test_ctx);
45d81b
 
45d81b
@@ -528,6 +530,9 @@ static void test_try_to_find_expected_dn(void **state)
45d81b
                               "child2.test_sysdb_subdomains_2", true);
45d81b
     assert_non_null(dom);
45d81b
 
45d81b
+    ret = domain_to_basedn(test_ctx, dom->name, &dom_basedn);
45d81b
+    assert_int_equal(ret, EOK);
45d81b
+
45d81b
     usr_attrs[0] = sysdb_new_attrs(test_ctx);
45d81b
     assert_non_null(usr_attrs[0]);
45d81b
 
45d81b
@@ -535,13 +540,13 @@ static void test_try_to_find_expected_dn(void **state)
45d81b
                   "uid=user,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2");
45d81b
     assert_int_equal(ret, EOK);
45d81b
 
45d81b
-    ret = sysdb_try_to_find_expected_dn(NULL, NULL, NULL, 0, NULL);
45d81b
+    ret = sysdb_try_to_find_expected_dn(NULL, NULL, NULL, NULL, 0, NULL);
45d81b
     assert_int_equal(ret, EINVAL);
45d81b
 
45d81b
-    ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 1, &result);
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 1, &result);
45d81b
     assert_int_equal(ret, ENOENT);
45d81b
 
45d81b
-    ret = sysdb_try_to_find_expected_dn(dom, "xy", usr_attrs, 1, &result);
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "xy", dom_basedn, usr_attrs, 1, &result);
45d81b
     assert_int_equal(ret, EOK);
45d81b
     assert_ptr_equal(result, usr_attrs[0]);
45d81b
 
45d81b
@@ -559,11 +564,11 @@ static void test_try_to_find_expected_dn(void **state)
45d81b
                  "uid=user2,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2");
45d81b
     assert_int_equal(ret, EOK);
45d81b
 
45d81b
-    ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 3, &result);
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 3, &result);
45d81b
     assert_int_equal(ret, EOK);
45d81b
     assert_ptr_equal(result, usr_attrs[1]);
45d81b
 
45d81b
-    ret = sysdb_try_to_find_expected_dn(dom, "xy", usr_attrs, 3, &result);
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "xy", dom_basedn, usr_attrs, 3, &result);
45d81b
     assert_int_equal(ret, EINVAL);
45d81b
 
45d81b
     /* Make sure cn=users match is preferred */
45d81b
@@ -575,10 +580,36 @@ static void test_try_to_find_expected_dn(void **state)
45d81b
                  "uid=user2,cn=abc,cn=users,dc=child2,dc=test_sysdb_subdomains_2");
45d81b
     assert_int_equal(ret, EOK);
45d81b
 
45d81b
-    ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 3, &result);
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 3, &result);
45d81b
     assert_int_equal(ret, EOK);
45d81b
     assert_ptr_equal(result, usr_attrs[2]);
45d81b
 
45d81b
+    /* test a case where the domain name does not match the basedn */
45d81b
+    dom->name = discard_const("default");
45d81b
+    dom_usr_attrs[0] = usr_attrs[0];
45d81b
+
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 1, &result);
45d81b
+    assert_int_equal(ret, ENOENT);
45d81b
+
45d81b
+    dom_usr_attrs[1] = usr_attrs[1];
45d81b
+    dom_usr_attrs[2] = usr_attrs[2];
45d81b
+
45d81b
+    /* Make sure cn=users match is preferred */
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 3, &result);
45d81b
+    assert_int_equal(ret, EOK);
45d81b
+    assert_ptr_equal(result, dom_usr_attrs[2]);
45d81b
+
45d81b
+    talloc_free(usr_attrs[2]);
45d81b
+    usr_attrs[2] = sysdb_new_attrs(test_ctx);
45d81b
+    assert_non_null(usr_attrs[2]);
45d81b
+    ret = sysdb_attrs_add_string(usr_attrs[2], SYSDB_ORIG_DN,
45d81b
+                 "uid=user2,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2");
45d81b
+    assert_int_equal(ret, EOK);
45d81b
+
45d81b
+    dom_usr_attrs[2] = usr_attrs[2];
45d81b
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 3, &result);
45d81b
+    assert_int_equal(ret, EOK);
45d81b
+    assert_ptr_equal(result, usr_attrs[1]);
45d81b
 
45d81b
     talloc_free(usr_attrs[0]);
45d81b
     talloc_free(usr_attrs[1]);
45d81b
-- 
45d81b
2.7.4
45d81b