diff options
Diffstat (limited to 'src/responder')
-rw-r--r-- | src/responder/common/cache_req/cache_req.c | 89 | ||||
-rw-r--r-- | src/responder/common/cache_req/cache_req_domain.c | 166 | ||||
-rw-r--r-- | src/responder/common/cache_req/cache_req_domain.h | 46 | ||||
-rw-r--r-- | src/responder/common/responder.h | 5 | ||||
-rw-r--r-- | src/responder/common/responder_common.c | 153 | ||||
-rw-r--r-- | src/responder/common/responder_get_domains.c | 14 |
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; } |