From faae3d55e5cf416f16158d3b9f8c8fd475ac6acf Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Tue, 25 Nov 2014 12:58:24 +0100 Subject: IFP: use new cache interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Michal Židek --- src/responder/ifp/ifpsrv_cmd.c | 365 +++++------------------------------------ 1 file changed, 45 insertions(+), 320 deletions(-) (limited to 'src/responder/ifp') diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c index 49792f53c..41b354367 100644 --- a/src/responder/ifp/ifpsrv_cmd.c +++ b/src/responder/ifp/ifpsrv_cmd.c @@ -23,6 +23,7 @@ #include "db/sysdb.h" #include "responder/ifp/ifp_private.h" +#include "responder/common/responder_cache_req.h" struct ifp_attr_req { const char *name; @@ -433,15 +434,8 @@ struct ifp_user_get_attr_state { int neg_timeout; }; -static void ifp_user_get_attr_dom(struct tevent_req *subreq); -static errno_t ifp_user_get_attr_search(struct tevent_req *req); -int ifp_cache_check(struct ifp_user_get_attr_state *state, - enum sss_dp_acct_type search_type, - sss_dp_callback_t callback, - unsigned int cache_refresh_percent, - const char *extra_flag, - void *pvt); -void ifp_user_get_attr_done(struct tevent_req *req); +static void ifp_user_get_attr_lookup(struct tevent_req *subreq); +static void ifp_user_get_attr_done(struct tevent_req *subreq); static struct tevent_req * ifp_user_get_attr_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, @@ -470,7 +464,7 @@ ifp_user_get_attr_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, ret = ENOMEM; goto done; } - tevent_req_set_callback(subreq, ifp_user_get_attr_dom, req); + tevent_req_set_callback(subreq, ifp_user_get_attr_lookup, req); ret = EOK; done: @@ -481,338 +475,69 @@ done: } static void -ifp_user_get_attr_dom(struct tevent_req *subreq) +ifp_user_get_attr_lookup(struct tevent_req *subreq) { + struct ifp_user_get_attr_state *state = NULL; + struct tevent_req *req = NULL; errno_t ret; - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct ifp_user_get_attr_state *state = tevent_req_data(req, - struct ifp_user_get_attr_state); + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ifp_user_get_attr_state); ret = sss_parse_inp_recv(subreq, state, &state->name, &state->domname); - talloc_free(subreq); + talloc_zfree(subreq); if (ret != EOK) { tevent_req_error(req, ret); return; } - if (state->domname) { - /* this is a search in one domain */ - state->dom = responder_get_domain(state->rctx, state->domname); - if (state->dom == NULL) { - tevent_req_error(req, EINVAL); - return; - } - state->check_next = false; - } else { - /* this is a multidomain search */ - state->dom = state->rctx->domains; - state->check_next = true; - } - - state->check_provider = NEED_CHECK_PROVIDER(state->dom->provider); - - /* All set up, do the search! */ - ret = ifp_user_get_attr_search(req); - if (ret == EOK) { - /* The data was cached. Just quit */ - tevent_req_done(req); - return; - } else if (ret != EAGAIN) { - tevent_req_error(req, ret); + subreq = cache_req_send(state, state->rctx->ev, state->rctx, + state->ncache, state->neg_timeout, 0, + state->search_type, state->domname, state->name); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); return; } - /* Execution will resume in ifp_dp_callback */ + tevent_req_set_callback(subreq, ifp_user_get_attr_done, req); } -static void ifp_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); - -static errno_t ifp_user_get_attr_search(struct tevent_req *req) +static void ifp_user_get_attr_done(struct tevent_req *subreq) { - struct ifp_user_get_attr_state *state = tevent_req_data(req, - struct ifp_user_get_attr_state); - struct sss_domain_info *dom = state->dom; - const char *extra_flag = NULL; - char *name = NULL; + struct ifp_user_get_attr_state *state = NULL; + struct tevent_req *req = NULL; errno_t ret; - while (dom) { - /* if it is a domainless search, skip domains that require fully - * qualified names instead */ - while (dom && state->check_next && dom->fqnames) { - dom = get_next_domain(dom, false); - } - - if (!dom) break; - - if (dom != state->dom) { - /* make sure we reset the check_provider flag when we check - * a new domain */ - state->check_provider = NEED_CHECK_PROVIDER(dom->provider); - } - - /* make sure to update the cache_req if we changed domain */ - state->dom = dom; - - talloc_free(name); - name = sss_get_cased_name(state, state->name, dom->case_sensitive); - if (!name) return ENOMEM; - - state->name = sss_reverse_replace_space(state, name, - state->rctx->override_space); - if (state->name == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "sss_reverse_replace_space failed\n"); - return ENOMEM; - } - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ret = sss_ncache_check_user(state->ncache, - state->neg_timeout, - dom, name); - /* if neg cached, return we didn't find it */ - if (ret == EEXIST) { - DEBUG(SSSDBG_TRACE_FUNC, - "User [%s] does not exist in [%s]! (negative cache)\n", - name, dom->name); - /* if a multidomain search, try with next */ - if (state->check_next) { - dom = get_next_domain(dom, false); - continue; - } - - /* There are no further domains or this was a - * fully-qualified user request. - */ - return ENOENT; - } - - DEBUG(SSSDBG_FUNC_DATA, - "Requesting info for [%s@%s]\n", name, dom->name); - - switch (state->search_type) { - case SSS_DP_USER: - ret = sysdb_get_user_attr_with_views(state, dom, name, - state->attrs, &state->res); - break; - case SSS_DP_INITGROUPS: - ret = sysdb_initgroups_with_views(state, dom, name, - &state->res); - break; - default: - DEBUG(SSSDBG_OP_FAILURE, "Unsupported operation\n"); - return EIO; - } - - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to make request to our cache!\n"); - return EIO; - } - - if (state->search_type == SSS_DP_USER) { - if (state->res->count > 1) { - DEBUG(SSSDBG_CRIT_FAILURE, - "getpwnam call returned more than one result !?!\n"); - return ENOENT; - } - } - - if (state->res->count == 0 && state->check_provider == false) { - /* set negative cache only if not result of cache check */ - ret = sss_ncache_set_user(state->ncache, false, dom, name); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s@%s\n", - name, dom->name); - /* Not fatal */ - } - - /* if a multidomain search, try with next */ - if (state->check_next) { - dom = get_next_domain(dom, false); - if (dom) continue; - } + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ifp_user_get_attr_state); - DEBUG(SSSDBG_TRACE_FUNC, "No results for getpwnam call\n"); - return ENOENT; - } - - /* if this is a caching provider (or if we haven't checked the cache - * yet) then verify that the cache is uptodate */ - if (state->check_provider) { - if (DOM_HAS_VIEWS(dom) && state->res->count == 0) { - extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW; - } - - ret = ifp_cache_check(state, state->search_type, - ifp_dp_callback, 0, extra_flag, req); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return ret; - } - } - - /* One result found */ - DEBUG(SSSDBG_TRACE_FUNC, - "Returning info for user [%s@%s]\n", name, dom->name); - return EOK; - } - - DEBUG(SSSDBG_MINOR_FAILURE, - "No matching domain found for [%s], fail!\n", state->inp); - return ENOENT; -} - -int ifp_cache_check(struct ifp_user_get_attr_state *state, - enum sss_dp_acct_type search_type, - sss_dp_callback_t callback, - unsigned int cache_refresh_percent, - const char *extra_flag, - void *pvt) -{ - uint64_t cache_expire = 0; - int ret; - struct tevent_req *req; - struct dp_callback_ctx *cb_ctx = NULL; - - if (search_type == SSS_DP_USER && state->res->count > 1) { - DEBUG(SSSDBG_OP_FAILURE, - "cache search call returned more than one result! " - "DB Corrupted?\n"); - return ENOENT; - } - - if (state->res->count > 0) { - if (search_type == SSS_DP_USER) { - cache_expire = ldb_msg_find_attr_as_uint64(state->res->msgs[0], - SYSDB_CACHE_EXPIRE, 0); - } else { - cache_expire = ldb_msg_find_attr_as_uint64(state->res->msgs[0], - SYSDB_INITGR_EXPIRE, 0); - } - - /* if we have any reply let's check cache validity */ - ret = sss_cmd_check_cache(state->res->msgs[0], cache_refresh_percent, - cache_expire); - if (ret == EOK) { - DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning..\n"); - return EOK; - } else if (ret != EAGAIN && ret != ENOENT) { - DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache: %d\n", ret); - return ret; - } - } else { - /* No replies */ - ret = ENOENT; - } - - /* EAGAIN (off band) or ENOENT (cache miss) -> check cache */ - if (ret == EAGAIN) { - /* No callback required - * This was an out-of-band update. We'll return EOK - * so the calling function can return the cached entry - * immediately. - */ - DEBUG(SSSDBG_TRACE_FUNC, "Performing midpoint cache update\n"); - - req = sss_dp_get_account_send(state, state->rctx, state->dom, true, - search_type, state->name, 0, - extra_flag); - if (req == 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 { - DEBUG(SSSDBG_TRACE_FUNC, "Updating cache out-of-band\n"); - } - - /* We don't need to listen for a reply, so we will free the - * request here. - */ - talloc_zfree(req); - } else { - /* This is a cache miss. Or the cache is expired. - * We need to get the updated user information before returning it. - */ - - /* dont loop forever; mark the provider as checked */ - state->check_provider = false; - - req = sss_dp_get_account_send(state, state->rctx, state->dom, true, - search_type, state->name, 0, extra_flag); - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Out of memory sending data provider request\n"); - return ENOMEM; - } - - cb_ctx = talloc_zero(state, struct dp_callback_ctx); - if (cb_ctx == NULL) { - talloc_zfree(req); - return ENOMEM; - } - cb_ctx->callback = callback; - cb_ctx->ptr = pvt; - cb_ctx->cctx = NULL; /* There is no client in ifp */ - cb_ctx->mem_ctx = state; - - tevent_req_set_callback(req, ifp_user_get_attr_done, cb_ctx); - return EAGAIN; - } - - return EOK; -} - -void ifp_user_get_attr_done(struct tevent_req *req) -{ - struct dp_callback_ctx *cb_ctx = - tevent_req_callback_data(req, struct dp_callback_ctx); - - errno_t ret; - dbus_uint16_t err_maj; - dbus_uint32_t err_min; - char *err_msg; - - ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req, - &err_maj, &err_min, - &err_msg); - talloc_zfree(req); + ret = cache_req_recv(state, subreq, &state->res, &state->dom); + talloc_zfree(subreq); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Could not get account info: %d\n", ret); - /* report error with callback */ + tevent_req_error(req, ret); + return; } - cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr); -} + if (state->search_type == SSS_DP_USER) { + /* throw away the result and perform attr search */ + talloc_zfree(state->res); -static void ifp_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) -{ - errno_t ret; - struct tevent_req *req = talloc_get_type(ptr, struct tevent_req); - - if (err_maj) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n" - "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg); - } - - /* Backend was updated successfully. Check again */ - ret = ifp_user_get_attr_search(req); - if (ret == EAGAIN) { - /* Another search in progress */ - return; - } else if (ret != EOK) { - tevent_req_error(req, ret); - return; + ret = sysdb_get_user_attr_with_views(state, state->dom, state->name, + state->attrs, &state->res); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_get_user_attr_with_views() " + "failed [%d]: %s\n", ret, sss_strerror(ret)); + tevent_req_error(req, ret); + return; + } else if (state->res->count == 0) { + tevent_req_error(req, ENOENT); + return; + } else if (state->res->count != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_get_user_attr_with_views() " + "returned more than one result!\n"); + tevent_req_error(req, ENOENT); + return; + } } tevent_req_done(req); -- cgit