From db6c8c38bd450f21a9f8d0489fc2b88b6cf3d1b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 23 Jan 2015 14:03:07 +0100
Subject: [PATCH 03/13] cache_req: preparations for different input type

Currently cache_req takes only user name as an input parameter. However,
this is not enough since we will need also UID and GID in the future.
This patch creates a structure to hold input parameters so it can be
simply extended to support other input types.
---
 src/responder/common/responder_cache_req.c | 341 +++++++++++++++++++++--------
 src/responder/common/responder_cache_req.h |  41 +++-
 src/responder/ifp/ifpsrv_cmd.c             |  24 +-
 3 files changed, 306 insertions(+), 100 deletions(-)

diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c
index 39f90cfe16fa7c726eae92110ce717ffefb556a2..b10dfbd783be1c8f4782f0b765644ca1083749a7 100644
--- a/src/responder/common/responder_cache_req.c
+++ b/src/responder/common/responder_cache_req.c
@@ -28,54 +28,175 @@
 #include "responder/common/responder_cache_req.h"
 #include "providers/data_provider.h"
 
-static errno_t cache_req_check_ncache(enum sss_dp_acct_type dp_type,
+struct cache_req_input {
+    enum cache_req_type type;
+
+    /* Provided input. */
+    const char *orig_name;
+
+    /* Data Provider request type resolved from @type. */
+    enum sss_dp_acct_type dp_type;
+
+    /* Domain related informations. */
+    struct sss_domain_info *domain;
+
+    /* Name sanitized according to domain rules such as case sensitivity and
+     * replacement of space character. This needs to be set up for each
+     * domain separately. */
+    const char *safe_name;
+
+    /* Fully qualified object name. */
+    const char *fqn;
+};
+
+struct cache_req_input *
+cache_req_input_create(TALLOC_CTX *mem_ctx,
+                       enum cache_req_type type,
+                       const char *name)
+{
+    struct cache_req_input *input;
+
+    input = talloc_zero(mem_ctx, struct cache_req_input);
+    if (input == NULL) {
+        return NULL;
+    }
+
+    input->type = type;
+
+    /* Check that input parameters match selected type. */
+    switch (input->type) {
+    case CACHE_REQ_USER_BY_NAME:
+    case CACHE_REQ_INITGROUPS:
+        if (name == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+            goto fail;
+        }
+
+        input->orig_name = talloc_strdup(input, name);
+        if (input->orig_name == NULL) {
+            goto fail;
+        }
+        break;
+    }
+
+    /* Resolve Data Provider request type. */
+    switch (type) {
+    case CACHE_REQ_USER_BY_NAME:
+        input->dp_type = SSS_DP_USER;
+        break;
+
+    case CACHE_REQ_INITGROUPS:
+        input->dp_type = SSS_DP_INITGROUPS;
+        break;
+    }
+
+    return input;
+
+fail:
+    talloc_free(input);
+    return NULL;
+}
+
+static errno_t
+cache_req_input_set_domain(struct cache_req_input *input,
+                           struct sss_domain_info *domain,
+                           struct resp_ctx *rctx)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char *name = NULL;
+    const char *fqn = NULL;
+    errno_t ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    talloc_zfree(input->safe_name);
+    talloc_zfree(input->fqn);
+
+    switch (input->type) {
+    case CACHE_REQ_USER_BY_NAME:
+    case CACHE_REQ_INITGROUPS:
+        name = sss_get_cased_name(tmp_ctx, input->orig_name,
+                                  domain->case_sensitive);
+        if (name == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        name = sss_reverse_replace_space(tmp_ctx, name, rctx->override_space);
+        if (name == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        fqn = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
+        if (fqn == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        break;
+    }
+
+    input->domain = domain;
+    input->safe_name = talloc_steal(input, name);
+    input->fqn = talloc_steal(input, fqn);
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static errno_t cache_req_check_ncache(struct cache_req_input *input,
                                       struct sss_nc_ctx *ncache,
-                                      int neg_timeout,
-                                      struct sss_domain_info *domain,
-                                      const char *name)
+                                      int neg_timeout)
 {
     errno_t ret;
 
-    switch (dp_type) {
-    case SSS_DP_USER:
-    case SSS_DP_INITGROUPS:
-        ret = sss_ncache_check_user(ncache, neg_timeout, domain, name);
+    switch (input->type) {
+    case CACHE_REQ_USER_BY_NAME:
+    case CACHE_REQ_INITGROUPS:
+        ret = sss_ncache_check_user(ncache, neg_timeout,
+                                    input->domain, input->safe_name);
         break;
     default:
         ret = EINVAL;
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported DP request type\n");
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported cache request type\n");
         break;
     }
 
     if (ret == EEXIST) {
-        DEBUG(SSSDBG_TRACE_FUNC, "[%s] does not exist in [%s]! "
-              "(negative cache)\n", name, domain->name);
+        DEBUG(SSSDBG_TRACE_FUNC, "[%s] does not exist (negative cache)\n",
+              input->fqn);
     }
 
     return ret;
 }
 
-static void cache_req_add_to_ncache(enum sss_dp_acct_type dp_type,
-                                    struct sss_nc_ctx *ncache,
-                                    struct sss_domain_info *domain,
-                                    const char *name)
+static void cache_req_add_to_ncache(struct cache_req_input *input,
+                                    struct sss_nc_ctx *ncache)
 {
     errno_t ret;
 
-    switch (dp_type) {
-    case SSS_DP_USER:
-    case SSS_DP_INITGROUPS:
-        ret = sss_ncache_set_user(ncache, false, domain, name);
+    switch (input->type) {
+    case CACHE_REQ_USER_BY_NAME:
+    case CACHE_REQ_INITGROUPS:
+        ret = sss_ncache_set_user(ncache, false, input->domain,
+                                  input->safe_name);
         break;
     default:
         ret = EINVAL;
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported DP request type\n");
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported cache request type\n");
         break;
     }
 
     if (ret != EOK) {
-        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s@%s [%d]: %s\n",
-              name, domain->name, ret, sss_strerror(ret));
+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for [%s] [%d]: %s\n",
+              input->fqn, ret, sss_strerror(ret));
 
         /* not fatal */
     }
@@ -84,30 +205,29 @@ static void cache_req_add_to_ncache(enum sss_dp_acct_type dp_type,
 }
 
 static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
-                                    enum sss_dp_acct_type dp_type,
-                                    struct sss_domain_info *domain,
-                                    const char *name,
+                                    struct cache_req_input *input,
                                     struct ldb_result **_result)
 {
     struct ldb_result *result = NULL;
     bool one_item_only;
     errno_t ret;
 
-    DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s@%s]\n",
-          name, domain->name);
+    DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s]\n", input->fqn);
 
-    switch (dp_type) {
-    case SSS_DP_USER:
+    switch (input->type) {
+    case CACHE_REQ_USER_BY_NAME:
         one_item_only = true;
-        ret = sysdb_getpwnam_with_views(mem_ctx, domain, name, &result);
+        ret = sysdb_getpwnam_with_views(mem_ctx, input->domain,
+                                        input->safe_name, &result);
         break;
-    case SSS_DP_INITGROUPS:
+    case CACHE_REQ_INITGROUPS:
         one_item_only = false;
-        ret = sysdb_initgroups_with_views(mem_ctx, domain, name, &result);
+        ret = sysdb_initgroups_with_views(mem_ctx, input->domain,
+                                          input->safe_name, &result);
         break;
     default:
         ret = EINVAL;
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported DP request type\n");
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported cache request type\n");
         break;
     }
 
@@ -136,9 +256,7 @@ struct cache_req_cache_state {
     struct sss_nc_ctx *ncache;
     int neg_timeout;
     int cache_refresh_percent;
-    enum sss_dp_acct_type dp_type;
-    struct sss_domain_info *domain;
-    const char *name;
+    struct cache_req_input *input;
 
     /* output data */
     struct ldb_result *result;
@@ -154,9 +272,7 @@ static struct tevent_req *cache_req_cache_send(TALLOC_CTX *mem_ctx,
                                                struct sss_nc_ctx *ncache,
                                                int neg_timeout,
                                                int cache_refresh_percent,
-                                               enum sss_dp_acct_type dp_type,
-                                               struct sss_domain_info *domain,
-                                               const char *name)
+                                               struct cache_req_input *input)
 {
     struct cache_req_cache_state *state = NULL;
     struct tevent_req *req = NULL;
@@ -173,28 +289,11 @@ static struct tevent_req *cache_req_cache_send(TALLOC_CTX *mem_ctx,
     state->ncache = ncache;
     state->neg_timeout = neg_timeout;
     state->cache_refresh_percent = cache_refresh_percent;
-    state->dp_type = dp_type;
-    state->domain = domain;
-
-    /* Sanitize input name. */
-    state->name = sss_get_cased_name(state, name, domain->case_sensitive);
-    if (state->name == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    state->name = sss_reverse_replace_space(state, state->name,
-                                            state->rctx->override_space);
-    if (state->name == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "sss_reverse_replace_space failed\n");
-        ret = ENOMEM;
-        goto immediately;
-    }
+    state->input = input;
 
     /* Check negative cache first. */
-    ret = cache_req_check_ncache(state->dp_type, state->ncache,
-                                 state->neg_timeout, state->domain,
-                                 state->name);
+    ret = cache_req_check_ncache(state->input, state->ncache,
+                                 state->neg_timeout);
     if (ret == EEXIST) {
         ret = ENOENT;
         goto immediately;
@@ -227,8 +326,7 @@ static errno_t cache_req_cache_search(struct tevent_req *req)
 
     state = tevent_req_data(req, struct cache_req_cache_state);
 
-    ret = cache_req_get_object(state, state->dp_type, state->domain,
-                               state->name, &state->result);
+    ret = cache_req_get_object(state, state->input, &state->result);
     if (ret != EOK && ret != ENOENT) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache "
               "[%d]: %s\n", ret, sss_strerror(ret));
@@ -242,8 +340,7 @@ static errno_t cache_req_cache_search(struct tevent_req *req)
     }
 
     /* One result found */
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Returning info for [%s@%s]\n", state->name, state->domain->name);
+    DEBUG(SSSDBG_TRACE_FUNC, "Returning info for [%s]\n", state->input->fqn);
     return EOK;
 }
 
@@ -260,7 +357,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
     if (state->result == NULL || state->result->count == 0) {
         ret = ENOENT;
     } else {
-        if (state->dp_type == SSS_DP_INITGROUPS) {
+        if (state->input->dp_type == SSS_DP_INITGROUPS) {
             cache_expire = ldb_msg_find_attr_as_uint64(state->result->msgs[0],
                                                        SYSDB_INITGR_EXPIRE, 0);
         } else {
@@ -282,9 +379,10 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
 
         DEBUG(SSSDBG_TRACE_FUNC, "Performing midpoint cache update\n");
 
-        subreq = sss_dp_get_account_send(state, state->rctx, state->domain,
-                                         true, state->dp_type, state->name,
-                                         0, NULL);
+        subreq = sss_dp_get_account_send(state, state->rctx,
+                                         state->input->domain, true,
+                                         state->input->dp_type,
+                                         state->input->safe_name, 0, NULL);
         if (subreq == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending out-of-band "
                                        "data provider request\n");
@@ -298,13 +396,15 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
         /* Cache miss or the cache is expired. We need to get the updated
          * information before returning it. */
 
-        if (DOM_HAS_VIEWS(state->domain)) {
+        if (DOM_HAS_VIEWS(state->input->domain)) {
             extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
         }
 
-        subreq = sss_dp_get_account_send(state, state->rctx, state->domain,
-                                         true, state->dp_type, state->name,
-                                         0, extra_flag);
+        subreq = sss_dp_get_account_send(state, state->rctx,
+                                         state->input->domain, true,
+                                         state->input->dp_type,
+                                         state->input->safe_name, 0,
+                                         extra_flag);
         if (subreq == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Out of memory sending data provider request\n");
@@ -349,11 +449,9 @@ static void cache_req_cache_done(struct tevent_req *subreq)
     }
 
     /* Get result from cache again. */
-    ret = cache_req_get_object(state, state->dp_type, state->domain,
-                               state->name, &state->result);
+    ret = cache_req_get_object(state, state->input, &state->result);
     if (ret == ENOENT) {
-        cache_req_add_to_ncache(state->dp_type, state->ncache,
-                                state->domain, state->name);
+        cache_req_add_to_ncache(state->input, state->ncache);
         ret = ENOENT;
     } else if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache "
@@ -366,8 +464,7 @@ static void cache_req_cache_done(struct tevent_req *subreq)
     }
 
     /* One result found */
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Returning info for [%s@%s]\n", state->name, state->domain->name);
+    DEBUG(SSSDBG_TRACE_FUNC, "Returning info for [%s]\n", state->input->fqn);
 
     tevent_req_done(req);
 }
@@ -394,8 +491,7 @@ struct cache_req_state {
     struct sss_nc_ctx *ncache;
     int neg_timeout;
     int cache_refresh_percent;
-    const char *name;
-    enum sss_dp_acct_type dp_type;
+    struct cache_req_input *input;
 
     /* work data */
     struct ldb_result *result;
@@ -413,9 +509,8 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
                                   struct sss_nc_ctx *ncache,
                                   int neg_timeout,
                                   int cache_refresh_percent,
-                                  enum sss_dp_acct_type dp_type,
                                   const char *domain,
-                                  const char *name)
+                                  struct cache_req_input *input)
 {
     struct cache_req_state *state = NULL;
     struct tevent_req *req = NULL;
@@ -432,12 +527,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
     state->ncache = ncache;
     state->neg_timeout = neg_timeout;
     state->cache_refresh_percent = cache_refresh_percent;
-    state->dp_type = dp_type;
-    state->name = talloc_strdup(state, name);
-    if (state->name == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
+    state->input = input;
 
     if (domain != NULL) {
         /* single-domain search */
@@ -476,6 +566,7 @@ static errno_t cache_req_next_domain(struct tevent_req *req)
 {
     struct cache_req_state *state = NULL;
     struct tevent_req *subreq = NULL;
+    errno_t ret;
 
     state = tevent_req_data(req, struct cache_req_state);
 
@@ -493,11 +584,16 @@ static errno_t cache_req_next_domain(struct tevent_req *req)
             break;
         }
 
+        ret = cache_req_input_set_domain(state->input, state->domain,
+                                         state->rctx);
+        if (ret != EOK) {
+            return ret;
+        }
+
         subreq = cache_req_cache_send(state, state->ev, state->rctx,
                                       state->ncache, state->neg_timeout,
                                       state->cache_refresh_percent,
-                                      state->dp_type, state->domain,
-                                      state->name);
+                                      state->input);
         if (subreq == NULL) {
             return ENOMEM;
         }
@@ -564,3 +660,70 @@ errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
 
     return EOK;
 }
+
+static struct tevent_req *
+cache_req_steal_input_and_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct resp_ctx *rctx,
+                               struct sss_nc_ctx *ncache,
+                               int neg_timeout,
+                               int cache_refresh_percent,
+                               const char *domain,
+                               struct cache_req_input *input)
+{
+    struct tevent_req *req;
+
+    req = cache_req_send(mem_ctx, ev, rctx, ncache, neg_timeout,
+                         cache_refresh_percent, domain, input);
+    if (req == NULL) {
+        talloc_zfree(input);
+    }
+
+    talloc_steal(req, input);
+
+    return req;
+}
+
+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 neg_timeout,
+                            int cache_refresh_percent,
+                            const char *domain,
+                            const char *name)
+{
+    struct cache_req_input *input;
+
+    input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_NAME, name);
+    if (input == NULL) {
+        return NULL;
+    }
+
+    return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
+                                          neg_timeout, cache_refresh_percent,
+                                          domain, input);
+}
+
+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 neg_timeout,
+                              int cache_refresh_percent,
+                              const char *domain,
+                              const char *name)
+{
+    struct cache_req_input *input;
+
+    input = cache_req_input_create(mem_ctx, CACHE_REQ_INITGROUPS, name);
+    if (input == NULL) {
+        return NULL;
+    }
+
+    return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
+                                          neg_timeout, cache_refresh_percent,
+                                          domain, input);
+}
diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h
index fdad94a13f521e5f32bde74f64898c867edf2ef8..3d11cd2344ee776c3b435bc16b75dc375ac87c5c 100644
--- a/src/responder/common/responder_cache_req.h
+++ b/src/responder/common/responder_cache_req.h
@@ -27,6 +27,18 @@
 #include "responder/common/responder.h"
 #include "responder/common/negcache.h"
 
+enum cache_req_type {
+    CACHE_REQ_USER_BY_NAME,
+    CACHE_REQ_INITGROUPS
+};
+
+struct cache_req_input;
+
+struct cache_req_input *
+cache_req_input_create(TALLOC_CTX *mem_ctx,
+                       enum cache_req_type type,
+                       const char *name);
+
 /**
  * Currently only SSS_DP_USER and SSS_DP_INITGROUPS are supported.
  *
@@ -38,27 +50,36 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
                                   struct sss_nc_ctx *ncache,
                                   int neg_timeout,
                                   int cache_refresh_percent,
-                                  enum sss_dp_acct_type dp_type,
                                   const char *domain,
-                                  const char *name);
+                                  struct cache_req_input *input);
 
 errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
                        struct tevent_req *req,
                        struct ldb_result **_result,
                        struct sss_domain_info **_domain);
 
-#define cache_req_user_by_name_send(mem_ctx, ev, rctx, ncache, neg_timeout, \
-                                    cache_refresh_percent, domain, name) \
-    cache_req_send(mem_ctx, ev, rctx, ncache, neg_timeout, \
-                   cache_refresh_percent, SSS_DP_USER, domain, name)
+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 neg_timeout,
+                            int cache_refresh_percent,
+                            const char *domain,
+                            const char *name);
 
 #define cache_req_user_by_name_recv(mem_ctx, req, _result, _domain) \
     cache_req_recv(mem_ctx, req, _result, _domain)
 
-#define cache_req_initgr_by_name_send(mem_ctx, ev, rctx, ncache, neg_timeout, \
-                                      cache_refresh_percent, domain, name) \
-    cache_req_send(mem_ctx, ev, rctx, ncache, neg_timeout, \
-                   cache_refresh_percent, SSS_DP_INITGROUPS, domain, name)
+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 neg_timeout,
+                              int cache_refresh_percent,
+                              const char *domain,
+                              const char *name);
 
 #define cache_req_initgr_by_name_recv(mem_ctx, req, _result, _domain) \
     cache_req_recv(mem_ctx, req, _result, _domain)
diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c
index 11a7fb26ce77c60a93017ef856a51d10e6972ee8..b57a33a8d03c0ce37bde791666b930817f30b7b9 100644
--- a/src/responder/ifp/ifpsrv_cmd.c
+++ b/src/responder/ifp/ifpsrv_cmd.c
@@ -477,6 +477,7 @@ static void
 ifp_user_get_attr_lookup(struct tevent_req *subreq)
 {
     struct ifp_user_get_attr_state *state = NULL;
+    struct cache_req_input *input = NULL;
     struct tevent_req *req = NULL;
     errno_t ret;
 
@@ -490,9 +491,30 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq)
         return;
     }
 
+    switch (state->search_type) {
+    case SSS_DP_USER:
+        input = cache_req_input_create(state, CACHE_REQ_USER_BY_NAME,
+                                       state->name);
+        break;
+    case SSS_DP_INITGROUPS:
+        input = cache_req_input_create(state, CACHE_REQ_INITGROUPS,
+                                       state->name);
+        break;
+    default:
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported search type [%d]!\n",
+              state->search_type);
+        tevent_req_error(req, ERR_INTERNAL);
+        return;
+    }
+
+    if (input == NULL) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+
     subreq = cache_req_send(state, state->rctx->ev, state->rctx,
                             state->ncache, state->neg_timeout, 0,
-                            state->search_type, state->domname, state->name);
+                            state->domname, input);
     if (subreq == NULL) {
         tevent_req_error(req, ENOMEM);
         return;
-- 
1.7.11.7

