From 28ebfa4373d1e7ce45b5d70a3619df1c074a661e Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Oct 08 2015 17:56:26 +0000 Subject: cache_req: add support for UPN Reviewed-by: Sumit Bose --- diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 3c76fb0..4f488c0 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -609,6 +609,11 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx, uid_t uid, struct ldb_result **res); +int sysdb_getpwupn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + struct ldb_result **res); + int sysdb_enumpwent(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, struct ldb_result **res); @@ -681,6 +686,11 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result **res); +int sysdb_initgroups_by_upn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + struct ldb_result **res); + int sysdb_initgroups_with_views(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *name, @@ -768,6 +778,12 @@ int sysdb_search_user_by_sid_str(TALLOC_CTX *mem_ctx, const char **attrs, struct ldb_message **msg); +int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + const char **attrs, + struct ldb_result **out_res); + int sysdb_search_user_by_upn(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *sid_str, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 38e7021..aedf78d 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -474,28 +474,28 @@ int sysdb_search_user_by_sid_str(TALLOC_CTX *mem_ctx, sid_str, attrs, msg); } -int sysdb_search_user_by_upn(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, - const char *upn, - const char **attrs, - struct ldb_message **msg) +int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + const char **attrs, + struct ldb_result **out_res) { TALLOC_CTX *tmp_ctx; - const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN, - NULL }; - struct ldb_message **msgs = NULL; - struct ldb_dn *basedn; - size_t msgs_count = 0; + struct ldb_result *res; + struct ldb_dn *base_dn; char *filter; int ret; + const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN, + NULL }; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { - return ENOMEM; + ret = ENOMEM; + goto done; } - basedn = sysdb_user_base_dn(tmp_ctx, domain); - if (basedn == NULL) { + base_dn = sysdb_user_base_dn(tmp_ctx, domain); + if (base_dn == NULL) { ret = ENOMEM; goto done; } @@ -506,29 +506,64 @@ int sysdb_search_user_by_upn(TALLOC_CTX *mem_ctx, goto done; } - ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE, - filter, attrs?attrs:def_attrs, &msgs_count, - &msgs); + ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, + base_dn, LDB_SCOPE_SUBTREE, attrs ? attrs : def_attrs, + filter); if (ret != EOK) { + ret = sysdb_error_to_errno(ret); goto done; } - if (msgs_count > 1) { + if (res->count == 0) { + /* set result anyway */ + *out_res = talloc_steal(mem_ctx, res); + ret = ENOENT; + goto done; + } else if (res->count > 1) { DEBUG(SSSDBG_OP_FAILURE, "Search for upn [%s] returns more than one result.\n", upn); ret = EINVAL; goto done; } - *msg = talloc_steal(mem_ctx, msgs[0]); + *out_res = talloc_steal(mem_ctx, res); + ret = EOK; done: + talloc_zfree(tmp_ctx); + return ret; +} + +int sysdb_search_user_by_upn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + const char **attrs, + struct ldb_message **msg) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_search_user_by_upn_res(tmp_ctx, domain, upn, attrs, &res); if (ret == ENOENT) { DEBUG(SSSDBG_TRACE_FUNC, "No entry with upn [%s] found.\n", upn); + goto done; } else if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); + goto done; } + *msg = talloc_steal(mem_ctx, res->msgs[0]); + + ret = EOK; + +done: talloc_zfree(tmp_ctx); return ret; } diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c index ab72add..1e40311 100644 --- a/src/db/sysdb_search.c +++ b/src/db/sysdb_search.c @@ -295,6 +295,35 @@ static char *enum_filter(TALLOC_CTX *mem_ctx, return filter; } +int sysdb_getpwupn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + struct ldb_result **_res) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + static const char *attrs[] = SYSDB_PW_ATTRS; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + ret = sysdb_search_user_by_upn_res(tmp_ctx, domain, upn, attrs, &res); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_upn_res() failed.\n"); + goto done; + } + + *_res = talloc_steal(mem_ctx, res); + +done: + talloc_free(tmp_ctx); + return ret; +} + int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *name_filter, @@ -957,6 +986,70 @@ done: return ret; } +int sysdb_initgroups_by_upn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *upn, + struct ldb_result **_res) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_message *msg; + struct ldb_result *res; + const char *sysdb_name; + static const char *attrs[] = SYSDB_INITGR_ATTRS; + size_t i; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + ret = sysdb_search_user_by_upn(tmp_ctx, domain, upn, attrs, &msg); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_upn() failed.\n"); + goto done; + } + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (res == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero() failed.\n"); + ret = ENOMEM; + goto done; + } + + if (ret == ENOENT) { + res->count = 0; + res->msgs = NULL; + } else { + sysdb_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); + if (sysdb_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Sysdb entry does not have a name.\n"); + return EINVAL; + } + + ret = sysdb_initgroups(tmp_ctx, domain, sysdb_name, &res); + if (ret == EOK && DOM_HAS_VIEWS(domain)) { + for (i = 0; i < res->count; i++) { + ret = sysdb_add_overrides_to_object(domain, res->msgs[i], + NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sysdb_add_overrides_to_object() failed.\n"); + return ret; + } + } + } + } + + *_res = talloc_steal(mem_ctx, res); + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + int sysdb_initgroups_with_views(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *name, diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c index fba5001..70a3010 100644 --- a/src/responder/common/responder_cache_req.c +++ b/src/responder/common/responder_cache_req.c @@ -70,6 +70,7 @@ struct cache_req_input { enum cache_req_type type; /* Provided input. */ + const char *raw_name; const char *orig_name; uint32_t id; const char *cert; @@ -113,15 +114,22 @@ cache_req_input_create(TALLOC_CTX *mem_ctx, /* Check that input parameters match selected type. */ switch (input->type) { case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: case CACHE_REQ_GROUP_BY_NAME: case CACHE_REQ_USER_BY_FILTER: case CACHE_REQ_GROUP_BY_FILTER: case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: if (name == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n"); goto fail; } + input->raw_name = talloc_strdup(input, name); + if (input->raw_name == NULL) { + goto fail; + } + input->orig_name = talloc_strdup(input, name); if (input->orig_name == NULL) { goto fail; @@ -152,6 +160,7 @@ cache_req_input_create(TALLOC_CTX *mem_ctx, /* Resolve Data Provider request type. */ switch (type) { case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: case CACHE_REQ_USER_BY_ID: input->dp_type = SSS_DP_USER; break; @@ -162,6 +171,7 @@ cache_req_input_create(TALLOC_CTX *mem_ctx, break; case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: input->dp_type = SSS_DP_INITGROUPS; break; @@ -222,10 +232,12 @@ cache_req_input_set_domain(struct cache_req_input *input, switch (input->type) { case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: case CACHE_REQ_GROUP_BY_NAME: case CACHE_REQ_USER_BY_FILTER: case CACHE_REQ_GROUP_BY_FILTER: case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: name = sss_get_cased_name(tmp_ctx, input->orig_name, domain->case_sensitive); if (name == NULL) { @@ -286,6 +298,56 @@ done: return ret; } +static bool +cache_req_input_is_upn(struct cache_req_input *input) +{ + switch (input->type) { + case CACHE_REQ_USER_BY_UPN: + case CACHE_REQ_INITGROUPS_BY_UPN: + return true; + default: + return false; + } +} + +static bool +cache_req_input_assume_upn(struct cache_req_input *input) +{ + errno_t ret; + bool bret; + + if (input->raw_name == NULL || strchr(input->raw_name, '@') == NULL) { + return false; + } + + switch (input->type) { + case CACHE_REQ_USER_BY_NAME: + input->type = CACHE_REQ_USER_BY_UPN; + bret = true; + break; + case CACHE_REQ_INITGROUPS: + input->type = CACHE_REQ_INITGROUPS_BY_UPN; + bret = true; + break; + default: + bret = false; + break; + } + + if (bret == true) { + ret = cache_req_input_set_orig_name(input, input->raw_name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "cache_req_input_set_orig_name() failed\n"); + return false; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Assuming UPN %s\n", input->raw_name); + } + + return bret; +} + static errno_t cache_req_check_ncache(struct cache_req_input *input, struct sss_nc_ctx *ncache, int neg_timeout) @@ -294,7 +356,9 @@ static errno_t cache_req_check_ncache(struct cache_req_input *input, switch (input->type) { case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: ret = sss_ncache_check_user(ncache, neg_timeout, input->domain, input->dom_objname); break; @@ -332,7 +396,9 @@ static void cache_req_add_to_ncache(struct cache_req_input *input, switch (input->type) { case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: ret = sss_ncache_set_user(ncache, false, input->domain, input->dom_objname); break; @@ -375,8 +441,10 @@ static void cache_req_add_to_ncache_global(struct cache_req_input *input, /* Nothing to do, adding a wildcard request to ncache doesn't * make sense */ case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: case CACHE_REQ_GROUP_BY_NAME: case CACHE_REQ_INITGROUPS: + case CACHE_REQ_INITGROUPS_BY_UPN: /* Nothing to do. Those types are already in ncache for selected * domains. */ ret = EOK; @@ -418,6 +486,11 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx, ret = sysdb_getpwnam_with_views(mem_ctx, input->domain, input->dom_objname, &result); break; + case CACHE_REQ_USER_BY_UPN: + one_item_only = true; + ret = sysdb_getpwupn(mem_ctx, input->domain, + input->dom_objname, &result); + break; case CACHE_REQ_USER_BY_ID: one_item_only = true; ret = sysdb_getpwuid_with_views(mem_ctx, input->domain, @@ -438,6 +511,11 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx, ret = sysdb_initgroups_with_views(mem_ctx, input->domain, input->dom_objname, &result); break; + case CACHE_REQ_INITGROUPS_BY_UPN: + one_item_only = false; + ret = sysdb_initgroups_by_upn(mem_ctx, input->domain, + input->dom_objname, &result); + break; case CACHE_REQ_USER_BY_CERT: one_item_only = true; ret = sysdb_search_user_by_cert(mem_ctx, input->domain, @@ -618,6 +696,8 @@ static errno_t cache_req_cache_check(struct tevent_req *req) if (DOM_HAS_VIEWS(state->input->domain)) { extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW; + } else if (cache_req_input_is_upn(state->input)) { + extra_flag = EXTRA_NAME_IS_UPN; } switch (ret) { @@ -821,23 +901,35 @@ static void cache_req_input_parsed(struct tevent_req *subreq) char *name; char *domain; errno_t ret; + bool maybe_upn; 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) { + switch (ret) { + case EOK: + 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; + } + } + break; + case ERR_DOMAIN_NOT_FOUND: + maybe_upn = cache_req_input_assume_upn(state->input); + if (!maybe_upn) { tevent_req_error(req, ret); return; } + + domain = NULL; + break; + default: + tevent_req_error(req, ret); + return; } ret = cache_req_select_domains(req, domain); @@ -943,6 +1035,12 @@ static void cache_req_done(struct tevent_req *subreq) } if (state->check_next == false) { + if (ret == ENOENT && cache_req_input_assume_upn(state->input)) { + /* search by upn now */ + cache_req_select_domains(req, NULL); + return; + } + tevent_req_error(req, ret); return; } diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h index 9e3f88a..474d426 100644 --- a/src/responder/common/responder_cache_req.h +++ b/src/responder/common/responder_cache_req.h @@ -29,13 +29,15 @@ enum cache_req_type { CACHE_REQ_USER_BY_NAME, + CACHE_REQ_USER_BY_UPN, CACHE_REQ_USER_BY_ID, CACHE_REQ_GROUP_BY_NAME, CACHE_REQ_GROUP_BY_ID, CACHE_REQ_INITGROUPS, + CACHE_REQ_INITGROUPS_BY_UPN, CACHE_REQ_USER_BY_CERT, CACHE_REQ_USER_BY_FILTER, - CACHE_REQ_GROUP_BY_FILTER, + CACHE_REQ_GROUP_BY_FILTER }; struct cache_req_input; diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c index 8fbab08..7fd0b48 100644 --- a/src/responder/common/responder_get_domains.c +++ b/src/responder/common/responder_get_domains.c @@ -446,6 +446,7 @@ struct sss_parse_inp_state { char *name; char *domname; + errno_t error; }; static void sss_parse_inp_done(struct tevent_req *subreq); @@ -527,14 +528,24 @@ static void sss_parse_inp_done(struct tevent_req *subreq) return; } + state->error = ERR_OK; + ret = sss_parse_name_for_domains(state, state->rctx->domains, state->rctx->default_domain, state->rawinp, &state->domname, &state->name); - if (ret != EOK) { + if (ret == EAGAIN && state->domname != NULL && state->name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + "Unknown domain in [%s]\n", state->rawinp); + state->error = ERR_DOMAIN_NOT_FOUND; + } else if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", state->rawinp); - tevent_req_error(req, ERR_INPUT_PARSE); + state->error = ERR_INPUT_PARSE; + } + + if (state->error != ERR_OK) { + tevent_req_error(req, state->error); return; } @@ -548,7 +559,9 @@ errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct sss_parse_inp_state *state = tevent_req_data(req, struct sss_parse_inp_state); - TEVENT_REQ_RETURN_ON_ERROR(req); + if (state->error != ERR_DOMAIN_NOT_FOUND) { + TEVENT_REQ_RETURN_ON_ERROR(req); + } if (_name) { *_name = talloc_steal(mem_ctx, state->name); @@ -558,5 +571,5 @@ errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, *_domname = talloc_steal(mem_ctx, state->domname); } - return EOK; + return state->error; } diff --git a/src/tests/cmocka/common_mock_resp.h b/src/tests/cmocka/common_mock_resp.h index 88c09c8..a4d8f55 100644 --- a/src/tests/cmocka/common_mock_resp.h +++ b/src/tests/cmocka/common_mock_resp.h @@ -59,6 +59,6 @@ void mock_account_recv(uint16_t dp_err, uint32_t dp_ret, char *msg, void mock_account_recv_simple(void); -void mock_parse_inp(const char *name, const char *domname); +void mock_parse_inp(const char *name, const char *domname, errno_t ret); #endif /* __COMMON_MOCK_RESP_H_ */ diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c index a67ceee..f62606e 100644 --- a/src/tests/cmocka/common_mock_resp_dp.c +++ b/src/tests/cmocka/common_mock_resp_dp.c @@ -92,13 +92,14 @@ errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, *_name = sss_mock_ptr_type(char *); *_domname = sss_mock_ptr_type(char *); - return test_request_recv(req); + return sss_mock_type(errno_t); } -void mock_parse_inp(const char *name, const char *domname) +void mock_parse_inp(const char *name, const char *domname, errno_t ret) { will_return(sss_parse_inp_recv, name); will_return(sss_parse_inp_recv, domname); + will_return(sss_parse_inp_recv, ret); } /* Mock subdomain requests */ diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c index 5fd4394..b4018ba 100644 --- a/src/tests/cmocka/test_responder_cache_req.c +++ b/src/tests/cmocka/test_responder_cache_req.c @@ -34,6 +34,7 @@ #define TEST_ID_PROVIDER "ldap" #define TEST_USER_NAME "test-user" +#define TEST_UPN "upn@upndomain.com" #define TEST_USER_ID 1000 #define TEST_GROUP_NAME "test-group" #define TEST_GROUP_ID 1000 @@ -89,6 +90,7 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, uint32_t opt_id, const char *extra) { + struct sysdb_attrs *attrs = NULL; struct cache_req_test_ctx *ctx = NULL; errno_t ret; @@ -96,9 +98,15 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, ctx->dp_called = true; if (ctx->create_user) { + attrs = sysdb_new_attrs(ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, TEST_UPN); + assert_int_equal(ret, EOK); + ret = sysdb_store_user(ctx->tctx->dom, TEST_USER_NAME, "pwd", TEST_USER_ID, 1000, NULL, NULL, NULL, - "cn=test-user,dc=test", NULL, NULL, + "cn=test-user,dc=test", attrs, NULL, 1000, time(NULL)); assert_int_equal(ret, EOK); } @@ -257,7 +265,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); + mock_parse_inp(name, NULL, ERR_OK); req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->rctx, test_ctx->ncache, 10, 0, @@ -300,7 +308,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); + mock_parse_inp(name, NULL, ERR_OK); req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->rctx, test_ctx->ncache, 10, 0, @@ -360,7 +368,7 @@ void test_user_by_name_multiple_domains_parse(void **state) req_mem_ctx = talloc_new(global_talloc_context); check_leaks_push(req_mem_ctx); - mock_parse_inp(name, "responder_cache_req_test_d"); + mock_parse_inp(name, "responder_cache_req_test_d", ERR_OK); req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->rctx, test_ctx->ncache, 10, 0, @@ -626,6 +634,363 @@ void test_user_by_name_missing_notfound(void **state) assert_true(test_ctx->dp_called); } +void test_user_by_upn_multiple_domains_found(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + struct sysdb_attrs *attrs = 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 *upn = TEST_UPN; + const char *ldbname = NULL; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + domain = find_domain_by_name(test_ctx->tctx->dom, + "responder_cache_req_test_d", true); + assert_non_null(domain); + + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, upn); + assert_int_equal(ret, EOK); + + ret = sysdb_store_user(domain, name, "pwd", 1000, 1000, + NULL, NULL, NULL, "cn=test-user,dc=test", attrs, + NULL, 1000, time(NULL)); + assert_int_equal(ret, EOK); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_get_account_recv, 0); + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 10, 0, + NULL, upn); + 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_true(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); + + assert_non_null(test_ctx->domain); + assert_string_equal(domain->name, test_ctx->domain->name); +} + +void test_user_by_upn_multiple_domains_notfound(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + const char *upn = TEST_UPN; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + will_return_always(__wrap_sss_dp_get_account_send, test_ctx); + will_return_always(sss_dp_get_account_recv, 0); + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 10, 0, + NULL, upn); + 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, ENOENT); + assert_true(check_leaks_pop(req_mem_ctx)); + + assert_true(test_ctx->dp_called); +} + +void test_user_by_upn_cache_valid(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + struct sysdb_attrs *attrs = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + const char *name = TEST_USER_NAME; + const char *upn = TEST_UPN; + const char *ldbname = NULL; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, upn); + assert_int_equal(ret, EOK); + + ret = sysdb_store_user(test_ctx->tctx->dom, name, "pwd", 1000, 1000, + NULL, NULL, NULL, "cn=test-user,dc=test", attrs, + NULL, 1000, time(NULL)); + assert_int_equal(ret, EOK); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 10, 0, + NULL, upn); + 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_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); +} + +void test_user_by_upn_cache_expired(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + struct sysdb_attrs *attrs = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + const char *name = TEST_USER_NAME; + const char *upn = TEST_UPN; + const char *ldbname = NULL; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, upn); + assert_int_equal(ret, EOK); + + ret = sysdb_store_user(test_ctx->tctx->dom, name, "pwd", 1000, 1000, + NULL, NULL, NULL, "cn=test-user,dc=test", attrs, + NULL, -1000, time(NULL)); + assert_int_equal(ret, EOK); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + /* DP should be contacted */ + will_return(__wrap_sss_dp_get_account_send, test_ctx); + mock_account_recv_simple(); + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 10, 0, + NULL, upn); + 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_true(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); +} + +void test_user_by_upn_cache_midpoint(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + struct sysdb_attrs *attrs = NULL; + const char *upn = TEST_UPN; + const char *name = TEST_USER_NAME; + const char *ldbname = NULL; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, upn); + assert_int_equal(ret, EOK); + + ret = sysdb_store_user(test_ctx->tctx->dom, name, "pwd", 1000, 1000, + NULL, NULL, NULL, "cn=test-user,dc=test", attrs, + NULL, 50, time(NULL) - 26); + assert_int_equal(ret, EOK); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + /* DP should be contacted without callback */ + will_return(__wrap_sss_dp_get_account_send, test_ctx); + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 10, 50, + NULL, upn); + 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_true(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); +} + +void test_user_by_upn_ncache(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + const char *upn = TEST_UPN; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + ret = sss_ncache_set_user(test_ctx->ncache, false, + test_ctx->tctx->dom, upn); + assert_int_equal(ret, EOK); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 100, 0, + NULL, upn); + 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, ENOENT); + assert_true(check_leaks_pop(req_mem_ctx)); + + assert_false(test_ctx->dp_called); +} + +void test_user_by_upn_missing_found(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + const char *upn = TEST_UPN; + const char *name = TEST_USER_NAME; + const char *ldbname = NULL; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + will_return(__wrap_sss_dp_get_account_send, test_ctx); + mock_account_recv_simple(); + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + test_ctx->create_user = true; + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 100, 0, + NULL, upn); + 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_true(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); +} + +void test_user_by_upn_missing_notfound(void **state) +{ + struct cache_req_test_ctx *test_ctx = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + struct tevent_req *req = NULL; + const char *upn = TEST_UPN; + errno_t ret; + + test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx); + + req_mem_ctx = talloc_new(global_talloc_context); + check_leaks_push(req_mem_ctx); + + will_return(__wrap_sss_dp_get_account_send, test_ctx); + mock_account_recv_simple(); + mock_parse_inp(NULL, NULL, ERR_DOMAIN_NOT_FOUND); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 100, 0, + NULL, upn); + 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, ENOENT); + assert_true(check_leaks_pop(req_mem_ctx)); + + assert_true(test_ctx->dp_called); +} + void test_user_by_id_multiple_domains_found(void **state) { struct cache_req_test_ctx *test_ctx = NULL; @@ -994,7 +1359,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); + mock_parse_inp(name, NULL, ERR_OK); req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->rctx, test_ctx->ncache, 10, 0, @@ -1037,7 +1402,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); + mock_parse_inp(name, NULL, ERR_OK); req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->rctx, test_ctx->ncache, 10, 0, @@ -1095,7 +1460,7 @@ void test_group_by_name_multiple_domains_parse(void **state) req_mem_ctx = talloc_new(global_talloc_context); check_leaks_push(req_mem_ctx); - mock_parse_inp(name, "responder_cache_req_test_d"); + mock_parse_inp(name, "responder_cache_req_test_d", ERR_OK); req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev, test_ctx->rctx, test_ctx->ncache, 10, 0, @@ -1910,6 +2275,15 @@ int main(int argc, const char *argv[]) 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_upn_cache_valid), + new_single_domain_test(user_by_upn_cache_expired), + new_single_domain_test(user_by_upn_cache_midpoint), + new_single_domain_test(user_by_upn_ncache), + new_single_domain_test(user_by_upn_missing_found), + new_single_domain_test(user_by_upn_missing_notfound), + new_multi_domain_test(user_by_upn_multiple_domains_found), + new_multi_domain_test(user_by_upn_multiple_domains_notfound), + new_single_domain_test(user_by_id_cache_valid), new_single_domain_test(user_by_id_cache_expired), new_single_domain_test(user_by_id_cache_midpoint),