URL: https://github.com/SSSD/sssd/pull/884
Author: sumit-bose
 Title: #884: ipa: support disabled domains
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/884/head:pr884
git checkout pr884
From 16bc34b649d82c52d8a8c3a352f6eaa1d2fbff77 Mon Sep 17 00:00:00 2001
From: Sumit Bose <[email protected]>
Date: Thu, 12 Sep 2019 14:49:30 +0200
Subject: [PATCH 1/5] utils: extend some find_domain_* calls to search disabled
 domain

This extension is needed to support disabled domains since it is
now important to know if a domain is really unknown or only disabled.
While an unknown domain might typically lead to an error, a caller might
just ignore requests for disabled domains or objects from disabled
domains.

Related to https://pagure.io/SSSD/sssd/issue/4078
---
 src/providers/ipa/ipa_id.c                 |  3 +-
 src/responder/sudo/sudosrv_get_sudorules.c |  3 +-
 src/tests/cmocka/test_utils.c              | 90 ++++++++++++++++++++++
 src/util/domain_info_utils.c               | 31 +++++---
 src/util/util.h                            |  7 +-
 5 files changed, 122 insertions(+), 12 deletions(-)

diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
index 05cc0facc5..94d5f9d90e 100644
--- a/src/providers/ipa/ipa_id.c
+++ b/src/providers/ipa/ipa_id.c
@@ -131,7 +131,8 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req)
 
     state->user_domain = find_domain_by_object_name_ex(
                                         state->ipa_ctx->sdap_id_ctx->be->domain,
-                                        ar->filter_value, true);
+                                        ar->filter_value, true,
+                                        SSS_GND_DESCEND);
     /* Use provided domain as fallback because no known domain was found in the
      * user name. */
     if (state->user_domain == NULL) {
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
index a0edb5b7e2..73720e3512 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -147,7 +147,8 @@ static errno_t sudosrv_format_runas(struct resp_ctx *rctx,
             continue;
         }
 
-        dom = find_domain_by_object_name_ex(rctx->domains, value, true);
+        dom = find_domain_by_object_name_ex(rctx->domains, value, true,
+                                            SSS_GND_DESCEND);
         if (dom == NULL) {
             continue;
         }
diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index 4bff56bb97..666f329030 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -401,6 +401,92 @@ void test_find_domain_by_name_disabled(void **state)
     }
 }
 
+void test_find_domain_by_name_ex_disabled(void **state)
+{
+    struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
+                                                      struct dom_list_test_ctx);
+    struct sss_domain_info *dom;
+    struct sss_domain_info *disabled_dom;
+    size_t c;
+    size_t mis;
+
+    mis = test_ctx->dom_count/2;
+    assert_true((mis >= 1 && mis < test_ctx->dom_count));
+
+    dom = test_ctx->dom_list;
+    for (c = 0; c < mis; c++) {
+        assert_non_null(dom);
+        dom = dom->next;
+    }
+    assert_non_null(dom);
+    sss_domain_set_state(dom, DOM_DISABLED);
+    disabled_dom = dom;
+
+    dom = find_domain_by_name(test_ctx->dom_list, disabled_dom->name, true);
+    assert_null(dom);
+
+    dom = find_domain_by_name_ex(test_ctx->dom_list, disabled_dom->name, true,
+                                 SSS_GND_DESCEND);
+    assert_null(dom);
+
+    dom = find_domain_by_name_ex(test_ctx->dom_list, disabled_dom->name, true,
+                                 SSS_GND_DESCEND | SSS_GND_INCLUDE_DISABLED);
+    assert_non_null(dom);
+    assert_ptr_equal(disabled_dom, dom);
+
+    dom = find_domain_by_name_ex(test_ctx->dom_list, disabled_dom->name, true,
+                                 SSS_GND_ALL_DOMAINS);
+    assert_non_null(dom);
+    assert_ptr_equal(disabled_dom, dom);
+}
+
+void test_find_domain_by_object_name_ex(void **state)
+{
+    struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
+                                                      struct dom_list_test_ctx);
+    struct sss_domain_info *dom;
+    struct sss_domain_info *disabled_dom;
+    size_t c;
+    size_t mis;
+    char *obj_name;
+
+    mis = test_ctx->dom_count/2;
+    assert_true((mis >= 1 && mis < test_ctx->dom_count));
+
+    dom = test_ctx->dom_list;
+    for (c = 0; c < mis; c++) {
+        assert_non_null(dom);
+        dom = dom->next;
+    }
+    assert_non_null(dom);
+    sss_domain_set_state(dom, DOM_DISABLED);
+    disabled_dom = dom;
+
+    obj_name = talloc_asprintf(global_talloc_context, "myname@%s",
+                               disabled_dom->name);
+    assert_non_null(obj_name);
+
+
+    dom = find_domain_by_object_name(test_ctx->dom_list, obj_name);
+    assert_null(dom);
+
+    dom = find_domain_by_object_name_ex(test_ctx->dom_list, obj_name, true,
+                                        SSS_GND_DESCEND);
+    assert_null(dom);
+
+    dom = find_domain_by_object_name_ex(test_ctx->dom_list, obj_name, true,
+                                    SSS_GND_DESCEND | SSS_GND_INCLUDE_DISABLED);
+    assert_non_null(dom);
+    assert_ptr_equal(disabled_dom, dom);
+
+    dom = find_domain_by_object_name_ex(test_ctx->dom_list, obj_name, true,
+                                        SSS_GND_ALL_DOMAINS);
+    assert_non_null(dom);
+    assert_ptr_equal(disabled_dom, dom);
+
+    talloc_free(obj_name);
+}
+
 void test_find_domain_by_sid_null(void **state)
 {
     struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
@@ -1897,6 +1983,10 @@ int main(int argc, const char *argv[])
                                         setup_dom_list, teardown_dom_list),
         cmocka_unit_test_setup_teardown(test_find_domain_by_name_disabled,
                                         setup_dom_list, teardown_dom_list),
+        cmocka_unit_test_setup_teardown(test_find_domain_by_name_ex_disabled,
+                                        setup_dom_list, teardown_dom_list),
+        cmocka_unit_test_setup_teardown(test_find_domain_by_object_name_ex,
+                                        setup_dom_list, teardown_dom_list),
 
         cmocka_unit_test_setup_teardown(test_sss_names_init,
                                         confdb_test_setup,
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index b95c89ed90..aa3582f038 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -93,9 +93,10 @@ bool subdomain_enumerates(struct sss_domain_info *parent,
     return false;
 }
 
-struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
-                                            const char *name,
-                                            bool match_any)
+struct sss_domain_info *find_domain_by_name_ex(struct sss_domain_info *domain,
+                                                const char *name,
+                                                bool match_any,
+                                                uint32_t gnd_flags)
 {
     struct sss_domain_info *dom = domain;
 
@@ -103,21 +104,31 @@ struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
         return NULL;
     }
 
-    while (dom && sss_domain_get_state(dom) == DOM_DISABLED) {
-        dom = get_next_domain(dom, SSS_GND_DESCEND);
+    if (!(gnd_flags & SSS_GND_INCLUDE_DISABLED)) {
+        while (dom && sss_domain_get_state(dom) == DOM_DISABLED) {
+            dom = get_next_domain(dom, gnd_flags);
+        }
     }
+
     while (dom) {
         if (strcasecmp(dom->name, name) == 0 ||
             ((match_any == true) && (dom->flat_name != NULL) &&
              (strcasecmp(dom->flat_name, name) == 0))) {
             return dom;
         }
-        dom = get_next_domain(dom, SSS_GND_DESCEND);
+        dom = get_next_domain(dom, gnd_flags);
     }
 
     return NULL;
 }
 
+struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
+                                            const char *name,
+                                            bool match_any)
+{
+    return find_domain_by_name_ex(domain, name, match_any, SSS_GND_DESCEND);
+}
+
 struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
                                               const char *sid)
 {
@@ -175,7 +186,8 @@ sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
 
 struct sss_domain_info *
 find_domain_by_object_name_ex(struct sss_domain_info *domain,
-                              const char *object_name, bool strict)
+                              const char *object_name, bool strict,
+                              uint32_t gnd_flags)
 {
     TALLOC_CTX *tmp_ctx;
     struct sss_domain_info *dom = NULL;
@@ -203,7 +215,7 @@ find_domain_by_object_name_ex(struct sss_domain_info *domain,
             dom = domain;
         }
     } else {
-        dom = find_domain_by_name(domain, domainname, true);
+        dom = find_domain_by_name_ex(domain, domainname, true, gnd_flags);
     }
 
 done:
@@ -215,7 +227,8 @@ struct sss_domain_info *
 find_domain_by_object_name(struct sss_domain_info *domain,
                            const char *object_name)
 {
-    return find_domain_by_object_name_ex(domain, object_name, false);
+    return find_domain_by_object_name_ex(domain, object_name, false,
+                                         SSS_GND_DESCEND);
 }
 
 errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
diff --git a/src/util/util.h b/src/util/util.h
index c7edbbbab0..f205c20888 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -534,6 +534,10 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
 struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain,
                                             const char *name,
                                             bool match_any);
+struct sss_domain_info *find_domain_by_name_ex(struct sss_domain_info *domain,
+                                               const char *name,
+                                               bool match_any,
+                                               uint32_t gnd_flags);
 struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
                                            const char *sid);
 enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom);
@@ -552,7 +556,8 @@ find_domain_by_object_name(struct sss_domain_info *domain,
 
 struct sss_domain_info *
 find_domain_by_object_name_ex(struct sss_domain_info *domain,
-                              const char *object_name, bool strict);
+                              const char *object_name, bool strict,
+                              uint32_t gnd_flags);
 
 bool subdomain_enumerates(struct sss_domain_info *parent,
                           const char *sd_name);

From e9969b7b1d41cd8277f2772ff864c2c7fe54e8c0 Mon Sep 17 00:00:00 2001
From: Sumit Bose <[email protected]>
Date: Wed, 7 Aug 2019 18:14:15 +0200
Subject: [PATCH 2/5] ipa: support disabled domains

IPA does not disable domains with the help of a flag in the domain
objects but more general with the help of the SID blacklist. With this
patch the blacklist is read with other data about trusted domains and if
the domain SID of a trusted domain is found the domain is disabled. As a
result uses and groups from this domain cannot be looked up anymore.

Related to https://pagure.io/SSSD/sssd/issue/4078
---
 src/providers/ipa/ipa_subdomains.c | 149 +++++++++++++++++++++++++++--
 1 file changed, 139 insertions(+), 10 deletions(-)

diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 1f26dcb251..2aa3da9cc4 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -43,6 +43,7 @@
 #define IPA_TRUSTED_DOMAIN_SID "ipaNTTrustedDomainSID"
 #define IPA_RANGE_TYPE "ipaRangeType"
 #define IPA_ADDITIONAL_SUFFIXES "ipaNTAdditionalSuffixes"
+#define IPA_SID_BLACKLIST_INCOMING "ipaNTSIDBlacklistIncoming"
 
 #define IPA_BASE_ID "ipaBaseID"
 #define IPA_ID_RANGE_SIZE "ipaIDRangeSize"
@@ -745,6 +746,129 @@ static void ipa_subdom_store_step(struct sss_domain_info *parent,
     }
 }
 
+static errno_t add_dom_sids_to_list(TALLOC_CTX *mem_ctx, const char **sids,
+                                    char ***list)
+{
+    size_t c;
+    errno_t ret;
+
+    for (c = 0; sids != NULL && sids[c] != NULL; c++) {
+        if (is_domain_sid(sids[c])) {
+            ret = add_string_to_list(mem_ctx, sids[c], list);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "add_string_to_list failed.\n");
+                return ret;
+            }
+        }
+    }
+
+    return EOK;
+}
+
+static errno_t ipa_get_disabled_domain_sids(TALLOC_CTX *mem_ctx, size_t count,
+                                            struct sysdb_attrs **reply,
+                                            char ***disabled_domain_sids)
+{
+    size_t c;
+    char **dom_sid_list = NULL;
+    const char **tmp_list;
+    int ret;
+
+    for (c = 0; c < count; c++) {
+        ret = sysdb_attrs_get_string_array(reply[c], IPA_SID_BLACKLIST_INCOMING,
+                                           mem_ctx, &tmp_list);
+        if (ret != EOK) {
+            if (ret != ENOENT) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sysdb_attrs_get_string_array failed, list of disabled "
+                      "domains might be incomplete.\n");
+            }
+            continue;
+        }
+
+        ret = add_dom_sids_to_list(mem_ctx, tmp_list, &dom_sid_list);
+        talloc_free(tmp_list);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "add_dom_sids_to_list failed.\n");
+            talloc_free(dom_sid_list);
+            return ret;
+        }
+    }
+
+    *disabled_domain_sids = dom_sid_list;
+
+    return EOK;
+}
+
+static errno_t ipa_subdomains_check_domain_state(struct sss_domain_info *dom,
+                                                 char **disabled_domain_sids)
+{
+    int ret;
+
+    if (dom->domain_id == NULL) {
+        return EINVAL;
+    }
+
+    if (disabled_domain_sids != NULL
+            && string_in_list(dom->domain_id, disabled_domain_sids, true)) {
+        DEBUG(SSSDBG_TRACE_ALL, "Domain [%s] is disabled on the server.\n",
+                                dom->name);
+        /* disable domain if not already disabled */
+        if (sss_domain_get_state(dom) != DOM_DISABLED) {
+            sss_domain_set_state(dom, DOM_DISABLED);
+            ret = sysdb_domain_set_enabled(dom->sysdb, dom->name, false);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_domain_set_enabled failed.\n");
+                return ret;
+            }
+        }
+    } else {
+        /* enabled domain if it was disabled */
+        DEBUG(SSSDBG_TRACE_ALL, "Domain [%s] is enabled on the server.\n",
+                                dom->name);
+        if (sss_domain_get_state(dom) == DOM_DISABLED) {
+            sss_domain_set_state(dom, DOM_ACTIVE);
+            ret = sysdb_domain_set_enabled(dom->sysdb, dom->name, true);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_domain_set_enabled failed.\n");
+                return ret;
+            }
+        }
+    }
+
+    return EOK;
+}
+
+
+static void ipa_subdomains_update_dom_state(struct sss_domain_info *parent,
+                                               int count,
+                                               struct sysdb_attrs **reply)
+{
+    int ret;
+    struct sss_domain_info *dom;
+    char **disabled_domain_sids = NULL;
+
+    ret = ipa_get_disabled_domain_sids(reply, count, reply,
+                                       &disabled_domain_sids);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "ipa_get_disabled_domain_sids failed, "
+                                 "assuming no domain is disabled.\n");
+        disabled_domain_sids = NULL;
+    }
+
+    for (dom = get_next_domain(parent, SSS_GND_DESCEND|SSS_GND_INCLUDE_DISABLED);
+         dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
+         dom = get_next_domain(dom, SSS_GND_INCLUDE_DISABLED)) {
+
+        /* check if domain should be disabled/enabled */
+        ret = ipa_subdomains_check_domain_state(dom, disabled_domain_sids);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to check domain state, "
+                  "state of domain [%s] might be wrong.\n", dom->name);
+        }
+    }
+}
+
 static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
                                       int count, struct sysdb_attrs **reply,
                                       bool *changes)
@@ -1376,7 +1500,7 @@ ipa_subdomains_slave_send(TALLOC_CTX *mem_ctx,
     errno_t ret;
     const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID,
                             IPA_TRUST_DIRECTION, IPA_ADDITIONAL_SUFFIXES,
-                            NULL };
+                            IPA_SID_BLACKLIST_INCOMING, NULL };
 
     req = tevent_req_create(mem_ctx, &state,
                             struct ipa_subdomains_slave_state);
@@ -1530,18 +1654,23 @@ static void ipa_subdomains_slave_search_done(struct tevent_req *subreq)
                                  "expected.\n");
     }
 
-    if (!has_changes) {
-        ret = EOK;
-        goto done;
+    /* If there are no changes this step can be skipped, but
+     * ipa_subdomains_update_dom_state() must be called after that in all case
+     * to cover existing an newly added domains. Since the domain state is not
+     * handled by a domain flag but by the blacklist has_changes does not
+     * cover the state. */
+    if (has_changes) {
+        ret = ipa_subdom_reinit(state->sd_ctx);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
+            goto done;
+        }
     }
 
-    ret = ipa_subdom_reinit(state->sd_ctx);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
-        goto done;
-    }
+    ipa_subdomains_update_dom_state(state->sd_ctx->be_ctx->domain,
+                                    reply_count, reply);
 
-    if (state->sd_ctx->ipa_id_ctx->server_mode == NULL) {
+    if (!has_changes || state->sd_ctx->ipa_id_ctx->server_mode == NULL) {
         ret = EOK;
         goto done;
     }

From 2a9c5317036e3af80f3647c90c1fda738ffac846 Mon Sep 17 00:00:00 2001
From: Sumit Bose <[email protected]>
Date: Thu, 12 Sep 2019 14:45:08 +0200
Subject: [PATCH 3/5] ipa: ignore objects from disabled domains on the client

It is possible that a domain is already disabled on an IPA client but
still  active on the server. This might happen e.g. if the version of
SSSD running on the IPA server does not support disabled domains or if
SSSD on the IPA client updates the domain data before the IPA server and
sees a freshly disabled domain more early.

As a result the server is still sending objects from disabled domains in
the lists of group members or group memberships of a user. The client
should just ignore those objects.

Related to https://pagure.io/SSSD/sssd/issue/4078
---
 src/providers/ipa/ipa_s2n_exop.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index e2ab61fe59..38eb530e70 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -637,10 +637,16 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
             }
 
             if (domain != NULL) {
-                obj_domain = find_domain_by_name(parent_domain, domain, true);
+                obj_domain = find_domain_by_name_ex(parent_domain, domain, true, SSS_GND_ALL_DOMAINS);
                 if (obj_domain == NULL) {
                     DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
                     return ENOMEM;
+                } else if (sss_domain_get_state(obj_domain) == DOM_DISABLED) {
+                    /* skipping objects from disabled domains */
+                    DEBUG(SSSDBG_TRACE_ALL,
+                          "Skipping object [%s] from disabled domain.\n",
+                          list[c]);
+                    continue;
                 }
             } else {
                 obj_domain = parent_domain;
@@ -656,6 +662,7 @@ static errno_t add_v1_user_data(struct sss_domain_info *dom,
             gc++;
         }
     }
+    attrs->ngroups = gc;
 
     tag = ber_peek_tag(ber, &ber_len);
     DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
@@ -1634,11 +1641,15 @@ static errno_t process_members(struct sss_domain_info *domain,
     parent_domain = get_domains_head(domain);
 
     for (c = 0; members[c] != NULL; c++) {
-        obj_domain = find_domain_by_object_name(parent_domain, members[c]);
+        obj_domain = find_domain_by_object_name_ex(parent_domain, members[c],
+                                                   false, SSS_GND_ALL_DOMAINS);
         if (obj_domain == NULL) {
             DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_object_name failed.\n");
             ret = ENOMEM;
             goto done;
+        } else if (sss_domain_get_state(obj_domain) == DOM_DISABLED) {
+            /* skip members from disabled domains */
+            continue;
         }
 
         ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], attrs,

From 0b40fac3f827b5f6fe0f861e7309ad900f7abcf6 Mon Sep 17 00:00:00 2001
From: Sumit Bose <[email protected]>
Date: Wed, 18 Sep 2019 17:33:55 +0200
Subject: [PATCH 4/5] sysdb: add sysdb_subdomain_content_delete()

sysdb_subdomain_content_delete() will remove all user and group objects
from a sub-domain container but not the sub-domain object and the user
and group container itself.

Related to https://pagure.io/SSSD/sssd/issue/4078
---
 src/db/sysdb.h            |  8 ++++
 src/db/sysdb_ops.c        | 17 ++++++--
 src/db/sysdb_subdomains.c | 20 ++++++++-
 src/tests/sysdb-tests.c   | 88 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 127 insertions(+), 6 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c6a2389895..b4e190843f 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -554,6 +554,9 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
 
 errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name);
 
+errno_t sysdb_subdomain_content_delete(struct sysdb_ctx *sysdb,
+                                       const char *name);
+
 errno_t sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
                              size_t *range_count,
                              struct range_info ***range_list);
@@ -894,6 +897,11 @@ int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
                            struct ldb_dn *dn,
                            bool ignore_not_found);
 
+int sysdb_delete_recursive_with_filter(struct sysdb_ctx *sysdb,
+                                       struct ldb_dn *dn,
+                                       bool ignore_not_found,
+                                       const char *filter);
+
 /* Mark entry as expired */
 errno_t sysdb_mark_entry_as_expired_ldb_dn(struct sss_domain_info *dom,
                                            struct ldb_dn *ldbdn);
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index c57a13be17..f148e938fc 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -196,9 +196,10 @@ int sysdb_delete_entry(struct sysdb_ctx *sysdb,
 
 /* =Remove-Subentries-From-Sysdb=========================================== */
 
-int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
-                           struct ldb_dn *dn,
-                           bool ignore_not_found)
+int sysdb_delete_recursive_with_filter(struct sysdb_ctx *sysdb,
+                                       struct ldb_dn *dn,
+                                       bool ignore_not_found,
+                                       const char *filter)
 {
     const char *no_attrs[] = { NULL };
     struct ldb_message **msgs;
@@ -219,7 +220,7 @@ int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
     }
 
     ret = sysdb_search_entry(tmp_ctx, sysdb, dn,
-                             LDB_SCOPE_SUBTREE, "(distinguishedName=*)",
+                             LDB_SCOPE_SUBTREE, filter,
                              no_attrs, &msgs_count, &msgs);
     if (ret) {
         if (ignore_not_found && ret == ENOENT) {
@@ -258,6 +259,14 @@ int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
     return ret;
 }
 
+int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
+                           struct ldb_dn *dn,
+                           bool ignore_not_found)
+{
+    return sysdb_delete_recursive_with_filter(sysdb, dn, ignore_not_found,
+                                              "(distinguishedName=*)");
+}
+
 
 /* =Search-Entry========================================================== */
 
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index af838b44c9..0ca6a611f5 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -1250,7 +1250,9 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
     return ret;
 }
 
-errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
+static errno_t sysdb_subdomain_delete_with_filter(struct sysdb_ctx *sysdb,
+                                                  const char *name,
+                                                  const char *filter)
 {
     TALLOC_CTX *tmp_ctx = NULL;
     struct ldb_dn *dn;
@@ -1269,7 +1271,7 @@ errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
         goto done;
     }
 
-    ret = sysdb_delete_recursive(sysdb, dn, true);
+    ret = sysdb_delete_recursive_with_filter(sysdb, dn, true, filter);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n");
         goto done;
@@ -1280,6 +1282,20 @@ errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
     return ret;
 }
 
+errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
+{
+    return sysdb_subdomain_delete_with_filter(sysdb, name,
+                                              "(distinguishedName=*)");
+}
+
+errno_t sysdb_subdomain_content_delete(struct sysdb_ctx *sysdb,
+                                       const char *name)
+{
+    const char *filter = "(|("SYSDB_UC")("SYSDB_GC"))";
+
+    return sysdb_subdomain_delete_with_filter(sysdb, name, filter);
+}
+
 errno_t
 sysdb_domain_get_domain_resolution_order(TALLOC_CTX *mem_ctx,
                                          struct sysdb_ctx *sysdb,
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 87f518baf4..eba91faede 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -6332,6 +6332,93 @@ START_TEST(test_sysdb_subdomain_store_user)
 }
 END_TEST
 
+START_TEST(test_sysdb_subdomain_content_delete)
+{
+    struct sysdb_test_ctx *test_ctx;
+    errno_t ret;
+    struct sss_domain_info *subdomain = NULL;
+    struct ldb_result *results = NULL;
+    struct ldb_dn *base_dn = NULL;
+    struct ldb_dn *check_dn = NULL;
+    struct ldb_dn *check_dom_dn = NULL;
+    struct test_data *data;
+    char *alias;
+
+    ret = setup_sysdb_tests(&test_ctx);
+    fail_if(ret != EOK, "Could not set up the test");
+
+    subdomain = new_subdomain(test_ctx, test_ctx->domain,
+                              testdom[0], testdom[1], testdom[2], testdom[3],
+                              MPG_DISABLED, false, NULL, NULL, 0, NULL, true);
+    fail_unless(subdomain != NULL, "Failed to create new subdomain.");
+    ret = sysdb_subdomain_store(test_ctx->sysdb,
+                                testdom[0], testdom[1], testdom[2], testdom[3],
+                                false, false, NULL, 0, NULL);
+    fail_if(ret != EOK, "Could not set up the test (test subdom)");
+
+    ret = sysdb_update_subdomains(test_ctx->domain, NULL);
+    fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
+                            ret, strerror(ret));
+
+    data = test_data_new_user(test_ctx, 12345);
+    fail_if(data == NULL);
+    data->username = test_asprintf_fqname(data, subdomain, "SubDomUser");
+
+    alias = test_asprintf_fqname(data, subdomain, "subdomuser");
+    fail_if(alias == NULL);
+
+    ret = sysdb_attrs_add_string(data->attrs, SYSDB_NAME_ALIAS, alias);
+    fail_unless(ret == EOK, "sysdb_store_user failed.");
+
+    ret = sysdb_store_user(subdomain, data->username,
+                           NULL, data->uid, 0, "Sub Domain User",
+                           "/home/subdomuser", "/bin/bash",
+                           NULL, data->attrs, NULL, -1, 0);
+    fail_unless(ret == EOK, "sysdb_store_user failed.");
+
+    base_dn =ldb_dn_new(test_ctx, test_ctx->sysdb->ldb, "cn=sysdb");
+    fail_unless(base_dn != NULL);
+
+    check_dn = sysdb_user_dn(data, subdomain, data->username);
+    fail_unless(check_dn != NULL);
+
+    ret = ldb_search(test_ctx->sysdb->ldb, test_ctx, &results, base_dn,
+                     LDB_SCOPE_SUBTREE, NULL, "name=%s", data->username);
+    fail_unless(ret == EOK, "ldb_search failed.");
+    fail_unless(results->count == 1, "Unexpected number of results, "
+                                     "expected [%d], got [%d]",
+                                     1, results->count);
+    fail_unless(ldb_dn_compare(results->msgs[0]->dn, check_dn) == 0,
+                "Unexpected DN returned");
+
+    ret = sysdb_subdomain_content_delete(test_ctx->sysdb, testdom[0]);
+    fail_unless(ret == EOK, "sysdb_subdomain_content_delete failed.");
+
+    /* Check if user is removed */
+    ret = ldb_search(test_ctx->sysdb->ldb, test_ctx, &results, base_dn,
+                     LDB_SCOPE_SUBTREE, NULL, "name=%s", alias);
+    fail_unless(ret == EOK, "ldb_search failed.");
+    fail_unless(results->count == 0, "Unexpected number of results, "
+                                     "expected [%d], got [%d]",
+                                     0, results->count);
+
+    check_dom_dn = ldb_dn_new_fmt(test_ctx, test_ctx->sysdb->ldb,
+                                  SYSDB_DOM_BASE, testdom[0]);
+    fail_unless(check_dom_dn != NULL, "ldb_dn_new_fmt failed.");
+
+    /* Check if domain object is still present */
+    ret = ldb_search(test_ctx->sysdb->ldb, test_ctx, &results, base_dn,
+                     LDB_SCOPE_SUBTREE, NULL, "cn=%s", testdom[0]);
+    fail_unless(ret == EOK, "ldb_search failed.");
+    fail_unless(results->count == 1, "Unexpected number of results, "
+                                     "expected [%d], got [%d]",
+                                     1, results->count);
+    fail_unless(ldb_dn_compare(results->msgs[0]->dn, check_dom_dn) == 0,
+                "Unexpected DN returned");
+
+}
+END_TEST
+
 START_TEST(test_sysdb_subdomain_user_ops)
 {
     struct sysdb_test_ctx *test_ctx;
@@ -7707,6 +7794,7 @@ Suite *create_sysdb_suite(void)
     TCase *tc_subdomain = tcase_create("SYSDB sub-domain Tests");
 
     tcase_add_test(tc_subdomain, test_sysdb_subdomain_store_user);
+    tcase_add_test(tc_subdomain, test_sysdb_subdomain_content_delete);
     tcase_add_test(tc_subdomain, test_sysdb_subdomain_user_ops);
     tcase_add_test(tc_subdomain, test_sysdb_subdomain_group_ops);
 

From c6e6b31fc7ba1b8e83dc73c24d3a36e3fd6573ca Mon Sep 17 00:00:00 2001
From: Sumit Bose <[email protected]>
Date: Wed, 18 Sep 2019 18:09:23 +0200
Subject: [PATCH 5/5] ipa: delete content of disabled domains

Related to https://pagure.io/SSSD/sssd/issue/4078
---
 src/providers/ipa/ipa_subdomains.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 2aa3da9cc4..03127e0f4c 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -821,6 +821,13 @@ static errno_t ipa_subdomains_check_domain_state(struct sss_domain_info *dom,
                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_domain_set_enabled failed.\n");
                 return ret;
             }
+
+            ret = sysdb_subdomain_content_delete(dom->sysdb, dom->name);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sysdb_subdomain_content_delete failed.\n");
+                return ret;
+            }
         }
     } else {
         /* enabled domain if it was disabled */
_______________________________________________
sssd-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
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/[email protected]

Reply via email to