From 74d32250c0c931aa1a61bc7237b61e62493d8302 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 6 Nov 2014 16:54:17 +0100
Subject: [PATCH 6/6] IFP: use new cache interface

---
 src/responder/ifp/ifpsrv_cmd.c | 371 ++++++-----------------------------------
 1 file changed, 48 insertions(+), 323 deletions(-)

diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c
index 3b7442233a5b4d01f430c9ffdbcdc949637d6db9..40d31aa687781fe83421c9b41d98d31fde0161c2 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;
@@ -423,15 +424,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,
@@ -460,7 +454,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:
@@ -471,338 +465,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;
-        }
-
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct ifp_user_get_attr_state);
+
+    ret = cache_req_recv(state, subreq, &state->res, &state->dom);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (state->search_type == SSS_DP_USER) {
+        /* throw away the result and perform attr search */
+        talloc_zfree(state->res);
+
+        ret = sysdb_get_user_attr_with_views(state, state->dom, state->name,
+                                             state->attrs, &state->res);
         if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Failed to make request to our cache!\n");
-            return EIO;
+            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;
         }
-
-        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;
-            }
-
-            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);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, "Could not get account info: %d\n", ret);
-        /* report error with callback */
-    }
-
-    cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
-}
-
-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;
     }
 
     tevent_req_done(req);
-- 
1.7.11.7

