summaryrefslogtreecommitdiffstats
path: root/src/responder/common/cache_req
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/responder/common/cache_req
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/responder/common/cache_req')
-rw-r--r--src/responder/common/cache_req/cache_req.c1612
-rw-r--r--src/responder/common/cache_req/cache_req.h521
-rw-r--r--src/responder/common/cache_req/cache_req_data.c519
-rw-r--r--src/responder/common/cache_req/cache_req_domain.c317
-rw-r--r--src/responder/common/cache_req/cache_req_domain.h63
-rw-r--r--src/responder/common/cache_req/cache_req_plugin.h331
-rw-r--r--src/responder/common/cache_req/cache_req_private.h227
-rw-r--r--src/responder/common/cache_req/cache_req_result.c274
-rw-r--r--src/responder/common/cache_req/cache_req_search.c643
-rw-r--r--src/responder/common/cache_req/cache_req_sr_overlay.c347
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c161
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c155
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c187
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_common.c192
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_enum_groups.c93
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_enum_ip_hosts.c126
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_enum_ip_networks.c126
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_enum_svc.c106
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_enum_users.c93
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_group_by_filter.c171
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_group_by_id.c246
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_group_by_name.c227
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c242
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c130
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_ip_host_by_addr.c174
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_ip_host_by_name.c170
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_ip_network_by_addr.c174
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_ip_network_by_name.c170
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c160
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_object_by_id.c236
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_object_by_name.c238
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_object_by_sid.c202
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_ssh_host_id_by_name.c164
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c143
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_svc_by_name.c185
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_svc_by_port.c159
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_user_by_cert.c127
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_user_by_filter.c176
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_user_by_id.c246
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_user_by_name.c256
-rw-r--r--src/responder/common/cache_req/plugins/cache_req_user_by_upn.c158
41 files changed, 10247 insertions, 0 deletions
diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
new file mode 100644
index 0000000..b827595
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req.c
@@ -0,0 +1,1612 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <ldb.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <errno.h>
+
+#include "util/util.h"
+#include "util/sss_chain_id.h"
+#include "responder/common/responder.h"
+#include "responder/common/cache_req/cache_req_private.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const struct cache_req_plugin *
+cache_req_get_plugin(enum cache_req_type type)
+{
+ static const struct cache_req_plugin *plugins[CACHE_REQ_SENTINEL] = {
+ &cache_req_user_by_name,
+ &cache_req_user_by_upn,
+ &cache_req_user_by_id,
+ &cache_req_user_by_cert,
+ &cache_req_user_by_filter,
+
+ &cache_req_group_by_name,
+ &cache_req_group_by_id,
+ &cache_req_group_by_filter,
+
+ &cache_req_initgroups_by_name,
+ &cache_req_initgroups_by_upn,
+
+#ifdef BUILD_SUBID
+ &cache_req_subid_ranges_by_name,
+#endif
+
+ &cache_req_object_by_sid,
+ &cache_req_object_by_name,
+ &cache_req_object_by_id,
+
+ &cache_req_enum_users,
+ &cache_req_enum_groups,
+ &cache_req_enum_svc,
+ &cache_req_enum_ip_hosts,
+ &cache_req_enum_ip_networks,
+
+ &cache_req_svc_by_name,
+ &cache_req_svc_by_port,
+
+ &cache_req_netgroup_by_name,
+
+ &cache_req_ssh_host_id_by_name,
+
+ &cache_req_autofs_map_entries,
+ &cache_req_autofs_map_by_name,
+ &cache_req_autofs_entry_by_name,
+
+ &cache_req_ip_host_by_name,
+ &cache_req_ip_host_by_addr,
+ &cache_req_ip_network_by_name,
+ &cache_req_ip_network_by_addr,
+ };
+
+ if (type >= CACHE_REQ_SENTINEL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Bug: invalid plugin type!");
+ return NULL;
+ }
+
+ return plugins[type];
+}
+
+static errno_t cache_req_set_plugin(struct cache_req *cr,
+ enum cache_req_type type)
+{
+ const struct cache_req_plugin *plugin;
+
+ plugin = cache_req_get_plugin(type);
+ if (plugin == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Bug: unset plugin!");
+ return EINVAL;
+ }
+
+ cr->reqname = plugin->name;
+ cr->plugin = plugin;
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_INTERNAL, cr, "Setting \"%s\" plugin\n",
+ plugin->name);
+
+ return EOK;
+}
+
+static const char *
+cache_req_dom_type_as_str(struct cache_req *cr)
+{
+ if (cr == NULL) {
+ return "BUG: Invalid cache_req pointer\n";
+ }
+ switch (cr->req_dom_type) {
+ case CACHE_REQ_POSIX_DOM:
+ return "POSIX-only";
+ case CACHE_REQ_APPLICATION_DOM:
+ return "Application-only";
+ case CACHE_REQ_ANY_DOM:
+ return "Any";
+ }
+
+ return "Unknown";
+}
+
+static struct cache_req *
+cache_req_create(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct cache_req_data *data,
+ struct sss_nc_ctx *ncache,
+ int midpoint,
+ enum cache_req_dom_type req_dom_type)
+{
+ struct cache_req *cr;
+ bool bypass_cache;
+ errno_t ret;
+
+ cr = talloc_zero(mem_ctx, struct cache_req);
+ if (cr == NULL) {
+ return NULL;
+ }
+
+ cr->rctx = rctx;
+ cr->data = data;
+ cr->ncache = ncache;
+ cr->midpoint = midpoint;
+ cr->req_dom_type = req_dom_type;
+ cr->req_start = time(NULL);
+
+ /* It is perfectly fine to just overflow here. */
+ cr->reqid = rctx->cache_req_num++;
+
+ ret = cache_req_set_plugin(cr, data->type);
+ if (ret != EOK) {
+ talloc_free(cr);
+ return NULL;
+ }
+
+ bypass_cache = cr->plugin->bypass_cache || cr->data->bypass_cache;
+ if (bypass_cache && cr->data->bypass_dp) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Cannot bypass cache and dp at the same time!");
+ talloc_free(cr);
+ return NULL;
+ }
+ if (rctx->cache_first) {
+ cr->cache_behavior = CACHE_REQ_CACHE_FIRST;
+ }
+ /* it is ok to override cache_first here */
+ if (bypass_cache) {
+ cr->cache_behavior = CACHE_REQ_BYPASS_CACHE;
+ } else if (cr->data->bypass_dp) {
+ cr->cache_behavior = CACHE_REQ_BYPASS_PROVIDER;
+ }
+
+ return cr;
+}
+
+static errno_t
+cache_req_set_name(struct cache_req *cr, const char *name)
+{
+ const char *dup_name;
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Setting name [%s]\n", name);
+
+ dup_name = talloc_strdup(cr->data, name);
+ if (dup_name == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, "Unable to set name!\n");
+ return ENOMEM;
+ }
+
+ talloc_zfree(cr->data->name.name);
+ cr->data->name.name = dup_name;
+
+ return EOK;
+}
+
+static bool
+cache_req_validate_domain_enumeration(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ if (!cr->plugin->require_enumeration) {
+ return true;
+ }
+
+ if (domain->enumerate == false) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Domain %s does not support "
+ "enumeration, skipping...\n", domain->name);
+ if (cr->rctx->enumeration_warn_logged == false) {
+ sss_log(SSS_LOG_NOTICE, "Enumeration requested but not enabled\n");
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Enumeration requested but not enabled\n");
+ cr->rctx->enumeration_warn_logged = true;
+ }
+ return false;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Domain %s supports enumeration\n",
+ domain->name);
+
+ return true;
+}
+
+static bool
+cache_req_validate_domain_type(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ bool valid = false;
+
+ switch (cr->req_dom_type) {
+ case CACHE_REQ_POSIX_DOM:
+ valid = domain->type == DOM_TYPE_POSIX ? true : false;
+ break;
+ case CACHE_REQ_APPLICATION_DOM:
+ valid = domain->type == DOM_TYPE_APPLICATION ? true : false;
+ break;
+ case CACHE_REQ_ANY_DOM:
+ valid = true;
+ break;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Request type %s for domain %s type %s is %svalid\n",
+ cache_req_dom_type_as_str(cr),
+ domain->name,
+ sss_domain_type_str(domain),
+ valid ? "" : "not ");
+ return valid;
+}
+
+static bool
+cache_req_validate_domain(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ bool ok;
+
+ ok = cache_req_validate_domain_enumeration(cr, domain);
+ if (ok == false) {
+ return false;
+ }
+
+ ok = cache_req_validate_domain_type(cr, domain);
+ if (ok == false) {
+ return false;
+ }
+
+ ok = !cr->data->hybrid_lookup || domain->mpg_mode == MPG_HYBRID;
+ if (ok == false) {
+ return false;
+ }
+
+ return true;
+}
+
+static errno_t
+cache_req_is_well_known_object(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_result **_result)
+{
+ errno_t ret;
+
+ if (cr->plugin->is_well_known_fn == NULL) {
+ return ENOENT;
+ }
+
+ ret = cr->plugin->is_well_known_fn(mem_ctx, cr, cr->data, _result);
+ if (ret == EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Object is well known!\n");
+ (*_result)->well_known_object = true;
+ } else if (ret != ENOENT) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to prepare data [%d]: %s\n",
+ ret, sss_strerror(ret));
+ }
+
+ return ret;
+}
+
+static errno_t
+cache_req_prepare_domain_data(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ errno_t ret;
+
+ if (cr->plugin->prepare_domain_data_fn == NULL) {
+ return EOK;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Preparing input data for domain [%s] rules\n",
+ domain->name);
+
+ ret = cr->plugin->prepare_domain_data_fn(cr, cr->data, domain);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to prepare data [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t
+cache_req_create_debug_name(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ if (cr->plugin->create_debug_name_fn == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Bug: no create debug name function specified!\n");
+ return ERR_INTERNAL;
+ }
+
+ talloc_zfree(cr->debugobj);
+
+ cr->debugobj = cr->plugin->create_debug_name_fn(cr, cr->data, domain);
+ if (cr->debugobj == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to create debug name!\n");
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+static errno_t
+cache_req_set_domain(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ errno_t ret;
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Using domain [%s]\n", domain->name);
+
+ ret = cache_req_prepare_domain_data(cr, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = cache_req_create_debug_name(cr, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ cr->domain = domain;
+
+ return EOK;
+}
+
+static void cache_req_global_ncache_add(struct cache_req *cr)
+{
+ errno_t ret;
+
+ if (cr->plugin->global_ncache_add_fn == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_INTERNAL, cr,
+ "This request type does not support "
+ "global negative cache\n");
+ return;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Adding [%s] to global "
+ "negative cache\n", cr->debugobj);
+
+ ret = cr->plugin->global_ncache_add_fn(cr->ncache, cr->data);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr,
+ "Cannot set negative cache for [%s] [%d]: %s\n",
+ cr->debugobj, ret, sss_strerror(ret));
+ /* not fatal */
+ }
+
+ return;
+}
+
+static bool cache_req_check_acct_domain_lookup_type(struct cache_req *cr,
+ struct sss_domain_info *dom)
+{
+ struct sss_domain_info *head;
+ int nret;
+
+ head = get_domains_head(dom);
+ if (head == NULL) {
+ return false;
+ }
+
+ nret = sss_ncache_check_domain_locate_type(cr->rctx->ncache,
+ head,
+ cr->plugin->name);
+ if (nret == ENOENT) {
+ return true;
+ }
+ return false;
+}
+
+static errno_t cache_req_set_acct_domain_lookup_type(struct cache_req *cr,
+ struct sss_domain_info *dom)
+{
+ struct sss_domain_info *head;
+
+ head = get_domains_head(dom);
+ if (head == NULL) {
+ return EINVAL;
+ }
+
+ return sss_ncache_set_domain_locate_type(cr->rctx->ncache,
+ head,
+ cr->plugin->name);
+}
+
+static void cache_req_domain_set_locate_flag(struct cache_req_domain *domains,
+ struct cache_req *cr)
+{
+ struct cache_req_domain *crd_iter;
+
+ DLIST_FOR_EACH(crd_iter, domains) {
+ if (cache_req_check_acct_domain_lookup_type(cr, crd_iter->domain)) {
+ crd_iter->locate_domain = true;
+ }
+ }
+}
+
+static bool
+cache_req_assume_upn(struct cache_req *cr)
+{
+ errno_t ret;
+
+ if (cr->plugin->allow_switch_to_upn == false
+ || cr->data->name.input == NULL
+ || strchr(cr->data->name.input, '@') == NULL) {
+ return false;
+ }
+
+ ret = cache_req_set_plugin(cr, cr->plugin->upn_equivalent);
+ if (ret != EOK) {
+ return false;
+ }
+
+ ret = cache_req_set_name(cr, cr->data->name.input);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_set_name() failed\n");
+ return false;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Assuming UPN [%s]\n",
+ cr->data->name.input);
+
+ return true;
+}
+
+struct cache_req_locate_dom_state {
+ /* input data */
+ struct tevent_context *ev;
+ struct cache_req *cr;
+ struct cache_req_domain *req_domains;
+
+ /* Return values in case the first cache lookup succeeds */
+ struct ldb_result *result;
+ bool dp_success;
+};
+
+static void cache_req_locate_dom_cache_done(struct tevent_req *subreq);
+static void cache_req_locate_dom_done(struct tevent_req *subreq);
+static void cache_req_locate_dom_mark_neg_all(
+ struct cache_req_locate_dom_state *state);
+static void cache_req_locate_dom_mark_neg_domains(
+ struct cache_req_locate_dom_state *state,
+ const char *found_domain_name);
+
+static struct tevent_req *cache_req_locate_dom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ struct cache_req_domain *req_domains)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct cache_req_locate_dom_state *state = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cache_req_locate_dom_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+ state->ev = ev;
+ state->cr = cr;
+ state->req_domains = req_domains;
+
+ /* It is wasteful to run the domain locator request if the results are
+ * present in the cache, because the domain locator always contacts
+ * the DP. Therefore, first run a cache-only search and only if the
+ * requested data is not available, run the locator
+ *
+ * FIXME - this could be optimized further if we are running the
+ * second iteration with cache_first, then we don't need to search
+ * again
+ */
+ subreq = cache_req_search_send(state,
+ state->ev,
+ state->cr,
+ false,
+ true);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+ tevent_req_set_callback(subreq, cache_req_locate_dom_cache_done, req);
+
+ return req;
+
+immediately:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void cache_req_locate_dom_cache_done(struct tevent_req *subreq)
+{
+ struct cache_req_locate_dom_state *state = NULL;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_locate_dom_state);
+
+ ret = cache_req_search_recv(state, subreq, &state->result, &state->dp_success);
+ talloc_zfree(subreq);
+
+ switch (ret) {
+ case EOK:
+ /* Just finish the request and let the caller handle the result */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Result found in the cache\n");
+ tevent_req_done(req);
+ return;
+ case ERR_ID_OUTSIDE_RANGE:
+ case ENOENT:
+ /* Not cached and locator was requested, run the locator
+ * DP request plugin
+ */
+ subreq = cache_req_locate_domain_send(state,
+ state->ev,
+ state->cr);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, cache_req_locate_dom_done, req);
+ return;
+ default:
+ DEBUG(SSSDBG_OP_FAILURE,
+ "cache_req_search_recv returned [%d]: %s\n", ret, sss_strerror(ret));
+ break;
+ }
+
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void cache_req_locate_dom_done(struct tevent_req *subreq)
+{
+ struct cache_req_locate_dom_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+ char *found_domain_name;
+ int nret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_locate_dom_state);
+
+ ret = cache_req_locate_domain_recv(state, subreq, &found_domain_name);
+ talloc_zfree(subreq);
+ switch (ret) {
+ case ERR_GET_ACCT_DOM_NOT_SUPPORTED:
+ nret = cache_req_set_acct_domain_lookup_type(state->cr,
+ state->cr->domain);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to disable domain locating functionality for %s\n",
+ state->cr->plugin->name);
+ }
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Disabled domain locating functionality for %s\n",
+ state->cr->plugin->name);
+ break;
+ case ERR_NOT_FOUND:
+ cache_req_locate_dom_mark_neg_all(state);
+ break;
+ case EOK:
+ cache_req_locate_dom_mark_neg_domains(state, found_domain_name);
+ break;
+ default:
+ /* We explicitly ignore errors here */
+ break;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+static void cache_req_locate_dom_mark_neg_all(
+ struct cache_req_locate_dom_state *state)
+{
+ struct cache_req_domain *iter;
+
+ DLIST_FOR_EACH(iter, state->req_domains) {
+ if (get_domains_head(state->cr->domain) != get_domains_head(iter->domain)) {
+ /* Only add to negative cache for domains from the same "main"
+ * domain" */
+ continue;
+ }
+ cache_req_search_ncache_add_to_domain(state->cr, iter->domain);
+ }
+}
+
+static void cache_req_locate_dom_mark_neg_domains(
+ struct cache_req_locate_dom_state *state,
+ const char *found_domain_name)
+{
+ struct sss_domain_info *found_domain;
+ struct cache_req_domain *iter;
+
+ found_domain = find_domain_by_name(get_domains_head(state->cr->domain),
+ found_domain_name,
+ true);
+ if (found_domain == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot find domain %s\n", found_domain_name);
+ return;
+ }
+
+ /* Set negcache in all subdomains of the one being examined
+ * except the found one */
+ DLIST_FOR_EACH(iter, state->req_domains) {
+ if (strcasecmp(found_domain_name,
+ iter->domain->name) == 0) {
+ continue;
+ }
+
+ if (get_domains_head(found_domain) != get_domains_head(iter->domain)) {
+ /* Don't set negative cache for domains outside the main
+ * domain/subdomain tree b/c the locator request is not
+ * authoritative for them
+ */
+ continue;
+ }
+ cache_req_search_ncache_add_to_domain(state->cr, iter->domain);
+ }
+}
+
+static errno_t cache_req_locate_dom_cache_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct ldb_result **_result,
+ bool *_dp_success)
+{
+ struct cache_req_locate_dom_state *state;
+
+ state = tevent_req_data(req, struct cache_req_locate_dom_state);
+
+ if (_dp_success != NULL) {
+ *_dp_success = state->dp_success;
+ }
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (_result != NULL) {
+ *_result = talloc_steal(mem_ctx, state->result);
+ }
+
+ return EOK;
+}
+
+struct cache_req_search_domains_state {
+ /* input data */
+ struct tevent_context *ev;
+ struct cache_req *cr;
+
+ /* work data */
+ struct cache_req_domain *cr_domain;
+ struct cache_req_domain *req_domains;
+ struct sss_domain_info *selected_domain;
+ struct cache_req_result **results;
+ size_t num_results;
+ bool check_next;
+ bool dp_success;
+ bool first_iteration;
+};
+
+static errno_t cache_req_search_domains_next(struct tevent_req *req);
+static errno_t cache_req_handle_result(struct tevent_req *req,
+ struct ldb_result *result);
+
+static void cache_req_search_domains_locate_done(struct tevent_req *subreq);
+
+static void cache_req_search_domains_done(struct tevent_req *subreq);
+
+static bool
+cache_req_dp_contacted(struct cache_req_search_domains_state *state)
+{
+ switch (state->cr->cache_behavior) {
+ case CACHE_REQ_CACHE_FIRST:
+ if (state->first_iteration) {
+ /* This is the first iteration so provider was bypassed. */
+ return false;
+ }
+
+ /* This is the second iteration so the provider was contacted. */
+ return true;
+ case CACHE_REQ_BYPASS_PROVIDER:
+ return false;
+ default:
+ /* Other schemas talks to provider immediately. */
+ return true;
+ }
+}
+
+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 first_iteration)
+{
+ struct tevent_req *req;
+ struct cache_req_search_domains_state *state = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cache_req_search_domains_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->cr = cr;
+
+ state->cr_domain = cr_domain;
+ state->req_domains = cr_domain;
+ state->check_next = check_next;
+ state->dp_success = true;
+ state->first_iteration = first_iteration;
+
+ if (cr->plugin->dp_get_domain_send_fn != NULL
+ && ((state->check_next && cr_domain->next != NULL)
+ || ((state->cr->cache_behavior == CACHE_REQ_CACHE_FIRST)
+ && !first_iteration))) {
+ /* If the request is not qualified with a domain name AND
+ * there are multiple domains to search OR if this is the second
+ * pass during the "check-cache-first" schema, it makes sense
+ * to try to run the domain-locator plugin
+ */
+ cache_req_domain_set_locate_flag(cr_domain, cr);
+ }
+
+ ret = cache_req_search_domains_next(req);
+ if (ret == EAGAIN) {
+ return req;
+ }
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+
+ tevent_req_post(req, ev);
+ return req;
+}
+
+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;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+ cr = state->cr;
+
+ next_domain_flag = cr->plugin->get_next_domain_flags;
+ allow_no_fqn = cr->plugin->allow_missing_fqn;
+
+ while (state->cr_domain != NULL) {
+ domain = state->cr_domain->domain;
+
+ if (domain == NULL) {
+ break;
+ }
+
+ /* 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, domain);
+ if (!is_domain_valid) {
+ state->cr_domain = state->cr_domain->next;
+ continue;
+ }
+
+ /* If not specified otherwise, we skip domains that require fully
+ * 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->cr_domain->fqnames) {
+ state->cr_domain = state->cr_domain->next;
+ continue;
+ }
+
+ state->selected_domain = domain;
+
+ ret = cache_req_set_domain(cr, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (state->cr_domain->locate_domain) {
+ subreq = cache_req_locate_dom_send(state,
+ state->ev,
+ cr,
+ state->req_domains);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(subreq, cache_req_search_domains_locate_done, req);
+ return EAGAIN;
+ }
+
+ subreq = cache_req_search_send(state, state->ev, cr,
+ state->first_iteration,
+ false);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(subreq, cache_req_search_domains_done, req);
+
+ /* we will continue with the following domain the next time */
+ if (state->check_next) {
+ state->cr_domain = state->cr_domain->next;
+ }
+
+ return EAGAIN;
+ }
+
+ /* If we've got some result from previous searches we want to return
+ * EOK here so the whole cache request is successfully finished. */
+ if (state->num_results > 0) {
+ return EOK;
+ }
+
+ /* We have searched all available domains and no result was found.
+ *
+ * If the plug-in uses a negative cache which is shared among all domains
+ * (e.g. unique identifiers such as user or group id or sid), we add it
+ * here and return object not found error.
+ *
+ * However, we can only set the negative cache if all data provider
+ * requests succeeded because only then we can be sure that it does
+ * not exist-
+ */
+ if (cache_req_dp_contacted(state) && state->dp_success) {
+ cache_req_global_ncache_add(cr);
+ }
+
+ return ENOENT;
+}
+
+static void cache_req_search_domains_locate_done(struct tevent_req *subreq)
+{
+ struct cache_req_search_domains_state *state;
+ struct ldb_result *result = NULL;
+ struct tevent_req *req;
+ bool dp_success;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+
+ ret = cache_req_locate_dom_cache_recv(state, subreq, &result, &dp_success);
+ talloc_zfree(subreq);
+
+ /* Remember if any DP request fails, but here it shouldn't matter
+ * as the only DP request that should realistically happen is midpoint
+ * refresh */
+ state->dp_success = !dp_success ? false : state->dp_success;
+
+ /* Don't locate the domain again */
+ state->cr_domain->locate_domain = false;
+
+ switch (ret) {
+ case EOK:
+ if (result != NULL) {
+ /* Handle result as normally */
+ ret = cache_req_handle_result(req, result);
+ if (ret != EAGAIN) {
+ goto done;
+ }
+ }
+ break;
+ default:
+ /* Some serious error has happened. Finish. */
+ goto done;
+ }
+
+ /* This is a domain less search, continue with the next domain. */
+ ret = cache_req_search_domains_next(req);
+
+done:
+ switch (ret) {
+ case EOK:
+ tevent_req_done(req);
+ break;
+ case EAGAIN:
+ break;
+ default:
+ tevent_req_error(req, ret);
+ break;
+ }
+ return;
+}
+
+static errno_t cache_req_handle_result(struct tevent_req *req,
+ struct ldb_result *result)
+{
+ struct cache_req_search_domains_state *state;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+
+ /* We got some data from this search. Save it. */
+ ret = cache_req_create_and_add_result(state,
+ state->cr,
+ state->selected_domain,
+ result,
+ state->cr->data->name.lookup,
+ &state->results,
+ &state->num_results);
+ if (ret != EOK) {
+ /* We were unable to save data. */
+ return ret;
+ }
+
+ if (!state->check_next || !state->cr->plugin->search_all_domains) {
+ /* We are not interested in more results. */
+ return EOK;
+ }
+
+ return EAGAIN;
+}
+
+static void cache_req_search_domains_done(struct tevent_req *subreq)
+{
+ struct cache_req_search_domains_state *state;
+ struct ldb_result *result;
+ struct tevent_req *req;
+ bool dp_success;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+
+ ret = cache_req_search_recv(state, subreq, &result, &dp_success);
+ talloc_zfree(subreq);
+
+ /* Remember if any DP request fails, if DP was contacted. */
+ if (cache_req_dp_contacted(state)) {
+ state->dp_success = !dp_success ? false : state->dp_success;
+ }
+
+ switch (ret) {
+ case EOK:
+ ret = cache_req_handle_result(req, result);
+ if (ret != EAGAIN) {
+ goto done;
+ }
+ break;
+ case ERR_ID_OUTSIDE_RANGE:
+ case ENOENT:
+ if (state->check_next == false) {
+ if (cache_req_dp_contacted(state)
+ && !state->dp_success
+ && state->cr->data->propogate_offline_status) {
+ /* Not found and data provider request failed so we were
+ * unable to fetch the data. */
+ ret = ERR_OFFLINE;
+ goto done;
+ }
+
+ /* Not found. */
+ ret = ENOENT;
+ goto done;
+ }
+
+ /* Continue with next domain. */
+ break;
+ default:
+ /* Some serious error has happened. Finish. */
+ goto done;
+ }
+
+ /* This is a domain less search, continue with the next domain. */
+ ret = cache_req_search_domains_next(req);
+
+done:
+ if (ret == ENOENT && state->results != NULL) {
+ /* We have at least one result. */
+ ret = EOK;
+ }
+
+ switch (ret) {
+ case EOK:
+ tevent_req_done(req);
+ break;
+ case EAGAIN:
+ break;
+ default:
+ if (cache_req_dp_contacted(state)
+ && ret == ENOENT
+ && !state->dp_success
+ && state->cr->data->propogate_offline_status) {
+ /* Not found and data provider request failed so we were
+ * unable to fetch the data. */
+ ret = ERR_OFFLINE;
+ }
+ tevent_req_error(req, ret);
+ break;
+ }
+
+ return;
+}
+
+static errno_t
+cache_req_search_domains_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req_result ***_results,
+ size_t *_num_results)
+{
+ struct cache_req_search_domains_state *state;
+
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (_results != NULL) {
+ *_results = talloc_steal(mem_ctx, state->results);
+ }
+ if (_num_results != NULL) {
+ *_num_results = state->num_results;
+ }
+
+ return EOK;
+}
+
+struct cache_req_state {
+ /* input data */
+ struct tevent_context *ev;
+ struct cache_req *cr;
+ const char *domain_name;
+
+ /* work data */
+ struct cache_req_domain *cr_domains;
+ struct cache_req_result **results;
+ size_t num_results;
+ bool first_iteration;
+};
+
+static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req *cr,
+ const char *domain);
+
+static errno_t cache_req_update_domains(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req *cr,
+ const char *domain);
+
+static void cache_req_domains_updated(struct tevent_req *subreq);
+
+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,
+ char **requested_domains);
+
+static errno_t
+cache_req_search_domains(struct tevent_req *req,
+ struct cache_req_domain *oredered_domain,
+ bool check_next);
+
+static void cache_req_process_result(struct tevent_req *subreq);
+
+static void cache_req_done(struct tevent_req *subreq);
+
+struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int midpoint,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ struct cache_req_data *data)
+{
+ struct cache_req_state *state;
+ struct cache_req_result *result;
+ struct cache_req *cr;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct cache_req_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->cr = cr = cache_req_create(state, rctx, data,
+ ncache, midpoint, req_dom_type);
+ if (state->cr == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ state->first_iteration = true;
+
+ SSS_REQ_TRACE_CID_CR(SSSDBG_TRACE_FUNC, cr, "New request [CID #%lu] '%s'\n",
+ sss_chain_id_get(), cr->reqname);
+
+ ret = cache_req_is_well_known_object(state, cr, &result);
+ if (ret == EOK) {
+ ret = cache_req_add_result(state, result, &state->results,
+ &state->num_results);
+ goto done;
+ } else if (ret != ENOENT) {
+ goto done;
+ }
+
+ state->domain_name = domain;
+ ret = cache_req_process_input(state, req, cr, domain);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = cache_req_select_domains(req, state->domain_name,
+ cr->data->requested_domains);
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req *cr,
+ const char *domain)
+{
+ struct tevent_req *subreq;
+ const char *default_domain;
+ errno_t ret;
+
+ if (cr->data->name.input == NULL) {
+ /* Call cache_req_update_domains() in order to get a up to date list
+ * of domains and subdomains, if needed. Otherwise just return EOK as
+ * the input was not a name, thus there's no need to process it
+ * further. */
+ return cache_req_update_domains(mem_ctx, req, cr, domain);
+ }
+
+ if (cr->plugin->parse_name == false) {
+ /* Call cache_req_update_domains() in order to get a up to date list
+ * of domains and subdomains, if needed. Otherwise, just use the input
+ * name as it is. */
+ ret = cache_req_update_domains(mem_ctx, req, cr, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return cache_req_set_name(cr, cr->data->name.input);
+ }
+
+ default_domain = NULL;
+ if (!cr->plugin->ignore_default_domain) {
+ default_domain = cr->rctx->default_domain;
+ }
+
+ /* Parse name since it may contain a domain name. */
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Parsing input name [%s]\n", cr->data->name.input);
+
+ subreq = sss_parse_inp_send(mem_ctx, cr->rctx, default_domain,
+ cr->data->name.input);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_inp_send() failed\n");
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, cache_req_input_parsed, req);
+
+ return EAGAIN;
+}
+
+static errno_t cache_req_update_domains(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req *cr,
+ const char *domain)
+{
+ struct tevent_req *subreq;
+
+ if (cr->rctx->get_domains_last_call.tv_sec != 0) {
+ return EOK;
+ }
+
+ subreq = sss_dp_get_domains_send(mem_ctx, cr->rctx, false, domain);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, cache_req_domains_updated, req);
+ return EAGAIN;
+}
+
+static void cache_req_domains_updated(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct cache_req_state *state;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_state);
+
+ ret = sss_dp_get_domains_recv(subreq);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (state->cr->data->name.input == NULL) {
+ /* Input was not name, there is no need to process it further. */
+ goto immediately;
+ }
+
+ if (state->cr->plugin->parse_name == false || state->domain_name != NULL) {
+ /* We do not want to parse the name. */
+ ret = cache_req_set_name(state->cr, state->cr->data->name.input);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+immediately:
+ ret = cache_req_select_domains(req, state->domain_name,
+ state->cr->data->requested_domains);
+
+done:
+ if (ret != EOK && ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ return;
+ }
+}
+
+static void cache_req_input_parsed(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct cache_req_state *state;
+ char *name;
+ char *domain = NULL;
+ bool maybe_upn;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_state);
+
+ ret = sss_parse_inp_recv(subreq, state, &name, &domain);
+
+ if (state->domain_name != NULL && domain != NULL
+ && strcmp(state->domain_name, domain) != 0){
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Mismatch between input domain name [%s] and parsed domain name [%s]\n",
+ state->domain_name, domain);
+ tevent_req_error(req, ERR_INPUT_PARSE);
+ return;
+ }
+
+ switch (ret) {
+ case EOK:
+ ret = cache_req_set_name(state->cr, name);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ break;
+ case ERR_DOMAIN_NOT_FOUND:
+ maybe_upn = cache_req_assume_upn(state->cr);
+ if (!maybe_upn) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ domain = NULL;
+ break;
+ default:
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (state->domain_name == NULL) {
+ state->domain_name = domain;
+ }
+ ret = cache_req_select_domains(req, state->domain_name,
+ state->cr->data->requested_domains);
+ if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ return;
+ }
+}
+
+static errno_t cache_req_select_domains(struct tevent_req *req,
+ const char *domain_name,
+ char **requested_domains)
+{
+ struct cache_req_state *state = NULL;
+ struct cache_req_domain *cr_domain;
+ bool check_next;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct cache_req_state);
+
+ if (state->cr->cache_behavior != CACHE_REQ_CACHE_FIRST) {
+
+ if (!state->first_iteration) {
+ /* We're done here. */
+ return EOK;
+ }
+ }
+
+ ret = cache_req_domain_copy_cr_domains(state,
+ state->cr->rctx->cr_domains,
+ requested_domains,
+ &state->cr_domains);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_copy_cr_domains() failed\n");
+ return EINVAL;
+ }
+
+ if (domain_name != NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Performing a single domain search\n");
+
+ cr_domain = cache_req_domain_get_domain_by_name(
+ state->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");
+
+ cr_domain = state->cr_domains;
+ check_next = true;
+ }
+
+ return cache_req_search_domains(req, cr_domain, check_next);
+}
+
+static errno_t
+cache_req_search_domains(struct tevent_req *req,
+ struct cache_req_domain *cr_domain,
+ bool check_next)
+{
+ struct tevent_req *subreq;
+ struct cache_req_state *state = NULL;
+ const char *cache_action;
+ const char *provider_action;
+
+ state = tevent_req_data(req, struct cache_req_state);
+
+ switch (state->cr->cache_behavior) {
+ case CACHE_REQ_CACHE_FIRST:
+ cache_action = (state->first_iteration) ? "check" : "bypass";
+ provider_action = (state->first_iteration) ? "bypass" : "check";
+ break;
+ case CACHE_REQ_BYPASS_CACHE:
+ cache_action = "bypass";
+ provider_action = "check";
+ break;
+ case CACHE_REQ_BYPASS_PROVIDER:
+ cache_action = "check";
+ provider_action = "bypass";
+ break;
+ default:
+ cache_action = "check";
+ provider_action = "check";
+ break;
+ }
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Search will %s the cache and %s the data provider\n",
+ cache_action, provider_action);
+
+ subreq = cache_req_search_domains_send(state, state->ev, state->cr,
+ cr_domain, check_next,
+ state->first_iteration);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, cache_req_process_result, req);
+ return EAGAIN;
+}
+
+static void cache_req_process_result(struct tevent_req *subreq)
+{
+ struct cache_req_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_state);
+
+ ret = cache_req_search_domains_recv(state, subreq,
+ &state->results, &state->num_results);
+ talloc_zfree(subreq);
+
+ if (ret == ENOENT && state->first_iteration) {
+ /* Try again different search schema. */
+ state->first_iteration = false;
+ ret = cache_req_select_domains(req, state->domain_name,
+ state->cr->data->requested_domains);
+ if (ret == EOK) {
+ /* We're done searching and we have found nothing. */
+ ret = ENOENT;
+ }
+ }
+
+ /* Have have tried all domains and found nothing. Let's try UPN search. */
+ if (ret == ENOENT) {
+ if (state->domain_name != NULL) {
+ /* Lookup domain was specified as input. Since we haven't
+ * found anything yet we may want to try UPN search with
+ * some plug-ins. */
+
+ if (cache_req_assume_upn(state->cr)) {
+ /* Try UPN now. */
+ state->first_iteration = true;
+ ret = cache_req_select_domains(req, NULL,
+ state->cr->data->requested_domains);
+ }
+ }
+ }
+
+ /* Overlay each result with session recording flag */
+ if (ret == EOK) {
+ subreq = cache_req_sr_overlay_send(state, state->ev, state->cr,
+ state->results,
+ state->num_results);
+ if (subreq == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed creating a session recording "
+ "overlay request\n");
+ ret = ENOMEM;
+ } else {
+ tevent_req_set_callback(subreq, cache_req_done, req);
+ ret = EAGAIN;
+ }
+ }
+
+ switch (ret) {
+ case EAGAIN:
+ break;
+ case ENOENT:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Finished: Not found\n");
+ tevent_req_error(req, ret);
+ break;
+ default:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Finished: Error %d: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ break;
+ }
+
+ return;
+}
+
+static void cache_req_done(struct tevent_req *subreq)
+{
+ struct cache_req_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_state);
+ ret = cache_req_sr_overlay_recv(subreq);
+ talloc_zfree(subreq);
+
+ switch (ret) {
+ case EOK:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Finished: Success\n");
+ tevent_req_done(req);
+ break;
+ default:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Finished: Error %d: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ break;
+ }
+}
+
+uint32_t cache_req_get_reqid(struct tevent_req *req)
+{
+ const struct cache_req_state *state;
+
+ state = tevent_req_data(req, struct cache_req_state);
+
+ if (state && state->cr) {
+ return state->cr->reqid;
+ }
+
+ return 0;
+}
+
+errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req_result ***_results)
+{
+ struct cache_req_state *state;
+
+ state = tevent_req_data(req, struct cache_req_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (_results != NULL) {
+ *_results = talloc_steal(mem_ctx, state->results);
+ }
+
+ return EOK;
+}
+
+errno_t cache_req_single_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req_result **_result)
+{
+ struct cache_req_state *state;
+
+ state = tevent_req_data(req, struct cache_req_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (_result != NULL) {
+ *_result = talloc_steal(mem_ctx, state->results[0]);
+ }
+
+ return EOK;
+}
+
+struct tevent_req *
+cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ struct cache_req_data *data)
+{
+ struct tevent_req *req;
+
+ req = cache_req_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ req_dom_type, domain, data);
+ if (req == NULL) {
+ talloc_zfree(data);
+ return NULL;
+ }
+
+ talloc_steal(req, data);
+
+ return req;
+}
diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
new file mode 100644
index 0000000..a0c6879
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req.h
@@ -0,0 +1,521 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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_H_
+#define _CACHE_REQ_H_
+
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "responder/common/negcache.h"
+
+enum cache_req_type {
+ CACHE_REQ_USER_BY_NAME,
+ CACHE_REQ_USER_BY_UPN,
+ CACHE_REQ_USER_BY_ID,
+ CACHE_REQ_USER_BY_CERT,
+ CACHE_REQ_USER_BY_FILTER,
+
+ CACHE_REQ_GROUP_BY_NAME,
+ CACHE_REQ_GROUP_BY_ID,
+ CACHE_REQ_GROUP_BY_FILTER,
+
+ CACHE_REQ_INITGROUPS,
+ CACHE_REQ_INITGROUPS_BY_UPN,
+
+#ifdef BUILD_SUBID
+ CACHE_REQ_SUBID_RANGES_BY_NAME,
+#endif
+
+ CACHE_REQ_OBJECT_BY_SID,
+ CACHE_REQ_OBJECT_BY_NAME,
+ CACHE_REQ_OBJECT_BY_ID,
+
+ CACHE_REQ_ENUM_USERS,
+ CACHE_REQ_ENUM_GROUPS,
+ CACHE_REQ_ENUM_SVC,
+ CACHE_REQ_ENUM_HOST,
+ CACHE_REQ_ENUM_IP_NETWORK,
+
+ CACHE_REQ_SVC_BY_NAME,
+ CACHE_REQ_SVC_BY_PORT,
+
+ CACHE_REQ_NETGROUP_BY_NAME,
+
+ CACHE_REQ_SSH_HOST_ID_BY_NAME,
+
+ CACHE_REQ_AUTOFS_MAP_ENTRIES,
+ CACHE_REQ_AUTOFS_MAP_BY_NAME,
+ CACHE_REQ_AUTOFS_ENTRY_BY_NAME,
+
+ CACHE_REQ_IP_HOST_BY_NAME,
+ CACHE_REQ_IP_HOST_BY_ADDR,
+ CACHE_REQ_IP_NETWORK_BY_NAME,
+ CACHE_REQ_IP_NETWORK_BY_ADDR,
+
+ CACHE_REQ_SENTINEL
+};
+
+/* Whether to limit the request type to a certain domain type
+ * (POSIX/non-POSIX)
+ */
+enum cache_req_dom_type {
+ /* Only look up data in POSIX domains */
+ CACHE_REQ_POSIX_DOM,
+ /* Only look up data in application domains */
+ CACHE_REQ_APPLICATION_DOM,
+ /* Look up data in any domain type */
+ CACHE_REQ_ANY_DOM
+};
+
+/* Controls behavior about how to use cached information during
+ * a lookup, this is to fine tune some behaviors for specific
+ * situations
+ */
+enum cache_req_behavior {
+ CACHE_REQ_NORMAL,
+ CACHE_REQ_CACHE_FIRST,
+ CACHE_REQ_BYPASS_CACHE,
+ CACHE_REQ_BYPASS_PROVIDER,
+};
+
+/* Input data. */
+
+struct cache_req_data;
+
+struct cache_req_data *
+cache_req_data_attr(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *attr,
+ const char *filter);
+
+struct cache_req_data *
+cache_req_data_name(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name);
+
+struct cache_req_data *
+cache_req_data_name_attrs(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name,
+ const char **attrs);
+
+struct cache_req_data *
+cache_req_data_id(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ uint32_t id);
+
+struct cache_req_data *
+cache_req_data_id_attrs(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ uint32_t id,
+ const char **attrs);
+
+struct cache_req_data *
+cache_req_data_cert(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *cert);
+
+struct cache_req_data *
+cache_req_data_sid(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *sid,
+ const char **attrs);
+
+struct cache_req_data *
+cache_req_data_addr(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ uint32_t af,
+ uint32_t addrlen,
+ uint8_t *addr);
+
+struct cache_req_data *
+cache_req_data_enum(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type);
+
+struct cache_req_data *
+cache_req_data_svc(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name,
+ const char *protocol,
+ uint16_t port);
+
+struct cache_req_data *
+cache_req_data_ssh_host_id(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name,
+ const char *alias,
+ const char **attrs);
+
+struct cache_req_data *
+cache_req_data_autofs_entry(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *mapname,
+ const char *entryname);
+
+void
+cache_req_data_set_bypass_cache(struct cache_req_data *data,
+ bool bypass_cache);
+
+void
+cache_req_data_set_bypass_dp(struct cache_req_data *data,
+ bool bypass_dp);
+
+void
+cache_req_data_set_requested_domains(struct cache_req_data *data,
+ char **requested_domains);
+
+void
+cache_req_data_set_propogate_offline_status(struct cache_req_data *data,
+ bool propogate_offline_status);
+
+void
+cache_req_data_set_hybrid_lookup(struct cache_req_data *data,
+ bool hybrid_lookup);
+
+enum cache_req_type
+cache_req_data_get_type(struct cache_req_data *data);
+
+/* Output data. */
+
+struct cache_req_result {
+ /**
+ * SSSD domain where the result was obtained.
+ */
+ struct sss_domain_info *domain;
+
+ /**
+ * Result from ldb lookup.
+ */
+ struct ldb_result *ldb_result;
+
+ /**
+ * Shortcuts into ldb_result. This shortens the code a little since
+ * callers usually don't don't need to work with ldb_result directly.
+ */
+ unsigned int count;
+ struct ldb_message **msgs;
+
+ /**
+ * If name was used as a lookup parameter, @lookup_name contains name
+ * normalized to @domain rules.
+ */
+ const char *lookup_name;
+
+ /**
+ * If true the result contain attributes of a well known object.
+ * Since this result is manually created it may not contain all
+ * requested attributes, depending on the plug-in.
+ */
+ bool well_known_object;
+
+ /* If this is a well known object, it may not be part of any particular
+ * SSSD domain, but still may be associated with a well known domain
+ * name such as "BUILTIN", or "LOCAL AUTHORITY".
+ */
+ const char *well_known_domain;
+};
+
+/**
+ * Shallow copy of cache request result, limiting the result to a maximum
+ * numbers of records.
+ */
+struct cache_req_result *
+cache_req_copy_limited_result(TALLOC_CTX *mem_ctx,
+ struct cache_req_result *result,
+ uint32_t start,
+ uint32_t limit);
+
+/* Generic request. */
+
+struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int midpoint,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ struct cache_req_data *data);
+
+uint32_t cache_req_get_reqid(struct tevent_req *req);
+
+errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req_result ***_results);
+
+errno_t cache_req_single_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct cache_req_result **_result);
+
+/* Plug-ins. */
+
+struct tevent_req *
+cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *name);
+
+#define cache_req_user_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_user_by_name_attrs_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs);
+
+#define cache_req_user_by_name_attrs_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_user_by_upn_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *upn);
+
+#define cache_req_user_by_upn_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result);
+
+struct tevent_req *
+cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ uid_t uid);
+
+#define cache_req_user_by_id_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result);
+
+struct tevent_req *
+cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *pem_cert);
+
+#define cache_req_user_by_cert_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *name);
+
+#define cache_req_group_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ gid_t gid);
+
+#define cache_req_group_by_id_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *name);
+
+#define cache_req_initgr_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *attr,
+ const char *filter);
+
+#define cache_req_user_by_filter_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *filter);
+
+#define cache_req_group_by_filter_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_object_by_sid_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *sid,
+ const char **attrs);
+
+#define cache_req_object_by_sid_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_object_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs);
+
+#define cache_req_object_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_object_by_id_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ uint32_t id,
+ const char **attrs);
+
+#define cache_req_object_by_id_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_svc_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char *protocol);
+
+#define cache_req_svc_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_svc_by_port_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ uint16_t port,
+ const char *protocol);
+
+#define cache_req_svc_by_port_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_netgroup_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name);
+
+#define cache_req_netgroup_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_ssh_host_id_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char *alias,
+ const char **attrs);
+
+#define cache_req_ssh_host_id_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name);
+
+#define cache_req_autofs_map_entries_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name);
+
+#define cache_req_autofs_map_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+struct tevent_req *
+cache_req_autofs_entry_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *mapname,
+ const char *entryname);
+
+#define cache_req_autofs_entry_by_name_recv(mem_ctx, req, _result) \
+ cache_req_single_domain_recv(mem_ctx, req, _result)
+
+#endif /* _CACHE_REQ_H_ */
diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c
new file mode 100644
index 0000000..c506de5
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_data.c
@@ -0,0 +1,519 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+
+#include "db/sysdb.h"
+#include "responder/common/cache_req/cache_req_private.h"
+
+static const char **
+cache_req_data_create_attrs(TALLOC_CTX *mem_ctx,
+ const char **requested)
+{
+ static const char *defattrs[] = { SYSDB_DEFAULT_ATTRS, SYSDB_NAME,
+ OVERRIDE_PREFIX SYSDB_NAME,
+ SYSDB_DEFAULT_OVERRIDE_NAME };
+ static size_t defnum = sizeof(defattrs) / sizeof(defattrs[0]);
+ const char **attrs;
+ size_t reqnum;
+ size_t total;
+ size_t i;
+
+ for (reqnum = 0; requested[reqnum] != NULL; reqnum++);
+
+ total = defnum + reqnum;
+
+ /* We always want to get default attributes. */
+ attrs = talloc_zero_array(mem_ctx, const char *, total + 1);
+ if (attrs == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < reqnum; i++) {
+ attrs[i] = talloc_strdup(attrs, requested[i]);
+ if (attrs[i] == NULL) {
+ talloc_free(attrs);
+ return NULL;
+ }
+ }
+
+ for (/* continue */; i < total; i++) {
+ attrs[i] = talloc_strdup(attrs, defattrs[i - reqnum]);
+ if (attrs[i] == NULL) {
+ talloc_free(attrs);
+ return NULL;
+ }
+ }
+
+ return attrs;
+}
+
+static struct cache_req_data *
+cache_req_data_create(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const struct cache_req_data *input)
+{
+ struct cache_req_data *data;
+ errno_t ret;
+
+ data = talloc_zero(mem_ctx, struct cache_req_data);
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
+ return NULL;
+ }
+
+ data->type = type;
+ data->svc.name = &data->name;
+
+ switch (type) {
+ case CACHE_REQ_USER_BY_FILTER:
+ if (input->name.attr == NULL) {
+ data->name.attr = NULL;
+ } else {
+ data->name.attr = talloc_strdup(data, input->name.attr);
+ if (data->name.attr == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ /* Fallthrough */
+ case CACHE_REQ_USER_BY_NAME:
+ case CACHE_REQ_USER_BY_UPN:
+ case CACHE_REQ_GROUP_BY_NAME:
+ case CACHE_REQ_GROUP_BY_FILTER:
+ case CACHE_REQ_INITGROUPS:
+ case CACHE_REQ_INITGROUPS_BY_UPN:
+#ifdef BUILD_SUBID
+ case CACHE_REQ_SUBID_RANGES_BY_NAME:
+#endif
+ case CACHE_REQ_NETGROUP_BY_NAME:
+ case CACHE_REQ_OBJECT_BY_NAME:
+ case CACHE_REQ_AUTOFS_MAP_ENTRIES:
+ case CACHE_REQ_AUTOFS_MAP_BY_NAME:
+ case CACHE_REQ_IP_HOST_BY_NAME:
+ case CACHE_REQ_IP_NETWORK_BY_NAME:
+ if (input->name.input == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->name.input = talloc_strdup(data, input->name.input);
+ if (data->name.input == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ case CACHE_REQ_IP_HOST_BY_ADDR:
+ case CACHE_REQ_IP_NETWORK_BY_ADDR:
+ data->addr.af = input->addr.af;
+ data->addr.len = input->addr.len;
+ data->addr.data = talloc_memdup(data, input->addr.data,
+ input->addr.len);
+ if (data->addr.data == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ case CACHE_REQ_USER_BY_CERT:
+ if (input->cert == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: certificate cannot be NULL!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->cert = talloc_strdup(data, input->cert);
+ if (data->cert == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ case CACHE_REQ_USER_BY_ID:
+ case CACHE_REQ_GROUP_BY_ID:
+ case CACHE_REQ_OBJECT_BY_ID:
+ data->id = input->id;
+ break;
+ case CACHE_REQ_OBJECT_BY_SID:
+ if (input->sid == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: SID cannot be NULL!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->sid = talloc_strdup(data, input->sid);
+ if (data->sid == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ case CACHE_REQ_ENUM_USERS:
+ case CACHE_REQ_ENUM_GROUPS:
+ case CACHE_REQ_ENUM_SVC:
+ case CACHE_REQ_ENUM_HOST:
+ case CACHE_REQ_ENUM_IP_NETWORK:
+ break;
+ case CACHE_REQ_SVC_BY_NAME:
+ if ((input->svc.name == NULL) || (input->svc.name->input == NULL)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->svc.name->input = talloc_strdup(data, input->svc.name->input);
+ if (data->svc.name->input == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (input->svc.protocol.name == NULL) {
+ break;
+ }
+
+ data->svc.protocol.name = talloc_strdup(data, input->svc.protocol.name);
+ if (data->svc.protocol.name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ break;
+ case CACHE_REQ_SVC_BY_PORT:
+ if (input->svc.port == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: port cannot be 0!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->svc.port = input->svc.port;
+
+ if (input->svc.protocol.name == NULL) {
+ break;
+ }
+
+ data->svc.protocol.name = talloc_strdup(data, input->svc.protocol.name);
+ if (data->svc.protocol.name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ break;
+ case CACHE_REQ_SSH_HOST_ID_BY_NAME:
+ if (input->name.input == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->name.input = talloc_strdup(data, input->name.input);
+ if (data->name.input == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (input->alias == NULL) {
+ break;
+ }
+
+ data->alias = talloc_strdup(data, input->alias);
+ if (data->alias == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ case CACHE_REQ_AUTOFS_ENTRY_BY_NAME:
+ if (input->name.input == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ data->name.input = talloc_strdup(data, input->name.input);
+ if (data->name.input == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ data->autofs_entry_name = talloc_strdup(data, input->autofs_entry_name);
+ if (data->autofs_entry_name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ case CACHE_REQ_SENTINEL:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid cache request type!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ if (input->attrs != NULL) {
+ data->attrs = cache_req_data_create_attrs(data, input->attrs);
+ if (data->attrs == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_zfree(data);
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create cache_req data "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return NULL;
+ }
+
+ return data;
+}
+
+struct cache_req_data *
+cache_req_data_name(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name)
+{
+ struct cache_req_data input = {0};
+
+ input.name.input = name;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_name_attrs(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data input = { 0 };
+
+ input.name.input = name;
+ input.attrs = attrs;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_attr(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *attr,
+ const char *filter)
+{
+ struct cache_req_data input = {0};
+
+ input.name.input = filter;
+ input.name.attr = attr;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_id(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ uint32_t id)
+{
+ struct cache_req_data input = {0};
+
+ input.id = id;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_id_attrs(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ uint32_t id,
+ const char **attrs)
+{
+ struct cache_req_data input = { 0 };
+
+ input.id = id;
+ input.attrs = attrs;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_cert(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *cert)
+{
+ struct cache_req_data input = {0};
+
+ input.cert = cert;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_sid(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *sid,
+ const char **attrs)
+{
+ struct cache_req_data input = {0};
+
+ input.sid = sid;
+ input.attrs = attrs;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_enum(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type)
+{
+ struct cache_req_data input = { 0 };
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_svc(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name,
+ const char *protocol,
+ uint16_t port)
+{
+ struct cache_req_data input = { 0 };
+
+ input.name.input = name;
+ input.svc.name = &input.name;
+ input.svc.protocol.name = protocol;
+ input.svc.port = port;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_ssh_host_id(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *name,
+ const char *alias,
+ const char **attrs)
+{
+ struct cache_req_data input = {0};
+
+ input.name.input = name;
+ input.alias = alias;
+ input.attrs = attrs;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_addr(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ uint32_t af,
+ uint32_t addrlen,
+ uint8_t *addr)
+{
+ struct cache_req_data input = {0};
+
+ input.addr.af = af;
+ input.addr.len = addrlen;
+ input.addr.data = addr;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+struct cache_req_data *
+cache_req_data_autofs_entry(TALLOC_CTX *mem_ctx,
+ enum cache_req_type type,
+ const char *mapname,
+ const char *entryname)
+{
+ struct cache_req_data input = {0};
+
+ input.name.input = mapname;
+ input.autofs_entry_name = entryname;
+
+ return cache_req_data_create(mem_ctx, type, &input);
+}
+
+void
+cache_req_data_set_bypass_cache(struct cache_req_data *data,
+ bool bypass_cache)
+{
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+ return;
+ }
+
+ data->bypass_cache = bypass_cache;
+}
+
+void
+cache_req_data_set_bypass_dp(struct cache_req_data *data,
+ bool bypass_dp)
+{
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+ return;
+ }
+
+ data->bypass_dp = bypass_dp;
+}
+
+void
+cache_req_data_set_requested_domains(struct cache_req_data *data,
+ char **requested_domains)
+{
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+ return;
+ }
+
+ data->requested_domains = requested_domains;
+}
+
+void
+cache_req_data_set_propogate_offline_status(struct cache_req_data *data,
+ bool propogate_offline_status)
+{
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+ return;
+ }
+
+ data->propogate_offline_status = propogate_offline_status;
+}
+
+void
+cache_req_data_set_hybrid_lookup(struct cache_req_data *data,
+ bool hybrid_lookup)
+{
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+ return;
+ }
+
+ data->hybrid_lookup = hybrid_lookup;
+}
+
+
+enum cache_req_type
+cache_req_data_get_type(struct cache_req_data *data)
+{
+ if (data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+ return CACHE_REQ_SENTINEL;
+ }
+
+ return data->type;
+}
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 0000000..1f3b690
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_domain.c
@@ -0,0 +1,317 @@
+/*
+ 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;
+}
+
+errno_t
+cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx,
+ struct cache_req_domain *src,
+ char **requested_domains,
+ struct cache_req_domain **_dest)
+{
+ struct cache_req_domain *cr_domains = NULL;
+ struct cache_req_domain *cr_domain;
+ struct cache_req_domain *iter;
+ errno_t ret;
+
+ if (src == NULL) {
+ return EINVAL;
+ }
+
+ DLIST_FOR_EACH(iter, src) {
+ if (requested_domains != NULL
+ && !string_in_list(iter->domain->name, requested_domains,
+ false)) {
+ continue;
+ }
+
+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
+ if (cr_domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cr_domain->domain = iter->domain;
+ cr_domain->fqnames = iter->fqnames;
+
+ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *);
+ }
+
+ if (cr_domains == NULL) {
+ if (requested_domains != NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "No requested domains found, "
+ "please check configuration options for typos.\n");
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to copy domains.\n");
+ }
+ ret = EINVAL;
+ goto done;
+ }
+
+ *_dest = cr_domains;
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ cache_req_domain_list_zfree(&cr_domains);
+ }
+
+ 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 bool
+cache_req_domain_use_fqnames(struct sss_domain_info *domain,
+ bool enforce_non_fqnames)
+{
+ struct sss_domain_info *head;
+
+ head = get_domains_head(domain);
+
+ /*
+ * In order to decide whether fully_qualified_names must be used on the
+ * lookups we have to take into consideration:
+ * - use_fully_qualified_name value of the head of the domains;
+ * (head->fqnames)
+ * - the presence of a domains' resolution order list;
+ * (non_fqnames_enforced)
+ *
+ * The relationship between those two can be described by:
+ * - head->fqnames:
+ * - true: in this case doesn't matter whether it's enforced or not,
+ * fully-qualified-names will _always_ be used
+ * - false: in this case (which is also the default case), the usage
+ * depends on it being enforced;
+ *
+ * - enforce_non_fqnames:
+ * - true: in this case, the usage of fully-qualified-names is not
+ * needed;
+ * - false: in this case, the usage of fully-qualified-names will be
+ * done accordingly to what's set for the domain itself.
+ */
+ if (head->fqnames) {
+ return true;
+ } else if (enforce_non_fqnames) {
+ return false;
+ } else {
+ return domain->fqnames;
+ }
+}
+
+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;
+ bool enforce_non_fqnames = false;
+ bool files_provider = false;
+ errno_t ret;
+
+ /* Firstly, in case a domains' resolution order is passed ... iterate over
+ * the list adding its domains to the flatten cache req domains' list */
+ if (resolution_order != NULL) {
+ enforce_non_fqnames = true;
+ 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;
+ cr_domain->fqnames =
+ cache_req_domain_use_fqnames(dom, enforce_non_fqnames);
+
+ /* when using the domain resolution order, using shortnames as
+ * input is allowed by default. However, we really want to use
+ * the fully qualified name as output in order to avoid
+ * conflicts whith users who have the very same name. */
+ sss_domain_info_set_output_fqnames(cr_domain->domain, true);
+
+ DLIST_ADD_END(cr_domains, cr_domain,
+ struct cache_req_domain *);
+ break;
+ }
+ }
+ }
+
+ /* Then iterate through all the other domains (and subdomains) and add them
+ * to the flatten cache req domains' list */
+ for (dom = domains; dom; dom = get_next_domain(dom, flag)) {
+ if (string_in_list(dom->name, resolution_order, false)) {
+ continue;
+ }
+
+ files_provider = is_files_provider(dom);
+
+ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
+ if (cr_domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cr_domain->domain = dom;
+ cr_domain->fqnames =
+ cache_req_domain_use_fqnames(dom, enforce_non_fqnames);
+
+ /* when using the domain resolution order, using shortnames as input
+ * is allowed by default. However, we really want to use the fully
+ * qualified name as output in order to avoid conflicts whith users
+ * who have the very same name.
+ *
+ * NOTE: we do *not* want to use fully qualified names for the
+ * files provider.*/
+ if (resolution_order != NULL) {
+ if (!files_provider) {
+ sss_domain_info_set_output_fqnames(cr_domain->domain, true);
+ }
+ }
+
+ /* The implicit files provider should always be searched firstly,
+ * doesn't matter whether the domain_resolution_order set!
+ *
+ * By doing this we avoid querying other domains for local users.
+ */
+ if (files_provider) {
+ DLIST_ADD(cr_domains, cr_domain);
+ continue;
+ }
+
+ 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;
+}
+
+errno_t
+cache_req_domain_new_list_from_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ const char *domain_resolution_order,
+ struct cache_req_domain **_cr_domains)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct cache_req_domain *cr_domains;
+ char **list = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ if (domain_resolution_order != NULL) {
+ if (strcmp(domain_resolution_order, ":") != 0) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Domain resolution order list (split by ':'): \"%s\"\n",
+ domain_resolution_order);
+
+ 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;
+ }
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Domain resolution order list: ':' "
+ "(do not use any specific order)\n");
+ }
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Domain resolution order list: not set\n");
+ }
+
+ 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;
+ }
+
+ *_cr_domains = cr_domains;
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
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 0000000..72e4995
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_domain.h
@@ -0,0 +1,63 @@
+/*
+ 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;
+ bool fqnames;
+ bool locate_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);
+
+/*
+ * This function may have a side effect of setting the output_fqnames' domain
+ * property when it's called.
+ *
+ * It happens as the output_fqnames' domain property must only be set depending
+ * on whether a domain resolution order is set or not, and the saner place to
+ * set it to all domains is when flattening those (thus, in this function).
+ */
+errno_t
+cache_req_domain_new_list_from_domain_resolution_order(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domains,
+ const char *domain_resolution_order,
+ struct cache_req_domain **_cr_domains);
+
+errno_t
+cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx,
+ struct cache_req_domain *src,
+ char **requested_domains,
+ struct cache_req_domain **_dest);
+
+void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains);
+
+
+#endif /* _CACHE_REQ_DOMAIN_H_ */
diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h
new file mode 100644
index 0000000..f86a020
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_plugin.h
@@ -0,0 +1,331 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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_PLUGIN_H_
+#define _CACHE_REQ_PLUGIN_H_
+
+#include "responder/common/cache_req/cache_req_private.h"
+#include "sss_iface/sss_iface_async.h"
+
+enum cache_object_status {
+ CACHE_OBJECT_VALID,
+ CACHE_OBJECT_EXPIRED,
+ CACHE_OBJECT_MISSING,
+ CACHE_OBJECT_MIDPOINT
+};
+
+/**
+ * Create cache request result manually, if the searched object is well known
+ * and thus can not be found in the cache.
+ *
+ *
+ * @return EOK If it is a well known object and a result was created.
+ * @return ENOENT If it is not a well known object.
+ * @return Other errno code in case of an error.
+ */
+typedef errno_t
+(*cache_req_is_well_known_result_fn)(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct cache_req_result **_result);
+
+/**
+ * Prepare domain data. Some plug-ins may require to alter lookup data
+ * per specific domain rules, such as case sensitivity, fully qualified
+ * format etc.
+ *
+ * @return EOK If everything went fine.
+ * @return Other errno code in case of an error.
+ */
+typedef errno_t
+(*cache_req_prepare_domain_data_fn)(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain);
+
+/**
+ * Create an object debug name that is used in debug messages to identify
+ * this object.
+ *
+ * @return Debug name or NULL in case of an error.
+ **/
+typedef const char *
+(*cache_req_create_debug_name_fn)(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain);
+
+/**
+ * Check if an object is stored in negative cache.
+ *
+ * @return EOK If the object is not found.
+ * @return EEXIST If the object is found in negative cache.
+ * @return Other errno code in case of an error.
+ */
+typedef errno_t
+(*cache_req_ncache_check_fn)(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data);
+
+/**
+ * Add an object into negative cache.
+ *
+ * @return EOK If everything went fine.
+ * @return Other errno code in case of an error.
+ */
+typedef errno_t
+(*cache_req_ncache_add_fn)(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data);
+
+/**
+ * Filter the result through the negative cache.
+ *
+ * This is useful for plugins which don't use name as an input
+ * token but can be affected by filter_users and filter_groups
+ * options.
+ */
+typedef errno_t
+(*cache_req_ncache_filter_fn)(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ const char *name);
+
+/**
+ * Add an object into global negative cache.
+ *
+ * @return EOK If everything went fine.
+ * @return Other errno code in case of an error.
+ */
+typedef errno_t
+(*cache_req_global_ncache_add_fn)(struct sss_nc_ctx *ncache,
+ struct cache_req_data *data);
+
+/**
+ * Lookup object in sysdb.
+ *
+ * @return EOK If the object is found.
+ * @return ENOENT If the object is not found.
+ * @return Other errno code in case of an error.
+ */
+typedef errno_t
+(*cache_req_lookup_fn)(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result);
+
+/**
+ * Send Data Provider request.
+ *
+ * @return Tevent request on success.
+ * @return NULL on error.
+ */
+typedef struct tevent_req *
+(*cache_req_dp_send_fn)(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result);
+
+/**
+ * Process result of Data Provider request.
+ *
+ * Do not free subreq! It will be freed in the caller.
+ *
+ * @return True if data provider request succeeded.
+ * @return False if there was an error.
+ */
+typedef bool
+(*cache_req_dp_recv_fn)(struct tevent_req *subreq,
+ struct cache_req *cr);
+
+/**
+ * Check whether the results of the domain locator can still
+ * be considered valid or whether it is time to call the request
+ * again.
+ *
+ * @param resp_ctx The responder context.
+ * @param domain The domain to check. This should be the domain-head,
+ * because the locator works across a domain and its
+ * subdomains.
+ * @param data The cache request data that contains primarily the key
+ * to look for.
+ *
+ * @return True if the locator plugin should be ran again.
+ * @return False if the lookup should just proceed with the
+ * data that is already in the negative cache.
+ */
+typedef bool
+(*cache_req_dp_get_domain_check_fn)(struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data);
+/**
+ * Send Data Provider request to locate the domain
+ * of an entry
+ *
+ * @param resp_ctx The responder context.
+ * @param domain The domain to check. This should be the domain-head,
+ * because the locator works across a domain and its
+ * subdomains.
+ * @param data The cache request data that contains primarily the key
+ * to look for.
+ *
+ *
+ * @return Tevent request on success.
+ * @return NULL on error.
+ */
+typedef struct tevent_req *
+(*cache_req_dp_get_domain_send_fn)(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data);
+
+/**
+ * Process result of Data Provider find-domain request.
+ *
+ * Do not free subreq! It will be freed in the caller.
+ *
+ * @param mem_ctx The memory context that owns the _found_domain
+ * result parameter.
+ * @param subreq The request to finish.
+ * @param cr The cache_req being processed.
+ * @param _found_domain The domain the request account belongs to. This
+ * parameter can be NULL even on success, in that
+ * case the account was not found and no lookups are
+ * needed, all domains can be skipped in this case.
+ *
+ * @return EOK if the request did not encounter any error. In this
+ * case, the _found_domain parameter can be considered authoritative,
+ * regarless of its value
+ * @return errno on error. _found_domain should be NULL in this case.
+ */
+typedef errno_t
+(*cache_req_dp_get_domain_recv_fn)(TALLOC_CTX *mem_ctx,
+ struct tevent_req *subreq,
+ struct cache_req *cr,
+ char **_found_domain);
+
+struct cache_req_plugin {
+ /**
+ * Plugin name.
+ */
+ const char *name;
+
+ /**
+ * Expiration timestamp attribute name.
+ */
+ const char *attr_expiration;
+
+ /**
+ * Flags that are passed to get_next_domain().
+ */
+ uint32_t get_next_domain_flags;
+
+ /**
+ * True if input name should be parsed for domain.
+ */
+ bool parse_name;
+
+ /**
+ * True if default domain suffix should be ignored when parsing name.
+ */
+ bool ignore_default_domain;
+
+ /**
+ * True if we always contact data provider.
+ */
+ bool bypass_cache;
+
+ /**
+ * True if only one result is expected.
+ */
+ bool only_one_result;
+
+ /**
+ * If true, cache request will iterate over all domains on domain-less
+ * search and merge acquired results.
+ */
+ bool search_all_domains;
+
+ /**
+ * True if only domains with enumeration enabled are searched.
+ */
+ bool require_enumeration;
+
+ /**
+ * Allow missing domain part even if domain requires fully qualified name
+ * on domain less searches.
+ */
+ bool allow_missing_fqn;
+
+ /**
+ * True if this plugin can be swapped for equivalent search with UPN.
+ */
+ bool allow_switch_to_upn;
+ enum cache_req_type upn_equivalent;
+
+ /* Operations */
+ cache_req_is_well_known_result_fn is_well_known_fn;
+ cache_req_prepare_domain_data_fn prepare_domain_data_fn;
+ cache_req_create_debug_name_fn create_debug_name_fn;
+ cache_req_global_ncache_add_fn global_ncache_add_fn;
+ cache_req_ncache_check_fn ncache_check_fn;
+ cache_req_ncache_add_fn ncache_add_fn;
+ cache_req_ncache_filter_fn ncache_filter_fn;
+ cache_req_lookup_fn lookup_fn;
+ cache_req_dp_send_fn dp_send_fn;
+ cache_req_dp_recv_fn dp_recv_fn;
+ cache_req_dp_get_domain_check_fn dp_get_domain_check_fn;
+ cache_req_dp_get_domain_send_fn dp_get_domain_send_fn;
+ cache_req_dp_get_domain_recv_fn dp_get_domain_recv_fn;
+};
+
+extern const struct cache_req_plugin cache_req_user_by_name;
+extern const struct cache_req_plugin cache_req_user_by_upn;
+extern const struct cache_req_plugin cache_req_user_by_id;
+extern const struct cache_req_plugin cache_req_group_by_name;
+extern const struct cache_req_plugin cache_req_group_by_id;
+extern const struct cache_req_plugin cache_req_initgroups_by_name;
+extern const struct cache_req_plugin cache_req_initgroups_by_upn;
+#ifdef BUILD_SUBID
+extern const struct cache_req_plugin cache_req_subid_ranges_by_name;
+#endif
+extern const struct cache_req_plugin cache_req_user_by_cert;
+extern const struct cache_req_plugin cache_req_user_by_filter;
+extern const struct cache_req_plugin cache_req_group_by_filter;
+extern const struct cache_req_plugin cache_req_object_by_sid;
+extern const struct cache_req_plugin cache_req_object_by_name;
+extern const struct cache_req_plugin cache_req_object_by_id;
+extern const struct cache_req_plugin cache_req_enum_users;
+extern const struct cache_req_plugin cache_req_enum_groups;
+extern const struct cache_req_plugin cache_req_enum_svc;
+extern const struct cache_req_plugin cache_req_enum_ip_hosts;
+extern const struct cache_req_plugin cache_req_enum_ip_networks;
+extern const struct cache_req_plugin cache_req_svc_by_name;
+extern const struct cache_req_plugin cache_req_svc_by_port;
+extern const struct cache_req_plugin cache_req_netgroup_by_name;
+extern const struct cache_req_plugin cache_req_ssh_host_id_by_name;
+extern const struct cache_req_plugin cache_req_autofs_map_entries;
+extern const struct cache_req_plugin cache_req_autofs_map_by_name;
+extern const struct cache_req_plugin cache_req_autofs_entry_by_name;
+extern const struct cache_req_plugin cache_req_ip_host_by_name;
+extern const struct cache_req_plugin cache_req_ip_host_by_addr;
+extern const struct cache_req_plugin cache_req_ip_network_by_name;
+extern const struct cache_req_plugin cache_req_ip_network_by_addr;
+
+#endif /* _CACHE_REQ_PLUGIN_H_ */
diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
new file mode 100644
index 0000000..22f197b
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_private.h
@@ -0,0 +1,227 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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_PRIVATE_H_
+#define _CACHE_REQ_PRIVATE_H_
+
+#include <stdint.h>
+
+#include "responder/common/responder.h"
+#include "responder/common/cache_req/cache_req.h"
+
+#define CACHE_REQ_DEBUG(level, cr, fmt, ...) \
+ DEBUG(level, "CR #%u: " fmt, (cr)->reqid, ##__VA_ARGS__)
+
+/* Tracing message, changing this can break log parsing tools */
+#define SSS_REQ_TRACE_CID_CR(level, cr, fmt, ...) \
+ CACHE_REQ_DEBUG(level, cr, "REQ_TRACE: " fmt, ##__VA_ARGS__)
+
+struct cache_req {
+ /* Provided input. */
+ struct cache_req_data *data;
+
+ const struct cache_req_plugin *plugin;
+ struct resp_ctx *rctx;
+ struct sss_nc_ctx *ncache;
+ int midpoint;
+
+ /* Domain related information. */
+ struct sss_domain_info *domain;
+
+ /* wanted cache behavior */
+ enum cache_req_behavior cache_behavior;
+
+ /* Only contact domains with this type */
+ enum cache_req_dom_type req_dom_type;
+
+ /* Debug information */
+ uint32_t reqid;
+ const char *reqname;
+ const char *debugobj;
+
+ /* Time when the request started. Useful for by-filter lookups */
+ time_t req_start;
+};
+
+/**
+ * Structure to hold the information the user passed as parameter
+ * and some strings after processing this information.
+ */
+struct cache_req_parsed_name {
+ const char *input; /* Original input. */
+ const char *name; /* Parsed name or UPN. */
+ const char *lookup; /* Converted per domain rules. */
+ const char *attr; /* Attribute name when looking for an attribute */
+};
+
+/**
+ * Structure to hold the input strings that cannot contain domain
+ * part but are transferred per each domain's case sensitivity.
+ */
+struct cache_req_cased_name {
+ const char *name; /* Parsed name or UPN. */
+ const char *lookup; /* Converted per domain rules. */
+};
+
+/* Input data. */
+struct cache_req_data {
+ enum cache_req_type type;
+ struct cache_req_parsed_name name;
+ uint32_t id;
+ const char *cert;
+ const char *sid;
+ const char *alias;
+ const char **attrs;
+ const char *autofs_entry_name;
+
+ struct {
+ struct cache_req_parsed_name *name;
+ struct cache_req_cased_name protocol;
+ uint16_t port;
+ } svc;
+
+ struct {
+ uint32_t af;
+ uint32_t len;
+ uint8_t *data;
+ } addr;
+
+ bool bypass_cache;
+ bool bypass_dp;
+
+ /* if set, only search in the listed domains */
+ char **requested_domains;
+
+ /* if set, ERR_OFFLINE is returned if data provider is offline */
+ bool propogate_offline_status;
+
+ /* if set, only domains with MPG_HYBRID are searched */
+ bool hybrid_lookup;
+};
+
+struct tevent_req *
+cache_req_search_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ bool first_iteration,
+ bool cache_only_override);
+
+errno_t cache_req_search_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct ldb_result **_result,
+ bool *_dp_success);
+
+struct tevent_req *cache_req_locate_domain_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr);
+errno_t cache_req_locate_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ char **_found_domain);
+
+struct tevent_req *
+cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ struct cache_req_data *data);
+
+void cache_req_search_ncache_add_to_domain(struct cache_req *cr,
+ struct sss_domain_info *domain);
+
+errno_t
+cache_req_add_result(TALLOC_CTX *mem_ctx,
+ struct cache_req_result *new_result,
+ struct cache_req_result ***_results,
+ size_t *_num_results);
+
+struct cache_req_result *
+cache_req_create_result(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_result *ldb_result,
+ const char *lookup_name,
+ const char *well_known_domain);
+
+errno_t
+cache_req_create_and_add_result(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct sss_domain_info *domain,
+ struct ldb_result *ldb_result,
+ const char *name,
+ struct cache_req_result ***_results,
+ size_t *_num_results);
+
+struct ldb_result *
+cache_req_create_ldb_result_from_msg_list(TALLOC_CTX *mem_ctx,
+ struct ldb_message **ldb_msgs,
+ size_t ldb_msg_count);
+
+struct ldb_result *
+cache_req_create_ldb_result_from_msg(TALLOC_CTX *mem_ctx,
+ struct ldb_message *ldb_msg);
+
+struct cache_req_result *
+cache_req_create_result_from_msg(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_message *ldb_msg,
+ const char *lookup_name,
+ const char *well_known_domain);
+
+struct tevent_req *
+cache_req_sr_overlay_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ struct cache_req_result **results,
+ size_t num_results);
+
+errno_t
+cache_req_sr_overlay_recv(struct tevent_req *req);
+
+/* Plug-in common. */
+
+struct cache_req_result *
+cache_req_well_known_sid_result(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ const char *domname,
+ const char *sid,
+ const char *name);
+
+bool
+cache_req_common_process_dp_reply(struct cache_req *cr,
+ errno_t ret,
+ uint16_t err_maj,
+ uint32_t err_min,
+ const char *err_msg);
+
+bool
+cache_req_common_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr);
+
+errno_t
+cache_req_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *subreq,
+ struct cache_req *cr,
+ char **_domain);
+
+errno_t cache_req_idminmax_check(struct cache_req_data *data,
+ struct sss_domain_info *domain);
+#endif /* _CACHE_REQ_PRIVATE_H_ */
diff --git a/src/responder/common/cache_req/cache_req_result.c b/src/responder/common/cache_req/cache_req_result.c
new file mode 100644
index 0000000..c1a3732
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_result.c
@@ -0,0 +1,274 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <ldb.h>
+#include <talloc.h>
+#include <errno.h>
+
+#include "util/util.h"
+#include "responder/common/cache_req/cache_req_private.h"
+
+errno_t
+cache_req_add_result(TALLOC_CTX *mem_ctx,
+ struct cache_req_result *new_result,
+ struct cache_req_result ***_results,
+ size_t *_num_results)
+{
+ struct cache_req_result **results = *_results;
+ size_t idx;
+ size_t count;
+
+ /* Make space for new results. */
+ idx = *_num_results;
+ count = *_num_results + 1;
+
+ results = talloc_realloc(mem_ctx, results, struct cache_req_result *,
+ count + 1);
+ if (results == NULL) {
+ return ENOMEM;
+ }
+
+ results[idx] = talloc_steal(results, new_result);
+ results[idx + 1] = NULL;
+
+ *_results = results;
+ *_num_results = count;
+
+ return EOK;
+}
+
+struct cache_req_result *
+cache_req_create_result(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_result *ldb_result,
+ const char *lookup_name,
+ const char *well_known_domain)
+{
+ struct cache_req_result *result;
+
+ result = talloc_zero(mem_ctx, struct cache_req_result);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ result->domain = domain;
+ result->ldb_result = talloc_steal(result, ldb_result);
+ result->count = ldb_result != NULL ? ldb_result->count : 0;
+ result->msgs = ldb_result != NULL ? ldb_result->msgs : NULL;
+
+ if (lookup_name != NULL) {
+ result->lookup_name = talloc_strdup(result, lookup_name);
+ if (result->lookup_name == NULL) {
+ talloc_free(result);
+ return NULL;
+ }
+ }
+
+ if (well_known_domain != NULL) {
+ result->well_known_domain = talloc_strdup(result, well_known_domain);
+ if (result->well_known_domain == NULL) {
+ talloc_free(result);
+ return NULL;
+ }
+ }
+
+ return result;
+}
+
+errno_t
+cache_req_create_and_add_result(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct sss_domain_info *domain,
+ struct ldb_result *ldb_result,
+ const char *name,
+ struct cache_req_result ***_results,
+ size_t *_num_results)
+{
+ struct cache_req_result *item;
+ errno_t ret;
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Found %u entries in domain %s\n",
+ ldb_result->count, domain->name);
+
+ item = cache_req_create_result(mem_ctx, domain, ldb_result, name, NULL);
+ if (item == NULL) {
+ return ENOMEM;
+ }
+
+ ret = cache_req_add_result(mem_ctx, item, _results, _num_results);
+ if (ret != EOK) {
+ talloc_free(item);
+ }
+
+ return ret;
+}
+
+struct ldb_result *
+cache_req_create_ldb_result_from_msg_list(TALLOC_CTX *mem_ctx,
+ struct ldb_message **ldb_msgs,
+ size_t ldb_msg_count)
+{
+ struct ldb_result *ldb_result;
+
+ if (ldb_msgs == NULL || ldb_msgs[0] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No message set!\n");
+ return NULL;
+ }
+
+ ldb_result = talloc_zero(NULL, struct ldb_result);
+ if (ldb_result == NULL) {
+ return NULL;
+ }
+
+ ldb_result->extended = NULL;
+ ldb_result->controls = NULL;
+ ldb_result->refs = NULL;
+ ldb_result->count = ldb_msg_count;
+ ldb_result->msgs = talloc_zero_array(ldb_result, struct ldb_message *,
+ ldb_msg_count + 1);
+ if (ldb_result->msgs == NULL) {
+ talloc_free(ldb_result);
+ return NULL;
+ }
+
+ for (size_t i = 0; i < ldb_msg_count; i++) {
+ ldb_result->msgs[i] = talloc_steal(ldb_result->msgs, ldb_msgs[i]);
+ }
+
+ return ldb_result;
+}
+
+struct ldb_result *
+cache_req_create_ldb_result_from_msg(TALLOC_CTX *mem_ctx,
+ struct ldb_message *ldb_msg)
+{
+ struct ldb_result *ldb_result;
+
+ if (ldb_msg == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No message set!\n");
+ return NULL;
+ }
+
+ ldb_result = talloc_zero(NULL, struct ldb_result);
+ if (ldb_result == NULL) {
+ return NULL;
+ }
+
+ ldb_result->extended = NULL;
+ ldb_result->controls = NULL;
+ ldb_result->refs = NULL;
+ ldb_result->count = 1;
+ ldb_result->msgs = talloc_zero_array(ldb_result, struct ldb_message *, 2);
+ if (ldb_result->msgs == NULL) {
+ talloc_free(ldb_result);
+ return NULL;
+ }
+
+ ldb_result->msgs[0] = talloc_steal(ldb_result->msgs, ldb_msg);
+
+ return ldb_result;
+}
+
+struct cache_req_result *
+cache_req_create_result_from_msg(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_message *ldb_msg,
+ const char *lookup_name,
+ const char *well_known_domain)
+{
+ struct cache_req_result *result;
+ struct ldb_result *ldb_result;
+
+ if (ldb_msg == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No message set!\n");
+ return NULL;
+ }
+
+ ldb_result = cache_req_create_ldb_result_from_msg(mem_ctx, ldb_msg);
+ if (ldb_result == NULL) {
+ return NULL;
+ }
+
+ result = cache_req_create_result(mem_ctx, domain, ldb_result,
+ lookup_name, well_known_domain);
+ if (result == NULL) {
+ talloc_free(ldb_result);
+ return NULL;
+ }
+
+ return result;
+}
+
+struct cache_req_result *
+cache_req_copy_limited_result(TALLOC_CTX *mem_ctx,
+ struct cache_req_result *result,
+ uint32_t start,
+ uint32_t limit)
+{
+ struct cache_req_result *out = NULL;
+ struct ldb_result *ldb_result;
+ unsigned int left;
+ errno_t ret;
+
+ if (start >= result->count) {
+ ret = ERANGE;
+ goto done;
+ }
+
+ out = talloc_zero(mem_ctx, struct cache_req_result);
+ if (out == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ldb_result = talloc_zero(out, struct ldb_result);
+ if (ldb_result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ left = result->count - start;
+
+ ldb_result->extended = result->ldb_result->extended;
+ ldb_result->controls = result->ldb_result->controls;
+ ldb_result->refs = result->ldb_result->refs;
+ ldb_result->msgs = &(result->ldb_result->msgs[start]);
+ ldb_result->count = left < limit ? left : limit;
+
+ out->domain = result->domain;
+ out->ldb_result = ldb_result;
+ out->lookup_name = result->lookup_name;
+ out->count = ldb_result->count;
+ out->msgs = ldb_result->msgs;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create cache request result "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+
+ talloc_free(out);
+ return NULL;
+ }
+
+ return out;
+}
diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c
new file mode 100644
index 0000000..d800f47
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_search.c
@@ -0,0 +1,643 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <ldb.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "util/util.h"
+#include "responder/common/cache_req/cache_req_private.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+#include "db/sysdb.h"
+
+static errno_t cache_req_search_ncache(struct cache_req *cr)
+{
+ errno_t ret;
+
+ if (cr->plugin->ncache_check_fn == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_INTERNAL, cr,
+ "This request type does not support negative cache\n");
+ return EOK;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Checking negative cache for [%s]\n",
+ cr->debugobj);
+
+ ret = cr->plugin->ncache_check_fn(cr->ncache, cr->domain, cr->data);
+ if (ret == EEXIST) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "[%s] does not exist (negative cache)\n",
+ cr->debugobj);
+ return ENOENT;
+ } else if (ret != EOK && ret != ENOENT) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to check negative cache [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "[%s] is not present in negative cache\n",
+ cr->debugobj);
+
+ return EOK;
+}
+
+void cache_req_search_ncache_add_to_domain(struct cache_req *cr,
+ struct sss_domain_info *domain)
+{
+ errno_t ret;
+
+ if (cr->plugin->ncache_add_fn == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_INTERNAL, cr,
+ "This request type does not support negative cache\n");
+ return;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Adding [%s] to negative cache\n",
+ cr->debugobj);
+
+ ret = cr->plugin->ncache_add_fn(cr->ncache, domain, cr->data);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr,
+ "Cannot set negative cache for [%s] [%d]: %s\n",
+ cr->debugobj, ret, sss_strerror(ret));
+ /* not fatal */
+ }
+
+ return;
+}
+
+static void cache_req_search_ncache_add(struct cache_req *cr)
+{
+ return cache_req_search_ncache_add_to_domain(cr, cr->domain);
+}
+
+static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result **_result)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *filtered_result;
+ struct ldb_message **msgs;
+ size_t msg_count;
+ const char *name;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ if (cr->plugin->ncache_filter_fn == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "This request type does not support filtering "
+ "result by negative cache\n");
+
+ ret = EOK;
+ goto done;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Filtering out results by negative cache\n");
+
+ msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, (*_result)->count);
+ msg_count = 0;
+
+ for (size_t i = 0; i < (*_result)->count; i++) {
+ name = sss_get_name_from_msg(cr->domain, (*_result)->msgs[i]);
+ if (name == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "sss_get_name_from_msg() returned NULL, which should never "
+ "happen in this scenario!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ ret = cr->plugin->ncache_filter_fn(cr->ncache, cr->domain, name);
+ if (ret == EEXIST) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "[%s] filtered out! (negative cache)\n",
+ name);
+ continue;
+ } else if (ret != EOK && ret != ENOENT) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to check negative cache [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ msgs[msg_count] = talloc_steal(msgs, (*_result)->msgs[i]);
+ msg_count++;
+ }
+
+ if (msg_count == 0) {
+ ret = ENOENT;
+ goto done;
+ }
+
+ filtered_result = cache_req_create_ldb_result_from_msg_list(tmp_ctx, msgs,
+ msg_count);
+ if (filtered_result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(*_result);
+ *_result = talloc_steal(mem_ctx, filtered_result);
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int
+cache_req_should_be_in_cache(struct cache_req *cr,
+ struct ldb_result *result)
+{
+ id_t id = 0;
+
+ if (result == NULL || result->count != 1) {
+ /* can't decide so keep it */
+ return EOK;
+ }
+
+ id = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_UIDNUM, 0);
+ if (id && OUT_OF_ID_RANGE(id, cr->domain->id_min, cr->domain->id_max)) {
+ return ERR_ID_OUTSIDE_RANGE;
+ }
+
+ id = ldb_msg_find_attr_as_uint(result->msgs[0], SYSDB_GIDNUM, 0);
+ if (id && OUT_OF_ID_RANGE(id, cr->domain->id_min, cr->domain->id_max)) {
+ return ERR_ID_OUTSIDE_RANGE;
+ }
+
+ return EOK;
+}
+
+static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result **_result)
+{
+ struct ldb_result *result = NULL;
+ errno_t ret;
+
+ if (cr->plugin->lookup_fn == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Bug: No cache lookup function specified\n");
+ return ERR_INTERNAL;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Looking up [%s] in cache\n",
+ cr->debugobj);
+
+ ret = cr->plugin->lookup_fn(mem_ctx, cr, cr->data, cr->domain, &result);
+ if (ret == EOK && (result == NULL || result->count == 0)) {
+ ret = ENOENT;
+ }
+
+ if (ret == EOK) {
+ ret = cache_req_should_be_in_cache(cr, result);
+ }
+
+ switch (ret) {
+ case EOK:
+ if (cr->plugin->only_one_result && result->count > 1) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Multiple objects were found when "
+ "only one was expected!\n");
+ ret = ERR_MULTIPLE_ENTRIES;
+ goto done;
+ }
+
+ *_result = result;
+ break;
+ case ERR_ID_OUTSIDE_RANGE:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "ID [%s] was filtered out\n",
+ cr->debugobj);
+ break;
+ case ENOENT:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Object [%s] was not found in cache\n",
+ cr->debugobj);
+ break;
+ default:
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to lookup [%s] in cache [%d]: %s\n",
+ cr->debugobj, ret, sss_strerror(ret));
+ break;
+ }
+
+done:
+ if (ret != EOK) {
+ talloc_free(result);
+ }
+
+ return ret;
+}
+
+static enum cache_object_status
+cache_req_expiration_status(struct cache_req *cr,
+ struct ldb_result *result)
+{
+ time_t expire;
+ errno_t ret;
+
+ if (result == NULL || result->count == 0 || cr->plugin->bypass_cache) {
+ return CACHE_OBJECT_MISSING;
+ }
+
+ expire = ldb_msg_find_attr_as_uint64(result->msgs[0],
+ cr->plugin->attr_expiration, 0);
+
+ ret = sss_cmd_check_cache(result->msgs[0], cr->midpoint, expire);
+ if (ret == EOK) {
+ return CACHE_OBJECT_VALID;
+ } else if (ret == EAGAIN) {
+ return CACHE_OBJECT_MIDPOINT;
+ }
+
+ return CACHE_OBJECT_EXPIRED;
+}
+
+struct cache_req_search_state {
+ /* input data */
+ struct tevent_context *ev;
+ struct resp_ctx *rctx;
+ struct cache_req *cr;
+
+ /* output data */
+ struct ldb_result *result;
+ bool dp_success;
+};
+
+static errno_t cache_req_search_dp(struct tevent_req *req,
+ enum cache_object_status status);
+static void cache_req_search_oob_done(struct tevent_req *subreq);
+static void cache_req_search_done(struct tevent_req *subreq);
+
+struct tevent_req *
+cache_req_search_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ bool first_iteration,
+ bool cache_only_override)
+{
+ struct cache_req_search_state *state;
+ enum cache_object_status status;
+ struct tevent_req *req;
+ bool bypass_cache = false;
+ bool bypass_dp = false;
+ bool skip_refresh = false;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct cache_req_search_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Looking up %s\n", cr->debugobj);
+
+ state->ev = ev;
+ state->cr = cr;
+
+ ret = cache_req_search_ncache(cr);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (cache_only_override) {
+ bypass_dp = true;
+ } else {
+ switch (cr->cache_behavior) {
+ case CACHE_REQ_CACHE_FIRST:
+ bypass_cache = first_iteration ? false : true;
+ bypass_dp = first_iteration ? true : false;
+ break;
+ case CACHE_REQ_BYPASS_CACHE:
+ bypass_cache = true;
+ break;
+ case CACHE_REQ_BYPASS_PROVIDER:
+ bypass_dp = true;
+ skip_refresh = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* If bypass_cache is enabled we always contact data provider before
+ * searching the cache. Thus we set expiration status to missing,
+ * which will trigger data provider request later.
+ *
+ * If disabled, we want to search the cache here to see if the
+ * object is already cached and valid or if data provider needs
+ * to be contacted.
+ */
+ state->result = NULL;
+ status = CACHE_OBJECT_MISSING;
+ if (!bypass_cache) {
+ ret = cache_req_search_cache(state, cr, &state->result);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
+ status = cache_req_expiration_status(cr, state->result);
+ if (status == CACHE_OBJECT_VALID) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Returning [%s] from cache\n", cr->debugobj);
+ ret = EOK;
+ goto done;
+ }
+
+ /* For the CACHE_REQ_CACHE_FIRST case, if bypass_dp is true but we
+ * found the object in this domain, we will contact the data provider
+ * anyway to refresh it so we can return it without searching the rest
+ * of the domains.
+ */
+ if (status != CACHE_OBJECT_MISSING && !skip_refresh) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Object found, but needs to be refreshed.\n");
+ bypass_dp = false;
+ } else {
+ ret = ENOENT;
+ }
+ }
+
+ if (!bypass_dp) {
+ ret = cache_req_search_dp(req, status);
+ }
+
+ if (ret != EAGAIN) {
+ goto done;
+ }
+
+ return req;
+
+done:
+ if (ret == EOK) {
+ ret = cache_req_search_ncache_filter(state, cr, &state->result);
+ }
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static errno_t cache_req_search_dp(struct tevent_req *req,
+ enum cache_object_status status)
+{
+ struct cache_req_search_state *state;
+ struct tevent_req *subreq;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct cache_req_search_state);
+
+ switch (status) {
+ case CACHE_OBJECT_MIDPOINT:
+ /* Out of band update. The calling function will return the cached
+ * entry immediately. We need to use rctx so the request is not
+ * removed when state is freed. */
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Performing midpoint cache update of [%s]\n",
+ state->cr->debugobj);
+
+ subreq = state->cr->plugin->dp_send_fn(state->rctx, state->cr,
+ state->cr->data,
+ state->cr->domain,
+ state->result);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending out-of-band "
+ "data provider request\n");
+ /* This is non-fatal, so we'll continue here */
+ } else {
+ tevent_req_set_callback(subreq, cache_req_search_oob_done, req);
+ }
+
+ ret = EOK;
+ break;
+ case CACHE_OBJECT_EXPIRED:
+ case CACHE_OBJECT_MISSING:
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Looking up [%s] in data provider\n",
+ state->cr->debugobj);
+
+ subreq = state->cr->plugin->dp_send_fn(state->cr, state->cr,
+ state->cr->data,
+ state->cr->domain,
+ state->result);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Out of memory sending data provider request\n");
+ ret = ENOMEM;
+ break;
+ }
+
+ tevent_req_set_callback(subreq, cache_req_search_done, req);
+ ret = EAGAIN;
+ break;
+ default:
+ /* error */
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Unexpected status [%d]\n", status);
+ ret = ERR_INTERNAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void cache_req_search_oob_done(struct tevent_req *subreq)
+{
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Out of band request finished\n");
+ talloc_zfree(subreq);
+
+ return;
+}
+
+static void cache_req_search_done(struct tevent_req *subreq)
+{
+ struct cache_req_search_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_search_state);
+
+ state->dp_success = state->cr->plugin->dp_recv_fn(subreq, state->cr);
+ talloc_zfree(subreq);
+
+ /* Do not try to read from cache if the domain is inconsistent */
+ if (sss_domain_get_state(state->cr->domain) == DOM_INCONSISTENT) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Domain inconsistent, "
+ "we will not return cached data\n");
+
+ ret = ENOENT;
+ goto done;
+ }
+
+ /* Get result from cache again. */
+ ret = cache_req_search_cache(state, state->cr, &state->result);
+ if (ret != EOK) {
+ if (ret == ENOENT) {
+ /* Only store entry in negative cache if DP request succeeded
+ * because only then we know that the entry does not exist. */
+ if (state->dp_success) {
+ cache_req_search_ncache_add(state->cr);
+ }
+ }
+ goto done;
+ }
+
+ /* ret == EOK */
+ ret = cache_req_search_ncache_filter(state, state->cr, &state->result);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
+ "Returning updated object [%s]\n", state->cr->debugobj);
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+errno_t cache_req_search_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct ldb_result **_result,
+ bool *_dp_success)
+{
+ struct cache_req_search_state *state = NULL;
+ state = tevent_req_data(req, struct cache_req_search_state);
+
+ *_dp_success = state->dp_success;
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_result = talloc_steal(mem_ctx, state->result);
+
+ return EOK;
+}
+
+struct cache_req_locate_domain_state {
+ struct cache_req *cr;
+
+ char *found_domain;
+};
+
+static void cache_req_locate_domain_done(struct tevent_req *subreq);
+
+struct tevent_req *cache_req_locate_domain_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr)
+{
+ struct cache_req_locate_domain_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ errno_t ret;
+ bool should_run;
+
+ req = tevent_req_create(mem_ctx, &state, struct cache_req_locate_domain_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+ state->cr = cr;
+
+ should_run = cr->plugin->dp_get_domain_check_fn(cr->rctx,
+ get_domains_head(cr->domain),
+ cr->data);
+ if (should_run == false) {
+ /* The request was tried too recently, don't issue a new one
+ * as its results are still valid
+ */
+ ret = ERR_GET_ACCT_DOM_CACHED;
+ goto immediate;
+ }
+
+ subreq = cr->plugin->dp_get_domain_send_fn(state,
+ cr->rctx,
+ get_domains_head(cr->domain),
+ cr->data);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediate;
+ }
+ tevent_req_set_callback(subreq, cache_req_locate_domain_done, req);
+ return req;
+
+immediate:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void cache_req_locate_domain_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct cache_req_locate_domain_state *state;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_locate_domain_state);
+
+ ret = state->cr->plugin->dp_get_domain_recv_fn(state,
+ subreq,
+ state->cr,
+ &state->found_domain);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+errno_t cache_req_locate_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ char **_found_domain)
+{
+ struct cache_req_locate_domain_state *state = NULL;
+
+ state = tevent_req_data(req, struct cache_req_locate_domain_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_found_domain = talloc_steal(mem_ctx, state->found_domain);
+ return EOK;
+}
diff --git a/src/responder/common/cache_req/cache_req_sr_overlay.c b/src/responder/common/cache_req/cache_req_sr_overlay.c
new file mode 100644
index 0000000..8deb06a
--- /dev/null
+++ b/src/responder/common/cache_req/cache_req_sr_overlay.c
@@ -0,0 +1,347 @@
+/*
+ Authors:
+ Nikolai Kondrashov <Nikolai.Kondrashov@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 "db/sysdb.h"
+#include "responder/common/cache_req/cache_req_private.h"
+
+struct cache_req_sr_overlay_state {
+ /* Input data */
+ struct tevent_context *ev;
+ struct cache_req *cr;
+ struct cache_req_result **results;
+ size_t num_results;
+ /* Work data */
+ size_t res_idx;
+ size_t msg_idx;
+};
+
+static errno_t cache_req_sr_overlay_match_users(
+ struct cache_req_sr_overlay_state *state);
+
+static errno_t cache_req_sr_overlay_match_users(
+ struct cache_req_sr_overlay_state *state);
+
+static struct tevent_req *cache_req_sr_overlay_match_all_step_send(
+ struct cache_req_sr_overlay_state *state);
+
+static void cache_req_sr_overlay_match_all_step_done(
+ struct tevent_req *subreq);
+
+struct tevent_req *cache_req_sr_overlay_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ struct cache_req_result **results,
+ size_t num_results)
+{
+ errno_t ret = EOK;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct cache_req_sr_overlay_state *state;
+ struct resp_ctx *rctx = cr->rctx;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cache_req_sr_overlay_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->cr = cr;
+ state->results = results;
+ state->num_results = num_results;
+
+ /* If session recording is selective */
+ if (rctx->sr_conf.scope != SESSION_RECORDING_SCOPE_NONE) {
+ /* If it's a request for a user/users */
+ switch (cr->data->type) {
+ case CACHE_REQ_USER_BY_NAME:
+ case CACHE_REQ_USER_BY_UPN:
+ case CACHE_REQ_USER_BY_ID:
+ case CACHE_REQ_ENUM_USERS:
+ /* If we have group names to match against */
+ if ((rctx->sr_conf.groups != NULL &&
+ rctx->sr_conf.groups[0] != NULL) ||
+ (rctx->sr_conf.exclude_groups != NULL &&
+ rctx->sr_conf.exclude_groups[0] != NULL)) {
+ /* Pull and match group and user names for each user entry */
+ subreq = cache_req_sr_overlay_match_all_step_send(state);
+ if (subreq == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed allocating a session recording "
+ "user overlay request\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ tevent_req_set_callback(
+ subreq, cache_req_sr_overlay_match_all_step_done, req);
+ ret = EAGAIN;
+ } else {
+ /* Only match user names for each user entry */
+ ret = cache_req_sr_overlay_match_users(state);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+done:
+ if (ret != EAGAIN) {
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static errno_t cache_req_sr_overlay_match_users(
+ struct cache_req_sr_overlay_state *state)
+{
+ struct cache_req *cr;
+ struct resp_ctx *rctx;
+ errno_t ret;
+ int lret;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct cache_req_result *result;
+ struct ldb_message *msg;
+ const char *name;
+ char *output_name;
+ char **conf_user;
+ char **conf_exclude_user;
+ bool enabled;
+ char *enabled_str;
+
+ cr = state->cr;
+ rctx = cr->rctx;
+
+ /* Create per-message talloc context */
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Failed creating temporary talloc context\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* For each result */
+ for (state->res_idx = 0;
+ state->res_idx < state->num_results;
+ state->res_idx++) {
+ result = state->results[state->res_idx];
+
+ /* For each message */
+ for (state->msg_idx = 0;
+ state->msg_idx < result->count;
+ state->msg_idx++) {
+ msg = result->msgs[state->msg_idx];
+
+ /* Format output username */
+ name = sss_get_name_from_msg(result->domain, msg);
+ ret = sss_output_fqname(tmp_ctx, result->domain, name,
+ rctx->override_space,
+ &output_name);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Failed formatting output username from %s: %s\n",
+ name, sss_strerror(ret));
+ goto done;
+ }
+
+ /* For each user name in session recording config */
+ enabled = false;
+ conf_user = rctx->sr_conf.users;
+ if (rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME) {
+ if (conf_user != NULL) {
+ for (; *conf_user != NULL; conf_user++) {
+ /* If it matches the requested user name */
+ if (strcmp(*conf_user, output_name) == 0) {
+ enabled = true;
+ break;
+ }
+ }
+ }
+ /* For each exclude user name in session recording config */
+ } else if (rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL) {
+ enabled = true;
+ conf_exclude_user = rctx->sr_conf.exclude_users;
+ if (conf_exclude_user != NULL) {
+ for (; *conf_exclude_user != NULL; conf_exclude_user++) {
+ /* If it matches the requested user name */
+ if (strcmp(*conf_exclude_user, output_name) == 0) {
+ enabled = false;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Set sessionRecording attribute to enabled value */
+ ldb_msg_remove_attr(msg, SYSDB_SESSION_RECORDING);
+ enabled_str = talloc_strdup(tmp_ctx, enabled ? "TRUE" : "FALSE");
+ if (enabled_str == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Failed to allocate a %s attribute value\n",
+ SYSDB_SESSION_RECORDING);
+ ret = ENOMEM;
+ goto done;
+ }
+ lret = ldb_msg_add_string(msg, SYSDB_SESSION_RECORDING, enabled_str);
+ if (lret != LDB_SUCCESS) {
+ ret = sss_ldb_error_to_errno(lret);
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Failed adding %s attribute: %s\n",
+ SYSDB_SESSION_RECORDING, sss_strerror(ret));
+ goto done;
+ }
+ talloc_steal(msg, enabled_str);
+
+ /* Free per-message allocations */
+ talloc_free_children(tmp_ctx);
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+static struct tevent_req *cache_req_sr_overlay_match_all_step_send(
+ struct cache_req_sr_overlay_state *state)
+{
+ struct cache_req *cr = state->cr;
+ struct cache_req_result *result =
+ state->results[state->res_idx];
+ const char *name;
+
+ name = ldb_msg_find_attr_as_string(result->msgs[state->msg_idx],
+ SYSDB_NAME, NULL);
+ return cache_req_initgr_by_name_send(state, state->ev, cr->rctx, cr->ncache,
+ cr->midpoint, CACHE_REQ_ANY_DOM,
+ NULL, name);
+}
+
+static void cache_req_sr_overlay_match_all_step_done(
+ struct tevent_req *subreq)
+{
+ int lret;
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct tevent_req *req;
+ struct cache_req_sr_overlay_state *state;
+ struct cache_req_result *result;
+ struct ldb_message *msg;
+ const char *enabled;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_sr_overlay_state);
+ msg = state->results[state->res_idx]->
+ msgs[state->msg_idx];
+
+ /* Create temporary allocation context */
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed creating temporary talloc context\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Get initgroups result */
+ ret = cache_req_initgr_by_name_recv(tmp_ctx, subreq, &result);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed retrieving initgr request results: %s\n",
+ sss_strerror(ret));
+ goto done;
+ }
+
+ /* Overwrite sessionRecording attribute */
+ ldb_msg_remove_attr(msg, SYSDB_SESSION_RECORDING);
+ enabled = ldb_msg_find_attr_as_string(result->msgs[0],
+ SYSDB_SESSION_RECORDING, NULL);
+ if (enabled != NULL) {
+ char *enabled_copy;
+ enabled_copy = talloc_strdup(tmp_ctx, enabled);
+ if (enabled_copy == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed to allocate a copy of %s attribute\n",
+ SYSDB_SESSION_RECORDING);
+ ret = ENOMEM;
+ goto done;
+ }
+ lret = ldb_msg_add_string(msg, SYSDB_SESSION_RECORDING, enabled_copy);
+ if (lret != LDB_SUCCESS) {
+ ret = sss_ldb_error_to_errno(lret);
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed adding %s attribute: %s\n",
+ SYSDB_SESSION_RECORDING, sss_strerror(ret));
+ goto done;
+ }
+ talloc_steal(msg, enabled_copy);
+ }
+
+ /* Move onto next entry, if any */
+ state->msg_idx++;
+ if (state->msg_idx >=
+ state->results[state->res_idx]->count) {
+ state->res_idx++;
+ if (state->res_idx >= state->num_results) {
+ ret = EOK;
+ goto done;
+ }
+ state->msg_idx = 0;
+ }
+
+ /* Schedule next entry overlay */
+ subreq = cache_req_sr_overlay_match_all_step_send(state);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr,
+ "Failed allocating a session recording "
+ "user overlay request\n");
+ goto done;
+ }
+ tevent_req_set_callback(subreq,
+ cache_req_sr_overlay_match_all_step_done, req);
+ ret = EAGAIN;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ }
+ talloc_free(tmp_ctx);
+}
+
+errno_t cache_req_sr_overlay_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
new file mode 100644
index 0000000..b2b0a06
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
@@ -0,0 +1,161 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2019 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_autofs.h"
+#include "util/util.h"
+#include "util/sss_chain_id.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_autofs_entry_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_asprintf(mem_ctx, "%s:%s",
+ data->name.name,
+ data->autofs_entry_name);
+}
+
+static errno_t
+cache_req_autofs_entry_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ struct ldb_message *entry;
+ struct ldb_result *result;
+ errno_t ret;
+
+ ret = sysdb_get_autofsentry(mem_ctx, domain, data->name.name,
+ data->autofs_entry_name, &entry);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ result = cache_req_create_ldb_result_from_msg(mem_ctx, entry);
+ if (result == NULL) {
+ talloc_free(entry);
+ return ENOMEM;
+ }
+
+ *_result = talloc_steal(mem_ctx, result);
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_autofs_entry_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ struct be_conn *be_conn;
+ errno_t ret;
+
+ ret = sss_dp_get_domain_conn(cr->rctx, domain->conn_name, &be_conn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "BUG: The Data Provider connection for %s is not available!\n",
+ domain->name);
+ return NULL;
+ }
+
+ return sbus_call_dp_autofs_GetEntry_send(mem_ctx, be_conn->conn,
+ be_conn->bus_name, SSS_BUS_PATH,
+ 0, data->name.name,
+ data->autofs_entry_name,
+ sss_chain_id_get());
+}
+
+bool
+cache_req_autofs_entry_by_name_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ errno_t ret;
+
+ ret = sbus_call_dp_autofs_GetEntry_recv(subreq);
+
+ if (ret == ERR_MISSING_DP_TARGET || ret == ENOENT) {
+ ret = EOK;
+ }
+
+ return ret == EOK;
+}
+
+const struct cache_req_plugin cache_req_autofs_entry_by_name = {
+ .name = "Get autofs entry",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_autofs_entry_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_autofs_entry_by_name_lookup,
+ .dp_send_fn = cache_req_autofs_entry_by_name_dp_send,
+ .dp_recv_fn = cache_req_autofs_entry_by_name_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_autofs_entry_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *mapname,
+ const char *entryname)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_autofs_entry(mem_ctx, CACHE_REQ_AUTOFS_ENTRY_BY_NAME,
+ mapname, entryname);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ cache_req_data_set_propogate_offline_status(data, true);
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
new file mode 100644
index 0000000..23b11b1
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
@@ -0,0 +1,155 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2019 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_autofs.h"
+#include "util/util.h"
+#include "util/sss_chain_id.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_autofs_map_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.name);
+}
+
+static errno_t
+cache_req_autofs_map_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ struct ldb_message *map;
+ struct ldb_result *result;
+ errno_t ret;
+
+ ret = sysdb_get_map_byname(mem_ctx, domain, data->name.name, &map);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ result = cache_req_create_ldb_result_from_msg(mem_ctx, map);
+ if (result == NULL) {
+ talloc_free(map);
+ return ENOMEM;
+ }
+
+ *_result = talloc_steal(mem_ctx, result);
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_autofs_map_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ struct be_conn *be_conn;
+ errno_t ret;
+
+ ret = sss_dp_get_domain_conn(cr->rctx, domain->conn_name, &be_conn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "BUG: The Data Provider connection for %s is not available!\n",
+ domain->name);
+ return NULL;
+ }
+
+ return sbus_call_dp_autofs_GetMap_send(mem_ctx, be_conn->conn,
+ be_conn->bus_name, SSS_BUS_PATH,
+ 0, data->name.name,
+ sss_chain_id_get());
+}
+
+bool
+cache_req_autofs_map_by_name_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ errno_t ret;
+
+ ret = sbus_call_dp_autofs_GetMap_recv(subreq);
+
+ if (ret == ERR_MISSING_DP_TARGET || ret == ENOENT) {
+ ret = EOK;
+ }
+
+ return ret == EOK;
+}
+
+const struct cache_req_plugin cache_req_autofs_map_by_name = {
+ .name = "Get autofs map",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_autofs_map_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_autofs_map_by_name_lookup,
+ .dp_send_fn = cache_req_autofs_map_by_name_dp_send,
+ .dp_recv_fn = cache_req_autofs_map_by_name_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_AUTOFS_MAP_BY_NAME, name);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ cache_req_data_set_propogate_offline_status(data, true);
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
new file mode 100644
index 0000000..18c08ca
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
@@ -0,0 +1,187 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2019 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_autofs.h"
+#include "util/util.h"
+#include "util/sss_chain_id.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_autofs_map_entries_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.name);
+}
+
+static errno_t
+cache_req_autofs_map_entries_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *map;
+ struct ldb_message **mounts;
+ struct ldb_message **msgs;
+ struct ldb_result *result;
+ size_t count;
+ size_t i;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_get_map_byname(tmp_ctx, domain, data->name.name, &map);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sysdb_autofs_entries_by_map(tmp_ctx, domain, data->name.name,
+ &count, &mounts);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
+ msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, count + 1);
+ if (msgs == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msgs[0] = talloc_steal(msgs, map);
+ for (i = 0; i < count; i++) {
+ msgs[i + 1] = talloc_steal(msgs, mounts[i]);
+ }
+
+ result = cache_req_create_ldb_result_from_msg_list(tmp_ctx, msgs, count + 1);
+ if (result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ *_result = talloc_steal(mem_ctx, result);
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static struct tevent_req *
+cache_req_autofs_map_entries_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ struct be_conn *be_conn;
+ errno_t ret;
+
+ ret = sss_dp_get_domain_conn(cr->rctx, domain->conn_name, &be_conn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "BUG: The Data Provider connection for %s is not available!\n",
+ domain->name);
+ return NULL;
+ }
+
+ return sbus_call_dp_autofs_Enumerate_send(mem_ctx, be_conn->conn,
+ be_conn->bus_name, SSS_BUS_PATH,
+ 0, data->name.name,
+ sss_chain_id_get());
+}
+
+bool
+cache_req_autofs_map_entries_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ errno_t ret;
+
+ ret = sbus_call_dp_autofs_Enumerate_recv(subreq);
+
+ if (ret == ERR_MISSING_DP_TARGET || ret == ENOENT) {
+ ret = EOK;
+ }
+
+ return ret == EOK;
+}
+
+const struct cache_req_plugin cache_req_autofs_map_entries = {
+ .name = "Get autofs entries",
+ .attr_expiration = SYSDB_ENUM_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_autofs_map_entries_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_autofs_map_entries_lookup,
+ .dp_send_fn = cache_req_autofs_map_entries_dp_send,
+ .dp_recv_fn = cache_req_autofs_map_entries_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_AUTOFS_MAP_ENTRIES, name);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ cache_req_data_set_propogate_offline_status(data, true);
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c
new file mode 100644
index 0000000..7eb0921
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_common.c
@@ -0,0 +1,192 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+errno_t cache_req_idminmax_check(struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ if (((domain->id_min != 0) && (data->id < domain->id_min)) ||
+ ((domain->id_max != 0) && (data->id > domain->id_max))) {
+ DEBUG(SSSDBG_FUNC_DATA, "id exceeds min/max boundaries\n");
+ return ERR_ID_OUTSIDE_RANGE;
+ }
+ return EOK;
+}
+
+static struct ldb_message *
+cache_req_well_known_sid_msg(TALLOC_CTX *mem_ctx,
+ const char *sid,
+ const char *name)
+{
+ struct ldb_message *msg;
+ const char *dup_sid;
+ const char *dup_name;
+ int ldberr;
+
+ msg = ldb_msg_new(NULL);
+ if (msg == NULL) {
+ return NULL;
+ }
+
+ dup_sid = talloc_strdup(msg, sid);
+ if (dup_sid == NULL) {
+ ldberr = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ dup_name = talloc_strdup(msg, name);
+ if (name == NULL) {
+ ldberr = LDB_ERR_OTHER;
+ goto done;
+ }
+
+ ldberr = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS);
+ if (ldberr != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ldberr = ldb_msg_add_string(msg, SYSDB_NAME, dup_name);
+ if (ldberr != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ldberr = ldb_msg_add_string(msg, SYSDB_SID_STR, dup_sid);
+ if (ldberr != LDB_SUCCESS) {
+ goto done;
+ }
+
+done:
+ if (ldberr != LDB_SUCCESS) {
+ talloc_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+struct cache_req_result *
+cache_req_well_known_sid_result(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ const char *domname,
+ const char *sid,
+ const char *name)
+{
+ struct cache_req_result *result;
+ struct sss_domain_info *domain;
+ struct ldb_message *msg;
+
+ msg = cache_req_well_known_sid_msg(NULL, sid, name);
+ if (msg == NULL) {
+ return NULL;
+ }
+
+ if (domname != NULL) {
+ domain = find_domain_by_name(cr->rctx->domains, domname, true);
+ } else {
+ domain = NULL;
+ }
+
+ result = cache_req_create_result_from_msg(mem_ctx, domain, msg,
+ name, domname);
+ if (result == NULL) {
+ talloc_free(msg);
+ }
+
+ return result;
+}
+
+bool
+cache_req_common_process_dp_reply(struct cache_req *cr,
+ errno_t ret,
+ uint16_t err_maj,
+ uint32_t err_min,
+ const char *err_msg)
+{
+ bool bret;
+
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_IMPORTANT_INFO, cr,
+ "Could not get account info [%d]: %s\n",
+ ret, sss_strerror(ret));
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Due to an error we will return cached data\n");
+
+ bret = false;
+ goto done;
+ }
+
+ if (err_maj) {
+ CACHE_REQ_DEBUG(SSSDBG_IMPORTANT_INFO, cr,
+ "Data Provider Error: %u, %u, %s\n",
+ (unsigned int)err_maj, (unsigned int)err_min, err_msg);
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
+ "Due to an error we will return cached data\n");
+
+ bret = false;
+ goto done;
+ }
+
+ bret = true;
+
+done:
+ return bret;
+}
+
+bool
+cache_req_common_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ const char *err_msg;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ bool bret;
+
+ /* Use subreq as memory context so err_msg is freed with it. */
+ ret = sss_dp_get_account_recv(subreq, subreq, &err_maj, &err_min, &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+errno_t
+cache_req_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *subreq,
+ struct cache_req *cr,
+ char **_domain)
+{
+ errno_t ret;
+
+ ret = sss_dp_get_account_domain_recv(mem_ctx, subreq, _domain);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr,
+ "Could not get account domain [%d]: %s\n",
+ ret, sss_strerror(ret));
+ }
+ return ret;
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
new file mode 100644
index 0000000..a0d1028
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
@@ -0,0 +1,93 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_enum_groups_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, "Groups enumeration");
+}
+
+static errno_t
+cache_req_enum_groups_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_enumgrent_with_views(mem_ctx, domain, _result);
+}
+
+static struct tevent_req *
+cache_req_enum_groups_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_GROUP, NULL, 0, NULL);
+}
+
+static errno_t
+cache_req_enum_groups_ncache_filter(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ return sss_ncache_check_group(ncache, domain, name);
+}
+
+const struct cache_req_plugin cache_req_enum_groups = {
+ .name = "Enumerate groups",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = true,
+ .require_enumeration = true,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_enum_groups_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = cache_req_enum_groups_ncache_filter,
+ .lookup_fn = cache_req_enum_groups_lookup,
+ .dp_send_fn = cache_req_enum_groups_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_ip_hosts.c b/src/responder/common/cache_req/plugins/cache_req_enum_ip_hosts.c
new file mode 100644
index 0000000..ae468b3
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_ip_hosts.c
@@ -0,0 +1,126 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_iphosts.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_enum_host_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, "IP hosts enumeration");
+}
+
+static errno_t
+cache_req_enum_host_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_enumhostent(mem_ctx, domain, _result);
+}
+
+static struct tevent_req *
+cache_req_enum_host_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_resolver_get_send(mem_ctx, cr->rctx, domain, true,
+ BE_REQ_HOST, BE_FILTER_ENUM, NULL);
+}
+
+static bool
+cache_req_enum_host_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ bool bret;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ const char *err_msg;
+
+ ret = sss_dp_resolver_get_recv(subreq, subreq, &err_maj, &err_min,
+ &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_enum_ip_hosts = {
+ .name = "Enumerate IP hosts",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = true,
+ .require_enumeration = true,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_enum_host_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_enum_host_lookup,
+ .dp_send_fn = cache_req_enum_host_dp_send,
+ .dp_recv_fn = cache_req_enum_host_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_enum_ip_hosts_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_enum(mem_ctx, CACHE_REQ_ENUM_HOST);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain, data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_ip_networks.c b/src/responder/common/cache_req/plugins/cache_req_enum_ip_networks.c
new file mode 100644
index 0000000..e03bf6a
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_ip_networks.c
@@ -0,0 +1,126 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_ipnetworks.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_enum_ip_networks_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, "IP networks enumeration");
+}
+
+static errno_t
+cache_req_enum_ip_networks_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_enumnetent(mem_ctx, domain, _result);
+}
+
+static struct tevent_req *
+cache_req_enum_ip_networks_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_resolver_get_send(mem_ctx, cr->rctx, domain, true,
+ BE_REQ_IP_NETWORK, BE_FILTER_ENUM, NULL);
+}
+
+static bool
+cache_req_enum_ip_networks_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ bool bret;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ const char *err_msg;
+
+ ret = sss_dp_resolver_get_recv(subreq, subreq, &err_maj, &err_min,
+ &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_enum_ip_networks = {
+ .name = "Enumerate IP networks",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = true,
+ .require_enumeration = true,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_enum_ip_networks_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_enum_ip_networks_lookup,
+ .dp_send_fn = cache_req_enum_ip_networks_dp_send,
+ .dp_recv_fn = cache_req_enum_ip_networks_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_enum_ip_networks_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_enum(mem_ctx, CACHE_REQ_ENUM_IP_NETWORK);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain, data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
new file mode 100644
index 0000000..282dc1c
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
@@ -0,0 +1,106 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_services.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_enum_svc_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, "Services enumeration");
+}
+
+static errno_t
+cache_req_enum_svc_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_enumservent(mem_ctx, domain, _result);
+}
+
+static struct tevent_req *
+cache_req_enum_svc_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_SERVICES, NULL, 0, NULL);
+}
+
+const struct cache_req_plugin cache_req_enum_svc = {
+ .name = "Enumerate services",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = true,
+ .require_enumeration = true,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_enum_svc_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_enum_svc_lookup,
+ .dp_send_fn = cache_req_enum_svc_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_enum_svc_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_enum(mem_ctx, CACHE_REQ_ENUM_SVC);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain, data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c
new file mode 100644
index 0000000..87da79f
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c
@@ -0,0 +1,93 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_enum_users_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, "Users enumeration");
+}
+
+static errno_t
+cache_req_enum_users_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_enumpwent_with_views(mem_ctx, domain, _result);
+}
+
+static struct tevent_req *
+cache_req_enum_users_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_USER, NULL, 0, NULL);
+}
+
+static errno_t
+cache_req_enum_users_ncache_filter(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ return sss_ncache_check_user(ncache, domain, name);
+}
+
+const struct cache_req_plugin cache_req_enum_users = {
+ .name = "Enumerate users",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = true,
+ .require_enumeration = true,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_enum_users_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = cache_req_enum_users_ncache_filter,
+ .lookup_fn = cache_req_enum_users_lookup,
+ .dp_send_fn = cache_req_enum_users_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
new file mode 100644
index 0000000..1292f18
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
@@ -0,0 +1,171 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_group_by_filter_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_group_by_filter_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_group_by_filter_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ char *recent_filter;
+ errno_t ret;
+
+ /* The "files" provider updates the record if /etc/passwd or /etc/group
+ * is touched. It does not perform any per-request update.
+ * Therefore the last update flag is not updated if no file was touched
+ * and we cannot use this optimization.
+ */
+ if (is_files_provider(domain)) {
+ recent_filter = NULL;
+ } else {
+ recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)", SYSDB_LAST_UPDATE,
+ cr->req_start);
+ if (recent_filter == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ ret = sysdb_enumgrent_filter_with_views(mem_ctx, domain, data->name.lookup,
+ recent_filter, _result);
+ talloc_free(recent_filter);
+
+ return ret;
+}
+
+static struct tevent_req *
+cache_req_group_by_filter_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_WILDCARD_GROUP,
+ cr->data->name.lookup, cr->data->id, NULL);
+}
+
+const struct cache_req_plugin cache_req_group_by_filter = {
+ .name = "Group by filter",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_group_by_filter_prepare_domain_data,
+ .create_debug_name_fn = cache_req_group_by_filter_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_group_by_filter_lookup,
+ .dp_send_fn = cache_req_group_by_filter_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *filter)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_GROUP_BY_FILTER, filter);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL,
+ 0,
+ req_dom_type, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
new file mode 100644
index 0000000..bb72ad9
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
@@ -0,0 +1,246 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_group_by_id_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_asprintf(mem_ctx, "GID:%"PRIu32"@%s", data->id, domain->name);
+}
+
+static errno_t
+cache_req_group_by_id_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ if (domain != NULL) {
+ ret = sss_ncache_check_gid(ncache, domain, data->id);
+ if (ret == EEXIST) {
+ return ret;
+ }
+ }
+
+ return sss_ncache_check_gid(ncache, NULL, data->id);
+}
+
+static errno_t
+cache_req_group_by_id_ncache_filter(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ return sss_ncache_check_group(ncache, domain, name);
+}
+
+static errno_t
+cache_req_group_by_id_global_ncache_add(struct sss_nc_ctx *ncache,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_gid(ncache, false, NULL, data->id);
+}
+
+static errno_t
+cache_req_group_by_id_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_gid(ncache, false, domain, data->id);
+}
+
+static errno_t
+cache_req_group_by_id_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ errno_t ret;
+
+ ret = cache_req_idminmax_check(data, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+ return sysdb_getgrgid_with_views(mem_ctx, domain, data->id, _result);
+}
+
+static errno_t
+cache_req_group_by_id_dpreq_params(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result *result,
+ const char **_string,
+ uint32_t *_id,
+ const char **_flag)
+{
+ uint32_t id;
+
+ *_id = cr->data->id;
+ *_string = NULL;
+ *_flag = NULL;
+
+ if (!DOM_HAS_VIEWS(cr->domain)) {
+ return EOK;
+ }
+
+ /* We must search with views. */
+ if (result == NULL || result->count == 0) {
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* If domain has views we will try to use original values instead of the
+ * overridden ones. This is a must for the LOCAL view since we can't look
+ * it up otherwise. But it is also a shortcut for non-local views where
+ * we will not fail over to the overridden value. */
+
+ id = ldb_msg_find_attr_as_uint64(result->msgs[0], SYSDB_GIDNUM, 0);
+ if (id == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0\n");
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* Now we have the original name and id. We don't have to search with
+ * views unless some error occurred. */
+ *_id = id;
+
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_group_by_id_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ const char *string;
+ const char *flag;
+ uint32_t id;
+ errno_t ret;
+
+ ret = cache_req_group_by_id_dpreq_params(mem_ctx, cr, result,
+ &string, &id, &flag);
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_GROUP, string, id, flag);
+}
+
+static bool
+cache_req_group_by_id_get_domain_check(struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_check_locate_gid(rctx->ncache, domain, data->id);
+ if (nret == EEXIST) {
+ return false;
+ }
+
+ return true;
+}
+
+static struct tevent_req *
+cache_req_group_by_id_get_domain_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_set_locate_gid(rctx->ncache, domain, data->id);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot set negative cache, this might result in performance degradation\n");
+ /* Not fatal */
+ }
+
+ return sss_dp_get_account_domain_send(mem_ctx,
+ rctx,
+ domain,
+ true, /* fast_reply */
+ SSS_DP_GROUP,
+ data->id,
+ NULL);
+}
+
+const struct cache_req_plugin cache_req_group_by_id = {
+ .name = "Group by ID",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_group_by_id_create_debug_name,
+ .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add,
+ .ncache_check_fn = cache_req_group_by_id_ncache_check,
+ .ncache_add_fn = cache_req_group_by_id_ncache_add,
+ .ncache_filter_fn = cache_req_group_by_id_ncache_filter,
+ .lookup_fn = cache_req_group_by_id_lookup,
+ .dp_send_fn = cache_req_group_by_id_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = cache_req_group_by_id_get_domain_check,
+ .dp_get_domain_send_fn = cache_req_group_by_id_get_domain_send,
+ .dp_get_domain_recv_fn = cache_req_common_get_acct_domain_recv,
+};
+
+struct tevent_req *
+cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ gid_t gid)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_id(mem_ctx, CACHE_REQ_GROUP_BY_ID, gid);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
new file mode 100644
index 0000000..3be0d5e
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
@@ -0,0 +1,227 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_group_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_create_internal_fqname(tmp_ctx, name, domain->name);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_group_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_group_by_name_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_group(ncache, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_group_by_name_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_group(ncache, false, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_group_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_getgrnam_with_views(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static errno_t
+cache_req_group_by_name_dpreq_params(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result *result,
+ const char **_string,
+ uint32_t *_id,
+ const char **_flag)
+{
+ const char *name;
+
+ *_id = 0;
+ *_string = cr->data->name.lookup;
+ *_flag = NULL;
+
+ if (!DOM_HAS_VIEWS(cr->domain)) {
+ return EOK;
+ }
+
+ /* We must search with views. */
+ if (result == NULL || result->count == 0) {
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* If domain has views we will try to use original values instead of the
+ * overridden ones. This is a must for the LOCAL view since we can't look
+ * it up otherwise. But it is also a shortcut for non-local views where
+ * we will not fail over to the overridden value. */
+
+ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* Now we have the original name and id. We don't have to search with
+ * views unless some error occurred. */
+ *_string = talloc_steal(mem_ctx, name);
+
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_group_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ const char *string;
+ const char *flag;
+ uint32_t id;
+ errno_t ret;
+
+ ret = cache_req_group_by_name_dpreq_params(mem_ctx, cr, result,
+ &string, &id, &flag);
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_GROUP, string, id, flag);
+}
+
+const struct cache_req_plugin cache_req_group_by_name = {
+ .name = "Group by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_group_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_group_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_group_by_name_ncache_check,
+ .ncache_add_fn = cache_req_group_by_name_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_group_by_name_lookup,
+ .dp_send_fn = cache_req_group_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *name)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_GROUP_BY_NAME, name);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
new file mode 100644
index 0000000..c5bea9d
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
@@ -0,0 +1,242 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_initgroups_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_create_internal_fqname(tmp_ctx, name, domain->name);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_initgroups_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_initgroups_by_name_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_user(ncache, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_initgroups_by_name_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_user(ncache, false, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_initgroups_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_initgroups_with_views(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static errno_t
+cache_req_initgroups_by_name_dpreq_params(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result *result,
+ const char **_string,
+ uint32_t *_id,
+ const char **_flag)
+{
+ struct ldb_result *user;
+ const char *name;
+ errno_t ret;
+
+ *_id = 0;
+ *_string = cr->data->name.lookup;
+ *_flag = NULL;
+
+ if (!DOM_HAS_VIEWS(cr->domain)) {
+ return EOK;
+ }
+
+ /* We must search with views. */
+ if (result == NULL || result->count == 0) {
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* If domain has views we will try to use original values instead of the
+ * overridden ones. This is a must for the LOCAL view since we can't look
+ * it up otherwise. But it is also a shortcut for non-local views where
+ * we will not fail over to the overridden value. */
+
+ ret = sysdb_getpwnam_with_views(NULL, cr->domain,
+ cr->data->name.lookup, &user);
+ if (ret != EOK || user == NULL || user->count != 1) {
+ /* Case where the user is not found has been already handled. If
+ * this is not OK, it is an error. */
+ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
+ "Unable to match initgroups user [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ name = ldb_msg_find_attr_as_string(user->msgs[0], SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
+ talloc_free(user);
+ return ERR_INTERNAL;
+ }
+
+ /* Now we have the original name. We don't have to search with
+ * views unless some error occurred. */
+ *_string = talloc_steal(mem_ctx, name);
+
+ talloc_free(user);
+
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_initgroups_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ const char *string;
+ const char *flag;
+ uint32_t id;
+ errno_t ret;
+
+ ret = cache_req_initgroups_by_name_dpreq_params(mem_ctx, cr, result,
+ &string, &id, &flag);
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_INITGROUPS, string, id, flag);
+}
+
+const struct cache_req_plugin cache_req_initgroups_by_name = {
+ .name = "Initgroups by name",
+ .attr_expiration = SYSDB_INITGR_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = true,
+ .upn_equivalent = CACHE_REQ_INITGROUPS_BY_UPN,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_initgroups_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_initgroups_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_initgroups_by_name_ncache_check,
+ .ncache_add_fn = cache_req_initgroups_by_name_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_initgroups_by_name_lookup,
+ .dp_send_fn = cache_req_initgroups_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *name)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_INITGROUPS, name);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c
new file mode 100644
index 0000000..9bd00f3
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c
@@ -0,0 +1,130 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_initgroups_by_upn_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *name;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed UPN is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ /* When looking up UPNs we don't want to reverse-replace spaces,
+ * just search whatever the user passed in. strdup the name so we
+ * can safely steal it later.
+ */
+ name = talloc_strdup(data, cr->data->name.name);
+ if (name == NULL) {
+ return ENOMEM;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ return EOK;
+}
+
+static const char *
+cache_req_initgroups_by_upn_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_initgroups_by_upn_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_upn(ncache, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_initgroups_by_upn_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_upn(ncache, false, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_initgroups_by_upn_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_initgroups_by_upn(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_initgroups_by_upn_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_INITGROUPS, cr->data->name.lookup,
+ 0, EXTRA_NAME_IS_UPN);
+}
+
+const struct cache_req_plugin cache_req_initgroups_by_upn = {
+ .name = "Initgroups by UPN",
+ .attr_expiration = SYSDB_INITGR_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_initgroups_by_upn_prepare_domain_data,
+ .create_debug_name_fn = cache_req_initgroups_by_upn_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_initgroups_by_upn_ncache_check,
+ .ncache_add_fn = cache_req_initgroups_by_upn_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_initgroups_by_upn_lookup,
+ .dp_send_fn = cache_req_initgroups_by_upn_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
diff --git a/src/responder/common/cache_req/plugins/cache_req_ip_host_by_addr.c b/src/responder/common/cache_req/plugins/cache_req_ip_host_by_addr.c
new file mode 100644
index 0000000..324d20e
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_ip_host_by_addr.c
@@ -0,0 +1,174 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ 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 <talloc.h>
+#include <ldb.h>
+#include <arpa/inet.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_iphosts.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_ip_host_by_addr_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ char buf[INET6_ADDRSTRLEN];
+ const char *addr;
+
+ if (data->addr.len == 0 || data->addr.data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: address is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ if (data->addr.af != AF_INET && data->addr.af != AF_INET6) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bad address family [%d]\n", data->addr.af);
+ return EAFNOSUPPORT;
+ }
+
+ addr = inet_ntop(data->addr.af, data->addr.data, buf, INET6_ADDRSTRLEN);
+ if (addr == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse address: %s\n",
+ strerror(errno));
+ return ERR_INTERNAL;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_strdup(data, addr);
+
+ return EOK;
+}
+
+static const char *
+cache_req_ip_host_by_addr_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *addr = NULL;
+ char buf[INET6_ADDRSTRLEN];
+
+ addr = inet_ntop(data->addr.af, data->addr.data, buf, INET6_ADDRSTRLEN);
+ if (addr == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse network address: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, addr);
+}
+
+static errno_t
+cache_req_ip_host_by_addr_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_gethostbyaddr(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_ip_host_by_addr_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_resolver_get_send(mem_ctx, cr->rctx, domain, true,
+ BE_REQ_HOST, BE_FILTER_ADDR,
+ data->name.lookup);
+}
+
+static bool
+cache_req_ip_host_by_addr_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ bool bret;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ const char *err_msg;
+
+ ret = sss_dp_resolver_get_recv(subreq, subreq, &err_maj, &err_min,
+ &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_ip_host_by_addr = {
+ .name = "IP host by address",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_ip_host_by_addr_prepare_domain_data,
+ .create_debug_name_fn = cache_req_ip_host_by_addr_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_ip_host_by_addr_lookup,
+ .dp_send_fn = cache_req_ip_host_by_addr_dp_send,
+ .dp_recv_fn = cache_req_ip_host_by_addr_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_ip_host_by_addr_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name_attrs(mem_ctx, CACHE_REQ_IP_HOST_BY_NAME,
+ name, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_ip_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_ip_host_by_name.c
new file mode 100644
index 0000000..b5f33ee
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_ip_host_by_name.c
@@ -0,0 +1,170 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_iphosts.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_ip_host_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ /* Host names always case insensitive */
+ name = sss_get_cased_name(tmp_ctx, data->name.name, false);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_ip_host_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *name = data->name.lookup;
+
+ return talloc_asprintf(mem_ctx, "%s@%s", name, domain->name);
+}
+
+static errno_t
+cache_req_ip_host_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_gethostbyname(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_ip_host_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_resolver_get_send(mem_ctx, cr->rctx, domain, true,
+ BE_REQ_HOST, BE_FILTER_NAME,
+ data->name.lookup);
+}
+
+static bool
+cache_req_ip_host_by_name_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ bool bret;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ const char *err_msg;
+
+ ret = sss_dp_resolver_get_recv(subreq, subreq, &err_maj, &err_min,
+ &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_ip_host_by_name = {
+ .name = "IP host by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_ip_host_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_ip_host_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_ip_host_by_name_lookup,
+ .dp_send_fn = cache_req_ip_host_by_name_dp_send,
+ .dp_recv_fn = cache_req_ip_host_by_name_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_ip_host_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name_attrs(mem_ctx, CACHE_REQ_IP_HOST_BY_NAME,
+ name, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_ip_network_by_addr.c b/src/responder/common/cache_req/plugins/cache_req_ip_network_by_addr.c
new file mode 100644
index 0000000..0ad7f61
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_ip_network_by_addr.c
@@ -0,0 +1,174 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ 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 <talloc.h>
+#include <ldb.h>
+#include <arpa/inet.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_ipnetworks.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_ip_network_by_addr_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ char buf[INET6_ADDRSTRLEN];
+ const char *addr;
+
+ if (data->addr.len == 0 || data->addr.data == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: address is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ if (data->addr.af != AF_INET && data->addr.af != AF_INET6) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bad address family [%d]\n", data->addr.af);
+ return EAFNOSUPPORT;
+ }
+
+ addr = inet_ntop(data->addr.af, data->addr.data, buf, INET6_ADDRSTRLEN);
+ if (addr == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse address: %s\n",
+ strerror(errno));
+ return ERR_INTERNAL;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_strdup(data, addr);
+
+ return EOK;
+}
+
+static const char *
+cache_req_ip_network_by_addr_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *addr = NULL;
+ char buf[INET6_ADDRSTRLEN];
+
+ addr = inet_ntop(data->addr.af, data->addr.data, buf, INET6_ADDRSTRLEN);
+ if (addr == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse network address: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, addr);
+}
+
+static errno_t
+cache_req_ip_network_by_addr_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_getipnetworkbyaddr(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_ip_network_by_addr_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_resolver_get_send(mem_ctx, cr->rctx, domain, true,
+ BE_REQ_IP_NETWORK, BE_FILTER_ADDR,
+ data->name.lookup);
+}
+
+static bool
+cache_req_ip_network_by_addr_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ bool bret;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ const char *err_msg;
+
+ ret = sss_dp_resolver_get_recv(subreq, subreq, &err_maj, &err_min,
+ &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_ip_network_by_addr = {
+ .name = "IP network by address",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_ip_network_by_addr_prepare_domain_data,
+ .create_debug_name_fn = cache_req_ip_network_by_addr_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_ip_network_by_addr_lookup,
+ .dp_send_fn = cache_req_ip_network_by_addr_dp_send,
+ .dp_recv_fn = cache_req_ip_network_by_addr_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_ip_network_by_addr_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name_attrs(mem_ctx, CACHE_REQ_IP_NETWORK_BY_NAME,
+ name, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_ip_network_by_name.c b/src/responder/common/cache_req/plugins/cache_req_ip_network_by_name.c
new file mode 100644
index 0000000..c02bc06
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_ip_network_by_name.c
@@ -0,0 +1,170 @@
+/*
+ SSSD
+
+ Authors:
+ Samuel Cabrero <scabrero@suse.com>
+
+ Copyright (C) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
+
+ 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_ipnetworks.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_ip_network_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ /* Network names always case insensitive */
+ name = sss_get_cased_name(tmp_ctx, data->name.name, false);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_ip_network_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *name = data->name.lookup;
+
+ return talloc_asprintf(mem_ctx, "%s@%s", name, domain->name);
+}
+
+static errno_t
+cache_req_ip_network_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_getipnetworkbyname(mem_ctx, domain, data->name.lookup,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_ip_network_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_resolver_get_send(mem_ctx, cr->rctx, domain, true,
+ BE_REQ_IP_NETWORK, BE_FILTER_NAME,
+ data->name.lookup);
+}
+
+static bool
+cache_req_ip_network_by_name_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ bool bret;
+ uint16_t err_maj;
+ uint32_t err_min;
+ errno_t ret;
+ const char *err_msg;
+
+ ret = sss_dp_resolver_get_recv(subreq, subreq, &err_maj, &err_min,
+ &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_ip_network_by_name = {
+ .name = "IP network by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_ip_network_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_ip_network_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_ip_network_by_name_lookup,
+ .dp_send_fn = cache_req_ip_network_by_name_dp_send,
+ .dp_recv_fn = cache_req_ip_network_by_name_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_ip_network_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name_attrs(mem_ctx, CACHE_REQ_IP_NETWORK_BY_NAME,
+ name, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
new file mode 100644
index 0000000..d370d34
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
@@ -0,0 +1,160 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_netgroup_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_netgroup_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_asprintf(mem_ctx, "%s@%s", data->name.lookup, domain->name);
+}
+
+static errno_t
+cache_req_netgroup_by_name_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_netgr(ncache, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_netgroup_by_name_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_netgr(ncache, false, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_netgroup_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_getnetgr(mem_ctx, domain, data->name.lookup, _result);
+}
+
+static struct tevent_req *
+cache_req_netgroup_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_NETGR, cr->data->name.lookup,
+ 0, NULL);
+}
+
+const struct cache_req_plugin cache_req_netgroup_by_name = {
+ .name = "Netgroup by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_netgroup_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_netgroup_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_netgroup_by_name_ncache_check,
+ .ncache_add_fn = cache_req_netgroup_by_name_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_netgroup_by_name_lookup,
+ .dp_send_fn = cache_req_netgroup_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_netgroup_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_NETGROUP_BY_NAME, name);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
new file mode 100644
index 0000000..2bff990
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
@@ -0,0 +1,236 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_object_by_id_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_asprintf(mem_ctx, "ID:%"PRIu32"@%s", data->id, domain->name);
+}
+
+static errno_t
+cache_req_object_by_id_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ ret = sss_ncache_check_uid(ncache, domain, data->id);
+ if (ret == EEXIST) {
+ ret = sss_ncache_check_gid(ncache, domain, data->id);
+ }
+
+ return ret;
+}
+
+static errno_t
+cache_req_object_by_id_ncache_filter(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ errno_t ret;
+
+ ret = sss_ncache_check_user(ncache, domain, name);
+ if (ret == EEXIST) {
+ ret = sss_ncache_check_group(ncache, domain, name);
+ }
+
+ return ret;
+}
+
+static errno_t
+cache_req_object_by_id_global_ncache_add(struct sss_nc_ctx *ncache,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ ret = sss_ncache_set_uid(ncache, false, NULL, data->id);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_ncache_set_gid(ncache, false, NULL, data->id);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t
+cache_req_object_by_id_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ ret = sss_ncache_set_uid(ncache, false, domain, data->id);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_ncache_set_gid(ncache, false, domain, data->id);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t
+cache_req_object_by_id_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ errno_t ret;
+
+ ret = cache_req_idminmax_check(data, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+ return sysdb_search_object_by_id(mem_ctx, domain, data->id,
+ data->attrs, _result);
+}
+
+static struct tevent_req *
+cache_req_object_by_id_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_USER_AND_GROUP, NULL,
+ cr->data->id, NULL);
+}
+
+static bool
+cache_req_object_by_id_get_domain_check(struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_check_locate_uid(rctx->ncache, domain, data->id);
+ if (nret == EEXIST) {
+ nret = sss_ncache_check_locate_gid(rctx->ncache, domain, data->id);
+ if (nret == EEXIST) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static struct tevent_req *
+cache_req_object_by_id_get_domain_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_set_locate_uid(rctx->ncache, domain, data->id);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot set negative cache, this might result in "
+ "performance degradation\n");
+ /* Not fatal */
+ }
+
+ nret = sss_ncache_set_locate_gid(rctx->ncache, domain, data->id);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot set negative cache, this might result in "
+ "performance degradation\n");
+ /* Not fatal */
+ }
+
+ return sss_dp_get_account_domain_send(mem_ctx,
+ rctx,
+ domain,
+ true, /* fast_reply */
+ SSS_DP_USER_AND_GROUP,
+ data->id,
+ NULL);
+}
+
+const struct cache_req_plugin cache_req_object_by_id = {
+ .name = "Object by ID",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_object_by_id_create_debug_name,
+ .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add,
+ .ncache_check_fn = cache_req_object_by_id_ncache_check,
+ .ncache_add_fn = cache_req_object_by_id_ncache_add,
+ .ncache_filter_fn = cache_req_object_by_id_ncache_filter,
+ .lookup_fn = cache_req_object_by_id_lookup,
+ .dp_send_fn = cache_req_object_by_id_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = cache_req_object_by_id_get_domain_check,
+ .dp_get_domain_send_fn = cache_req_object_by_id_get_domain_send,
+ .dp_get_domain_recv_fn = cache_req_common_get_acct_domain_recv,
+};
+
+struct tevent_req *
+cache_req_object_by_id_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ uint32_t id,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_id_attrs(mem_ctx, CACHE_REQ_OBJECT_BY_ID, id, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
new file mode 100644
index 0000000..907f1f3
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
@@ -0,0 +1,238 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_object_by_name_well_known(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct cache_req_result **_result)
+{
+ struct cache_req_result *result;
+ const char *sid;
+ char *domname;
+ char *name;
+ errno_t ret;
+
+ ret = sss_parse_name(mem_ctx, cr->rctx->global_names,
+ data->name.input, &domname, &name);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, cr, "Unable to parse name "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
+ }
+
+ if (domname == NULL || name == NULL) {
+ CACHE_REQ_DEBUG(SSSDBG_FUNC_DATA, cr, "Unable to split [%s] in "
+ "name and domain part. Skipping detection of "
+ "well-known name.\n", data->name.input);
+ return ENOENT;
+ }
+
+ ret = name_to_well_known_sid(domname, name, &sid);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ result = cache_req_well_known_sid_result(mem_ctx, cr, domname, sid, name);
+ talloc_free(domname);
+ talloc_free(name);
+ if (result == NULL) {
+ return ENOMEM;
+ }
+
+ *_result = result;
+
+ return EOK;
+}
+
+static errno_t
+cache_req_object_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_create_internal_fqname(tmp_ctx, name, domain->name);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_object_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_object_by_name_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ ret = sss_ncache_check_user(ncache, domain, data->name.lookup);
+ if (ret == EEXIST) {
+ ret = sss_ncache_check_group(ncache, domain, data->name.lookup);
+ }
+
+ return ret;
+}
+
+static errno_t
+cache_req_object_by_name_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ ret = sss_ncache_set_user(ncache, false, domain, data->name.lookup);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_ncache_set_group(ncache, false, domain, data->name.lookup);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t
+cache_req_object_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_search_object_by_name(mem_ctx, domain, data->name.lookup,
+ data->attrs, _result);
+}
+
+static struct tevent_req *
+cache_req_object_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_USER_AND_GROUP,
+ cr->data->name.lookup, 0, NULL);
+}
+
+const struct cache_req_plugin cache_req_object_by_name = {
+ .name = "Object by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = true,
+ .upn_equivalent = CACHE_REQ_USER_BY_UPN,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = cache_req_object_by_name_well_known,
+ .prepare_domain_data_fn = cache_req_object_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_object_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_object_by_name_ncache_check,
+ .ncache_add_fn = cache_req_object_by_name_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_object_by_name_lookup,
+ .dp_send_fn = cache_req_object_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_object_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name_attrs(mem_ctx, CACHE_REQ_OBJECT_BY_NAME,
+ name, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
new file mode 100644
index 0000000..db731b1
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
@@ -0,0 +1,202 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_object_by_sid_well_known(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct cache_req_result **_result)
+{
+ struct cache_req_result *result;
+ const char *domname;
+ const char *name;
+ errno_t ret;
+
+ ret = well_known_sid_to_name(data->sid, &domname, &name);
+ if (ret != EOK) {
+ CACHE_REQ_DEBUG(SSSDBG_TRACE_ALL, cr,
+ "SID [%s] is not a Well-Known SID.\n", data->sid);
+ return ret;
+ }
+
+ result = cache_req_well_known_sid_result(mem_ctx, cr, domname,
+ data->sid, name);
+ if (result == NULL) {
+ return ENOMEM;
+ }
+
+ *_result = result;
+
+ return EOK;
+}
+
+static const char *
+cache_req_object_by_sid_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_asprintf(mem_ctx, "SID:%s@%s", data->sid, domain->name);
+}
+
+static errno_t
+cache_req_object_by_sid_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_sid(ncache, domain, data->sid);
+}
+
+static errno_t
+cache_req_object_by_sid_global_ncache_add(struct sss_nc_ctx *ncache,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_sid(ncache, false, NULL, data->sid);
+}
+
+static errno_t
+cache_req_object_by_sid_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_sid(ncache, false, domain, data->sid);
+}
+
+static errno_t
+cache_req_object_by_sid_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_search_object_by_sid(mem_ctx, domain, data->sid, data->attrs,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_object_by_sid_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_SECID, cr->data->sid, 0, NULL);
+}
+
+static bool
+cache_req_object_by_sid_get_domain_check(struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_check_locate_sid(rctx->ncache, domain, data->sid);
+ if (nret == EEXIST) {
+ return false;
+ }
+
+ return true;
+}
+
+static struct tevent_req *
+cache_req_object_by_sid_get_domain_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_set_locate_sid(rctx->ncache, domain, data->sid);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot set negative cache, this might result in "
+ "performance degradation\n");
+ /* Not fatal */
+ }
+
+ return sss_dp_get_account_domain_send(mem_ctx,
+ rctx,
+ domain,
+ true, /* fast_reply */
+ SSS_DP_SECID,
+ 0,
+ data->sid);
+}
+
+
+const struct cache_req_plugin cache_req_object_by_sid = {
+ .name = "Object by SID",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = cache_req_object_by_sid_well_known,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_object_by_sid_create_debug_name,
+ .global_ncache_add_fn = cache_req_object_by_sid_global_ncache_add,
+ .ncache_check_fn = cache_req_object_by_sid_ncache_check,
+ .ncache_add_fn = cache_req_object_by_sid_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_object_by_sid_lookup,
+ .dp_send_fn = cache_req_object_by_sid_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = cache_req_object_by_sid_get_domain_check,
+ .dp_get_domain_send_fn = cache_req_object_by_sid_get_domain_send,
+ .dp_get_domain_recv_fn = cache_req_common_get_acct_domain_recv,
+};
+
+struct tevent_req *
+cache_req_object_by_sid_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *sid,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_sid(mem_ctx, CACHE_REQ_OBJECT_BY_SID, sid, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_ssh_host_id_by_name.c b/src/responder/common/cache_req/plugins/cache_req_ssh_host_id_by_name.c
new file mode 100644
index 0000000..29f52f1
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_ssh_host_id_by_name.c
@@ -0,0 +1,164 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb_ssh.h"
+#include "util/util.h"
+#include "util/sss_chain_id.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_host_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.name);
+}
+
+static errno_t
+cache_req_host_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+#ifdef BUILD_SSH
+ struct ldb_result *result;
+ struct ldb_message *msg;
+ errno_t ret;
+
+ ret = sysdb_get_ssh_host(mem_ctx, domain, data->name.name,
+ data->attrs, &msg);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ result = cache_req_create_ldb_result_from_msg(mem_ctx, msg);
+ if (result == NULL) {
+ return ENOMEM;
+ }
+
+ *_result = result;
+
+ return EOK;
+#else
+ return ERR_INTERNAL;
+#endif /* BUILD_SSH */
+}
+
+static struct tevent_req *
+cache_req_host_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ struct be_conn *be_conn;
+ errno_t ret;
+
+ ret = sss_dp_get_domain_conn(cr->rctx, domain->conn_name, &be_conn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "BUG: The Data Provider connection for %s is not available!\n",
+ domain->name);
+ return NULL;
+ }
+
+ return sbus_call_dp_dp_hostHandler_send(mem_ctx, be_conn->conn,
+ be_conn->bus_name, SSS_BUS_PATH,
+ 0, data->name.name, data->alias,
+ sss_chain_id_get());
+}
+
+static bool
+cache_req_host_by_name_dp_recv(struct tevent_req *subreq,
+ struct cache_req *cr)
+{
+ const char *err_msg;
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+ errno_t ret;
+ bool bret;
+
+ /* Use subreq as memory context so err_msg is freed with it. */
+ ret = sbus_call_dp_dp_hostHandler_recv(subreq, subreq, &err_maj,
+ &err_min, &err_msg);
+ bret = cache_req_common_process_dp_reply(cr, ret, err_maj,
+ err_min, err_msg);
+
+ return bret;
+}
+
+const struct cache_req_plugin cache_req_ssh_host_id_by_name = {
+ .name = "SSH Host ID by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = true,
+ .bypass_cache = true,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = 0,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_host_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_host_by_name_lookup,
+ .dp_send_fn = cache_req_host_by_name_dp_send,
+ .dp_recv_fn = cache_req_host_by_name_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_ssh_host_id_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char *alias,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_ssh_host_id(mem_ctx, CACHE_REQ_SSH_HOST_ID_BY_NAME,
+ name, alias, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c b/src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c
new file mode 100644
index 0000000..5485271
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_subid_ranges_by_name.c
@@ -0,0 +1,143 @@
+/*
+ Copyright (C) 2021 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_subid.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_subid_ranges_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_subid_ranges_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_subid_ranges_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ struct ldb_result *result;
+ struct ldb_message *msg;
+ errno_t ret;
+
+ ret = sysdb_get_subid_ranges(mem_ctx, domain, data->name.name,
+ data->attrs, &msg);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ result = cache_req_create_ldb_result_from_msg(mem_ctx, msg);
+ if (result == NULL) {
+ return ENOMEM;
+ }
+
+ *_result = result;
+
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_subid_ranges_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ /* Views aren't yet supported */
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_SUBID_RANGES, cr->data->name.lookup, 0, NULL);
+}
+
+const struct cache_req_plugin cache_req_subid_ranges_by_name = {
+ .name = "SubID ranges by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_subid_ranges_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_subid_ranges_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_subid_ranges_by_name_lookup,
+ .dp_send_fn = cache_req_subid_ranges_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
new file mode 100644
index 0000000..5b17051
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
@@ -0,0 +1,185 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_services.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_svc_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ const char *protocol;
+ errno_t ret;
+
+ if (data->svc.name->name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, data->svc.name->name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (data->svc.protocol.name == NULL) {
+ protocol = NULL;
+ } else {
+ protocol = sss_get_cased_name(tmp_ctx, data->svc.protocol.name,
+ domain->case_sensitive);
+ if (protocol == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ talloc_zfree(data->svc.name->lookup);
+ talloc_zfree(data->svc.protocol.lookup);
+ data->svc.name->lookup = talloc_steal(data, name);
+ data->svc.protocol.lookup = talloc_steal(data, protocol);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_svc_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *protocol = data->svc.protocol.lookup;
+ const char *name = data->svc.name->lookup;
+
+ protocol = protocol == NULL ? "<ANY>" : protocol;
+
+ return talloc_asprintf(mem_ctx, "%s %s@%s", protocol, name, domain->name);
+}
+
+static errno_t
+cache_req_svc_by_name_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_service(ncache, domain, data->svc.name->lookup,
+ data->svc.protocol.lookup);
+}
+
+static errno_t
+cache_req_svc_by_name_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_service_name(ncache, false, domain,
+ data->svc.name->lookup,
+ data->svc.protocol.lookup);
+}
+
+static errno_t
+cache_req_svc_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_getservbyname(mem_ctx, domain, data->svc.name->lookup,
+ data->svc.protocol.lookup, _result);
+}
+
+static struct tevent_req *
+cache_req_svc_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_SERVICES, cr->data->svc.name->lookup,
+ 0, cr->data->svc.protocol.lookup);
+}
+
+const struct cache_req_plugin cache_req_svc_by_name = {
+ .name = "Service by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_svc_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_svc_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_svc_by_name_ncache_check,
+ .ncache_add_fn = cache_req_svc_by_name_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_svc_by_name_lookup,
+ .dp_send_fn = cache_req_svc_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_svc_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char *protocol)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_svc(mem_ctx, CACHE_REQ_SVC_BY_NAME, name, protocol, 0);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
new file mode 100644
index 0000000..4c005df
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
@@ -0,0 +1,159 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "db/sysdb_services.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_svc_by_port_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *protocol;
+
+ if (data->svc.protocol.name == NULL) {
+ return EOK;
+ }
+
+ protocol = sss_get_cased_name(NULL, data->svc.protocol.name,
+ domain->case_sensitive);
+ if (protocol == NULL) {
+ return ENOMEM;
+ }
+
+ talloc_zfree(data->svc.protocol.lookup);
+ data->svc.protocol.lookup = talloc_steal(data, protocol);
+
+ return EOK;
+}
+
+static const char *
+cache_req_svc_by_port_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *protocol = data->svc.protocol.lookup;
+
+ protocol = protocol == NULL ? "<ANY>" : protocol;
+
+ return talloc_asprintf(mem_ctx, "%s %u@%s", protocol,
+ data->svc.port, domain->name);
+}
+
+static errno_t
+cache_req_svc_by_port_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_service_port(ncache, domain, data->svc.port,
+ data->svc.protocol.lookup);
+}
+
+static errno_t
+cache_req_svc_by_port_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_service_port(ncache, false, domain,
+ data->svc.port,
+ data->svc.protocol.lookup);
+}
+
+static errno_t
+cache_req_svc_by_port_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_getservbyport(mem_ctx, domain, data->svc.port,
+ data->svc.protocol.lookup, _result);
+}
+
+static struct tevent_req *
+cache_req_svc_by_port_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_SERVICES, NULL, cr->data->svc.port,
+ cr->data->svc.protocol.lookup);
+}
+
+const struct cache_req_plugin cache_req_svc_by_port = {
+ .name = "Service by port",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_svc_by_port_prepare_domain_data,
+ .create_debug_name_fn = cache_req_svc_by_port_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_svc_by_port_ncache_check,
+ .ncache_add_fn = cache_req_svc_by_port_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_svc_by_port_lookup,
+ .dp_send_fn = cache_req_svc_by_port_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_svc_by_port_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ uint16_t port,
+ const char *protocol)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_svc(mem_ctx, CACHE_REQ_SVC_BY_PORT,
+ NULL, protocol, port);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
new file mode 100644
index 0000000..a2dc1fa
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
@@ -0,0 +1,127 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_user_by_cert_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ /* Certificates might be quite long, thus we only use
+ * the last 10 characters for logging. */
+ return talloc_asprintf(mem_ctx, "CERT:%s@%s",
+ get_last_x_chars(data->cert, 10), domain->name);
+}
+
+static errno_t
+cache_req_user_by_cert_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_cert(ncache, data->cert);
+}
+
+static errno_t
+cache_req_user_by_cert_global_ncache_add(struct sss_nc_ctx *ncache,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_cert(ncache, false, data->cert);
+}
+
+static errno_t
+cache_req_user_by_cert_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ return sysdb_search_user_by_cert_with_views(mem_ctx, domain, data->cert,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_user_by_cert_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_CERT, cr->data->cert, 0, NULL);
+}
+
+const struct cache_req_plugin cache_req_user_by_cert = {
+ .name = "User by certificate",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = false,
+ .search_all_domains = true,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_user_by_cert_create_debug_name,
+ .global_ncache_add_fn = cache_req_user_by_cert_global_ncache_add,
+ .ncache_check_fn = cache_req_user_by_cert_ncache_check,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_user_by_cert_lookup,
+ .dp_send_fn = cache_req_user_by_cert_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *pem_cert)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_cert(mem_ctx, CACHE_REQ_USER_BY_CERT, pem_cert);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
new file mode 100644
index 0000000..11ea9ec
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
@@ -0,0 +1,176 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_user_by_filter_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_user_by_filter_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_filter_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ char *recent_filter;
+ const char *attr = (data->name.attr == NULL ? SYSDB_NAME : data->name.attr);
+ errno_t ret;
+
+ /* The "files" provider updates the record if /etc/passwd or /etc/group
+ * is touched. It does not perform any per-request update.
+ * Therefore the last update flag is not updated if no file was touched
+ * and we cannot use this optimization.
+ * Neither it is possible to use it when asking for a non-"name" attribute
+ * as it could not be present in the timestamp cache.
+ */
+ if (is_files_provider(domain) || data->name.attr != NULL) {
+ recent_filter = NULL;
+ } else {
+ recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)", SYSDB_LAST_UPDATE,
+ cr->req_start);
+ if (recent_filter == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ ret = sysdb_enumpwent_filter_with_views(mem_ctx, domain,
+ attr, data->name.lookup,
+ recent_filter, _result);
+ talloc_free(recent_filter);
+
+ return ret;
+}
+
+static struct tevent_req *
+cache_req_user_by_filter_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_WILDCARD_USER, cr->data->name.lookup,
+ cr->data->id, NULL);
+}
+
+const struct cache_req_plugin cache_req_user_by_filter = {
+ .name = "User by filter",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = true,
+ .only_one_result = false,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_user_by_filter_prepare_domain_data,
+ .create_debug_name_fn = cache_req_user_by_filter_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = NULL,
+ .ncache_add_fn = NULL,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_user_by_filter_lookup,
+ .dp_send_fn = cache_req_user_by_filter_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *attr,
+ const char *filter)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_attr(mem_ctx, CACHE_REQ_USER_BY_FILTER, attr, filter);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL,
+ 0,
+ req_dom_type, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
new file mode 100644
index 0000000..fee5736
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
@@ -0,0 +1,246 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static const char *
+cache_req_user_by_id_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_asprintf(mem_ctx, "UID:%"PRIu32"@%s", data->id, domain->name);
+}
+
+static errno_t
+cache_req_user_by_id_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ errno_t ret;
+
+ if (domain != NULL) {
+ ret = sss_ncache_check_uid(ncache, domain, data->id);
+ if (ret == EEXIST) {
+ return ret;
+ }
+ }
+
+ return sss_ncache_check_uid(ncache, NULL, data->id);
+}
+
+static errno_t
+cache_req_user_by_id_ncache_filter(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ return sss_ncache_check_user(ncache, domain, name);
+}
+
+static errno_t
+cache_req_user_by_id_global_ncache_add(struct sss_nc_ctx *ncache,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_uid(ncache, false, NULL, data->id);
+}
+
+static errno_t
+cache_req_user_by_id_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_uid(ncache, false, domain, data->id);
+}
+
+static errno_t
+cache_req_user_by_id_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ errno_t ret;
+ ret = cache_req_idminmax_check(data, domain);
+ if (ret != EOK) {
+ return ret;
+ }
+ return sysdb_getpwuid_with_views(mem_ctx, domain, data->id, _result);
+}
+
+static errno_t
+cache_req_user_by_id_dpreq_params(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result *result,
+ const char **_string,
+ uint32_t *_id,
+ const char **_flag)
+{
+ uint32_t id;
+
+ *_id = cr->data->id;
+ *_string = NULL;
+ *_flag = NULL;
+
+ if (!DOM_HAS_VIEWS(cr->domain)) {
+ return EOK;
+ }
+
+ /* We must search with views. */
+ if (result == NULL || result->count == 0) {
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* If domain has views we will try to use original values instead of the
+ * overridden ones. This is a must for the LOCAL view since we can't look
+ * it up otherwise. But it is also a shortcut for non-local views where
+ * we will not fail over to the overridden value. */
+
+ id = ldb_msg_find_attr_as_uint64(result->msgs[0], SYSDB_UIDNUM, 0);
+ if (id == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0\n");
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* Now we have the original name and id. We don't have to search with
+ * views unless some error occurred. */
+ *_id = id;
+
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_user_by_id_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ const char *string;
+ const char *flag;
+ uint32_t id;
+ errno_t ret;
+
+ ret = cache_req_user_by_id_dpreq_params(mem_ctx, cr, result,
+ &string, &id, &flag);
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_USER, string, id, flag);
+}
+
+static bool
+cache_req_user_by_id_get_domain_check(struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_check_locate_uid(rctx->ncache, domain, data->id);
+ if (nret == EEXIST) {
+ return false;
+ }
+
+ return true;
+}
+
+static struct tevent_req *
+cache_req_user_by_id_get_domain_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ int nret;
+
+ nret = sss_ncache_set_locate_uid(rctx->ncache, domain, data->id);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot set negative cache, this might result in "
+ "performance degradation\n");
+ /* Not fatal */
+ }
+
+ return sss_dp_get_account_domain_send(mem_ctx,
+ rctx,
+ domain,
+ true, /* fast_reply */
+ SSS_DP_USER,
+ data->id,
+ NULL);
+}
+
+const struct cache_req_plugin cache_req_user_by_id = {
+ .name = "User by ID",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = NULL,
+ .create_debug_name_fn = cache_req_user_by_id_create_debug_name,
+ .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add,
+ .ncache_check_fn = cache_req_user_by_id_ncache_check,
+ .ncache_add_fn = cache_req_user_by_id_ncache_add,
+ .ncache_filter_fn = cache_req_user_by_id_ncache_filter,
+ .lookup_fn = cache_req_user_by_id_lookup,
+ .dp_send_fn = cache_req_user_by_id_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = cache_req_user_by_id_get_domain_check,
+ .dp_get_domain_send_fn = cache_req_user_by_id_get_domain_send,
+ .dp_get_domain_recv_fn = cache_req_common_get_acct_domain_recv,
+};
+
+struct tevent_req *
+cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ uid_t uid)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_id(mem_ctx, CACHE_REQ_USER_BY_ID, uid);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
new file mode 100644
index 0000000..d24a222
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
@@ -0,0 +1,256 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_user_by_name_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *name;
+ errno_t ret;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed name is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ name = sss_get_cased_name(tmp_ctx, cr->data->name.name,
+ domain->case_sensitive);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_reverse_replace_space(tmp_ctx, name, cr->rctx->override_space);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ name = sss_create_internal_fqname(tmp_ctx, name, domain->name);
+ if (name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static const char *
+cache_req_user_by_name_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_name_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_user(ncache, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_name_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_user(ncache, false, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_name_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ if (data->attrs == NULL) {
+ return sysdb_getpwnam_with_views(mem_ctx, domain, data->name.lookup,
+ _result);
+ }
+
+ return sysdb_get_user_attr_with_views(mem_ctx, domain, data->name.lookup,
+ data->attrs, _result);
+}
+
+static errno_t
+cache_req_user_by_name_dpreq_params(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct ldb_result *result,
+ const char **_string,
+ uint32_t *_id,
+ const char **_flag)
+{
+ const char *name;
+
+ *_id = 0;
+ *_string = cr->data->name.lookup;
+ *_flag = NULL;
+
+ if (!DOM_HAS_VIEWS(cr->domain)) {
+ return EOK;
+ }
+
+ /* We must search with views. */
+ if (result == NULL || result->count == 0) {
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* If domain has views we will try to use original values instead of the
+ * overridden ones. This is a must for the LOCAL view since we can't look
+ * it up otherwise. But it is also a shortcut for non-local views where
+ * we will not fail over to the overridden value. */
+
+ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL\n");
+ *_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
+ return EOK;
+ }
+
+ /* Now we have the original name and id. We don't have to search with
+ * views unless some error occurred. */
+ *_string = talloc_steal(mem_ctx, name);
+
+ return EOK;
+}
+
+static struct tevent_req *
+cache_req_user_by_name_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ const char *string;
+ const char *flag;
+ uint32_t id;
+ errno_t ret;
+
+ ret = cache_req_user_by_name_dpreq_params(mem_ctx, cr, result,
+ &string, &id, &flag);
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_USER, string, id, flag);
+}
+
+const struct cache_req_plugin cache_req_user_by_name = {
+ .name = "User by name",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = true,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = false,
+ .allow_switch_to_upn = true,
+ .upn_equivalent = CACHE_REQ_USER_BY_UPN,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_user_by_name_prepare_domain_data,
+ .create_debug_name_fn = cache_req_user_by_name_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_user_by_name_ncache_check,
+ .ncache_add_fn = cache_req_user_by_name_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_user_by_name_lookup,
+ .dp_send_fn = cache_req_user_by_name_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *name)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_USER_BY_NAME, name);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
+}
+
+struct tevent_req *
+cache_req_user_by_name_attrs_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ const char *domain,
+ const char *name,
+ const char **attrs)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name_attrs(mem_ctx, CACHE_REQ_USER_BY_NAME,
+ name, attrs);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ CACHE_REQ_POSIX_DOM, domain,
+ data);
+}
diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c
new file mode 100644
index 0000000..037994c
--- /dev/null
+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c
@@ -0,0 +1,158 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <talloc.h>
+#include <ldb.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "responder/common/cache_req/cache_req_plugin.h"
+
+static errno_t
+cache_req_user_by_upn_prepare_domain_data(struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ const char *name;
+
+ if (cr->data->name.name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: parsed UPN is NULL?\n");
+ return ERR_INTERNAL;
+ }
+
+ /* When looking up UPNs we don't want to reverse-replace spaces,
+ * just search whatever the user passed in. strdup the name so we
+ * can safely steal it later.
+ */
+ name = talloc_strdup(data, cr->data->name.name);
+ if (name == NULL) {
+ return ENOMEM;
+ }
+
+ talloc_zfree(data->name.lookup);
+ data->name.lookup = talloc_steal(data, name);
+
+ return EOK;
+}
+
+static const char *
+cache_req_user_by_upn_create_debug_name(TALLOC_CTX *mem_ctx,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain)
+{
+ return talloc_strdup(mem_ctx, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_upn_ncache_check(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_check_upn(ncache, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_upn_ncache_add(struct sss_nc_ctx *ncache,
+ struct sss_domain_info *domain,
+ struct cache_req_data *data)
+{
+ return sss_ncache_set_upn(ncache, false, domain, data->name.lookup);
+}
+
+static errno_t
+cache_req_user_by_upn_lookup(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result **_result)
+{
+ if (data->attrs == NULL) {
+ return sysdb_getpwupn(mem_ctx, domain, true, data->name.lookup, _result);
+ }
+
+ return sysdb_search_user_by_upn_res(mem_ctx, domain, true,
+ data->name.lookup, data->attrs,
+ _result);
+}
+
+static struct tevent_req *
+cache_req_user_by_upn_dp_send(TALLOC_CTX *mem_ctx,
+ struct cache_req *cr,
+ struct cache_req_data *data,
+ struct sss_domain_info *domain,
+ struct ldb_result *result)
+{
+ return sss_dp_get_account_send(mem_ctx, cr->rctx, domain, true,
+ SSS_DP_USER, cr->data->name.lookup,
+ 0, EXTRA_NAME_IS_UPN);
+}
+
+const struct cache_req_plugin cache_req_user_by_upn = {
+ .name = "User by UPN",
+ .attr_expiration = SYSDB_CACHE_EXPIRE,
+ .parse_name = false,
+ .ignore_default_domain = false,
+ .bypass_cache = false,
+ .only_one_result = true,
+ .search_all_domains = false,
+ .require_enumeration = false,
+ .allow_missing_fqn = true,
+ .allow_switch_to_upn = false,
+ .upn_equivalent = CACHE_REQ_SENTINEL,
+ .get_next_domain_flags = SSS_GND_DESCEND,
+
+ .is_well_known_fn = NULL,
+ .prepare_domain_data_fn = cache_req_user_by_upn_prepare_domain_data,
+ .create_debug_name_fn = cache_req_user_by_upn_create_debug_name,
+ .global_ncache_add_fn = NULL,
+ .ncache_check_fn = cache_req_user_by_upn_ncache_check,
+ .ncache_add_fn = cache_req_user_by_upn_ncache_add,
+ .ncache_filter_fn = NULL,
+ .lookup_fn = cache_req_user_by_upn_lookup,
+ .dp_send_fn = cache_req_user_by_upn_dp_send,
+ .dp_recv_fn = cache_req_common_dp_recv,
+ .dp_get_domain_check_fn = NULL,
+ .dp_get_domain_send_fn = NULL,
+ .dp_get_domain_recv_fn = NULL,
+};
+
+struct tevent_req *
+cache_req_user_by_upn_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_nc_ctx *ncache,
+ int cache_refresh_percent,
+ enum cache_req_dom_type req_dom_type,
+ const char *domain,
+ const char *upn)
+{
+ struct cache_req_data *data;
+
+ data = cache_req_data_name(mem_ctx, CACHE_REQ_USER_BY_UPN, upn);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
+ cache_refresh_percent,
+ req_dom_type, domain,
+ data);
+}