dpward / rpms / sssd

Forked from rpms/sssd 3 years ago
Clone

Blame SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch

bb7cd1
From 5091507c13dfdbde29aa75d6e90eda9ddaa89cff Mon Sep 17 00:00:00 2001
bb7cd1
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
bb7cd1
Date: Sun, 26 Mar 2017 00:27:50 +0100
bb7cd1
Subject: [PATCH 52/54] CACHE_REQ: Make use of domainResolutionOrder
bb7cd1
MIME-Version: 1.0
bb7cd1
Content-Type: text/plain; charset=UTF-8
bb7cd1
Content-Transfer-Encoding: 8bit
bb7cd1
bb7cd1
domainResolutionOrder has been introduced in the previous commits and
bb7cd1
allows the admin to set up a specific order which the domains will be
bb7cd1
resolved during a lookup and with this patch we can take advantage of
bb7cd1
this.
bb7cd1
bb7cd1
In order to have it working a new structure has been added
bb7cd1
(struct domain_resolution_order) to the responder context and will be
bb7cd1
used by the cache_req to perform the lookups based on this list.
bb7cd1
bb7cd1
As the ipaDomainResolutionOrder may be set globally on IPA or per View,
bb7cd1
SSSD does respect the following precedence order: View > Globally.
bb7cd1
bb7cd1
The way the list is built is quite simple, basically having the domains
bb7cd1
present on ipaDomainResolutionOrder as the first domains (in that
bb7cd1
specific order) and then appending the remaining domains to this list.
bb7cd1
The final result is a completely flat list with all the domains
bb7cd1
respecting the specified order (it's important to remember that the
bb7cd1
domains not specified won't follow any specific order, they're just
bb7cd1
"random" based on the domains list present in the responder context.
bb7cd1
bb7cd1
Related:
bb7cd1
https://pagure.io/SSSD/sssd/issue/3001
bb7cd1
bb7cd1
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
bb7cd1
bb7cd1
Reviewed-by: Sumit Bose <sbose@redhat.com>
bb7cd1
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
bb7cd1
---
bb7cd1
 Makefile.am                                       |   3 +
bb7cd1
 src/responder/common/cache_req/cache_req.c        |  89 +++++++-----
bb7cd1
 src/responder/common/cache_req/cache_req_domain.c | 166 ++++++++++++++++++++++
bb7cd1
 src/responder/common/cache_req/cache_req_domain.h |  46 ++++++
bb7cd1
 src/responder/common/responder.h                  |   5 +
bb7cd1
 src/responder/common/responder_common.c           | 153 ++++++++++++++++++++
bb7cd1
 src/responder/common/responder_get_domains.c      |  14 ++
bb7cd1
 src/tests/cmocka/common_mock_resp.c               |   6 +
bb7cd1
 src/tests/cmocka/common_mock_resp_dp.c            |   7 +
bb7cd1
 src/tests/cmocka/test_nss_srv.c                   |   4 +
bb7cd1
 src/tests/cwrap/Makefile.am                       |   1 +
bb7cd1
 11 files changed, 457 insertions(+), 37 deletions(-)
bb7cd1
 create mode 100644 src/responder/common/cache_req/cache_req_domain.c
bb7cd1
 create mode 100644 src/responder/common/cache_req/cache_req_domain.h
bb7cd1
bb7cd1
diff --git a/Makefile.am b/Makefile.am
bb7cd1
index 450785bf4c482cce1e1440f1336879150537888e..573b37c52fdeab1add4ea057e1e1844ea4d348a5 100644
bb7cd1
--- a/Makefile.am
bb7cd1
+++ b/Makefile.am
bb7cd1
@@ -528,6 +528,7 @@ SSSD_CACHE_REQ_OBJ = \
bb7cd1
 	src/responder/common/cache_req/cache_req_result.c \
bb7cd1
 	src/responder/common/cache_req/cache_req_search.c \
bb7cd1
 	src/responder/common/cache_req/cache_req_data.c \
bb7cd1
+	src/responder/common/cache_req/cache_req_domain.c \
bb7cd1
 	src/responder/common/cache_req/plugins/cache_req_common.c \
bb7cd1
 	src/responder/common/cache_req/plugins/cache_req_enum_users.c \
bb7cd1
 	src/responder/common/cache_req/plugins/cache_req_enum_groups.c \
bb7cd1
@@ -689,6 +690,7 @@ dist_noinst_HEADERS = \
bb7cd1
     src/responder/common/iface/responder_iface.h \
bb7cd1
     src/responder/common/iface/responder_iface_generated.h \
bb7cd1
     src/responder/common/cache_req/cache_req.h \
bb7cd1
+    src/responder/common/cache_req/cache_req_domain.h \
bb7cd1
     src/responder/common/cache_req/cache_req_plugin.h \
bb7cd1
     src/responder/common/cache_req/cache_req_private.h \
bb7cd1
     src/responder/common/data_provider/rdp.h \
bb7cd1
@@ -2199,6 +2201,7 @@ responder_socket_access_tests_SOURCES = \
bb7cd1
     src/responder/common/responder_common.c \
bb7cd1
     src/responder/common/responder_packet.c \
bb7cd1
     src/responder/common/responder_cmd.c \
bb7cd1
+    src/responder/common/cache_req/cache_req_domain.c \
bb7cd1
     src/responder/common/data_provider/rdp_message.c \
bb7cd1
     src/responder/common/data_provider/rdp_client.c \
bb7cd1
     $(SSSD_RESPONDER_IFACE_OBJ) \
bb7cd1
diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
bb7cd1
index aca150d69b398ceb1a52e5cd6a87d35dbc87020b..483126396f8addbad744ae03bfc739801cd0c18b 100644
bb7cd1
--- a/src/responder/common/cache_req/cache_req.c
bb7cd1
+++ b/src/responder/common/cache_req/cache_req.c
bb7cd1
@@ -24,6 +24,7 @@
bb7cd1
 #include <errno.h>
bb7cd1
 
bb7cd1
 #include "util/util.h"
bb7cd1
+#include "responder/common/responder.h"
bb7cd1
 #include "responder/common/cache_req/cache_req_private.h"
bb7cd1
 #include "responder/common/cache_req/cache_req_plugin.h"
bb7cd1
 
bb7cd1
@@ -316,7 +317,7 @@ struct cache_req_search_domains_state {
bb7cd1
     struct cache_req *cr;
bb7cd1
 
bb7cd1
     /* work data */
bb7cd1
-    struct sss_domain_info *domain;
bb7cd1
+    struct cache_req_domain *cr_domain;
bb7cd1
     struct sss_domain_info *selected_domain;
bb7cd1
     struct cache_req_result **results;
bb7cd1
     size_t num_results;
bb7cd1
@@ -330,13 +331,14 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req);
bb7cd1
 
bb7cd1
 static void cache_req_search_domains_done(struct tevent_req *subreq);
bb7cd1
 
bb7cd1
-struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
bb7cd1
-                                                 struct tevent_context *ev,
bb7cd1
-                                                 struct cache_req *cr,
bb7cd1
-                                                 struct sss_domain_info *domain,
bb7cd1
-                                                 bool check_next,
bb7cd1
-                                                 bool bypass_cache,
bb7cd1
-                                                 bool bypass_dp)
bb7cd1
+struct tevent_req *
bb7cd1
+cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                              struct tevent_context *ev,
bb7cd1
+                              struct cache_req *cr,
bb7cd1
+                              struct cache_req_domain *cr_domain,
bb7cd1
+                              bool check_next,
bb7cd1
+                              bool bypass_cache,
bb7cd1
+                              bool bypass_dp)
bb7cd1
 {
bb7cd1
     struct tevent_req *req;
bb7cd1
     struct cache_req_search_domains_state *state = NULL;
bb7cd1
@@ -352,7 +354,7 @@ struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
bb7cd1
     state->ev = ev;
bb7cd1
     state->cr = cr;
bb7cd1
 
bb7cd1
-    state->domain = domain;
bb7cd1
+    state->cr_domain = cr_domain;
bb7cd1
     state->check_next = check_next;
bb7cd1
     state->dp_success = true;
bb7cd1
     state->bypass_cache = bypass_cache;
bb7cd1
@@ -378,6 +380,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
bb7cd1
     struct cache_req_search_domains_state *state;
bb7cd1
     struct tevent_req *subreq;
bb7cd1
     struct cache_req *cr;
bb7cd1
+    struct sss_domain_info *domain;
bb7cd1
     uint32_t next_domain_flag;
bb7cd1
     bool is_domain_valid;
bb7cd1
     bool allow_no_fqn;
bb7cd1
@@ -389,11 +392,21 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
bb7cd1
     next_domain_flag = cr->plugin->get_next_domain_flags;
bb7cd1
     allow_no_fqn = cr->plugin->allow_missing_fqn;
bb7cd1
 
bb7cd1
-    while (state->domain != NULL) {
bb7cd1
+    while (state->cr_domain != NULL) {
bb7cd1
+        domain = state->cr_domain->domain;
bb7cd1
+        /* As the cr_domain list is a flatten version of the domains
bb7cd1
+         * list, we have to ensure to only go through the subdomains in
bb7cd1
+         * case it's specified in the plugin to do so.
bb7cd1
+         */
bb7cd1
+        if (next_domain_flag == 0 && IS_SUBDOMAIN(domain)) {
bb7cd1
+            state->cr_domain = state->cr_domain->next;
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
         /* Check if this domain is valid for this request. */
bb7cd1
-        is_domain_valid = cache_req_validate_domain(cr, state->domain);
bb7cd1
+        is_domain_valid = cache_req_validate_domain(cr, domain);
bb7cd1
         if (!is_domain_valid) {
bb7cd1
-            state->domain = get_next_domain(state->domain, next_domain_flag);
bb7cd1
+            state->cr_domain = state->cr_domain->next;
bb7cd1
             continue;
bb7cd1
         }
bb7cd1
 
bb7cd1
@@ -401,18 +414,18 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
bb7cd1
          * qualified names on domain less search. We do not descend into
bb7cd1
          * subdomains here since those are implicitly qualified.
bb7cd1
          */
bb7cd1
-        if (state->check_next && !allow_no_fqn && state->domain->fqnames) {
bb7cd1
-            state->domain = get_next_domain(state->domain, 0);
bb7cd1
+        if (state->check_next && !allow_no_fqn && domain->fqnames) {
bb7cd1
+            state->cr_domain = state->cr_domain->next;
bb7cd1
             continue;
bb7cd1
         }
bb7cd1
 
bb7cd1
-        state->selected_domain = state->domain;
bb7cd1
+        state->selected_domain = domain;
bb7cd1
 
bb7cd1
-        if (state->domain == NULL) {
bb7cd1
+        if (domain == NULL) {
bb7cd1
             break;
bb7cd1
         }
bb7cd1
 
bb7cd1
-        ret = cache_req_set_domain(cr, state->domain);
bb7cd1
+        ret = cache_req_set_domain(cr, domain);
bb7cd1
         if (ret != EOK) {
bb7cd1
             return ret;
bb7cd1
         }
bb7cd1
@@ -427,8 +440,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
bb7cd1
 
bb7cd1
         /* we will continue with the following domain the next time */
bb7cd1
         if (state->check_next) {
bb7cd1
-            state->domain = get_next_domain(state->domain,
bb7cd1
-                                            cr->plugin->get_next_domain_flags);
bb7cd1
+            state->cr_domain = state->cr_domain->next;
bb7cd1
         }
bb7cd1
 
bb7cd1
         return EAGAIN;
bb7cd1
@@ -625,11 +637,12 @@ static void cache_req_input_parsed(struct tevent_req *subreq);
bb7cd1
 static errno_t cache_req_select_domains(struct tevent_req *req,
bb7cd1
                                         const char *domain_name);
bb7cd1
 
bb7cd1
-static errno_t cache_req_search_domains(struct tevent_req *req,
bb7cd1
-                                        struct sss_domain_info *domain,
bb7cd1
-                                        bool check_next,
bb7cd1
-                                        bool bypass_cache,
bb7cd1
-                                        bool bypass_dp);
bb7cd1
+static errno_t
bb7cd1
+cache_req_search_domains(struct tevent_req *req,
bb7cd1
+                         struct cache_req_domain *oredered_domain,
bb7cd1
+                         bool check_next,
bb7cd1
+                         bool bypass_cache,
bb7cd1
+                         bool bypass_dp);
bb7cd1
 
bb7cd1
 static void cache_req_done(struct tevent_req *subreq);
bb7cd1
 
bb7cd1
@@ -778,7 +791,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
bb7cd1
                                         const char *domain_name)
bb7cd1
 {
bb7cd1
     struct cache_req_state *state = NULL;
bb7cd1
-    struct sss_domain_info *domain;
bb7cd1
+    struct cache_req_domain *cr_domain;
bb7cd1
     bool check_next;
bb7cd1
     bool bypass_cache;
bb7cd1
     bool bypass_dp;
bb7cd1
@@ -798,29 +811,30 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
bb7cd1
         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
bb7cd1
                         "Performing a single domain search\n");
bb7cd1
 
bb7cd1
-        domain = responder_get_domain(state->cr->rctx, domain_name);
bb7cd1
-        if (domain == NULL) {
bb7cd1
+        cr_domain = cache_req_domain_get_domain_by_name(
bb7cd1
+                                    state->cr->rctx->cr_domains, domain_name);
bb7cd1
+        if (cr_domain == NULL) {
bb7cd1
             return ERR_DOMAIN_NOT_FOUND;
bb7cd1
         }
bb7cd1
-
bb7cd1
         check_next = false;
bb7cd1
     } else {
bb7cd1
         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
bb7cd1
                         "Performing a multi-domain search\n");
bb7cd1
 
bb7cd1
-        domain = state->cr->rctx->domains;
bb7cd1
+        cr_domain = state->cr->rctx->cr_domains;
bb7cd1
         check_next = true;
bb7cd1
     }
bb7cd1
 
bb7cd1
-    return cache_req_search_domains(req, domain, check_next,
bb7cd1
+    return cache_req_search_domains(req, cr_domain, check_next,
bb7cd1
                                     bypass_cache, bypass_dp);
bb7cd1
 }
bb7cd1
 
bb7cd1
-static errno_t cache_req_search_domains(struct tevent_req *req,
bb7cd1
-                                        struct sss_domain_info *domain,
bb7cd1
-                                        bool check_next,
bb7cd1
-                                        bool bypass_cache,
bb7cd1
-                                        bool bypass_dp)
bb7cd1
+static errno_t
bb7cd1
+cache_req_search_domains(struct tevent_req *req,
bb7cd1
+                         struct cache_req_domain *cr_domain,
bb7cd1
+                         bool check_next,
bb7cd1
+                         bool bypass_cache,
bb7cd1
+                         bool bypass_dp)
bb7cd1
 {
bb7cd1
     struct tevent_req *subreq;
bb7cd1
     struct cache_req_state *state = NULL;
bb7cd1
@@ -832,8 +846,9 @@ static errno_t cache_req_search_domains(struct tevent_req *req,
bb7cd1
                     bypass_cache ? "bypass" : "check",
bb7cd1
                     bypass_dp ? "bypass" : "check");
bb7cd1
 
bb7cd1
-    subreq = cache_req_search_domains_send(state, state->ev, state->cr, domain,
bb7cd1
-                                           check_next, bypass_cache, bypass_dp);
bb7cd1
+    subreq = cache_req_search_domains_send(state, state->ev, state->cr,
bb7cd1
+                                           cr_domain, check_next,
bb7cd1
+                                           bypass_cache, bypass_dp);
bb7cd1
     if (subreq == NULL) {
bb7cd1
         return ENOMEM;
bb7cd1
     }
bb7cd1
diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c
bb7cd1
new file mode 100644
bb7cd1
index 0000000000000000000000000000000000000000..bbabd695f1c6b6c29b7e61f571382ab9adfb0ea2
bb7cd1
--- /dev/null
bb7cd1
+++ b/src/responder/common/cache_req/cache_req_domain.c
bb7cd1
@@ -0,0 +1,166 @@
bb7cd1
+/*
bb7cd1
+    Authors:
bb7cd1
+        Fabiano Fidêncio <fidencio@redhat.com>
bb7cd1
+
bb7cd1
+    Copyright (C) 2017 Red Hat
bb7cd1
+
bb7cd1
+    This program is free software; you can redistribute it and/or modify
bb7cd1
+    it under the terms of the GNU General Public License as published by
bb7cd1
+    the Free Software Foundation; either version 3 of the License, or
bb7cd1
+    (at your option) any later version.
bb7cd1
+
bb7cd1
+    This program is distributed in the hope that it will be useful,
bb7cd1
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
bb7cd1
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bb7cd1
+    GNU General Public License for more details.
bb7cd1
+
bb7cd1
+    You should have received a copy of the GNU General Public License
bb7cd1
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
bb7cd1
+*/
bb7cd1
+
bb7cd1
+#include "responder/common/cache_req/cache_req_domain.h"
bb7cd1
+
bb7cd1
+struct cache_req_domain *
bb7cd1
+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
bb7cd1
+                                    const char *name)
bb7cd1
+{
bb7cd1
+    struct cache_req_domain *dom;
bb7cd1
+    struct cache_req_domain *ret = NULL;
bb7cd1
+
bb7cd1
+    DLIST_FOR_EACH(dom, domains) {
bb7cd1
+        if (sss_domain_get_state(dom->domain) == DOM_DISABLED) {
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        if (strcasecmp(dom->domain->name, name) == 0 ||
bb7cd1
+            (dom->domain->flat_name != NULL &&
bb7cd1
+             strcasecmp(dom->domain->flat_name, name) == 0)) {
bb7cd1
+            ret = dom;
bb7cd1
+            break;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (ret == NULL) {
bb7cd1
+        DEBUG(SSSDBG_OP_FAILURE, "Unknown domains [%s].\n", name);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    return ret;
bb7cd1
+}
bb7cd1
+
bb7cd1
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains)
bb7cd1
+{
bb7cd1
+    struct cache_req_domain *p, *q, *r;
bb7cd1
+
bb7cd1
+    DLIST_FOR_EACH_SAFE(p, q, *cr_domains) {
bb7cd1
+        r = p;
bb7cd1
+        DLIST_REMOVE(*cr_domains, p);
bb7cd1
+        talloc_zfree(r);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    *cr_domains = NULL;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct cache_req_domain *
bb7cd1
+cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx,
bb7cd1
+                                           struct sss_domain_info *domains,
bb7cd1
+                                           char **resolution_order)
bb7cd1
+{
bb7cd1
+    struct cache_req_domain *cr_domains = NULL;
bb7cd1
+    struct cache_req_domain *cr_domain;
bb7cd1
+    struct sss_domain_info *dom;
bb7cd1
+    char *name;
bb7cd1
+    int flag = SSS_GND_ALL_DOMAINS;
bb7cd1
+    int i;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    if (resolution_order != NULL) {
bb7cd1
+        for (i = 0; resolution_order[i] != NULL; i++) {
bb7cd1
+            name = resolution_order[i];
bb7cd1
+            for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
bb7cd1
+                if (strcasecmp(name, dom->name) != 0) {
bb7cd1
+                    continue;
bb7cd1
+                }
bb7cd1
+
bb7cd1
+                cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
bb7cd1
+                if (cr_domain == NULL) {
bb7cd1
+                    ret = ENOMEM;
bb7cd1
+                    goto done;
bb7cd1
+                }
bb7cd1
+                cr_domain->domain = dom;
bb7cd1
+
bb7cd1
+                DLIST_ADD_END(cr_domains, cr_domain,
bb7cd1
+                              struct cache_req_domain *);
bb7cd1
+                break;
bb7cd1
+            }
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
bb7cd1
+        if (string_in_list(dom->name, resolution_order, false)) {
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
bb7cd1
+        if (cr_domain == NULL) {
bb7cd1
+            ret = ENOMEM;
bb7cd1
+            goto done;
bb7cd1
+        }
bb7cd1
+        cr_domain->domain = dom;
bb7cd1
+
bb7cd1
+        DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+
bb7cd1
+done:
bb7cd1
+    if (ret != EOK) {
bb7cd1
+        cache_req_domain_list_zfree(&cr_domains);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    return cr_domains;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct cache_req_domain *
bb7cd1
+cache_req_domain_new_list_from_domain_resolution_order(
bb7cd1
+                                        TALLOC_CTX *mem_ctx,
bb7cd1
+                                        struct sss_domain_info *domains,
bb7cd1
+                                        const char *domain_resolution_order)
bb7cd1
+{
bb7cd1
+    TALLOC_CTX *tmp_ctx;
bb7cd1
+    struct cache_req_domain *cr_domains = NULL;
bb7cd1
+    char **list = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    tmp_ctx = talloc_new(NULL);
bb7cd1
+    if (tmp_ctx == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (domain_resolution_order != NULL) {
bb7cd1
+        if (strcmp(domain_resolution_order, ":") != 0) {
bb7cd1
+            ret = split_on_separator(tmp_ctx, domain_resolution_order, ':',
bb7cd1
+                                     true, true, &list, NULL);
bb7cd1
+            if (ret != EOK) {
bb7cd1
+                DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+                        "split_on_separator() failed [%d]: [%s].\n",
bb7cd1
+                        ret, sss_strerror(ret));
bb7cd1
+                goto done;
bb7cd1
+            }
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains,
bb7cd1
+                                                            list);
bb7cd1
+    if (cr_domains == NULL) {
bb7cd1
+        ret = ENOMEM;
bb7cd1
+        DEBUG(SSSDBG_OP_FAILURE,
bb7cd1
+              "cache_req_domain_new_list_from_domain_resolution_order() "
bb7cd1
+              "failed [%d]: [%s].\n",
bb7cd1
+              ret, sss_strerror(ret));
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+done:
bb7cd1
+    talloc_free(tmp_ctx);
bb7cd1
+    return cr_domains;
bb7cd1
+}
bb7cd1
diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h
bb7cd1
new file mode 100644
bb7cd1
index 0000000000000000000000000000000000000000..41c50e8c293d7b032cb2f05482c40e93e4f723dc
bb7cd1
--- /dev/null
bb7cd1
+++ b/src/responder/common/cache_req/cache_req_domain.h
bb7cd1
@@ -0,0 +1,46 @@
bb7cd1
+/*
bb7cd1
+    Authors:
bb7cd1
+        Fabiano Fidêncio <fidencio@redhat.com>
bb7cd1
+
bb7cd1
+    Copyright (C) 2017 Red Hat
bb7cd1
+
bb7cd1
+    This program is free software; you can redistribute it and/or modify
bb7cd1
+    it under the terms of the GNU General Public License as published by
bb7cd1
+    the Free Software Foundation; either version 3 of the License, or
bb7cd1
+    (at your option) any later version.
bb7cd1
+
bb7cd1
+    This program is distributed in the hope that it will be useful,
bb7cd1
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
bb7cd1
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bb7cd1
+    GNU General Public License for more details.
bb7cd1
+
bb7cd1
+    You should have received a copy of the GNU General Public License
bb7cd1
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
bb7cd1
+*/
bb7cd1
+
bb7cd1
+#ifndef _CACHE_REQ_DOMAIN_H_
bb7cd1
+#define _CACHE_REQ_DOMAIN_H_
bb7cd1
+
bb7cd1
+#include "responder/common/responder.h"
bb7cd1
+
bb7cd1
+struct cache_req_domain {
bb7cd1
+    struct sss_domain_info *domain;
bb7cd1
+
bb7cd1
+    struct cache_req_domain *prev;
bb7cd1
+    struct cache_req_domain *next;
bb7cd1
+};
bb7cd1
+
bb7cd1
+struct cache_req_domain *
bb7cd1
+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
bb7cd1
+                                    const char *name);
bb7cd1
+
bb7cd1
+struct cache_req_domain *
bb7cd1
+cache_req_domain_new_list_from_domain_resolution_order(
bb7cd1
+                                        TALLOC_CTX *mem_ctx,
bb7cd1
+                                        struct sss_domain_info *domains,
bb7cd1
+                                        const char *domain_resolution_order);
bb7cd1
+
bb7cd1
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains);
bb7cd1
+
bb7cd1
+
bb7cd1
+#endif /* _CACHE_REQ_DOMAIN_H_ */
bb7cd1
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
bb7cd1
index 4d1048a1e0c9be2cad91317d51baf670ecb3307e..29e3f95caf484f43307c9c28d4abd3f50f360a95 100644
bb7cd1
--- a/src/responder/common/responder.h
bb7cd1
+++ b/src/responder/common/responder.h
bb7cd1
@@ -37,6 +37,7 @@
bb7cd1
 #include "sbus/sssd_dbus.h"
bb7cd1
 #include "responder/common/negcache.h"
bb7cd1
 #include "sss_client/sss_cli.h"
bb7cd1
+#include "responder/common/cache_req/cache_req_domain.h"
bb7cd1
 
bb7cd1
 extern hash_table_t *dp_requests;
bb7cd1
 
bb7cd1
@@ -113,6 +114,8 @@ struct resp_ctx {
bb7cd1
     int domains_timeout;
bb7cd1
     int client_idle_timeout;
bb7cd1
 
bb7cd1
+    struct cache_req_domain *cr_domains;
bb7cd1
+
bb7cd1
     time_t last_request_time;
bb7cd1
     int idle_timeout;
bb7cd1
     struct tevent_timer *idle;
bb7cd1
@@ -387,4 +390,6 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx,
bb7cd1
                              bool name_is_upn,
bb7cd1
                              const char *orig_name);
bb7cd1
 
bb7cd1
+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx);
bb7cd1
+
bb7cd1
 #endif /* __SSS_RESPONDER_H__ */
bb7cd1
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
bb7cd1
index 76f43609651217e537ffa515aaf5b5caa98a2e90..1792a4c3771fa326c7cca31e1981dce315c03758 100644
bb7cd1
--- a/src/responder/common/responder_common.c
bb7cd1
+++ b/src/responder/common/responder_common.c
bb7cd1
@@ -1453,3 +1453,156 @@ fail:
bb7cd1
     return ret;
bb7cd1
 
bb7cd1
 }
bb7cd1
+
bb7cd1
+/* ====== Helper functions for the domain resolution order ======= */
bb7cd1
+static struct cache_req_domain *
bb7cd1
+sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx,
bb7cd1
+                                         struct sss_domain_info *domains,
bb7cd1
+                                         struct sysdb_ctx *sysdb)
bb7cd1
+{
bb7cd1
+    TALLOC_CTX *tmp_ctx;
bb7cd1
+    struct cache_req_domain *cr_domains = NULL;
bb7cd1
+    const char *domain_resolution_order = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    tmp_ctx = talloc_new(NULL);
bb7cd1
+    if (tmp_ctx == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb,
bb7cd1
+                                                 &domain_resolution_order);
bb7cd1
+    if (ret != EOK && ret != ENOENT) {
bb7cd1
+        DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+              "sysdb_get_view_cache_req_domain() failed [%d]: [%s].\n",
bb7cd1
+              ret, sss_strerror(ret));
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    /* Using mem_ctx (which is rctx) directly here to avoid copying
bb7cd1
+     * this memory around. */
bb7cd1
+    cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
bb7cd1
+                                    mem_ctx, domains, domain_resolution_order);
bb7cd1
+    if (cr_domains == NULL) {
bb7cd1
+        ret = ENOMEM;
bb7cd1
+        DEBUG(SSSDBG_DEFAULT,
bb7cd1
+              "cache_req_domain_new_list_from_domain_resolution_order() "
bb7cd1
+              "failed [%d]: [%s].\n",
bb7cd1
+              ret, sss_strerror(ret));
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+done:
bb7cd1
+    talloc_free(tmp_ctx);
bb7cd1
+    return cr_domains;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct cache_req_domain *
bb7cd1
+sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx,
bb7cd1
+                                        struct sss_domain_info *domains,
bb7cd1
+                                        struct sysdb_ctx *sysdb,
bb7cd1
+                                        const char *domain)
bb7cd1
+{
bb7cd1
+    TALLOC_CTX *tmp_ctx;
bb7cd1
+    struct cache_req_domain *cr_domains = NULL;
bb7cd1
+    const char *domain_resolution_order = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    tmp_ctx = talloc_new(NULL);
bb7cd1
+    if (tmp_ctx == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain,
bb7cd1
+                                                   &domain_resolution_order);
bb7cd1
+
bb7cd1
+    if (ret != EOK && ret != ENOENT) {
bb7cd1
+        DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+              "sysdb_domain_get_cache_req_domain() failed [%d]: [%s].\n",
bb7cd1
+              ret, sss_strerror(ret));
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    /* Using mem_ctx (which is rctx) directly here to avoid copying
bb7cd1
+     * this memory around. */
bb7cd1
+    cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
bb7cd1
+                                    mem_ctx, domains, domain_resolution_order);
bb7cd1
+    if (cr_domains == NULL) {
bb7cd1
+        DEBUG(SSSDBG_DEFAULT,
bb7cd1
+              "cache_req_domain_new_list_from_domain_resolution_order() "
bb7cd1
+              "failed [%d]: [%s].\n",
bb7cd1
+              ret, sss_strerror(ret));
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+done:
bb7cd1
+    talloc_free(tmp_ctx);
bb7cd1
+    return cr_domains;
bb7cd1
+}
bb7cd1
+
bb7cd1
+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx)
bb7cd1
+{
bb7cd1
+    struct cache_req_domain *cr_domains = NULL;
bb7cd1
+    struct sss_domain_info *dom;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    for (dom = rctx->domains; dom != NULL; dom = dom->next) {
bb7cd1
+        if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) {
bb7cd1
+            break;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (dom == NULL) {
bb7cd1
+        cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
bb7cd1
+                                                    rctx, rctx->domains, NULL);
bb7cd1
+        if (cr_domains == NULL) {
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE,
bb7cd1
+                  "Failed to flatten the list of domains.\n");
bb7cd1
+        }
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (dom->has_views) {
bb7cd1
+        cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx,
bb7cd1
+                                                              rctx->domains,
bb7cd1
+                                                              dom->sysdb);
bb7cd1
+        if (cr_domains == NULL) {
bb7cd1
+            DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+                  "Failed to use ipaDomainResolutionOrder set for the "
bb7cd1
+                  "view \"%s\".\n"
bb7cd1
+                  "Trying to fallback to use ipaDomainOrderResolution "
bb7cd1
+                  "set in ipaConfig for the domain: %s.\n",
bb7cd1
+                  dom->view_name, dom->name);
bb7cd1
+        } else {
bb7cd1
+            goto done;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains,
bb7cd1
+                                                         dom->sysdb,
bb7cd1
+                                                         dom->name);
bb7cd1
+    if (cr_domains == NULL) {
bb7cd1
+        DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+              "Failed to use ipaDomainResolutionOrder set in ipaConfig "
bb7cd1
+              "for the domain: \"%s\".\n"
bb7cd1
+              "No ipaDomainResolutionOrder will be followed.\n",
bb7cd1
+              dom->name);
bb7cd1
+    } else {
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
bb7cd1
+                                                    rctx, rctx->domains, NULL);
bb7cd1
+    if (cr_domains == NULL) {
bb7cd1
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n");
bb7cd1
+        goto done;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+done:
bb7cd1
+    ret = cr_domains != NULL ? EOK : ENOMEM;
bb7cd1
+
bb7cd1
+    cache_req_domain_list_zfree(&rctx->cr_domains);
bb7cd1
+    rctx->cr_domains = cr_domains;
bb7cd1
+
bb7cd1
+    return ret;
bb7cd1
+}
bb7cd1
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
bb7cd1
index 0f9c01214631200f9687635f6302fa5c07e8a1fe..8c90b7773e248e1dd6d846c5050e1931fc50c786 100644
bb7cd1
--- a/src/responder/common/responder_get_domains.c
bb7cd1
+++ b/src/responder/common/responder_get_domains.c
bb7cd1
@@ -192,6 +192,13 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
bb7cd1
 
bb7cd1
     if (state->dom == NULL) {
bb7cd1
         /* All domains were local */
bb7cd1
+        ret = sss_resp_populate_cr_domains(state->rctx);
bb7cd1
+        if (ret != EOK) {
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE,
bb7cd1
+                  "sss_resp_populate_cr_domains() failed [%d]: [%s]\n",
bb7cd1
+                  ret, sss_strerror(ret));
bb7cd1
+            goto immediately;
bb7cd1
+        }
bb7cd1
         ret = EOK;
bb7cd1
         goto immediately;
bb7cd1
     }
bb7cd1
@@ -253,6 +260,13 @@ sss_dp_get_domains_process(struct tevent_req *subreq)
bb7cd1
     if (state->dom == NULL) {
bb7cd1
         /* All domains were local */
bb7cd1
         set_time_of_last_request(state->rctx);
bb7cd1
+        ret = sss_resp_populate_cr_domains(state->rctx);
bb7cd1
+        if (ret != EOK) {
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE,
bb7cd1
+                  "sss_resp_populate_cr_domains() failed [%d]: [%s]\n",
bb7cd1
+                  ret, sss_strerror(ret));
bb7cd1
+            goto fail;
bb7cd1
+        }
bb7cd1
         tevent_req_done(req);
bb7cd1
         return;
bb7cd1
     }
bb7cd1
diff --git a/src/tests/cmocka/common_mock_resp.c b/src/tests/cmocka/common_mock_resp.c
bb7cd1
index 88808b1b9394b7a9ee7e58b30b4fbd9d467493d3..175101fc51fd395d792b1fccaecdb327caef2b64 100644
bb7cd1
--- a/src/tests/cmocka/common_mock_resp.c
bb7cd1
+++ b/src/tests/cmocka/common_mock_resp.c
bb7cd1
@@ -51,6 +51,12 @@ mock_rctx(TALLOC_CTX *mem_ctx,
bb7cd1
     rctx->ev = ev;
bb7cd1
     rctx->domains = domains;
bb7cd1
     rctx->pvt_ctx = pvt_ctx;
bb7cd1
+    if (domains != NULL) {
bb7cd1
+        ret = sss_resp_populate_cr_domains(rctx);
bb7cd1
+        if (ret != EOK) {
bb7cd1
+            return NULL;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
     return rctx;
bb7cd1
 }
bb7cd1
 
bb7cd1
diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c
bb7cd1
index 5db5255ab61231870982c4b78a39504ae8954bcd..4b38a38e6f53499132f9fe14a0ec0af157cf85ca 100644
bb7cd1
--- a/src/tests/cmocka/common_mock_resp_dp.c
bb7cd1
+++ b/src/tests/cmocka/common_mock_resp_dp.c
bb7cd1
@@ -21,6 +21,7 @@
bb7cd1
 */
bb7cd1
 
bb7cd1
 #include "util/util.h"
bb7cd1
+#include "responder/common/responder.h"
bb7cd1
 #include "tests/cmocka/common_mock_resp.h"
bb7cd1
 
bb7cd1
 /* Mock DP requests that finish immediatelly and return
bb7cd1
@@ -165,6 +166,12 @@ sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
bb7cd1
                         bool force,
bb7cd1
                         const char *hint)
bb7cd1
 {
bb7cd1
+    errno_t ret;
bb7cd1
+    ret = sss_resp_populate_cr_domains(rctx);
bb7cd1
+    if (ret != EOK) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
     return test_req_succeed_send(mem_ctx, rctx->ev);
bb7cd1
 }
bb7cd1
 
bb7cd1
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
bb7cd1
index ede72b341b60842ad470df2794aa90ea9797e999..2f526660cbbbf2443dbae4e213c1336feb6c661e 100644
bb7cd1
--- a/src/tests/cmocka/test_nss_srv.c
bb7cd1
+++ b/src/tests/cmocka/test_nss_srv.c
bb7cd1
@@ -3440,6 +3440,10 @@ static int nss_subdom_test_setup(void **state)
bb7cd1
                                   nss_test_ctx->tctx->confdb);
bb7cd1
     assert_int_equal(ret, EOK);
bb7cd1
 
bb7cd1
+    ret = sss_resp_populate_cr_domains(nss_test_ctx->rctx);
bb7cd1
+    assert_int_equal(ret, EOK);
bb7cd1
+    assert_non_null(nss_test_ctx->rctx->cr_domains);
bb7cd1
+
bb7cd1
     nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains;
bb7cd1
 
bb7cd1
     ret = store_group(nss_test_ctx, nss_test_ctx->subdom,
bb7cd1
diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
bb7cd1
index 4a4090df9296aadde308249f533e7ba246e92f93..c99ebde5f0fc18d1283392cbb307434579d5d811 100644
bb7cd1
--- a/src/tests/cwrap/Makefile.am
bb7cd1
+++ b/src/tests/cwrap/Makefile.am
bb7cd1
@@ -41,6 +41,7 @@ SSSD_CACHE_REQ_OBJ = \
bb7cd1
     ../../../src/responder/common/cache_req/cache_req_result.c \
bb7cd1
     ../../../src/responder/common/cache_req/cache_req_search.c \
bb7cd1
     ../../../src/responder/common/cache_req/cache_req_data.c \
bb7cd1
+    ../../../src/responder/common/cache_req/cache_req_domain.c \
bb7cd1
     ../../../src/responder/common/cache_req/plugins/cache_req_common.c \
bb7cd1
     ../../../src/responder/common/cache_req/plugins/cache_req_enum_users.c \
bb7cd1
     ../../../src/responder/common/cache_req/plugins/cache_req_enum_groups.c \
bb7cd1
-- 
bb7cd1
2.9.3
bb7cd1