>From 41c562640b13e9d3aa7afc04cf4f43d9616bda2a Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Mon, 14 Jan 2013 20:30:04 -0500
Subject: [PATCH 09/11] Change the way domains are linked.

- Use a double-linked list for domains and subdomains.
- Never remove a subdomain, simply mark it as disabled if it becomes
  unused.
- Rework the way subdomains are refreshed.
  Now sysdb_update_subdomains() actually updates the current subdomains
  and marks as disabled the ones not found in the sysdb or add new ones
  found. It never removes them.
  Removal of missing domains from sysdb is deferred to the providers,
  which will perform it at refresh time, for the ipa provider that is
  done by ipa_subdomains_write_mappings() now.
  sysdb_update_subdomains() is then used to update the memory hierarchy
  of the subdomains.

- Removes sysdb_get_subdomains()
- Removes copy_subdomain()
- Add sysdb_subdomain_delete()
---
 src/confdb/confdb.c                          |  10 +-
 src/confdb/confdb.h                          |   4 +-
 src/db/sysdb.h                               |   7 +-
 src/db/sysdb_subdomains.c                    | 167 +++++++++++----------------
 src/providers/ipa/ipa_subdomains.c           | 152 ++++++++----------------
 src/responder/common/responder_common.c      |  31 ++---
 src/responder/common/responder_get_domains.c |  68 ++++-------
 src/responder/pac/pacsrv_utils.c             |  11 +-
 src/tests/pac_responder-tests.c              |  41 +++----
 src/tests/sysdb-tests.c                      |  87 +++++---------
 src/util/domain_info_utils.c                 |  33 ++++--
 src/util/usertools.c                         |  20 +---
 src/util/util.h                              |   6 +-
 13 files changed, 224 insertions(+), 413 deletions(-)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index 14e9f057ca8cd0b3c35c66abc5c4955749776e90..31efd9443be8490715961c8a45f9352bd1ade653 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -1122,7 +1122,7 @@ int confdb_get_domains(struct confdb_ctx *cdb,
                        struct sss_domain_info **domains)
 {
     TALLOC_CTX *tmp_ctx;
-    struct sss_domain_info *domain, *prevdom = NULL;
+    struct sss_domain_info *domain = NULL;
     char **domlist;
     int ret, i;
 
@@ -1155,13 +1155,7 @@ int confdb_get_domains(struct confdb_ctx *cdb,
             continue;
         }
 
-        if (cdb->doms == NULL) {
-            cdb->doms = domain;
-            prevdom = cdb->doms;
-        } else {
-            prevdom->next = domain;
-            prevdom = domain;
-        }
+        DLIST_ADD_END(cdb->doms, domain, struct sss_domain_info *);
     }
 
     if (cdb->doms == NULL) {
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 71c30367f6f9901bf4b4d19aa976676bcfc8c392..c1b9253497a04d04242bce51cdee02d9517012be 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -229,14 +229,14 @@ struct sss_domain_info {
     struct sysdb_ctx *sysdb;
     struct sss_names_ctx *names;
 
-    struct sss_domain_info **subdomains;
-    uint32_t subdomain_count;
     struct sss_domain_info *parent;
+    struct sss_domain_info *subdomains;
     char *realm;
     char *flat_name;
     char *domain_id;
     struct timeval subdomains_last_checked;
 
+    struct sss_domain_info *prev;
     struct sss_domain_info *next;
 
     bool disabled;
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 2bc858edb215abe1f6684333745485e52a3023a7..fff97a8aaf2d0b2d31debaa3517139df820ea317 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -355,11 +355,6 @@ int sysdb_transaction_commit(struct sysdb_ctx *sysdb);
 int sysdb_transaction_cancel(struct sysdb_ctx *sysdb);
 
 /* functions related to subdomains */
-errno_t sysdb_get_subdomains(TALLOC_CTX *mem_ctx,
-                             struct sss_domain_info *domain,
-                             size_t *subdomain_count,
-                             struct sss_domain_info ***subdomain_list);
-
 errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name);
 
 errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
@@ -374,6 +369,8 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
                                      const char *realm, const char *flat,
                                      const char *id);
 
+errno_t sysdb_subdomain_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);
diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
index c2719075740294b17b1d906f0ede1bb6c631d5bb..3e0d7b40a3ac2efb598ef20f0c0932696d824359 100644
--- a/src/db/sysdb_subdomains.c
+++ b/src/db/sysdb_subdomains.c
@@ -23,10 +23,7 @@
 #include "util/util.h"
 #include "db/sysdb_private.h"
 
-errno_t sysdb_get_subdomains(TALLOC_CTX *mem_ctx,
-                             struct sss_domain_info *domain,
-                             size_t *subdomain_count,
-                             struct sss_domain_info ***subdomain_list)
+errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
 {
     int i;
     errno_t ret;
@@ -37,7 +34,7 @@ errno_t sysdb_get_subdomains(TALLOC_CTX *mem_ctx,
                            SYSDB_SUBDOMAIN_FLAT,
                            SYSDB_SUBDOMAIN_ID,
                            NULL};
-    struct sss_domain_info **list;
+    struct sss_domain_info *dom;
     struct ldb_dn *basedn;
 
     tmp_ctx = talloc_new(NULL);
@@ -59,10 +56,14 @@ errno_t sysdb_get_subdomains(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    list = talloc_zero_array(tmp_ctx, struct sss_domain_info *,
-                             res->count + 1);
-    if (list == NULL) {
-        ret = ENOMEM;
+    /* disable all domains,
+     * let the search result refresh any that are still valid */
+    for (dom = domain->subdomains; dom; dom = get_next_domain(dom, false)) {
+        dom->disabled = true;
+    }
+
+    if (res->count == 0) {
+        ret = EOK;
         goto done;
     }
 
@@ -90,17 +91,58 @@ errno_t sysdb_get_subdomains(TALLOC_CTX *mem_ctx,
         id = ldb_msg_find_attr_as_string(res->msgs[i],
                                          SYSDB_SUBDOMAIN_ID, NULL);
 
-        list[i] = new_subdomain(list, domain, name, realm, flat, id);
-        if (list[i] == NULL) {
-            ret = ENOMEM;
-            goto done;
+        /* explicitly use dom->next as we need to check 'disabled' domains */
+        for (dom = domain->subdomains; dom; dom = dom->next) {
+            if (strcasecmp(dom->name, name) == 0) {
+                dom->disabled = false;
+                /* in theory these may change, but it should never happen */
+                if (strcasecmp(dom->realm, realm) != 0) {
+                    DEBUG(SSSDBG_TRACE_INTERNAL,
+                          ("Realm name changed from [%s] to [%s]!\n",
+                           dom->realm, realm));
+                    talloc_zfree(dom->realm);
+                    dom->realm = talloc_strdup(dom, realm);
+                    if (dom->realm == NULL) {
+                        ret = ENOMEM;
+                        goto done;
+                    }
+                }
+                if (strcasecmp(dom->flat_name, flat) != 0) {
+                    DEBUG(SSSDBG_TRACE_INTERNAL,
+                          ("Flat name changed from [%s] to [%s]!\n",
+                           dom->flat_name, flat));
+                    talloc_zfree(dom->flat_name);
+                    dom->flat_name = talloc_strdup(dom, flat);
+                    if (dom->flat_name == NULL) {
+                        ret = ENOMEM;
+                        goto done;
+                    }
+                }
+                if (strcasecmp(dom->domain_id, id) != 0) {
+                    DEBUG(SSSDBG_TRACE_INTERNAL,
+                          ("Domain changed from [%s] to [%s]!\n",
+                           dom->domain_id, id));
+                    talloc_zfree(dom->domain_id);
+                    dom->domain_id = talloc_strdup(dom, id);
+                    if (dom->domain_id == NULL) {
+                        ret = ENOMEM;
+                        goto done;
+                    }
+                }
+                break;
+            }
+        }
+        /* If not found in loop it is a new subdomain */
+        if (dom == NULL) {
+            dom = new_subdomain(domain, domain, name, realm, flat, id);
+            if (dom == NULL) {
+                ret = ENOMEM;
+                goto done;
+            }
+            DLIST_ADD_END(domain->subdomains, dom, struct sss_domain_info *);
         }
     }
 
-    list[res->count] = NULL;
-
-    *subdomain_count = res->count;
-    *subdomain_list = talloc_steal(mem_ctx, list);
     ret = EOK;
 
 done:
@@ -460,18 +502,11 @@ done:
     return ret;
 }
 
-errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
+errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
 {
-    int ret;
-    int sret;
-    size_t c;
-    size_t d;
     TALLOC_CTX *tmp_ctx = NULL;
-    size_t cur_subdomains_count;
-    struct sss_domain_info **cur_subdomains;
     struct ldb_dn *dn;
-    bool in_transaction = false;
-    bool *keep_subdomain;
+    int ret;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -479,90 +514,20 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
         goto done;
     }
 
-    /* Retrieve all subdomains that are currently in sysdb */
-    ret = sysdb_get_subdomains(tmp_ctx, domain, &cur_subdomains_count,
-                               &cur_subdomains);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_get_subdomains failed.\n"));
-        goto done;
-    }
-
-    keep_subdomain = talloc_zero_array(tmp_ctx, bool, cur_subdomains_count);
-    if (keep_subdomain == NULL) {
+    DEBUG(SSSDBG_TRACE_FUNC, ("Removing sub-domain [%s] from db.\n", name));
+    dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, name);
+    if (dn == NULL) {
         ret = ENOMEM;
-        DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero_array failed.\n"));
         goto done;
     }
 
-    ret = sysdb_transaction_start(domain->sysdb);
+    ret = sysdb_delete_recursive(sysdb, dn, true);
     if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_transaction_start failed.\n"));
+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_delete_recursive failed.\n"));
         goto done;
     }
-    in_transaction = true;
-
-    /* Go through a list of retrieved subdomains and:
-     * - if a subdomain already exists in sysdb, mark it for preservation
-     * - if the subdomain doesn't exist in sysdb, create its bare structure
-     */
-    for (c = 0; c < domain->subdomain_count; c++) {
-        for (d = 0; d < cur_subdomains_count; d++) {
-            if (strcasecmp(domain->subdomains[c]->name,
-                           cur_subdomains[d]->name) == 0) {
-                keep_subdomain[d] = true;
-                /* sub-domain already in cache, nothing to do */
-                break;
-            }
-        }
-
-        if (d == cur_subdomains_count) {
-            DEBUG(SSSDBG_TRACE_FUNC, ("Adding sub-domain [%s].\n",
-                                      domain->subdomains[c]->name));
-            ret = sysdb_subdomain_create(domain->subdomains[c]);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_create failed.\n"));
-                goto done;
-            }
-        }
-    }
-
-    /* Now delete all subdomains that have been in sysdb prior to
-     * refreshing the list and are not marked for preservation
-     * (i.e. they are not in the new list of subdomains)
-     */
-    for (d = 0; d < cur_subdomains_count; d++) {
-        if (!keep_subdomain[d]) {
-            DEBUG(SSSDBG_TRACE_FUNC, ("Removing sub-domain [%s].\n",
-                                      cur_subdomains[d]->name));
-            dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE,
-                                cur_subdomains[d]->name);
-            if (dn == NULL) {
-                ret = ENOMEM;
-                goto done;
-            }
-
-            ret = sysdb_delete_recursive(domain->sysdb, dn, true);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE, ("sysdb_delete_recursive failed.\n"));
-                goto done;
-            }
-        }
-    }
-
-    ret = sysdb_transaction_commit(domain->sysdb);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_MINOR_FAILURE, ("Could not commit transaction\n"));
-        goto done;
-    }
-    in_transaction = false;
 
 done:
-    if (in_transaction) {
-        sret = sysdb_transaction_cancel(domain->sysdb);
-        if (sret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
-        }
-    }
     talloc_free(tmp_ctx);
     return ret;
 }
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 312813c00de83ec9f85437f82d206169005430f8..deee153b8b90de6178b27af8f729109e16bcbfc6 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -82,9 +82,8 @@ struct ipa_subdomains_ctx {
 const char *get_flat_name_from_subdomain_name(struct be_ctx *be_ctx,
                                               const char *name)
 {
-    size_t c;
     struct ipa_subdomains_ctx *ctx;
-    struct sss_domain_info *domain;
+    struct sss_domain_info *dom;
 
     ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
                           struct ipa_subdomains_ctx);
@@ -93,14 +92,9 @@ const char *get_flat_name_from_subdomain_name(struct be_ctx *be_ctx,
         return NULL;
     }
 
-    domain = ctx->be_ctx->domain;
-
-    for (c = 0; c < domain->subdomain_count; c++) {
-        if (strcasecmp(domain->subdomains[c]->name, name) == 0 ||
-            (domain->subdomains[c]->flat_name != NULL &&
-             strcasecmp(domain->subdomains[c]->flat_name, name) == 0)) {
-            return domain->subdomains[c]->flat_name;
-        }
+    dom = find_subdomain_by_name(ctx->be_ctx->domain, name, true);
+    if (dom) {
+        return dom->flat_name;
     }
 
     return NULL;
@@ -197,91 +191,56 @@ done:
     return ret;
 }
 
-static errno_t ipa_subdom_parse(TALLOC_CTX *memctx,
-                                struct sss_domain_info *parent,
-                                struct sysdb_attrs *attrs,
-                                struct sss_domain_info **_subdom)
+static errno_t ipa_subdom_store(struct sss_domain_info *domain,
+                                struct sysdb_attrs *attrs)
 {
-    struct sss_domain_info *subdom = *_subdom;
-    const char *value;
+    TALLOC_CTX *tmp_ctx;
+    const char *name;
+    char *realm;
+    const char *flat;
+    const char *id;
     int ret;
 
-    ret = sysdb_attrs_get_string(attrs, IPA_CN, &value);
+    tmp_ctx = talloc_new(domain);
+
+    ret = sysdb_attrs_get_string(attrs, IPA_CN, &name);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-        return ret;
+        goto done;
     }
 
-    if (subdom == NULL) {
-        subdom = new_subdomain(memctx, parent, value, NULL, NULL, NULL);
-        if (subdom == NULL) {
-            return ENOMEM;
-        }
-    } else if (strcmp(subdom->name, value) != 0) {
-        DEBUG(SSSDBG_OP_FAILURE, ("subdomain name mismatch!\n"));
-        return EINVAL;
+    realm = get_uppercase_realm(tmp_ctx, name);
+    if (!realm) {
+        ret = ENOMEM;
+        goto done;
     }
 
-    if (subdom->realm == NULL) {
-        /* Add Realm as upper(domain name), this is generally always correct
-         * with AD domains */
-        subdom->realm = get_uppercase_realm(subdom, subdom->name);
-        if (!subdom->realm) {
-            return ENOMEM;
-        }
-    }
-
-    ret = sysdb_attrs_get_string(attrs, IPA_FLATNAME, &value);
+    ret = sysdb_attrs_get_string(attrs, IPA_FLATNAME, &flat);
     if (ret) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-        return ret;
+        goto done;
     }
 
-    /* in theory this may change, it should never happen, so we will log a
-     * warning if it does, but we will allow it for now */
-    if (subdom->flat_name != NULL) {
-        if (strcmp(subdom->flat_name, value) != 0) {
-            DEBUG(SSSDBG_TRACE_INTERNAL,
-                  ("Flat name for subdomain changed!\n"));
-            talloc_zfree(subdom->flat_name);
-        }
-    }
-    if (subdom->flat_name == NULL) {
-        subdom->flat_name = talloc_strdup(subdom, value);
-        if (subdom->flat_name == NULL) {
-            return ENOMEM;
-        }
-    }
-
-    ret = sysdb_attrs_get_string(attrs, IPA_TRUSTED_DOMAIN_SID, &value);
+    ret = sysdb_attrs_get_string(attrs, IPA_TRUSTED_DOMAIN_SID, &id);
     if (ret) {
         DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
-        return ret;
+        goto done;
     }
 
-    /* in theory this may change, it should never happen, so we will log a
-     * warning if it does, but we will allow it for now */
-    if (subdom->domain_id != NULL) {
-        if (strcmp(subdom->domain_id, value) != 0) {
-            DEBUG(SSSDBG_TRACE_INTERNAL,
-                  ("ID for subdomain changed!\n"));
-            talloc_zfree(subdom->domain_id);
-        }
-    }
-    if (subdom->domain_id == NULL) {
-        subdom->domain_id = talloc_strdup(subdom, value);
-        if (subdom->domain_id == NULL) {
-            return ENOMEM;
-        }
+    ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, id);
+    if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n"));
     }
 
-    *_subdom = subdom;
+done:
+    talloc_free(tmp_ctx);
     return EOK;
 }
 
 static errno_t
 ipa_subdomains_write_mappings(struct sss_domain_info *domain)
 {
+    struct sss_domain_info *dom;
     errno_t ret;
     errno_t err;
     TALLOC_CTX *tmp_ctx;
@@ -290,7 +249,6 @@ ipa_subdomains_write_mappings(struct sss_domain_info *domain)
     int fd = -1;
     mode_t old_mode;
     FILE *fstream = NULL;
-    size_t i;
 
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) return ENOMEM;
@@ -342,12 +300,11 @@ ipa_subdomains_write_mappings(struct sss_domain_info *domain)
         goto done;
     }
 
-    for (i = 0; i < domain->subdomain_count; i++) {
+    for (dom = get_next_domain(domain, true);
+         dom && dom->parent; /* if we get back to a parent, stop */
+         dom = get_next_domain(dom, false)) {
         ret = fprintf(fstream, ".%s = %s\n%s = %s\n",
-                               domain->subdomains[i]->name,
-                               domain->subdomains[i]->realm,
-                               domain->subdomains[i]->name,
-                               domain->subdomains[i]->realm);
+                               dom->name, dom->realm, dom->name, dom->realm);
         if (ret < 0) {
             DEBUG(SSSDBG_CRIT_FAILURE, ("fprintf failed\n"));
             goto done;
@@ -410,18 +367,20 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
                                       int count, struct sysdb_attrs **reply,
                                       bool *changes)
 {
-    struct sss_domain_info *domain;
+    struct sss_domain_info *domain, *dom;
     bool handled[count];
     const char *value;
     int c, h;
     int ret;
-    int i, j;
 
     domain = ctx->be_ctx->domain;
     memset(handled, 0, sizeof(bool) * count);
+    h = 0;
 
     /* check existing subdomains */
-    for (i = 0, h = 0; i < domain->subdomain_count; i++) {
+    for (dom = get_next_domain(domain, true);
+         dom && dom->parent;
+         dom = get_next_domain(dom, false)) {
         for (c = 0; c < count; c++) {
             if (handled[c]) {
                 continue;
@@ -431,26 +390,21 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
                 DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n"));
                 goto done;
             }
-            if (strcmp(value, domain->subdomains[i]->name) == 0) {
+            if (strcmp(value, dom->name) == 0) {
                 break;
             }
         }
 
         if (c >= count) {
             /* ok this subdomain does not exist anymore, let's clean up */
-            for (j = i; j < domain->subdomain_count - 1; j++) {
-                talloc_zfree(domain->subdomains[j]);
-                domain->subdomains[j] = domain->subdomains[j + 1];
+            dom->disabled = true;
+            ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
+            if (ret != EOK) {
+                goto done;
             }
-            if (i != 0) {
-                domain->subdomains[i - 1]->next = domain->subdomains[i];
-            }
-            domain->subdomain_count--;
-            i--;
         } else {
             /* ok let's try to update it */
-            ret = ipa_subdom_parse(domain->subdomains, domain,
-                                   reply[c], &domain->subdomains[i]);
+            ret = ipa_subdom_store(domain, reply[c]);
             if (ret) {
                 DEBUG(SSSDBG_OP_FAILURE, ("Failed to parse subdom data\n"));
                 goto done;
@@ -469,29 +423,15 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
     /* if we get here it means we have changes to the subdomains list */
     *changes = true;
 
-    /* add space for unhandled domains */
-    c = count - h;
-    domain->subdomains = talloc_realloc(domain, domain->subdomains,
-                                        struct sss_domain_info *,
-                                        domain->subdomain_count + c);
-    if (domain->subdomains == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
     for (c = 0; c < count; c++) {
         if (handled[c]) {
             continue;
         }
-        i = domain->subdomain_count;
-        domain->subdomains[i] = NULL;
-        ret = ipa_subdom_parse(domain->subdomains, domain,
-                               reply[c], &domain->subdomains[i]);
+        ret = ipa_subdom_store(domain, reply[c]);
         if (ret) {
             DEBUG(SSSDBG_OP_FAILURE, ("Failed to parse subdom data\n"));
             goto done;
         }
-        domain->subdomain_count++;
     }
 
     ret = EOK;
@@ -499,8 +439,6 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
 done:
     if (ret != EOK) {
         ctx->last_refreshed = 0;
-        domain->subdomain_count = 0;
-        talloc_zfree(domain->subdomains);
     } else {
         ctx->last_refreshed = time(NULL);
     }
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 3a634e03bf481a452db88d90b07ef737e21fc9ac..877181f8df1ad8ba8eaa89ea59b73e90ad8186bc 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -886,41 +886,32 @@ int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain,
 
 struct sss_domain_info *
 responder_get_domain(TALLOC_CTX *sd_mem_ctx, struct resp_ctx *rctx,
-                     const char *domain)
+                     const char *name)
 {
     time_t now = time(NULL);
     time_t time_diff;
     struct sss_domain_info *dom;
     struct sss_domain_info *ret_dom = NULL;
-    int i;
 
-    for (dom = rctx->domains; dom; dom = get_next_domain(dom, false)) {
-        if (strcasecmp(dom->name, domain) == 0 ||
+    for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
+        if (!dom->parent) {
+            time_diff = now - dom->subdomains_last_checked.tv_sec;
+        }
+        if (strcasecmp(dom->name, name) == 0 ||
             (dom->flat_name != NULL &&
-             strcasecmp(dom->flat_name, domain) == 0)) {
+             strcasecmp(dom->flat_name, name) == 0)) {
             ret_dom = dom;
-            break;
-        }
-
-        for (i = 0; i < dom->subdomain_count; i++) {
-            if (strcasecmp(dom->subdomains[i]->name, domain) == 0 ||
-                (dom->subdomains[i]->flat_name != NULL &&
-                 strcasecmp(dom->subdomains[i]->flat_name, domain) == 0)) {
-                /* Sub-domains may come and go, so we better copy the struct
-                 * for each request. */
-                ret_dom = copy_subdomain(sd_mem_ctx, dom->subdomains[i]);
+            if (!dom->parent ||
+                (dom->parent && time_diff < rctx->domains_timeout)) {
                 break;
             }
         }
 
-        time_diff = now - dom->subdomains_last_checked.tv_sec;
-        if (i < dom->subdomain_count && time_diff < rctx->domains_timeout) break;
     }
-    /* FIXME: we might want to return a real error, e.g. if copy_subdomain
-     * fails. */
+
     if (!ret_dom) {
         DEBUG(SSSDBG_OP_FAILURE, ("Unknown domain [%s], checking for"
-                                  "possible subdomains!\n", domain));
+                                  "possible subdomains!\n", name));
     }
 
     return ret_dom;
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
index 77e2b146d6dcc6299c3a28032c4153b80f14eab5..b69875e1c37a52060605db5a4e17f75dc5fd0850 100644
--- a/src/responder/common/responder_get_domains.c
+++ b/src/responder/common/responder_get_domains.c
@@ -280,32 +280,6 @@ static errno_t
 process_subdomains(struct sss_domain_info *domain)
 {
     int ret;
-    size_t c;
-    size_t subdomain_count;
-    struct sss_domain_info **subdomains;
-
-    /* Retrieve all subdomains of this domain from sysdb
-     * and create their struct sss_domain_info representations
-     */
-    ret = sysdb_get_subdomains(domain, domain,
-                               &subdomain_count, &subdomains);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_FUNC_DATA, ("sysdb_get_subdomains failed.\n"));
-        goto done;
-    }
-
-    if (subdomain_count == 0) {
-        talloc_zfree(domain->subdomains);
-        domain->subdomain_count = 0;
-        goto done;
-    }
-
-    /* Link all subdomains into single-linked list
-     * (the list is used when processing all domains)
-     */
-    for (c = 0; c < subdomain_count - 1; c++) {
-        subdomains[c]->next = subdomains[c + 1];
-    }
 
     if (domain->realm == NULL ||
         domain->flat_name == NULL ||
@@ -318,6 +292,15 @@ process_subdomains(struct sss_domain_info *domain)
         }
     }
 
+    /* Retrieve all subdomains of this domain from sysdb
+     * and create their struct sss_domain_info representations
+     */
+    ret = sysdb_update_subdomains(domain);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FUNC_DATA, ("sysdb_update_subdomains failed.\n"));
+        goto done;
+    }
+
     errno = 0;
     ret = gettimeofday(&domain->subdomains_last_checked, NULL);
     if (ret == -1) {
@@ -325,17 +308,12 @@ process_subdomains(struct sss_domain_info *domain)
         goto done;
     }
 
-    talloc_zfree(domain->subdomains);
-    domain->subdomain_count = subdomain_count;
-    domain->subdomains = subdomains;
-
     ret = EOK;
 
 done:
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("Failed to update sub-domains "
                                   "of domain [%s].\n", domain->name));
-        talloc_free(subdomains);
     }
 
     return ret;
@@ -366,32 +344,26 @@ static errno_t check_last_request(struct resp_ctx *rctx, const char *hint)
     struct sss_domain_info *dom;
     time_t now = time(NULL);
     time_t diff;
-    int i;
 
-    diff = now-rctx->get_domains_last_call.tv_sec;
+    diff = now - rctx->get_domains_last_call.tv_sec;
     if (diff >= rctx->domains_timeout) {
         /* Timeout, expired, fetch domains again */
         return EAGAIN;
     }
 
     if (hint != NULL) {
-        dom = rctx->domains;
-        while (dom) {
-            for (i = 0; i< dom->subdomain_count; i++) {
-                if (strcasecmp(dom->subdomains[i]->name, hint) == 0) {
-                    diff = now-dom->subdomains_last_checked.tv_sec;
-                    if (diff >= rctx->domains_timeout) {
-                        /* Timeout, expired, fetch domains again */
-                        return EAGAIN;
-                    }
-                    /* Skip the rest of this domain, but check other domains
-                     * perhaps this subdomain will be also a part of another
-                     * domain where it will need refreshing
-                     */
-                    break;
+        for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
+            if (dom->parent == NULL) {
+                diff = now - dom->subdomains_last_checked.tv_sec;
+                /* not a subdomain */
+                continue;
+            }
+            if (strcasecmp(dom->name, hint) == 0) {
+                if (diff >= rctx->domains_timeout) {
+                    /* Timeout, expired, fetch domains again */
+                    return EAGAIN;
                 }
             }
-            dom = get_next_domain(dom, false);
         }
     }
 
diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
index 57f2a2bb371c1b4e660b5bb2679b190d1e8ee352..44299db6d64c418482479e43dd9dabb0d362ffc5 100644
--- a/src/responder/pac/pacsrv_utils.c
+++ b/src/responder/pac/pacsrv_utils.c
@@ -76,14 +76,13 @@ struct sss_domain_info *find_domain_by_id(struct sss_domain_info *domains,
 {
     struct sss_domain_info *dom;
     struct sss_domain_info *ret_dom = NULL;
-    size_t c;
 
     if (id_str == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, ("Missing domain id.\n"));
         return NULL;
     }
 
-    for (dom = domains; dom; dom = get_next_domain(dom, false)) {
+    for (dom = domains; dom; dom = get_next_domain(dom, true)) {
         if (dom->domain_id == NULL) {
             continue;
         }
@@ -92,14 +91,6 @@ struct sss_domain_info *find_domain_by_id(struct sss_domain_info *domains,
             ret_dom = dom;
             break;
         }
-
-        for (c = 0; c < dom->subdomain_count; c++) {
-            if (strcasecmp(dom->subdomains[c]->domain_id, id_str) == 0) {
-                ret_dom = dom->subdomains[c];
-                break;
-            }
-        }
-
     }
 
     if (!ret_dom) {
diff --git a/src/tests/pac_responder-tests.c b/src/tests/pac_responder-tests.c
index 7d352a0e89e492418513e00adab62027d24b21e7..847dbe009470a3b8bf7931c36062dd3cbde9e722 100644
--- a/src/tests/pac_responder-tests.c
+++ b/src/tests/pac_responder-tests.c
@@ -98,15 +98,7 @@ void pac_setup(void) {
     fail_unless(pac_ctx->rctx->domains->domain_id != NULL,
                 "talloc_strdup failed.");
 
-    pac_ctx->rctx->domains->subdomain_count = 1;
-    pac_ctx->rctx->domains->subdomains = talloc_zero_array(pac_ctx->rctx->domains,
-                                                       struct sss_domain_info *,
-                                       pac_ctx->rctx->domains->subdomain_count);
-    fail_unless(pac_ctx->rctx->domains->subdomains != NULL,
-                "talloc_array_zero failed");
-
-    sd = talloc_zero(pac_ctx->rctx->domains->subdomains,
-                     struct sss_domain_info);
+    sd = talloc_zero(pac_ctx->rctx->domains, struct sss_domain_info);
     fail_unless(sd != NULL, "talloc_zero failed.");
 
     sd->name = talloc_strdup(sd, "remote.dom");
@@ -118,7 +110,7 @@ void pac_setup(void) {
     sd->domain_id = talloc_strdup(sd, test_remote_dom_sid_str);
     fail_unless(sd->domain_id != NULL, "talloc_strdup failed");
 
-    pac_ctx->rctx->domains->subdomains[0] = sd;
+    pac_ctx->rctx->domains->subdomains = sd;
 
     err = sss_idmap_init(idmap_talloc, pac_ctx, idmap_talloc_free,
                          &pac_ctx->idmap_ctx);
@@ -285,8 +277,8 @@ END_TEST
 #define NUM_DOMAINS 10
 START_TEST(pac_test_find_domain_by_id)
 {
+    struct sss_domain_info *domains;
     struct sss_domain_info *dom;
-    struct sss_domain_info **domains;
     size_t c;
     char *id;
 
@@ -296,33 +288,30 @@ START_TEST(pac_test_find_domain_by_id)
     dom = find_domain_by_id(NULL, "id");
     fail_unless(dom == NULL, "Domain returned without domain list.");
 
-    domains = talloc_zero_array(global_talloc_context, struct sss_domain_info *,
-                                NUM_DOMAINS);
+    domains = NULL;
     for (c = 0; c < NUM_DOMAINS; c++) {
-        domains[c] = talloc_zero(domains, struct sss_domain_info);
-        fail_unless(domains[c] != NULL, "talloc_zero failed.");
+        dom = talloc_zero(domains, struct sss_domain_info);
+        fail_unless(dom != NULL, "talloc_zero failed.");
 
-        domains[c]->domain_id = talloc_asprintf(domains[c],
-                                                "ID-of-domains-%zu", c);
-        fail_unless(domains[c]->domain_id != NULL, "talloc_asprintf failed.");
-        if (c > 0) {
-            domains[c-1]->next = domains[c];
-        }
+        dom->domain_id = talloc_asprintf(dom, "ID-of-domains-%zu", c);
+        fail_unless(dom->domain_id != NULL, "talloc_aprintf failed.");
+
+        DLIST_ADD(domains, dom);
     }
 
-    dom = find_domain_by_id(domains[0], NULL);
+    dom = find_domain_by_id(domains, NULL);
     fail_unless(dom == NULL, "Domain returned without search domain.");
 
-    dom = find_domain_by_id(domains[0], "DOES-NOT_EXISTS");
+    dom = find_domain_by_id(domains, "DOES-NOT_EXISTS");
     fail_unless(dom == NULL, "Domain returned with non existing id.");
 
     for (c = 0; c < NUM_DOMAINS; c++) {
         id = talloc_asprintf(global_talloc_context, "ID-of-domains-%zu", c);
         fail_unless(id != NULL, "talloc_asprintf failed.\n");
 
-        dom = find_domain_by_id(domains[0], id);
-        fail_unless(dom == domains[c], "Wrong domain returned for id [%s].",
-                                       id);
+        dom = find_domain_by_id(domains, id);
+        fail_unless((strcmp(dom->domain_id, id) == 0),
+                    "Wrong domain returned for id [%s].", id);
 
         talloc_free(id);
     }
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 58198d5080408adaccaad30f6870e395bb111b0d..081df6cf6258852d197fadca0881b0ccf7765d16 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -4471,90 +4471,54 @@ START_TEST(test_sysdb_subdomain_create)
 {
     struct sysdb_test_ctx *test_ctx;
     errno_t ret;
-    struct sss_domain_info **cur_subdomains = NULL;
-    size_t cur_subdomains_count;
-    struct sss_domain_info *new_subdom1;
-    struct sss_domain_info *new_subdom2;
+    const char const *dom1[4] = { "dom1.sub", "DOM1.SUB", "dom1", "S-1" };
+    const char const *dom2[4] = { "dom2.sub", "DOM2.SUB", "dom2", "S-2" };
 
     ret = setup_sysdb_tests(&test_ctx);
     fail_if(ret != EOK, "Could not set up the test");
 
-    ret = sysdb_get_subdomains(test_ctx, test_ctx->domain,
-                               &cur_subdomains_count, &cur_subdomains);
-    fail_unless(ret == EOK, "sysdb_get_subdomains failed with [%d][%s]",
-                            ret, strerror(ret));
-    fail_unless(cur_subdomains != NULL, "Non zero sub-domains returned.");
-    fail_unless(cur_subdomains[0] == NULL, "No empty sub-domain list returned.");
-
-    test_ctx->domain->subdomains = talloc_array(test_ctx->domain,
-                                                struct sss_domain_info *, 2);
-    fail_unless(test_ctx->domain->subdomains != NULL,
-                "talloc_array_zero failed");
-
-    new_subdom1 = new_subdomain(test_ctx, test_ctx->domain,
-                                "dom1.sub", "DOM1.SUB", "dom1", "S-1");
-    fail_unless(new_subdom1 != NULL, "Failed to create new subdomin.");
-    test_ctx->domain->subdomains[0] = new_subdom1;
-    test_ctx->domain->subdomain_count = 1;
-
     ret = sysdb_subdomain_store(test_ctx->sysdb,
-                                "dom1.sub", "DOM1.SUB", "dom1", "S-1");
+                                dom1[0], dom1[1], dom1[2], dom1[3]);
     fail_if(ret != EOK, "Could not set up the test (dom1)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
     fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
                             ret, strerror(ret));
 
-    ret = sysdb_get_subdomains(test_ctx, test_ctx->domain,
-                               &cur_subdomains_count, &cur_subdomains);
-    fail_unless(ret == EOK, "sysdb_get_subdomains failed with [%d][%s]",
-                            ret, strerror(ret));
-    fail_if(cur_subdomains_count != 1, "Wrong number of sub-domains returned.");
-    fail_if(cur_subdomains[0] == NULL, "Empyt sub-domain list returned.");
-    fail_if(strcmp(cur_subdomains[0]->name, new_subdom1->name) != 0,
+    fail_if(test_ctx->domain->subdomains == NULL, "Empyt sub-domain list.");
+    fail_if(strcmp(test_ctx->domain->subdomains->name, dom1[0]) != 0,
             "Unexpected sub-domain found, expected [%s], got [%s]",
-            new_subdom1->name, cur_subdomains[0]->name);
-
-    new_subdom2 = new_subdomain(test_ctx, test_ctx->domain,
-                                "dom2.sub", "DOM2.SUB", "dom2", "S-2");
-    fail_unless(new_subdom2 != NULL, "Failed to create new subdomin.");
-    test_ctx->domain->subdomains[1] = new_subdom2;
-    test_ctx->domain->subdomain_count = 2;
+            dom1[0], test_ctx->domain->subdomains->name);
 
     ret = sysdb_subdomain_store(test_ctx->sysdb,
-                                "dom2.sub", "DOM2.SUB", "dom2", "S-2");
+                                dom2[0], dom2[1], dom2[2], dom2[3]);
     fail_if(ret != EOK, "Could not set up the test (dom2)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
     fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
                             ret, strerror(ret));
 
-    ret = sysdb_get_subdomains(test_ctx, test_ctx->domain,
-                               &cur_subdomains_count, &cur_subdomains);
-    fail_unless(ret == EOK, "sysdb_get_subdomains failed with [%d][%s]",
-                            ret, strerror(ret));
-    fail_if(cur_subdomains_count != 2, "Wrong number of sub-domains returned.");
-    fail_if(cur_subdomains[1] == NULL, "Empyt sub-domain list returned.");
-    fail_if(strcmp(cur_subdomains[1]->name, new_subdom2->name) != 0,
+    fail_if(test_ctx->domain->subdomains->next == NULL, "Missing sub-domain");
+    fail_if(strcmp(test_ctx->domain->subdomains->next->name, dom2[0]) != 0,
             "Unexpected sub-domain found, expected [%s], got [%s]",
-            new_subdom2->name, cur_subdomains[1]->name);
+            dom2[0], test_ctx->domain->subdomains->next->name);
 
-    test_ctx->domain->subdomain_count = 0;
-    talloc_zfree(test_ctx->domain->subdomains);
+    ret = sysdb_subdomain_delete(test_ctx->sysdb, dom2[0]);
+    fail_if(ret != EOK, "Could not delete subdomain");
+
+    ret = sysdb_subdomain_delete(test_ctx->sysdb, dom1[0]);
+    fail_if(ret != EOK, "Could not delete subdomain");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
     fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]",
                             ret, strerror(ret));
 
-    ret = sysdb_get_subdomains(test_ctx, test_ctx->domain,
-                               &cur_subdomains_count, &cur_subdomains);
-    fail_unless(ret == EOK, "sysdb_get_subdomains failed with [%d][%s]",
-                            ret, strerror(ret));
-    fail_unless(cur_subdomains != NULL, "No sub-domains returned.");
-    fail_if(cur_subdomains[0] != NULL, "No empty sub-domain list returned.");
+    fail_unless(test_ctx->domain->subdomains->disabled, "Subdomain not disabled.");
 }
 END_TEST
 
+const char const *testdom[4] = { "test.sub", "TEST.SUB", "test", "S-3" };
+
 START_TEST(test_sysdb_subdomain_store_user)
 {
     struct sysdb_test_ctx *test_ctx;
@@ -4568,9 +4532,10 @@ START_TEST(test_sysdb_subdomain_store_user)
     fail_if(ret != EOK, "Could not set up the test");
 
     subdomain = new_subdomain(test_ctx, test_ctx->domain,
-                              "test.sub", "TEST.SUB", "test", "S-3");
+                              testdom[0], testdom[1], testdom[2], testdom[3]);
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
-    ret = sysdb_subdomain_create(subdomain);
+    ret = sysdb_subdomain_store(test_ctx->sysdb,
+                              testdom[0], testdom[1], testdom[2], testdom[3]);
     fail_if(ret != EOK, "Could not set up the test (test subdom)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
@@ -4624,9 +4589,10 @@ START_TEST(test_sysdb_subdomain_user_ops)
     fail_if(ret != EOK, "Could not set up the test");
 
     subdomain = new_subdomain(test_ctx, test_ctx->domain,
-                                "test.sub", "TEST.SUB", "test", "S-3");
+                              testdom[0], testdom[1], testdom[2], testdom[3]);
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
-    ret = sysdb_subdomain_create(subdomain);
+    ret = sysdb_subdomain_store(test_ctx->sysdb,
+                              testdom[0], testdom[1], testdom[2], testdom[3]);
     fail_if(ret != EOK, "Could not set up the test (test subdom)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
@@ -4676,9 +4642,10 @@ START_TEST(test_sysdb_subdomain_group_ops)
     fail_if(ret != EOK, "Could not set up the test");
 
     subdomain = new_subdomain(test_ctx, test_ctx->domain,
-                                "test.sub", "TEST.SUB", "test", "S-3");
+                              testdom[0], testdom[1], testdom[2], testdom[3]);
     fail_unless(subdomain != NULL, "Failed to create new subdomin.");
-    ret = sysdb_subdomain_create(subdomain);
+    ret = sysdb_subdomain_store(test_ctx->sysdb,
+                              testdom[0], testdom[1], testdom[2], testdom[3]);
     fail_if(ret != EOK, "Could not set up the test (test subdom)");
 
     ret = sysdb_update_subdomains(test_ctx->domain);
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 59d5c534bc753d8d3fd3740bf9309413ee8598fe..6db7e157a3e6d1ce84c8dcb0ffc0b45552c6603a 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -29,8 +29,8 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
 
     dom = domain;
     while (dom) {
-        if (descend && dom->subdomain_count > 0) {
-            dom = dom->subdomains[0];
+        if (descend && dom->subdomains) {
+            dom = dom->subdomains;
         } else if (dom->next) {
             dom = dom->next;
         } else if (descend && dom->parent) {
@@ -44,6 +44,27 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
     return dom;
 }
 
+struct sss_domain_info *find_subdomain_by_name(struct sss_domain_info *domain,
+                                               const char *name,
+                                               bool match_any)
+{
+    struct sss_domain_info *dom = domain;
+
+    while (dom && dom->disabled) {
+        dom = get_next_domain(dom, true);
+    }
+    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, true);
+    }
+
+    return NULL;
+}
+
 struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       struct sss_domain_info *parent,
                                       const char *name,
@@ -136,14 +157,6 @@ fail:
     return NULL;
 }
 
-struct sss_domain_info *copy_subdomain(TALLOC_CTX *mem_ctx,
-                                       struct sss_domain_info *subdomain)
-{
-    return new_subdomain(mem_ctx, subdomain->parent,
-                         subdomain->name, subdomain->realm,
-                         subdomain->flat_name, subdomain->domain_id);
-}
-
 errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
                          struct confdb_ctx *cdb,
                          const char *domain_name,
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 33a2a7bd5979925ff660dcb7075d2e73a6b4d869..587fd9cbfe083dcf0082eb2f8a41b5ef4912333c 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -298,24 +298,16 @@ int sss_parse_name(TALLOC_CTX *memctx,
     return EOK;
 }
 
-static struct sss_domain_info * match_any_domain_or_subdomain_name (
-        struct sss_domain_info *dom, const char *dmatch)
+static struct sss_domain_info * match_any_domain_or_subdomain_name(
+                                                struct sss_domain_info *dom,
+                                                const char *dmatch)
 {
-    uint32_t i;
-
-    if (strcasecmp (dom->name, dmatch) == 0 ||
-        (dom->flat_name != NULL && strcasecmp(dom->flat_name, dmatch) == 0))
+    if (strcasecmp(dom->name, dmatch) == 0 ||
+        (dom->flat_name != NULL && strcasecmp(dom->flat_name, dmatch) == 0)) {
         return dom;
-
-    for (i = 0; i < dom->subdomain_count; i++) {
-        if (strcasecmp(dom->subdomains[i]->name, dmatch) == 0 ||
-            (dom->subdomains[i]->flat_name != NULL &&
-             strcasecmp(dom->subdomains[i]->flat_name, dmatch) == 0)) {
-            return dom->subdomains[i];
-        }
     }
 
-    return NULL;
+    return find_subdomain_by_name(dom, dmatch, true);
 }
 
 int sss_parse_name_for_domains(TALLOC_CTX *memctx,
diff --git a/src/util/util.h b/src/util/util.h
index de212811f315700cf4c4bebf79055f9e95fa38bc..7697dbb51bca4bc158528105cfd648717352579a 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -568,14 +568,16 @@ void to_sized_string(struct sized_string *out, const char *in);
 /* form domain_info.c */
 struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
                                         bool descend);
+struct sss_domain_info *find_subdomain_by_name(struct sss_domain_info *domain,
+                                               const char *name,
+                                               bool match_any);
+
 struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       struct sss_domain_info *parent,
                                       const char *name,
                                       const char *realm,
                                       const char *flat_name,
                                       const char *id);
-struct sss_domain_info *copy_subdomain(TALLOC_CTX *mem_ctx,
-                                       struct sss_domain_info *subdomain);
 
 errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
                          struct confdb_ctx *cdb,
-- 
1.8.1.2

