>From be708a5356ed9488422e2b3e397f02f638f0b35b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 27 Jan 2015 14:01:08 +0100
Subject: [PATCH 09/11] cache_req: parse input name if needed

The input name is now parse automatically by cache_req if
none particullar domain is specified. The parsed named is
returned from _recv as an output parameter.
---
 src/responder/common/responder_cache_req.c  | 131 +++++++++++++++++----
 src/responder/common/responder_cache_req.h  |  19 ++--
 src/responder/ifp/ifpsrv_cmd.c              |   2 +-
 src/tests/cmocka/test_responder_cache_req.c | 171 +++++++++++++++++++++++++++-
 4 files changed, 292 insertions(+), 31 deletions(-)

diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c
index 42cbd0a525dcd368597dd0f949e7970789e978da..2bdca5373a566cabda9250f232f1e434f096874f 100644
--- a/src/responder/common/responder_cache_req.c
+++ b/src/responder/common/responder_cache_req.c
@@ -116,6 +116,23 @@ fail:
 }
 
 static errno_t
+cache_req_input_set_orig_name(struct cache_req_input *input,
+                              const char *name)
+{
+    const char *dup;
+
+    dup = talloc_strdup(input, name);
+    if (dup == NULL) {
+        return ENOMEM;
+    }
+
+    talloc_zfree(input->orig_name);
+    input->orig_name = dup;
+
+    return EOK;
+}
+
+static errno_t
 cache_req_input_set_domain(struct cache_req_input *input,
                            struct sss_domain_info *domain,
                            struct resp_ctx *rctx)
@@ -587,7 +604,13 @@ struct cache_req_state {
     bool check_next;
 };
 
+static void cache_req_input_parsed(struct tevent_req *subreq);
+
+static errno_t cache_req_select_domains(struct tevent_req *req,
+                                        const char *domain);
+
 static errno_t cache_req_next_domain(struct tevent_req *req);
+
 static void cache_req_done(struct tevent_req *subreq);
 
 struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
@@ -601,6 +624,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
 {
     struct cache_req_state *state = NULL;
     struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
     errno_t ret;
 
     req = tevent_req_create(mem_ctx, &state, struct cache_req_state);
@@ -616,12 +640,80 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
     state->cache_refresh_percent = cache_refresh_percent;
     state->input = input;
 
+    if (state->input->orig_name != NULL && domain == NULL) {
+        /* Parse input name first, since it may contain domain name. */
+        subreq = sss_parse_inp_send(state, rctx, input->name);
+        if (subreq == NULL) {
+            ret = ENOMEM;
+            goto immediately;
+        }
+
+        tevent_req_set_callback(subreq, cache_req_input_parsed, req);
+    } else {
+        ret = cache_req_select_domains(req, domain);
+        if (ret != EAGAIN) {
+            goto immediately;
+        }
+    }
+
+    return req;
+
+immediately:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, ev);
+
+    return req;
+}
+
+static void cache_req_input_parsed(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct cache_req_state *state;
+    char *name;
+    char *domain;
+    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 (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (strcmp(name, state->input->orig_name) != 0) {
+        /* The name has changed during input parse phase. */
+        ret = cache_req_input_set_orig_name(state->input, name);
+        if (ret != EOK) {
+            tevent_req_error(req, ret);
+            return;
+        }
+    }
+
+    ret = cache_req_select_domains(req, domain);
+    if (ret != EAGAIN) {
+        tevent_req_error(req, ret);
+        return;
+    }
+}
+
+static errno_t cache_req_select_domains(struct tevent_req *req,
+                                        const char *domain)
+{
+    struct cache_req_state *state = NULL;
+
+    state = tevent_req_data(req, struct cache_req_state);
+
     if (domain != NULL) {
         /* single-domain search */
         state->domain = responder_get_domain(state->rctx, domain);
         if (state->domain == NULL) {
-            ret = EINVAL;
-            goto immediately;
+            return ERR_DOMAIN_NOT_FOUND;
         }
 
         state->check_next = false;
@@ -631,22 +723,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
         state->check_next = true;
     }
 
-    ret = cache_req_next_domain(req);
-    if (ret != EAGAIN) {
-        goto immediately;
-    }
-
-    return req;
-
-immediately:
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-    tevent_req_post(req, ev);
-
-    return req;
+    return cache_req_next_domain(req);
 }
 
 static errno_t cache_req_next_domain(struct tevent_req *req)
@@ -736,13 +813,29 @@ static void cache_req_done(struct tevent_req *subreq)
 errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
                        struct tevent_req *req,
                        struct ldb_result **_result,
-                       struct sss_domain_info **_domain)
+                       struct sss_domain_info **_domain,
+                       char **_name)
 {
     struct cache_req_state *state = NULL;
+    char *name;
+
     state = tevent_req_data(req, struct cache_req_state);
 
     TEVENT_REQ_RETURN_ON_ERROR(req);
 
+    if (_name != NULL) {
+        if (state->input->name == NULL) {
+            *_name = NULL;
+        } else {
+            name = talloc_strdup(mem_ctx, state->input->orig_name);
+            if (name == NULL) {
+                return ENOMEM;
+            }
+
+            *_name = name;
+        }
+    }
+
     if (_result != NULL) {
         *_result = talloc_steal(mem_ctx, state->result);
     }
diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h
index 3b8f3f713ec0fc6558f91ef07988af4237f016b4..088e8efe0ceefe49510bc5eab37e7825b667e5f3 100644
--- a/src/responder/common/responder_cache_req.h
+++ b/src/responder/common/responder_cache_req.h
@@ -60,7 +60,8 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
 errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
                        struct tevent_req *req,
                        struct ldb_result **_result,
-                       struct sss_domain_info **_domain);
+                       struct sss_domain_info **_domain,
+                       char **_name);
 
 struct tevent_req *
 cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
@@ -72,8 +73,8 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
                             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_user_by_name_recv(mem_ctx, req, _result, _domain, _name) \
+    cache_req_recv(mem_ctx, req, _result, _domain, _name)
 
 struct tevent_req *
 cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
@@ -86,7 +87,7 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
                           uid_t uid);
 
 #define cache_req_user_by_id_recv(mem_ctx, req, _result, _domain) \
-    cache_req_recv(mem_ctx, req, _result, _domain)
+    cache_req_recv(mem_ctx, req, _result, _domain, NULL)
 
 struct tevent_req *
 cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
@@ -98,8 +99,8 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
                              const char *domain,
                              const char *name);
 
-#define cache_req_group_by_name_recv(mem_ctx, req, _result, _domain) \
-    cache_req_recv(mem_ctx, req, _result, _domain)
+#define cache_req_group_by_name_recv(mem_ctx, req, _result, _domain, _name) \
+    cache_req_recv(mem_ctx, req, _result, _domain, _name)
 
 struct tevent_req *
 cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
@@ -112,7 +113,7 @@ cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
                            gid_t gid);
 
 #define cache_req_group_by_id_recv(mem_ctx, req, _result, _domain) \
-    cache_req_recv(mem_ctx, req, _result, _domain)
+    cache_req_recv(mem_ctx, req, _result, _domain, NULL)
 
 struct tevent_req *
 cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
@@ -124,7 +125,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
                               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)
+#define cache_req_initgr_by_name_recv(mem_ctx, req, _result, _domain, _name) \
+    cache_req_recv(mem_ctx, req, _result, _domain, _name)
 
 #endif /* RESPONDER_CACHE_H_ */
diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c
index 0a4bd0530eab217d399d4a6f8a352824772815f0..a2e9d82058938a6acd62b8ffa9af78bc13028cc2 100644
--- a/src/responder/ifp/ifpsrv_cmd.c
+++ b/src/responder/ifp/ifpsrv_cmd.c
@@ -532,7 +532,7 @@ static void ifp_user_get_attr_done(struct tevent_req *subreq)
     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);
+    ret = cache_req_recv(state, subreq, &state->res, &state->dom,  NULL);
     talloc_zfree(subreq);
     if (ret != EOK) {
         tevent_req_error(req, ret);
diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
index a4b44dea8052a8d5bed3db3f3e6e9179d20276b5..1c942170abaf11c46364915305096cdd3df3074e 100644
--- a/src/tests/cmocka/test_responder_cache_req.c
+++ b/src/tests/cmocka/test_responder_cache_req.c
@@ -55,6 +55,7 @@ struct cache_req_test_ctx {
 
     struct ldb_result *result;
     struct sss_domain_info *domain;
+    char *name;
     bool dp_called;
     bool create_user;
     bool create_group;
@@ -115,7 +116,9 @@ static void cache_req_user_by_name_test_done(struct tevent_req *req)
     ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
 
     ctx->tctx->error = cache_req_user_by_name_recv(ctx, req,
-                                                   &ctx->result, &ctx->domain);
+                                                   &ctx->result,
+                                                   &ctx->domain,
+                                                   &ctx->name);
     talloc_zfree(req);
 
     ctx->tctx->done = true;
@@ -141,7 +144,9 @@ static void cache_req_group_by_name_test_done(struct tevent_req *req)
     ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
 
     ctx->tctx->error = cache_req_group_by_name_recv(ctx, req,
-                                                    &ctx->result, &ctx->domain);
+                                                    &ctx->result,
+                                                    &ctx->domain,
+                                                    &ctx->name);
     talloc_zfree(req);
 
     ctx->tctx->done = true;
@@ -245,6 +250,7 @@ void test_user_by_name_multiple_domains_found(void **state)
 
     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
     will_return_always(sss_dp_get_account_recv, 0);
+    mock_parse_inp(name, NULL);
 
     req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
                                       test_ctx->rctx, test_ctx->ncache, 10, 0,
@@ -287,6 +293,7 @@ void test_user_by_name_multiple_domains_notfound(void **state)
 
     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
     will_return_always(sss_dp_get_account_recv, 0);
+    mock_parse_inp(name, NULL);
 
     req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
                                       test_ctx->rctx, test_ctx->ncache, 10, 0,
@@ -301,6 +308,85 @@ void test_user_by_name_multiple_domains_notfound(void **state)
     assert_true(test_ctx->dp_called);
 }
 
+void test_user_by_name_multiple_domains_parse(void **state)
+{
+    struct cache_req_test_ctx *test_ctx = NULL;
+    struct sss_domain_info *domain = NULL;
+    TALLOC_CTX *req_mem_ctx = NULL;
+    struct tevent_req *req = NULL;
+    const char *name = TEST_USER_NAME;
+    const char *fqn = NULL;
+    const char *ldbname = NULL;
+    uid_t uid = 2000;
+    uid_t ldbuid;
+    errno_t ret;
+
+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+    /* Add user to the first domain. */
+    domain = find_domain_by_name(test_ctx->tctx->dom,
+                                 "responder_cache_req_test_a", true);
+    assert_non_null(domain);
+
+    ret = sysdb_store_user(domain, name, "pwd", 1000, 1000,
+                           NULL, NULL, NULL, "cn=test-user,dc=test", NULL,
+                           NULL, 1000, time(NULL));
+    assert_int_equal(ret, EOK);
+
+    /* Add user to the last domain, with different uid. */
+
+    domain = find_domain_by_name(test_ctx->tctx->dom,
+                                 "responder_cache_req_test_d", true);
+    assert_non_null(domain);
+
+    ret = sysdb_store_user(domain, name, "pwd", uid, 1000,
+                           NULL, NULL, NULL, "cn=test-user,dc=test", NULL,
+                           NULL, 1000, time(NULL));
+    assert_int_equal(ret, EOK);
+
+    /* Append domain name to the username. */
+    fqn = talloc_asprintf(test_ctx, "%s@%s", name,
+                          "responder_cache_req_test_d");
+    assert_non_null(fqn);
+
+    /* Test. */
+    req_mem_ctx = talloc_new(global_talloc_context);
+    check_leaks_push(req_mem_ctx);
+
+    mock_parse_inp(name, "responder_cache_req_test_d");
+
+    req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
+                                      test_ctx->rctx, test_ctx->ncache, 10, 0,
+                                      NULL, fqn);
+    assert_non_null(req);
+    tevent_req_set_callback(req, cache_req_user_by_name_test_done, test_ctx);
+
+    ret = test_ev_loop(test_ctx->tctx);
+    assert_int_equal(ret, ERR_OK);
+    assert_true(check_leaks_pop(req_mem_ctx));
+    assert_false(test_ctx->dp_called);
+
+    assert_non_null(test_ctx->result);
+    assert_int_equal(test_ctx->result->count, 1);
+    assert_non_null(test_ctx->result->msgs);
+    assert_non_null(test_ctx->result->msgs[0]);
+
+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+                                          SYSDB_NAME, NULL);
+    assert_non_null(ldbname);
+    assert_string_equal(ldbname, name);
+
+    ldbuid = ldb_msg_find_attr_as_uint(test_ctx->result->msgs[0],
+                                       SYSDB_UIDNUM, 0);
+    assert_int_equal(ldbuid, uid);
+
+    assert_non_null(test_ctx->domain);
+    assert_string_equal(domain->name, test_ctx->domain->name);
+
+    assert_non_null(test_ctx->name);
+    assert_string_equal(name, test_ctx->name);
+}
+
 void test_user_by_name_cache_valid(void **state)
 {
     struct cache_req_test_ctx *test_ctx = NULL;
@@ -901,6 +987,7 @@ void test_group_by_name_multiple_domains_found(void **state)
 
     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
     will_return_always(sss_dp_get_account_recv, 0);
+    mock_parse_inp(name, NULL);
 
     req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
                                        test_ctx->rctx, test_ctx->ncache, 10, 0,
@@ -943,6 +1030,7 @@ void test_group_by_name_multiple_domains_notfound(void **state)
 
     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
     will_return_always(sss_dp_get_account_recv, 0);
+    mock_parse_inp(name, NULL);
 
     req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
                                        test_ctx->rctx, test_ctx->ncache, 10, 0,
@@ -957,6 +1045,83 @@ void test_group_by_name_multiple_domains_notfound(void **state)
     assert_true(test_ctx->dp_called);
 }
 
+void test_group_by_name_multiple_domains_parse(void **state)
+{
+    struct cache_req_test_ctx *test_ctx = NULL;
+    struct sss_domain_info *domain = NULL;
+    TALLOC_CTX *req_mem_ctx = NULL;
+    struct tevent_req *req = NULL;
+    const char *name = TEST_GROUP_NAME;
+    const char *fqn = NULL;
+    const char *ldbname = NULL;
+    uid_t gid = 2000;
+    uid_t ldbgid;
+    errno_t ret;
+
+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+    /* Add user to the first domain. */
+    domain = find_domain_by_name(test_ctx->tctx->dom,
+                                 "responder_cache_req_test_a", true);
+    assert_non_null(domain);
+
+    ret = sysdb_store_group(domain, name, 1000, NULL,
+                            1000, time(NULL));
+    assert_int_equal(ret, EOK);
+
+    /* Add user to the last domain, with different uid. */
+
+    domain = find_domain_by_name(test_ctx->tctx->dom,
+                                 "responder_cache_req_test_d", true);
+    assert_non_null(domain);
+
+    ret = sysdb_store_group(domain, name, gid, NULL,
+                            1000, time(NULL));
+    assert_int_equal(ret, EOK);
+
+    /* Append domain name to the username. */
+    fqn = talloc_asprintf(test_ctx, "%s@%s", name,
+                          "responder_cache_req_test_d");
+    assert_non_null(fqn);
+
+    /* Test. */
+    req_mem_ctx = talloc_new(global_talloc_context);
+    check_leaks_push(req_mem_ctx);
+
+    mock_parse_inp(name, "responder_cache_req_test_d");
+
+    req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev,
+                                       test_ctx->rctx, test_ctx->ncache, 10, 0,
+                                       NULL, fqn);
+    assert_non_null(req);
+    tevent_req_set_callback(req, cache_req_group_by_name_test_done, test_ctx);
+
+    ret = test_ev_loop(test_ctx->tctx);
+    assert_int_equal(ret, ERR_OK);
+    assert_true(check_leaks_pop(req_mem_ctx));
+    assert_false(test_ctx->dp_called);
+
+    assert_non_null(test_ctx->result);
+    assert_int_equal(test_ctx->result->count, 1);
+    assert_non_null(test_ctx->result->msgs);
+    assert_non_null(test_ctx->result->msgs[0]);
+
+    ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+                                          SYSDB_NAME, NULL);
+    assert_non_null(ldbname);
+    assert_string_equal(ldbname, name);
+
+    ldbgid = ldb_msg_find_attr_as_uint(test_ctx->result->msgs[0],
+                                       SYSDB_GIDNUM, 0);
+    assert_int_equal(ldbgid, gid);
+
+    assert_non_null(test_ctx->domain);
+    assert_string_equal(domain->name, test_ctx->domain->name);
+
+    assert_non_null(test_ctx->name);
+    assert_string_equal(name, test_ctx->name);
+}
+
 void test_group_by_name_cache_valid(void **state)
 {
     struct cache_req_test_ctx *test_ctx = NULL;
@@ -1544,6 +1709,7 @@ int main(int argc, const char *argv[])
         new_single_domain_test(user_by_name_missing_notfound),
         new_multi_domain_test(user_by_name_multiple_domains_found),
         new_multi_domain_test(user_by_name_multiple_domains_notfound),
+        new_multi_domain_test(user_by_name_multiple_domains_parse),
 
         new_single_domain_test(user_by_id_cache_valid),
         new_single_domain_test(user_by_id_cache_expired),
@@ -1562,6 +1728,7 @@ int main(int argc, const char *argv[])
         new_single_domain_test(group_by_name_missing_notfound),
         new_multi_domain_test(group_by_name_multiple_domains_found),
         new_multi_domain_test(group_by_name_multiple_domains_notfound),
+        new_multi_domain_test(group_by_name_multiple_domains_parse),
 
         new_single_domain_test(group_by_id_cache_valid),
         new_single_domain_test(group_by_id_cache_expired),
-- 
1.9.3

