dpward / rpms / sssd

Forked from rpms/sssd 3 years ago
Clone

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

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