diff options
-rw-r--r-- | src/responder/common/responder_cache_req.c | 123 | ||||
-rw-r--r-- | src/responder/common/responder_cache_req.h | 19 | ||||
-rw-r--r-- | src/responder/ifp/ifpsrv_cmd.c | 2 | ||||
-rw-r--r-- | src/tests/cmocka/test_responder_cache_req.c | 171 |
4 files changed, 288 insertions, 27 deletions
diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c index ed5c7a249..57cb3a811 100644 --- a/src/responder/common/responder_cache_req.c +++ b/src/responder/common/responder_cache_req.c @@ -118,6 +118,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) @@ -595,7 +612,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, @@ -609,6 +632,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); @@ -624,24 +648,20 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, state->cache_refresh_percent = cache_refresh_percent; state->input = input; - if (domain != NULL) { - /* single-domain search */ - state->domain = responder_get_domain(state->rctx, domain); - if (state->domain == NULL) { - ret = EINVAL; + 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->orig_name); + if (subreq == NULL) { + ret = ENOMEM; goto immediately; } - state->check_next = false; + tevent_req_set_callback(subreq, cache_req_input_parsed, req); } else { - /* multi-domain search */ - state->domain = state->rctx->domains; - state->check_next = true; - } - - ret = cache_req_next_domain(req); - if (ret != EAGAIN) { - goto immediately; + ret = cache_req_select_domains(req, domain); + if (ret != EAGAIN) { + goto immediately; + } } return req; @@ -657,6 +677,63 @@ immediately: 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) { + return ERR_DOMAIN_NOT_FOUND; + } + + state->check_next = false; + } else { + /* multi-domain search */ + state->domain = state->rctx->domains; + state->check_next = true; + } + + return cache_req_next_domain(req); +} + static errno_t cache_req_next_domain(struct tevent_req *req) { struct cache_req_state *state = NULL; @@ -744,13 +821,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->dom_objname == 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 3b8f3f713..088e8efe0 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 0a4bd0530..a2e9d8205 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 43a0491b9..e30deed1c 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; @@ -249,6 +254,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, @@ -291,6 +297,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, @@ -305,6 +312,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; @@ -905,6 +991,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, @@ -947,6 +1034,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, @@ -961,6 +1049,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; @@ -1548,6 +1713,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), @@ -1566,6 +1732,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), |