Blob Blame History Raw
From a315e923a930e743de51c05183de383245f1c83e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 31 Oct 2016 21:39:57 +0100
Subject: [PATCH 151/151] SYSDB: Augment sysdb_try_to_find_expected_dn to match
 search base as well

In cases where the domain name in sssd.conf does not match the AD
domain, our previous matching process wouldn't match. This patch
augments the matching as follows:
    - the search base is known to sysdb_try_to_find_expected_dn and is
      expected to be non-NULL
    - the existing matching is ran first
    - during the search base, matching, all the non-DC components are
      stripped from the search base to 'canonicalize' the search base
    - if only a single entry that matches with a non-DC DN component
      (matching with a DC component would mean the DN comes from a
      different domain) then this entry is a match and is returned

Resolves:
https://fedorahosted.org/sssd/ticket/3199

Reviewed-by: Sumit Bose <sbose@redhat.com>
(cherry picked from commit 24d8c85fae253f988165c112af208198cf48eef6)
---
 src/db/sysdb.h                             |  1 +
 src/db/sysdb_subdomains.c                  | 99 ++++++++++++++++++++++++++++++
 src/providers/ldap/sdap_async_initgroups.c |  8 ++-
 src/tests/cmocka/test_sysdb_subdomains.c   | 43 +++++++++++--
 4 files changed, 144 insertions(+), 7 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index a0279fb249e1258c9cb73a4fcab55e4b242c61f3..6a1bbf089206970892590e85ae1f5c741a79f969 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -1296,6 +1296,7 @@ errno_t sysdb_handle_original_uuid(const char *orig_name,
 
 errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
                                       const char *domain_component_name,
+                                      const char *ldap_search_base,
                                       struct sysdb_attrs **usr_attrs,
                                       size_t count,
                                       struct sysdb_attrs **exp_usr);
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index b011bad6c988db952622e7ddaabf015ec24e54ba..780140484f6f023bc6e8c12266e3b81ff016ec10 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -1320,8 +1320,97 @@ static errno_t match_basedn(TALLOC_CTX *tmp_ctx,
                              _result);
 }
 
+static errno_t match_search_base(TALLOC_CTX *tmp_ctx,
+                                 struct sss_domain_info *dom,
+                                 const char *domain_component_name,
+                                 const char *domain_search_base,
+                                 struct sysdb_attrs **usr_attrs,
+                                 size_t count,
+                                 struct sysdb_attrs **_result)
+{
+    errno_t ret;
+    bool ok;
+    const char *search_base;
+    struct ldb_context *ldb_ctx;
+    struct sysdb_attrs *result = NULL;
+    struct ldb_dn *ldb_search_base;
+    int search_base_comp_num;
+    int non_dc_comp_num;
+    const char *component_name;
+
+    ldb_ctx = sysdb_ctx_get_ldb(dom->sysdb);
+    if (ldb_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Missing ldb context.\n");
+        ret = EINVAL;
+        goto done;
+    }
+
+    ldb_search_base = ldb_dn_new(tmp_ctx, ldb_ctx, domain_search_base);
+    if (ldb_search_base == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* strip non-DC components from the search base */
+    search_base_comp_num = ldb_dn_get_comp_num(ldb_search_base);
+    for (non_dc_comp_num = 0;
+         non_dc_comp_num < search_base_comp_num;
+         non_dc_comp_num++) {
+
+        component_name = ldb_dn_get_component_name(ldb_search_base,
+                                                   non_dc_comp_num);
+        if (strcasecmp(domain_component_name, component_name) == 0) {
+            break;
+        }
+    }
+
+    if (non_dc_comp_num == search_base_comp_num) {
+        /* The search base does not have any non-DC components, the search wouldn't
+         * match anyway
+         */
+        ret = EOK;
+        *_result = NULL;
+        goto done;
+    }
+
+    ok = ldb_dn_remove_child_components(ldb_search_base, non_dc_comp_num);
+    if (!ok) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    search_base = ldb_dn_get_linearized(ldb_search_base);
+    if (search_base == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = match_cn_users(tmp_ctx, usr_attrs, count, search_base, &result);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    if (result == NULL) {
+        ret = match_non_dc_comp(tmp_ctx, dom,
+                                usr_attrs, count,
+                                ldb_search_base, search_base,
+                                domain_component_name,
+                                &result);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    ret = EOK;
+    *_result = result;
+done:
+    return ret;
+}
+
 errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
                                       const char *domain_component_name,
+                                      const char *domain_search_base,
                                       struct sysdb_attrs **usr_attrs,
                                       size_t count,
                                       struct sysdb_attrs **exp_usr)
@@ -1332,6 +1421,7 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
     struct sysdb_attrs *result = NULL;
 
     if (dom == NULL || domain_component_name == NULL
+            || domain_search_base == NULL
             || usr_attrs == NULL || count == 0) {
         return EINVAL;
     }
@@ -1364,6 +1454,15 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom,
     }
 
     if (result == NULL) {
+        ret = match_search_base(tmp_ctx, dom, domain_component_name,
+                                   domain_search_base, usr_attrs, count,
+                                   &result);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    if (result == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "No matching DN found.\n");
         ret = ENOENT;
         goto done;
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 8eaba261c49082d086df9f19464ac0f40fae71fb..1173f4a875a1ea79990ff491ee7f2512f8435ac7 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2947,7 +2947,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
         DEBUG(SSSDBG_OP_FAILURE,
               "Expected one user entry and got %zu\n", count);
 
-        ret = sysdb_try_to_find_expected_dn(state->dom, "dc", usr_attrs, count,
+        /* When matching against a search base, it's sufficient to pick only
+         * the first search base because all bases in a single domain would
+         * have the same DC= components
+         */
+        ret = sysdb_try_to_find_expected_dn(state->dom, "dc",
+                                            state->sdom->search_bases[0]->basedn,
+                                            usr_attrs, count,
                                             &state->orig_user);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE,
diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
index c9db56841e841472c81d00a79f475dbbd975ccb0..52056e0435d2793893f1a4e336f38acf7a70b2c0 100644
--- a/src/tests/cmocka/test_sysdb_subdomains.c
+++ b/src/tests/cmocka/test_sysdb_subdomains.c
@@ -520,7 +520,9 @@ static void test_try_to_find_expected_dn(void **state)
     int ret;
     struct sysdb_attrs *result;
     struct sysdb_attrs *usr_attrs[10] = { NULL };
+    struct sysdb_attrs *dom_usr_attrs[10] = { NULL };
     struct sss_domain_info *dom;
+    char *dom_basedn;
     struct subdom_test_ctx *test_ctx =
         talloc_get_type(*state, struct subdom_test_ctx);
 
@@ -528,6 +530,9 @@ static void test_try_to_find_expected_dn(void **state)
                               "child2.test_sysdb_subdomains_2", true);
     assert_non_null(dom);
 
+    ret = domain_to_basedn(test_ctx, dom->name, &dom_basedn);
+    assert_int_equal(ret, EOK);
+
     usr_attrs[0] = sysdb_new_attrs(test_ctx);
     assert_non_null(usr_attrs[0]);
 
@@ -535,13 +540,13 @@ static void test_try_to_find_expected_dn(void **state)
                   "uid=user,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2");
     assert_int_equal(ret, EOK);
 
-    ret = sysdb_try_to_find_expected_dn(NULL, NULL, NULL, 0, NULL);
+    ret = sysdb_try_to_find_expected_dn(NULL, NULL, NULL, NULL, 0, NULL);
     assert_int_equal(ret, EINVAL);
 
-    ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 1, &result);
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 1, &result);
     assert_int_equal(ret, ENOENT);
 
-    ret = sysdb_try_to_find_expected_dn(dom, "xy", usr_attrs, 1, &result);
+    ret = sysdb_try_to_find_expected_dn(dom, "xy", dom_basedn, usr_attrs, 1, &result);
     assert_int_equal(ret, EOK);
     assert_ptr_equal(result, usr_attrs[0]);
 
@@ -559,11 +564,11 @@ static void test_try_to_find_expected_dn(void **state)
                  "uid=user2,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2");
     assert_int_equal(ret, EOK);
 
-    ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 3, &result);
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 3, &result);
     assert_int_equal(ret, EOK);
     assert_ptr_equal(result, usr_attrs[1]);
 
-    ret = sysdb_try_to_find_expected_dn(dom, "xy", usr_attrs, 3, &result);
+    ret = sysdb_try_to_find_expected_dn(dom, "xy", dom_basedn, usr_attrs, 3, &result);
     assert_int_equal(ret, EINVAL);
 
     /* Make sure cn=users match is preferred */
@@ -575,10 +580,36 @@ static void test_try_to_find_expected_dn(void **state)
                  "uid=user2,cn=abc,cn=users,dc=child2,dc=test_sysdb_subdomains_2");
     assert_int_equal(ret, EOK);
 
-    ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 3, &result);
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 3, &result);
     assert_int_equal(ret, EOK);
     assert_ptr_equal(result, usr_attrs[2]);
 
+    /* test a case where the domain name does not match the basedn */
+    dom->name = discard_const("default");
+    dom_usr_attrs[0] = usr_attrs[0];
+
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 1, &result);
+    assert_int_equal(ret, ENOENT);
+
+    dom_usr_attrs[1] = usr_attrs[1];
+    dom_usr_attrs[2] = usr_attrs[2];
+
+    /* Make sure cn=users match is preferred */
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 3, &result);
+    assert_int_equal(ret, EOK);
+    assert_ptr_equal(result, dom_usr_attrs[2]);
+
+    talloc_free(usr_attrs[2]);
+    usr_attrs[2] = sysdb_new_attrs(test_ctx);
+    assert_non_null(usr_attrs[2]);
+    ret = sysdb_attrs_add_string(usr_attrs[2], SYSDB_ORIG_DN,
+                 "uid=user2,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2");
+    assert_int_equal(ret, EOK);
+
+    dom_usr_attrs[2] = usr_attrs[2];
+    ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 3, &result);
+    assert_int_equal(ret, EOK);
+    assert_ptr_equal(result, usr_attrs[1]);
 
     talloc_free(usr_attrs[0]);
     talloc_free(usr_attrs[1]);
-- 
2.7.4