summaryrefslogtreecommitdiffstats
path: root/src/responder
diff options
context:
space:
mode:
Diffstat (limited to 'src/responder')
-rw-r--r--src/responder/common/cache_req/cache_req.c89
-rw-r--r--src/responder/common/cache_req/cache_req_domain.c166
-rw-r--r--src/responder/common/cache_req/cache_req_domain.h46
-rw-r--r--src/responder/common/responder.h5
-rw-r--r--src/responder/common/responder_common.c153
-rw-r--r--src/responder/common/responder_get_domains.c14
6 files changed, 436 insertions, 37 deletions
diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
index aca150d69..483126396 100644
--- a/src/responder/common/cache_req/cache_req.c
+++ b/src/responder/common/cache_req/cache_req.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include "util/util.h"
+#include "responder/common/responder.h"
#include "responder/common/cache_req/cache_req_private.h"
#include "responder/common/cache_req/cache_req_plugin.h"
@@ -316,7 +317,7 @@ struct cache_req_search_domains_state {
struct cache_req *cr;
/* work data */
- struct sss_domain_info *domain;
+ struct cache_req_domain *cr_domain;
struct sss_domain_info *selected_domain;
struct cache_req_result **results;
size_t num_results;
@@ -330,13 +331,14 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req);
static void cache_req_search_domains_done(struct tevent_req *subreq);
-struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct cache_req *cr,
- struct sss_domain_info *domain,
- bool check_next,
- bool bypass_cache,
- bool bypass_dp)
+struct tevent_req *
+cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ struct cache_req_domain *cr_domain,
+ bool check_next,
+ bool bypass_cache,
+ bool bypass_dp)
{
struct tevent_req *req;
struct cache_req_search_domains_state *state = NULL;
@@ -352,7 +354,7 @@ struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->cr = cr;
- state->domain = domain;
+ state->cr_domain = cr_domain;
state->check_next = check_next;
state->dp_success = true;
state->bypass_cache = bypass_cache;
@@ -378,6 +380,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
struct cache_req_search_domains_state *state;
struct tevent_req *subreq;
struct cache_req *cr;
+ struct sss_domain_info *domain;
uint32_t next_domain_flag;
bool is_domain_valid;
bool allow_no_fqn;
@@ -389,11 +392,21 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
next_domain_flag = cr->plugin->get_next_domain_flags;
allow_no_fqn = cr->plugin->allow_missing_fqn;
- while (state->domain != NULL) {
+ while (state->cr_domain != NULL) {
+ domain = state->cr_domain->domain;
+ /* As the cr_domain list is a flatten version of the domains
+ * list, we have to ensure to only go through the subdomains in
+ * case it's specified in the plugin to do so.
+ */
+ if (next_domain_flag == 0 && IS_SUBDOMAIN(domain)) {
+ state->cr_domain = state->cr_domain->next;
+ continue;
+ }
+
/* Check if this domain is valid for this request. */
- is_domain_valid = cache_req_validate_domain(cr, state->domain);
+ is_domain_valid = cache_req_validate_domain(cr, domain);
if (!is_domain_valid) {
- state->domain = get_next_domain(state->domain, next_domain_flag);
+ state->cr_domain = state->cr_domain->next;
continue;
}
@@ -401,18 +414,18 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
* qualified names on domain less search. We do not descend into
* subdomains here since those are implicitly qualified.
*/
- if (state->check_next && !allow_no_fqn && state->domain->fqnames) {
- state->domain = get_next_domain(state->domain, 0);
+ if (state->check_next && !allow_no_fqn && domain->fqnames) {
+ state->cr_domain = state->cr_domain->next;
continue;
}
- state->selected_domain = state->domain;
+ state->selected_domain = domain;
- if (state->domain == NULL) {
+ if (domain == NULL) {
break;
}
- ret = cache_req_set_domain(cr, state->domain);
+ ret = cache_req_set_domain(cr, domain);
if (ret != EOK) {
return ret;
}
@@ -427,8 +440,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
/* we will continue with the following domain the next time */
if (state->check_next) {
- state->domain = get_next_domain(state->domain,
- cr->plugin->get_next_domain_flags);
+ state->cr_domain = state->cr_domain->next;
}
return EAGAIN;
@@ -625,11 +637,12 @@ static void cache_req_input_parsed(struct tevent_req *subreq);
static errno_t cache_req_select_domains(struct tevent_req *req,
const char *domain_name);
-static errno_t cache_req_search_domains(struct tevent_req *req,
- struct sss_domain_info *domain,
- bool check_next,
- bool bypass_cache,
- bool bypass_dp);
+static errno_t
+cache_req_search_domains(struct tevent_req *req,
+ struct cache_req_domain *oredered_domain,
+ bool check_next,
+ bool bypass_cache,
+ bool bypass_dp);
static void cache_req_done(struct tevent_req *subreq);
@@ -778,7 +791,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
const char *domain_name)
{
struct cache_req_state *state = NULL;
- struct sss_domain_info *domain;
+ struct cache_req_domain *cr_domain;
bool check_next;
bool bypass_cache;
bool bypass_dp;
@@ -798,29 +811,30 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
"Performing a single domain search\n");
- domain = responder_get_domain(state->cr->rctx, domain_name);
- if (domain == NULL) {
+ cr_domain = cache_req_domain_get_domain_by_name(
+ state->cr->rctx->cr_domains, domain_name);
+ if (cr_domain == NULL) {
return ERR_DOMAIN_NOT_FOUND;
}
-
check_next = false;
} else {
CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
"Performing a multi-domain search\n");
- domain = state->cr->rctx->domains;
+ cr_domain = state->cr->rctx->cr_domains;
check_next = true;
}
- return cache_req_search_domains(req, domain, check_next,
+ return cache_req_search_domains(req, cr_domain, check_next,
bypass_cache, bypass_dp);
}
-static errno_t cache_req_search_domains(struct tevent_req *req,
- struct sss_domain_info *domain,
- bool check_next,
- bool bypass_cache,
- bool bypass_dp)
+static errno_t
+cache_req_search_domains(struct tevent_req *req,
+ struct cache_req_domain *cr_domain,
+ bool check_next,
+ bool bypass_cache,
+ bool bypass_dp)
{
struct tevent_req *subreq;
struct cache_req_state *state = NULL;
@@ -832,8 +846,9 @@ static errno_t cache_req_search_domains(struct tevent_req *req,
bypass_cache ? "bypass" : "check",
bypass_dp ? "bypass" : "check");
- subreq = cache_req_search_domains_send(state, state->ev, state->cr, domain,
- check_next, bypass_cache, bypass_dp);
+ subreq = cache_req_search_domains_send(state, state->ev, state->cr,
+ cr_domain, check_next,
+ bypass_cache, bypass_dp);
if (subreq == NULL) {
return ENOMEM;
}
diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c
new file mode 100644
index 000000000..bbabd695f
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_domain.c
@@ -0,0 +1,166 @@
+/*
+ Authors:
+ Fabiano FidĂȘncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "responder/common/cache_req/cache_req_domain.h"
+
+struct cache_req_domain *
+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
+ const char *name)
+{
+ struct cache_req_domain *dom;
+ struct cache_req_domain *ret = NULL;
+
+ DLIST_FOR_EACH(dom, domains) {
+ if (sss_domain_get_state(dom->domain) == DOM_DISABLED) {
+ continue;
+ }
+
+ if (strcasecmp(dom->domain->name, name) == 0 ||
+ (dom->domain->flat_name != NULL &&
+ strcasecmp(dom->domain->flat_name, name) == 0)) {
+ ret = dom;
+ break;
+ }
+ }
+
+ if (ret == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unknown domains [%s].\n", name);
+ }
+
+ return ret;
+}
+
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains)
+{
+ struct cache_req_domain *p, *q, *r;
+
+ DLIST_FOR_EACH_SAFE(p, q, *cr_domains) {
+ r = p;
+ DLIST_REMOVE(*cr_domains, p);
+ talloc_zfree(r);
+ }
+
+ *cr_domains = NULL;
+}
+
+static struct cache_req_domain *
+cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ char **resolution_order)
+{
+ struct cache_req_domain *cr_domains = NULL;
+ struct cache_req_domain *cr_domain;
+ struct sss_domain_info *dom;
+ char *name;
+ int flag = SSS_GND_ALL_DOMAINS;
+ int i;
+ errno_t ret;
+
+ if (resolution_order != NULL) {
+ for (i = 0; resolution_order[i] != NULL; i++) {
+ name = resolution_order[i];
+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
+ if (strcasecmp(name, dom->name) != 0) {
+ continue;
+ }
+
+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
+ if (cr_domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cr_domain->domain = dom;
+
+ DLIST_ADD_END(cr_domains, cr_domain,
+ struct cache_req_domain *);
+ break;
+ }
+ }
+ }
+
+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
+ if (string_in_list(dom->name, resolution_order, false)) {
+ continue;
+ }
+
+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
+ if (cr_domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cr_domain->domain = dom;
+
+ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *);
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ cache_req_domain_list_zfree(&cr_domains);
+ }
+
+ return cr_domains;
+}
+
+struct cache_req_domain *
+cache_req_domain_new_list_from_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ const char *domain_resolution_order)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains = NULL;
+ char **list = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ if (domain_resolution_order != NULL) {
+ if (strcmp(domain_resolution_order, ":") != 0) {
+ ret = split_on_separator(tmp_ctx, domain_resolution_order, ':',
+ true, true, &list, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "split_on_separator() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+ }
+
+ cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains,
+ list);
+ if (cr_domains == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_OP_FAILURE,
+ "cache_req_domain_new_list_from_domain_resolution_order() "
+ "failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return cr_domains;
+}
diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h
new file mode 100644
index 000000000..41c50e8c2
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_domain.h
@@ -0,0 +1,46 @@
+/*
+ Authors:
+ Fabiano FidĂȘncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CACHE_REQ_DOMAIN_H_
+#define _CACHE_REQ_DOMAIN_H_
+
+#include "responder/common/responder.h"
+
+struct cache_req_domain {
+ struct sss_domain_info *domain;
+
+ struct cache_req_domain *prev;
+ struct cache_req_domain *next;
+};
+
+struct cache_req_domain *
+cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
+ const char *name);
+
+struct cache_req_domain *
+cache_req_domain_new_list_from_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ const char *domain_resolution_order);
+
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains);
+
+
+#endif /* _CACHE_REQ_DOMAIN_H_ */
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 4d1048a1e..29e3f95ca 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -37,6 +37,7 @@
#include "sbus/sssd_dbus.h"
#include "responder/common/negcache.h"
#include "sss_client/sss_cli.h"
+#include "responder/common/cache_req/cache_req_domain.h"
extern hash_table_t *dp_requests;
@@ -113,6 +114,8 @@ struct resp_ctx {
int domains_timeout;
int client_idle_timeout;
+ struct cache_req_domain *cr_domains;
+
time_t last_request_time;
int idle_timeout;
struct tevent_timer *idle;
@@ -387,4 +390,6 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx,
bool name_is_upn,
const char *orig_name);
+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx);
+
#endif /* __SSS_RESPONDER_H__ */
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 76f436096..1792a4c37 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -1453,3 +1453,156 @@ fail:
return ret;
}
+
+/* ====== Helper functions for the domain resolution order ======= */
+static struct cache_req_domain *
+sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ struct sysdb_ctx *sysdb)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains = NULL;
+ const char *domain_resolution_order = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb,
+ &domain_resolution_order);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "sysdb_get_view_cache_req_domain() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Using mem_ctx (which is rctx) directly here to avoid copying
+ * this memory around. */
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ mem_ctx, domains, domain_resolution_order);
+ if (cr_domains == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_DEFAULT,
+ "cache_req_domain_new_list_from_domain_resolution_order() "
+ "failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return cr_domains;
+}
+
+static struct cache_req_domain *
+sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ struct sysdb_ctx *sysdb,
+ const char *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains = NULL;
+ const char *domain_resolution_order = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain,
+ &domain_resolution_order);
+
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "sysdb_domain_get_cache_req_domain() failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Using mem_ctx (which is rctx) directly here to avoid copying
+ * this memory around. */
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ mem_ctx, domains, domain_resolution_order);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_DEFAULT,
+ "cache_req_domain_new_list_from_domain_resolution_order() "
+ "failed [%d]: [%s].\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return cr_domains;
+}
+
+errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx)
+{
+ struct cache_req_domain *cr_domains = NULL;
+ struct sss_domain_info *dom;
+ errno_t ret;
+
+ for (dom = rctx->domains; dom != NULL; dom = dom->next) {
+ if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) {
+ break;
+ }
+ }
+
+ if (dom == NULL) {
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ rctx, rctx->domains, NULL);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to flatten the list of domains.\n");
+ }
+ goto done;
+ }
+
+ if (dom->has_views) {
+ cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx,
+ rctx->domains,
+ dom->sysdb);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to use ipaDomainResolutionOrder set for the "
+ "view \"%s\".\n"
+ "Trying to fallback to use ipaDomainOrderResolution "
+ "set in ipaConfig for the domain: %s.\n",
+ dom->view_name, dom->name);
+ } else {
+ goto done;
+ }
+ }
+
+ cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains,
+ dom->sysdb,
+ dom->name);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to use ipaDomainResolutionOrder set in ipaConfig "
+ "for the domain: \"%s\".\n"
+ "No ipaDomainResolutionOrder will be followed.\n",
+ dom->name);
+ } else {
+ goto done;
+ }
+
+ cr_domains = cache_req_domain_new_list_from_domain_resolution_order(
+ rctx, rctx->domains, NULL);
+ if (cr_domains == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n");
+ goto done;
+ }
+
+done:
+ ret = cr_domains != NULL ? EOK : ENOMEM;
+
+ cache_req_domain_list_zfree(&rctx->cr_domains);
+ rctx->cr_domains = cr_domains;
+
+ return ret;
+}
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
index 0f9c01214..8c90b7773 100644
--- a/src/responder/common/responder_get_domains.c
+++ b/src/responder/common/responder_get_domains.c
@@ -192,6 +192,13 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
if (state->dom == NULL) {
/* All domains were local */
+ ret = sss_resp_populate_cr_domains(state->rctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n",
+ ret, sss_strerror(ret));
+ goto immediately;
+ }
ret = EOK;
goto immediately;
}
@@ -253,6 +260,13 @@ sss_dp_get_domains_process(struct tevent_req *subreq)
if (state->dom == NULL) {
/* All domains were local */
set_time_of_last_request(state->rctx);
+ ret = sss_resp_populate_cr_domains(state->rctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n",
+ ret, sss_strerror(ret));
+ goto fail;
+ }
tevent_req_done(req);
return;
}