>From f88f24c77d92e7a1cc854dc6fdae71a2ea58fceb Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Mon, 14 Jan 2013 17:04:00 -0500
Subject: [PATCH 07/12] Add function get_next_domain()

Use this function instead of explicitly calling domain->next

This function allows to get the next primary domain or to descend into the
subdomains and replaces also get_next_dom_or_subdom()
---
 src/confdb/confdb.c                          |  2 +-
 src/monitor/monitor.c                        | 10 +--
 src/responder/autofs/autofssrv_cmd.c         |  8 +--
 src/responder/common/negcache.c              |  8 +--
 src/responder/common/responder_common.c      |  4 +-
 src/responder/common/responder_get_domains.c |  8 +--
 src/responder/nss/nsssrv_cmd.c               | 94 +++++++++++-----------------
 src/responder/nss/nsssrv_netgroup.c          | 10 +--
 src/responder/nss/nsssrv_services.c          | 24 ++++---
 src/responder/pac/pacsrv_utils.c             |  2 +-
 src/responder/pam/pamsrv_cmd.c               |  8 ++-
 src/responder/ssh/sshsrv_cmd.c               | 10 +--
 src/responder/sudo/sudosrv_get_sudorules.c   |  6 +-
 src/tools/sss_cache.c                        |  2 +-
 src/tools/sss_debuglevel.c                   |  6 +-
 src/util/domain_info_utils.c                 | 18 ++++++
 src/util/usertools.c                         |  4 +-
 src/util/util.h                              |  2 +
 18 files changed, 113 insertions(+), 113 deletions(-)

diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
index c2df3a04a4972e99fd524a0370ffd742afa020a1..9d9307eb9b0dca4d17bdcf06f2c2d1b4b4ecb49a 100644
--- a/src/confdb/confdb.c
+++ b/src/confdb/confdb.c
@@ -1189,7 +1189,7 @@ int confdb_get_domain(struct confdb_ctx *cdb,
         return ret;
     }
 
-    for (dom = doms; dom; dom = dom->next) {
+    for (dom = doms; dom; dom = get_next_domain(dom, false)) {
         if (strcasecmp(dom->name, name) == 0) {
             *_domain = dom;
             return EOK;
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 2b699ca7e2ae5cec5320c038ba4b83db808acfb9..2c8cdb607520ac7169a624c30015ccf1a7f9452c 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -772,7 +772,7 @@ static int check_domain_ranges(struct sss_domain_info *domains)
     uint32_t id_min, id_max;
 
     while (dom) {
-        other = dom->next;
+        other = get_next_domain(dom, false);
         if (dom->id_max && dom->id_min > dom->id_max) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   ("Domain '%s' does not have a valid ID range\n", dom->name));
@@ -788,9 +788,9 @@ static int check_domain_ranges(struct sss_domain_info *domains)
                       ("Domains '%s' and '%s' overlap in range %u - %u\n",
                       dom->name, other->name, id_min, id_max));
             }
-            other = other->next;
+            other = get_next_domain(other, false);
         }
-        dom = dom->next;
+        dom = get_next_domain(dom, false);
     }
 
     return EOK;
@@ -811,7 +811,7 @@ static int check_local_domain_unique(struct sss_domain_info *domains)
             break;
         }
 
-        dom = dom->next;
+        dom = get_next_domain(dom, false);
     }
 
     if (count > 1) {
@@ -2235,7 +2235,7 @@ int monitor_process_init(struct mt_ctx *ctx,
 
     /* start providers */
     num_providers = 0;
-    for (dom = ctx->domains; dom; dom = dom->next) {
+    for (dom = ctx->domains; dom; dom = get_next_domain(dom, false)) {
         ret = add_new_provider(ctx, dom->name, 0);
         if (ret != EOK && ret != ENOENT) {
             return ret;
diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
index 7443ebbfaae7f95f7bd4a740cef8820c48738ce5..afb0627c20736de9baa23ccd7d12df2177c26e94 100644
--- a/src/responder/autofs/autofssrv_cmd.c
+++ b/src/responder/autofs/autofssrv_cmd.c
@@ -627,7 +627,7 @@ lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx)
         /* if it is a domainless search, skip domains that require fully
          * qualified names instead */
         while (dom && dctx->cmd_ctx->check_next && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         /* No domains left to search */
@@ -666,7 +666,7 @@ lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx)
             if (!dctx->check_provider) {
                 if (dctx->cmd_ctx->check_next) {
                     DEBUG(SSSDBG_TRACE_INTERNAL, ("Moving on to next domain\n"));
-                    dom = dom->next;
+                    dom = get_next_domain(dom, false);
                     continue;
                 }
                 else break;
@@ -873,8 +873,8 @@ static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
                "Will try to return what we have in cache\n",
                (unsigned int)err_maj, (unsigned int)err_min, err_msg));
         /* Loop to the next domain if possible */
-        if (dctx->domain->next && dctx->cmd_ctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (dctx->cmd_ctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         }
     }
diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 5be1ea688c8770c587e3ceed008147252bf7aeca..57d1fc8b3a05cb37bed038234fd436d28b4fbcc6 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -579,7 +579,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
     int i;
 
     /* Populate domain-specific negative cache entries */
-    for (dom = domain_list; dom; dom = dom->next) {
+    for (dom = domain_list; dom; dom = get_next_domain(dom, false)) {
         conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL,
                                     dom->name);
         if (!conf_path) {
@@ -667,7 +667,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
                 continue;
             }
         } else {
-            for (dom = domain_list; dom; dom = dom->next) {
+            for (dom = domain_list; dom; dom = get_next_domain(dom, false)) {
                 ret = sss_ncache_set_user(ncache, true, dom, name);
                 if (ret != EOK) {
                    DEBUG(1, ("Failed to store permanent user filter for"
@@ -681,7 +681,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
     }
 
     filter_set = false;
-    for (dom = domain_list; dom; dom = dom->next) {
+    for (dom = domain_list; dom; dom = get_next_domain(dom, false)) {
         conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name);
         if (!conf_path) {
             ret = ENOMEM;
@@ -765,7 +765,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
                 continue;
             }
         } else {
-            for (dom = domain_list; dom; dom = dom->next) {
+            for (dom = domain_list; dom; dom = get_next_domain(dom, false)) {
                 ret = sss_ncache_set_group(ncache, true, dom, name);
                 if (ret != EOK) {
                    DEBUG(1, ("Failed to store permanent group filter for"
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 9defdba46a600d9a02a826d5dbfc981819a36e51..3a634e03bf481a452db88d90b07ef737e21fc9ac 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -817,7 +817,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
         return ret;
     }
 
-    for (dom = rctx->domains; dom; dom = dom->next) {
+    for (dom = rctx->domains; dom; dom = get_next_domain(dom, false)) {
         ret = sss_names_init(rctx->cdb, rctx->cdb, dom->name, &dom->names);
         if (ret != EOK) {
             DEBUG(SSSDBG_FATAL_FAILURE,
@@ -894,7 +894,7 @@ responder_get_domain(TALLOC_CTX *sd_mem_ctx, struct resp_ctx *rctx,
     struct sss_domain_info *ret_dom = NULL;
     int i;
 
-    for (dom = rctx->domains; dom; dom = dom->next) {
+    for (dom = rctx->domains; dom; dom = get_next_domain(dom, false)) {
         if (strcasecmp(dom->name, domain) == 0 ||
             (dom->flat_name != NULL &&
              strcasecmp(dom->flat_name, domain) == 0)) {
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
index 7049d60a88dc43dd853fda582719dfd7a96ce2a7..77e2b146d6dcc6299c3a28032c4153b80f14eab5 100644
--- a/src/responder/common/responder_get_domains.c
+++ b/src/responder/common/responder_get_domains.c
@@ -192,7 +192,7 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
 
     state->dom = rctx->domains;
     while(state->dom != NULL && !NEED_CHECK_PROVIDER(state->dom->provider)) {
-        state->dom = state->dom->next;
+        state->dom = get_next_domain(state->dom, false);
     }
 
     if (state->dom == NULL) {
@@ -249,11 +249,11 @@ sss_dp_get_domains_process(struct tevent_req *subreq)
     }
 
     /* Advance to the next domain */
-    state->dom = state->dom->next;
+    state->dom = get_next_domain(state->dom, false);
 
     /* Skip local domains */
     while(state->dom != NULL && !NEED_CHECK_PROVIDER(state->dom->provider)) {
-        state->dom = state->dom->next;
+        state->dom = get_next_domain(state->dom, false);
     }
 
     if (state->dom == NULL) {
@@ -391,7 +391,7 @@ static errno_t check_last_request(struct resp_ctx *rctx, const char *hint)
                     break;
                 }
             }
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
     }
 
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 63d82e22c2510c1c7ffa8d4b8f535d9f92bbadd7..445450eaa4c915cfd9977293003d2c276dabe9ee 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -120,7 +120,7 @@ void nss_update_pw_memcache(struct nss_ctx *nctx)
 
     now = time(NULL);
 
-    for (dom = nctx->rctx->domains; dom != NULL; dom = dom->next) {
+    for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, false)) {
         ret = sysdb_enumpwent(nctx, dom->sysdb, dom, &res);
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
@@ -713,7 +713,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
        /* if it is a domainless search, skip domains that require fully
          * qualified names instead */
         while (dom && cmdctx->check_next && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -742,7 +742,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
                       name, dom->name));
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 continue;
             }
             /* There are no further domains or this was a
@@ -779,7 +779,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx)
 
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 if (dom) continue;
             }
 
@@ -842,8 +842,8 @@ static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min,
         }
 
         /* no previous results, just loop to next domain if possible */
-        if (dctx->domain->next && cmdctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         } else {
             /* nothing available */
@@ -1030,28 +1030,6 @@ static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min,
  *   anything else on a fatal error
  */
 
-struct sss_domain_info *get_next_dom_or_subdom(struct sss_domain_info *dom)
-{
-    /* Note that we don't know if the dom is a domain or a subdomain,
-     * therefore:
-     *
-     * If it is a subdomain and it doesn't have any siblings (subdomains
-     * of the same primary domain), return next primary domain
-     */
-    if (dom->next == NULL && dom->parent != NULL) {
-        return dom->parent->next;
-    }
-
-    /* If it's primary domain, the next returned should be its first
-     * subdomain */
-    if (dom->subdomains != NULL) {
-        return dom->subdomains[0];
-    }
-
-    /* Any other scenario */
-    return dom->next;
-}
-
 static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
 {
     struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
@@ -1072,7 +1050,7 @@ static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
                       "(id out of range)\n",
                       (unsigned long)cmdctx->id, dom->name));
             if (cmdctx->check_next) {
-                dom = get_next_dom_or_subdom(dom);
+                dom = get_next_domain(dom, true);
                 continue;
             }
             return ENOENT;
@@ -1109,7 +1087,7 @@ static int nss_cmd_getpwuid_search(struct nss_dom_ctx *dctx)
         if (dctx->res->count == 0 && !dctx->check_provider) {
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = get_next_dom_or_subdom(dom);
+                dom = get_next_domain(dom, true);
                 continue;
             }
 
@@ -1169,8 +1147,8 @@ static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min,
         }
 
         /* no previous results, just loop to next domain if possible */
-        if (dctx->domain->next && cmdctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         } else {
             /* nothing available */
@@ -1366,7 +1344,7 @@ struct tevent_req *nss_cmd_setpwent_send(TALLOC_CTX *mem_ctx,
     }
 
     /* check if enumeration is enabled in any domain */
-    for (dom = client->rctx->domains; dom; dom = dom->next) {
+    for (dom = client->rctx->domains; dom; dom = get_next_domain(dom, false)) {
         if (dom->enumerate != 0) break;
     }
     state->dctx->domain = dom;
@@ -1479,7 +1457,7 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
 
     while (dom) {
         while (dom && dom->enumerate == 0) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -1537,13 +1515,13 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
         if (ret != EOK) {
             DEBUG(1, ("Enum from cache failed, skipping domain [%s]\n",
                       dom->name));
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
             continue;
         }
 
         if (res->count == 0) {
             DEBUG(4, ("Domain [%s] has no users, skipping.\n", dom->name));
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
             continue;
         }
 
@@ -1561,7 +1539,7 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
         nctx->pctx->num++;
 
         /* do not reply until all domain searches are done */
-        dom = dom->next;
+        dom = get_next_domain(dom, false);
     }
 
     /* We've finished all our lookups
@@ -1858,7 +1836,7 @@ void nss_update_gr_memcache(struct nss_ctx *nctx)
 
     now = time(NULL);
 
-    for (dom = nctx->rctx->domains; dom != NULL; dom = dom->next) {
+    for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, false)) {
         ret = sysdb_enumgrent(nctx, dom->sysdb, dom, &res);
         if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
@@ -2310,7 +2288,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
        /* if it is a domainless search, skip domains that require fully
          * qualified names instead */
         while (dom && cmdctx->check_next && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -2339,7 +2317,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
                     name, dom->name));
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 continue;
             }
             /* There are no further domains or this was a
@@ -2376,7 +2354,7 @@ static int nss_cmd_getgrnam_search(struct nss_dom_ctx *dctx)
 
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 if (dom) continue;
             }
 
@@ -2440,8 +2418,8 @@ static void nss_cmd_getgrnam_dp_callback(uint16_t err_maj, uint32_t err_min,
         }
 
         /* no previous results, just loop to next domain if possible */
-        if (dctx->domain->next && cmdctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         } else {
             /* nothing available */
@@ -2647,7 +2625,7 @@ static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx)
                       "(id out of range)\n",
                       (unsigned long)cmdctx->id, dom->name));
             if (cmdctx->check_next) {
-                dom = get_next_dom_or_subdom(dom);
+                dom = get_next_domain(dom, true);
                 continue;
             }
             return ENOENT;
@@ -2684,7 +2662,7 @@ static int nss_cmd_getgrgid_search(struct nss_dom_ctx *dctx)
         if (dctx->res->count == 0 && !dctx->check_provider) {
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = get_next_dom_or_subdom(dom);
+                dom = get_next_domain(dom, true);
                 continue;
             }
 
@@ -2744,8 +2722,8 @@ static void nss_cmd_getgrgid_dp_callback(uint16_t err_maj, uint32_t err_min,
         }
 
         /* no previous results, just loop to next domain if possible */
-        if (dctx->domain->next && cmdctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         } else {
             /* nothing available */
@@ -2934,7 +2912,7 @@ struct tevent_req *nss_cmd_setgrent_send(TALLOC_CTX *mem_ctx,
     }
 
     /* check if enumeration is enabled in any domain */
-    for (dom = client->rctx->domains; dom; dom = dom->next) {
+    for (dom = client->rctx->domains; dom; dom = get_next_domain(dom, false)) {
         if (dom->enumerate != 0) break;
     }
     state->dctx->domain = dom;
@@ -3047,7 +3025,7 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
 
     while (dom) {
         while (dom && dom->enumerate == 0) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -3105,13 +3083,13 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
         if (ret != EOK) {
             DEBUG(1, ("Enum from cache failed, skipping domain [%s]\n",
                       dom->name));
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
             continue;
         }
 
         if (res->count == 0) {
             DEBUG(4, ("Domain [%s] has no groups, skipping.\n", dom->name));
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
             continue;
         }
 
@@ -3129,7 +3107,7 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
         nctx->gctx->num++;
 
         /* do not reply until all domain searches are done */
-        dom = dom->next;
+        dom = get_next_domain(dom, false);
     }
 
     /* We've finished all our lookups
@@ -3421,7 +3399,7 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx,
         return;
     }
 
-    for (dom = nctx->rctx->domains; dom != NULL; dom = dom->next) {
+    for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, false)) {
         if (strcasecmp(dom->name, domain) == 0) {
             break;
         }
@@ -3589,7 +3567,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
        /* if it is a domainless search, skip domains that require fully
          * qualified names instead */
         while (dom && cmdctx->check_next && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -3618,7 +3596,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
                       name, dom->name));
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 continue;
             }
             /* There are no further domains or this was a
@@ -3651,7 +3629,7 @@ static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx)
 
             /* if a multidomain search, try with next */
             if (cmdctx->check_next) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 if (dom) continue;
             }
 
@@ -3704,8 +3682,8 @@ static void nss_cmd_initgroups_dp_callback(uint16_t err_maj, uint32_t err_min,
         }
 
         /* no previous results, just loop to next domain if possible */
-        if (dctx->domain->next && cmdctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         } else {
             /* nothing available */
diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
index e6debffa52890ad2d9ab01d27c55d14731885172..30459beaa9f9b98aab5d29c81fbc9a195e071bff 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -424,7 +424,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
         /* if it is a domainless search, skip domains that require fully
          * qualified names instead */
         while (dom && step_ctx->check_next && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         /* No domains left to search */
@@ -463,7 +463,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
             /* This netgroup was not found in this domain */
             if (!step_ctx->dctx->check_provider) {
                 if (step_ctx->check_next) {
-                    dom = dom->next;
+                    dom = get_next_domain(dom, false);
                     continue;
                 }
                 else break;
@@ -494,7 +494,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
 
             if (!step_ctx->dctx->check_provider) {
                 if (step_ctx->check_next) {
-                    dom = dom->next;
+                    dom = get_next_domain(dom, false);
                     continue;
                 }
                 else break;
@@ -588,8 +588,8 @@ static void lookup_netgr_dp_callback(uint16_t err_maj, uint32_t err_min,
                   "Will try to return what we have in cache\n",
                   (unsigned int)err_maj, (unsigned int)err_min, err_msg));
         /* Loop to the next domain if possible */
-        if (dctx->domain->next && cmdctx->check_next) {
-            dctx->domain = dctx->domain->next;
+        if (cmdctx->check_next && get_next_domain(dctx->domain, false)) {
+            dctx->domain = get_next_domain(dctx->domain, false);
             dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
         }
     }
diff --git a/src/responder/nss/nsssrv_services.c b/src/responder/nss/nsssrv_services.c
index dd12fa412c051f1e02d4c6320c143b15bfffeb36..ac94ef15c1563fa643959aacff50a917448b7016 100644
--- a/src/responder/nss/nsssrv_services.c
+++ b/src/responder/nss/nsssrv_services.c
@@ -99,7 +99,8 @@ getserv_send(TALLOC_CTX *mem_ctx,
     if (!req) return NULL;
     state->dctx = dctx;
 
-    for (dom = cctx->rctx->domains; dom; dom = dom->next) num_domains++;
+    for (dom = cctx->rctx->domains; dom; dom = get_next_domain(dom, false))
+        num_domains++;
 
     /* Create an array of domains to check. To save resizes, we'll
      * assume that all will be checked
@@ -160,7 +161,7 @@ getserv_send(TALLOC_CTX *mem_ctx,
         /* if it is a domainless search, skip domains that require fully
           * qualified names instead */
          while (dom && cmdctx->check_next && dom->fqnames) {
-             dom = dom->next;
+             dom = get_next_domain(dom, false);
          }
          if (!dom) break;
 
@@ -191,7 +192,7 @@ getserv_send(TALLOC_CTX *mem_ctx,
 
                  /* If this is a multi-domain search, try the next one */
                  if (cmdctx->check_next) {
-                     dom = dom->next;
+                     dom = get_next_domain(dom, false);
                  } else {
                      /* This was a single-domain search.
                       * exit the loop. Since it was negatively-
@@ -232,7 +233,7 @@ getserv_send(TALLOC_CTX *mem_ctx,
 
                  /* If this is a multi-domain search, try the next one */
                  if (cmdctx->check_next) {
-                     dom = dom->next;
+                     dom = get_next_domain(dom, false);
                  } else {
                      /* This was a single-domain search.
                       * exit the loop. Since it was negatively-
@@ -298,7 +299,7 @@ getserv_send(TALLOC_CTX *mem_ctx,
 
              /* If this is a multi-domain search, try the next one */
              if (cmdctx->check_next) {
-                 dom = dom->next;
+                 dom = get_next_domain(dom, false);
              } else {
                  /* This was a single-domain search.
                   * exit the loop.
@@ -380,7 +381,7 @@ getserv_send(TALLOC_CTX *mem_ctx,
 
              /* If this is a multi-domain search, try the next one */
              if (cmdctx->check_next) {
-                 dom = dom->next;
+                 dom = get_next_domain(dom, false);
              } else {
                  /* This was a single-domain search.
                   * exit the loop.
@@ -1257,11 +1258,8 @@ setservent_send(TALLOC_CTX *mem_ctx, struct cli_ctx *cctx)
      * to reallocate later
      */
     num_domains = 0;
-    dom = state->cctx->rctx->domains;
-    while (dom) {
+    for (dom = state->cctx->rctx->domains; dom; dom = get_next_domain(dom, false))
         num_domains++;
-        dom = dom->next;
-    }
 
     state->nctx->svcctx->doms = talloc_zero_array(state->nctx->svcctx,
                                                   struct dom_ctx,
@@ -1306,7 +1304,7 @@ setservent_send(TALLOC_CTX *mem_ctx, struct cli_ctx *cctx)
               ("Error [%s] requesting info from domain [%s]. Skipping.\n",
                strerror(ret), step_ctx->dctx->domain->name));
 
-        step_ctx->dctx->domain = step_ctx->dctx->domain->next;
+        step_ctx->dctx->domain = get_next_domain(step_ctx->dctx->domain, false);
     }
 
     /* All domains failed */
@@ -1501,7 +1499,7 @@ setservent_step_done(struct tevent_req *req)
         svcctx->num++;
     }
 
-    step_ctx->dctx->domain = step_ctx->dctx->domain->next;
+    step_ctx->dctx->domain = get_next_domain(step_ctx->dctx->domain, false);
 
     while (step_ctx->dctx->domain) {
         /* There are more domains to check */
@@ -1515,7 +1513,7 @@ setservent_step_done(struct tevent_req *req)
               ("Error [%s] requesting info from domain [%s]. Skipping.\n",
                strerror(ret), step_ctx->dctx->domain->name));
 
-        step_ctx->dctx->domain = step_ctx->dctx->domain->next;
+        step_ctx->dctx->domain = get_next_domain(step_ctx->dctx->domain, false);
     }
 
     /* All domains have been checked */
diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c
index 202f7ba3233497340e246d6390d82eb1ef4c47ee..57f2a2bb371c1b4e660b5bb2679b190d1e8ee352 100644
--- a/src/responder/pac/pacsrv_utils.c
+++ b/src/responder/pac/pacsrv_utils.c
@@ -83,7 +83,7 @@ struct sss_domain_info *find_domain_by_id(struct sss_domain_info *domains,
         return NULL;
     }
 
-    for (dom = domains; dom; dom = dom->next) {
+    for (dom = domains; dom; dom = get_next_domain(dom, false)) {
         if (dom->domain_id == NULL) {
             continue;
         }
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index dd3637b0f8a6530e80e0b0d9f993a58bf6f34818..d7850efae50b0d6c1f5e4464c6d3e6c6d07fc256 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -1088,7 +1088,9 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
             goto done;
         }
     } else {
-        for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) {
+        for (dom = preq->cctx->rctx->domains;
+             dom;
+             dom = get_next_domain(dom, false)) {
             if (dom->fqnames) continue;
 
             ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
@@ -1186,7 +1188,7 @@ static int pam_check_user_search(struct pam_auth_req *preq)
        /* if it is a domainless search, skip domains that require fully
          * qualified names instead */
         while (dom && !preq->pd->domain && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -1248,7 +1250,7 @@ static int pam_check_user_search(struct pam_auth_req *preq)
         if (preq->res->count == 0) {
             /* if a multidomain search, try with next */
             if (!preq->pd->domain) {
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 continue;
             }
 
diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
index 1f4035e644f2673f82c36646d04d1b817993aca3..07568d6f3d6b70d866cbc8860cf4f789c31f7a96 100644
--- a/src/responder/ssh/sshsrv_cmd.c
+++ b/src/responder/ssh/sshsrv_cmd.c
@@ -173,7 +173,7 @@ ssh_user_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx)
     /* if it is a domainless search, skip domains that require fully
      * qualified names instead */
     while (cmd_ctx->domain && cmd_ctx->check_next && cmd_ctx->domain->fqnames) {
-        cmd_ctx->domain = cmd_ctx->domain->next;
+        cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
     }
 
     if (!cmd_ctx->domain) {
@@ -250,7 +250,7 @@ ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
     if (!res->count) {
         /* if a multidomain search, try with next */
         if (cmd_ctx->check_next) {
-            cmd_ctx->domain = cmd_ctx->domain->next;
+            cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
             return ssh_user_pubkeys_search(cmd_ctx);
         }
 
@@ -303,7 +303,7 @@ ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx)
     /* if it is a domainless search, skip domains that require fully
      * qualified names instead */
     while (cmd_ctx->domain && cmd_ctx->check_next && cmd_ctx->domain->fqnames) {
-        cmd_ctx->domain = cmd_ctx->domain->next;
+        cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
     }
 
     if (!cmd_ctx->domain) {
@@ -375,7 +375,7 @@ ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
     if (ret == ENOENT) {
         /* if a multidomain search, try with next */
         if (cmd_ctx->check_next) {
-            cmd_ctx->domain = cmd_ctx->domain->next;
+            cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
             return ssh_host_pubkeys_search(cmd_ctx);
         }
 
@@ -598,7 +598,7 @@ ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx)
         goto done;
     }
 
-    for (; dom; dom = dom->next) {
+    for (; dom; dom = get_next_domain(dom, false)) {
         sysdb = dom->sysdb;
         if (sysdb == NULL) {
             DEBUG(SSSDBG_FATAL_FAILURE,
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
index a8e866661b0ad66783f01ec37b01100af363ee60..160406b699471d18e6b12f180355e8bfcd1c4039 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -108,7 +108,7 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
        /* if it is a domainless search, skip domains that require fully
         * qualified names instead */
         while (dom && cmd_ctx->check_next && dom->fqnames) {
-            dom = dom->next;
+            dom = get_next_domain(dom, false);
         }
 
         if (!dom) break;
@@ -155,7 +155,7 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
             /* if a multidomain search, try with next */
             if (cmd_ctx->check_next) {
                 dctx->check_provider = true;
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 if (dom) continue;
             }
 
@@ -209,7 +209,7 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
             /* if a multidomain search, try with next */
             if (cmd_ctx->check_next) {
                 dctx->check_provider = true;
-                dom = dom->next;
+                dom = get_next_domain(dom, false);
                 if (dom) continue;
             }
 
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 15dcf7e1c0ffb76d0bf6f3977208a33361e72210..2d9a6b63a80e74bfd14fbf98f318c7a326cf90ac 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -103,7 +103,7 @@ int main(int argc, const char *argv[])
         goto done;
     }
 
-    for (dinfo = tctx->domains; dinfo; dinfo = dinfo->next) {
+    for (dinfo = tctx->domains; dinfo; dinfo = get_next_domain(dinfo, false)) {
         sysdb = dinfo->sysdb;
 
         /* Update filters for each domain */
diff --git a/src/tools/sss_debuglevel.c b/src/tools/sss_debuglevel.c
index e955ec381aa6404ca77864a3c0d3e0b5271e477c..a24bfef58a65c680c76f43695207f772aa9ed027 100644
--- a/src/tools/sss_debuglevel.c
+++ b/src/tools/sss_debuglevel.c
@@ -253,7 +253,7 @@ errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
     if (ret != EOK)
         DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to get domain list\n"));
 
-    for (domain = domain_list; domain != NULL; domain = domain->next)
+    for (domain = domain_list; domain; domain = get_next_domain(domain, false))
         domain_count++;
 
     /* allocate output space */
@@ -275,7 +275,9 @@ errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
         }
     }
 
-    for (domain = domain_list; domain != NULL; domain = domain->next, i++) {
+    for (domain = domain_list;
+         domain;
+         domain = get_next_domain(domain, false), i++) {
         sections[i] = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL,
                                       domain->name);
         if (sections[i] == NULL) {
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 1ff7c0c6d0050bb1a9f5e5a0fd1263ffcfe1e913..8cba7dca7ae095e162ac1f31681020f24be977d0 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -22,6 +22,24 @@
 #include "db/sysdb.h"
 #include "util/util.h"
 
+struct sss_domain_info *get_next_domain(struct sss_domain_info *domain,
+                                        bool descend)
+{
+    struct sss_domain_info *dom;
+
+    dom = domain;
+    if (descend && dom->subdomain_count > 0) {
+        dom = dom->subdomains[0];
+    } else if (dom->next) {
+        dom = dom->next;
+    } else if (descend && dom->parent) {
+        dom = dom->parent->next;
+    } else {
+        dom = NULL;
+    }
+    return dom;
+}
+
 struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
                                       struct sss_domain_info *parent,
                                       const char *name,
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 0a657a1826f06b457fcd62c439b3877183801661..33a2a7bd5979925ff660dcb7075d2e73a6b4d869 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -339,7 +339,7 @@ int sss_parse_name_for_domains(TALLOC_CTX *memctx,
     rname = NULL;
     rdomain = NULL;
 
-    for (dom = domains; dom != NULL; dom = dom->next) {
+    for (dom = domains; dom != NULL; dom = get_next_domain(dom, false)) {
         ret = sss_parse_name(tmp_ctx, dom->names, orig, &dmatch, &nmatch);
         if (ret == EOK) {
             /*
@@ -397,7 +397,7 @@ int sss_parse_name_for_domains(TALLOC_CTX *memctx,
                     goto done;
                 }
 
-                for (dom = domains; dom != NULL; dom = dom->next) {
+                for (dom = domains; dom != NULL; dom = get_next_domain(dom, false)) {
                     match = match_any_domain_or_subdomain_name(dom, rdomain);
                     if (match != NULL) {
                         break;
diff --git a/src/util/util.h b/src/util/util.h
index a2b2a2d3e48d6ba916b4d1d5a62537f85af7e6ce..de212811f315700cf4c4bebf79055f9e95fa38bc 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -566,6 +566,8 @@ struct sized_string {
 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 *new_subdomain(TALLOC_CTX *mem_ctx,
                                       struct sss_domain_info *parent,
                                       const char *name,
-- 
1.8.0.1

