/* Authors: Jakub Hrozek Copyright (C) 2013 Red Hat SSSD tests: NSS responder tests This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "tests/cmocka/common_mock.h" #include "tests/cmocka/common_mock_resp.h" #include "responder/common/negcache.h" #include "responder/nss/nsssrv.h" #include "responder/nss/nsssrv_private.h" #include "sss_client/idmap/sss_nss_idmap.h" #include "util/util_sss_idmap.h" #include "util/crypto/sss_crypto.h" #include "util/crypto/nss/nss_util.h" #include "db/sysdb_private.h" /* new_subdomain() */ #define TESTS_PATH "tp_" BASE_FILE_STEM #define TEST_CONF_DB "test_nss_conf.ldb" #define TEST_DOM_NAME "nss_test" #define TEST_SUBDOM_NAME "test.subdomain" #define TEST_ID_PROVIDER "ldap" #define TEST_DOM_SID "S-1-5-21-444379608-1639770488-2995963434" struct nss_test_ctx { struct sss_test_ctx *tctx; struct sss_domain_info *subdom; struct resp_ctx *rctx; struct cli_ctx *cctx; struct sss_cmd_table *nss_cmds; struct nss_ctx *nctx; int ncache_hits; }; const char *global_extra_attrs[] = {"phone", "mobile", NULL}; struct nss_test_ctx *nss_test_ctx; /* Mock NSS structure */ struct nss_ctx * mock_nctx(TALLOC_CTX *mem_ctx) { struct nss_ctx *nctx; enum idmap_error_code err; nctx = talloc_zero(mem_ctx, struct nss_ctx); if (!nctx) { return NULL; } nctx->pwfield = discard_const("*"); err = sss_idmap_init(sss_idmap_talloc, nctx, sss_idmap_talloc_free, &nctx->idmap_ctx); if (err != IDMAP_SUCCESS) { DEBUG(SSSDBG_FATAL_FAILURE, "sss_idmap_init failed.\n"); talloc_free(nctx); return NULL; } return nctx; } /* Mock reading requests from a client. Use values passed from mock * instead */ void __real_sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen); void __wrap_sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen) { enum sss_test_wrapper_call wtype = sss_mock_type(enum sss_test_wrapper_call); size_t len; if (wtype == WRAP_CALL_REAL) { return __real_sss_packet_get_body(packet, body, blen); } *body = sss_mock_ptr_type(uint8_t *); len = sss_mock_type(size_t); if (len == 0) { len = strlen((const char *) *body)+1; } *blen = len; return; } /* Mock returning result to client. Terminate the unit test instead. */ typedef int (*cmd_cb_fn_t)(uint32_t, uint8_t *, size_t ); static void set_cmd_cb(cmd_cb_fn_t fn) { will_return(__wrap_sss_cmd_done, fn); } void __wrap_sss_cmd_done(struct cli_ctx *cctx, void *freectx) { struct cli_protocol *pctx; struct sss_packet *packet; uint8_t *body; size_t blen; cmd_cb_fn_t check_cb; check_cb = sss_mock_ptr_type(cmd_cb_fn_t); pctx = talloc_get_type(cctx->protocol_ctx, struct cli_protocol); packet = pctx->creq->out; __real_sss_packet_get_body(packet, &body, &blen); nss_test_ctx->tctx->error = check_cb(sss_packet_get_status(packet), body, blen); nss_test_ctx->tctx->done = true; talloc_free(freectx); } enum sss_cli_command __wrap_sss_packet_get_cmd(struct sss_packet *packet) { return sss_mock_type(enum sss_cli_command); } int __wrap_sss_cmd_send_empty(struct cli_ctx *cctx, TALLOC_CTX *freectx) { nss_test_ctx->tctx->done = true; nss_test_ctx->tctx->error = ENOENT; return EOK; } /* Intercept negative cache lookups */ int __real_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl, struct sss_domain_info *dom, const char *name); int __wrap_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl, struct sss_domain_info *dom, const char *name) { int ret; ret = __real_sss_ncache_check_user(ctx, ttl, dom, name); if (ret == EEXIST) { nss_test_ctx->ncache_hits++; } return ret; } int __real_sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, struct sss_domain_info *dom, uid_t uid); int __wrap_sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, struct sss_domain_info *dom, uid_t uid) { int ret; ret = __real_sss_ncache_check_uid(ctx, ttl, dom, uid); if (ret == EEXIST) { nss_test_ctx->ncache_hits++; } return ret; } int __real_sss_ncache_check_sid(struct sss_nc_ctx *ctx, int ttl, const char *sid); int __wrap_sss_ncache_check_sid(struct sss_nc_ctx *ctx, int ttl, const char *sid) { int ret; ret = __real_sss_ncache_check_sid(ctx, ttl, sid); if (ret == EEXIST) { nss_test_ctx->ncache_hits++; } return ret; } int __real_sss_ncache_check_cert(struct sss_nc_ctx *ctx, int ttl, const char *cert); int __wrap_sss_ncache_check_cert(struct sss_nc_ctx *ctx, int ttl, const char *cert) { int ret; ret = __real_sss_ncache_check_cert(ctx, ttl, cert); if (ret == EEXIST) { nss_test_ctx->ncache_hits++; } return ret; } /* Mock input from the client library */ static void mock_input_user_or_group(const char *username) { will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, username); will_return(__wrap_sss_packet_get_body, 0); } static void mock_input_id(TALLOC_CTX *mem_ctx, uint32_t id) { uint8_t *body; body = talloc_zero_array(mem_ctx, uint8_t, 4); if (body == NULL) return; SAFEALIGN_SETMEM_UINT32(body, id, NULL); will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, body); will_return(__wrap_sss_packet_get_body, sizeof(uint32_t)); } static void mock_fill_user(void) { /* One packet for the entry and one for num entries */ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); } static void mock_fill_bysid(void) { /* One packet for the entry and one for num entries */ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); } static void mock_fill_initgr_user(void) { will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); } static void mock_fill_group_with_members(unsigned members) { unsigned i; will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); if (members == 0) return; will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); /* Member header , one per member */ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); for (i=0; ipw_uid, body+rp, &rp); SAFEALIGN_COPY_UINT32(&pwd->pw_gid, body+rp, &rp); /* Sequence of null terminated strings (name, passwd, gecos, dir, shell) */ pwd->pw_name = (char *) body+rp; rp += strlen(pwd->pw_name) + 1; if (rp >= blen) return EINVAL; pwd->pw_passwd = (char *) body+rp; rp += strlen(pwd->pw_passwd) + 1; if (rp >= blen) return EINVAL; pwd->pw_gecos = (char *) body+rp; rp += strlen(pwd->pw_gecos) + 1; if (rp >= blen) return EINVAL; pwd->pw_dir = (char *) body+rp; rp += strlen(pwd->pw_dir) + 1; if (rp >= blen) return EINVAL; pwd->pw_shell = (char *) body+rp; rp += strlen(pwd->pw_shell) + 1; if (rp != blen) return EINVAL; return EOK; } static int parse_group_packet(uint8_t *body, size_t blen, struct group *gr, uint32_t *nmem) { size_t rp = 2 * sizeof(uint32_t); /* Len and reserved */ unsigned i; SAFEALIGN_COPY_UINT32(&gr->gr_gid, body+rp, &rp); SAFEALIGN_COPY_UINT32(nmem, body+rp, &rp); gr->gr_name = (char *) body+rp; rp += strlen(gr->gr_name) + 1; if (rp >= blen) return EINVAL; gr->gr_passwd = (char *) body+rp; rp += strlen(gr->gr_passwd) + 1; if (*nmem > 0) { gr->gr_mem = talloc_zero_array(nss_test_ctx, char *, *nmem); if (gr->gr_mem == NULL) return ENOMEM; for (i = 0; i < *nmem; i++) { if (rp >= blen) return EINVAL; gr->gr_mem[i] = talloc_strdup(gr->gr_mem, (char *) body+rp); rp += strlen(gr->gr_mem[i]) + 1; } } /* Make sure we exactly matched the end of the packet */ if (rp != blen) return EINVAL; return EOK; } static void check_initgr_packet(uint8_t *body, size_t blen, gid_t *gids, size_t num_gids) { size_t rp; unsigned i; gid_t cur_gid; uint32_t num_ret; rp = 0; SAFEALIGN_COPY_UINT32(&num_ret, body, NULL); assert_int_equal(num_ret, num_gids); rp = 2 * sizeof(uint32_t); /* Len and reserved */ for (i = 0; i < num_gids; i++) { SAFEALIGN_COPY_UINT32(&cur_gid, body + rp, &rp); assert_int_equal(cur_gid, gids[i]); } } static errno_t store_user(struct nss_test_ctx *ctx, struct sss_domain_info *dom, struct passwd *user, struct sysdb_attrs *attrs, time_t cache_update) { errno_t ret; char *fqname; fqname = sss_create_internal_fqname(ctx, user->pw_name, dom->name); if (fqname == NULL) { return ENOMEM; } /* Prime the cache with a valid user */ ret = sysdb_store_user(dom, fqname, user->pw_passwd, user->pw_uid, user->pw_gid, user->pw_gecos, user->pw_dir, user->pw_shell, NULL, attrs, NULL, 300, cache_update); talloc_free(fqname); return ret; } static errno_t set_user_attr(struct nss_test_ctx *ctx, struct sss_domain_info *dom, struct passwd *user, struct sysdb_attrs *attrs) { errno_t ret; char *fqname; fqname = sss_create_internal_fqname(ctx, user->pw_name, dom->name); if (fqname == NULL) { return ENOMEM; } ret = sysdb_set_user_attr(nss_test_ctx->tctx->dom, fqname, attrs, SYSDB_MOD_REP); talloc_free(fqname); return ret; } static int get_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *shortname, struct ldb_result **_res) { errno_t ret; char *fqname; fqname = sss_create_internal_fqname(mem_ctx, shortname, domain->name); if (fqname == NULL) { return ENOMEM; } ret = sysdb_getpwnam(mem_ctx, domain, fqname, _res); talloc_free(fqname); return ret; } static void assert_users_equal(struct passwd *a, struct passwd *b) { assert_int_equal(a->pw_uid, b->pw_uid); assert_int_equal(a->pw_gid, b->pw_gid); assert_string_equal(a->pw_name, b->pw_name); assert_string_equal(a->pw_shell, b->pw_shell); assert_string_equal(a->pw_passwd, b->pw_passwd); } static errno_t store_group(struct nss_test_ctx *ctx, struct sss_domain_info *dom, struct group *group, time_t cache_update) { errno_t ret; char *fqname; fqname = sss_create_internal_fqname(ctx, group->gr_name, dom->name); if (fqname == NULL) { return ENOMEM; } ret = sysdb_add_group(dom, fqname, group->gr_gid, NULL, 300, 0); talloc_free(fqname); return ret; } static void assert_groups_equal(struct group *expected, struct group *gr, const int nmem) { int i; assert_int_equal(gr->gr_gid, expected->gr_gid); assert_string_equal(gr->gr_name, expected->gr_name); assert_string_equal(gr->gr_passwd, expected->gr_passwd); for (i = 0; i < nmem; i++) { assert_string_equal(gr->gr_mem[i], expected->gr_mem[i]); } } static errno_t store_group_member(struct nss_test_ctx *ctx, const char *shortname_group, struct sss_domain_info *group_dom, const char *shortname_member, struct sss_domain_info *member_dom, enum sysdb_member_type type) { errno_t ret; char *group_fqname = NULL; char *member_fqname = NULL; group_fqname = sss_create_internal_fqname(ctx, shortname_group, group_dom->name); if (group_fqname == NULL) { return ENOMEM; } member_fqname = sss_create_internal_fqname(ctx, shortname_member, member_dom->name); if (member_fqname == NULL) { talloc_free(group_fqname); return ENOMEM; } ret = sysdb_add_group_member(group_dom, group_fqname, member_fqname, SYSDB_MEMBER_USER, false); talloc_free(group_fqname); talloc_free(member_fqname); return ret; } /* ====================== The tests =============================== */ struct passwd getpwnam_usr = { .pw_name = discard_const("testuser"), .pw_uid = 123, .pw_gid = 456, .pw_dir = discard_const("/home/testuser"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; /* Check getting cached and valid user from cache. Account callback will * not be called and test_nss_getpwnam_check will make sure the user is * the same as the test entered before starting */ static int test_nss_getpwnam_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwnam_usr); return EOK; } void test_nss_getpwnam(void **state) { errno_t ret; ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwnam_usr, NULL, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("testuser"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Test that searching for a nonexistant user yields ENOENT. * Account callback will be called */ void test_nss_getpwnam_neg(void **state) { errno_t ret; mock_input_user_or_group("testuser_neg"); mock_account_recv_simple(); assert_int_equal(nss_test_ctx->ncache_hits, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); assert_int_equal(nss_test_ctx->ncache_hits, 0); /* Test that subsequent search for a nonexistent user yields * ENOENT and Account callback is not called, on the other hand * the ncache functions will be called */ nss_test_ctx->tctx->done = false; mock_input_user_or_group("testuser_neg"); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* Negative cache was hit this time */ assert_int_equal(nss_test_ctx->ncache_hits, 1); } struct passwd getpwnam_search_usr = { .pw_name = discard_const("testuser_search"), .pw_uid = 567, .pw_gid = 890, .pw_dir = discard_const("/home/testuser_search"), .pw_gecos = discard_const("test search user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwnam_search_acct_cb(void *pvt) { struct nss_test_ctx *ctx = talloc_get_type(pvt, struct nss_test_ctx); return store_user(ctx, ctx->tctx->dom, &getpwnam_search_usr, NULL, 0); } static int test_nss_getpwnam_search_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwnam_search_usr); return EOK; } void test_nss_getpwnam_search(void **state) { errno_t ret; struct ldb_result *res; mock_input_user_or_group("testuser_search"); mock_account_recv(0, 0, NULL, test_nss_getpwnam_search_acct_cb, nss_test_ctx); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); set_cmd_cb(test_nss_getpwnam_search_check); ret = get_user(nss_test_ctx, nss_test_ctx->tctx->dom, "testuser_search", &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); /* test_nss_getpwnam_search_check will check the user attributes */ ret = get_user(nss_test_ctx, nss_test_ctx->tctx->dom, "testuser_search", &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 1); } /* Test that searching for a user that is expired in the cache goes to the DP * which updates the record and the NSS responder returns the updated record * * The user's shell attribute is updated. */ struct passwd getpwnam_update = { .pw_name = discard_const("testuser_update"), .pw_uid = 10, .pw_gid = 11, .pw_dir = discard_const("/home/testuser"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwnam_update_acct_cb(void *pvt) { struct nss_test_ctx *ctx = talloc_get_type(pvt, struct nss_test_ctx); getpwnam_update.pw_shell = discard_const("/bin/ksh"); return store_user(ctx, ctx->tctx->dom, &getpwnam_update, NULL, 0); } static int test_nss_getpwnam_update_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwnam_update); return EOK; } void test_nss_getpwnam_update(void **state) { errno_t ret; struct ldb_result *res; const char *shell; ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwnam_update, NULL, 1); assert_int_equal(ret, EOK); /* Mock client input */ mock_input_user_or_group("testuser_update"); /* Mock client command */ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); /* Call this function when user is updated by the mock DP request */ mock_account_recv(0, 0, NULL, test_nss_getpwnam_update_acct_cb, nss_test_ctx); /* Call this function to check what the responder returned to the client */ set_cmd_cb(test_nss_getpwnam_update_check); /* Mock output buffer */ mock_fill_user(); /* Fire the command */ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); /* Check the user was updated in the cache */ ret = get_user(nss_test_ctx, nss_test_ctx->tctx->dom, "testuser_update" , &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 1); shell = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SHELL, NULL); assert_string_equal(shell, "/bin/ksh"); } /* Check that a FQDN is returned if the domain is FQDN-only and a * FQDN is requested */ struct passwd getpwnam_fqdn = { .pw_name = discard_const("testuser_fqdn"), .pw_uid = 124, .pw_gid = 457, .pw_dir = discard_const("/home/testuser"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwnam_check_fqdn(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); nss_test_ctx->cctx->rctx->domains[0].fqnames = false; ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); getpwnam_fqdn.pw_name = discard_const("testuser_fqdn@"TEST_DOM_NAME); assert_users_equal(&pwd, &getpwnam_fqdn); return EOK; } void test_nss_getpwnam_fqdn(void **state) { errno_t ret; ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwnam_fqdn, NULL, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("testuser_fqdn@"TEST_DOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_check_fqdn); nss_test_ctx->cctx->rctx->domains[0].fqnames = true; ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Check that a user with a space in his username is returned fine. */ struct passwd getpwnam_space = { .pw_name = discard_const("space user"), .pw_uid = 225, .pw_gid = 558, .pw_dir = discard_const("/home/testuser"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwnam_check_space(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwnam_space); return EOK; } void test_nss_getpwnam_space(void **state) { errno_t ret; /* Prime the cache with a valid user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwnam_space, NULL, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("space user"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_check_space); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getpwnam_check_space_sub(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_int_equal(pwd.pw_uid, 225); assert_int_equal(pwd.pw_gid, 558); assert_string_equal(pwd.pw_name, "space_user"); assert_string_equal(pwd.pw_shell, "/bin/sh"); return EOK; } void test_nss_getpwnam_space_sub(void **state) { errno_t ret; /* Set whitespace substitution */ nss_test_ctx->rctx->override_space = '_'; mock_input_user_or_group("space user"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_check_space_sub); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); nss_test_ctx->rctx->override_space = '\0'; assert_int_equal(ret, EOK); } void test_nss_getpwnam_space_sub_query(void **state) { errno_t ret; /* Set whitespace substitution */ nss_test_ctx->rctx->override_space = '_'; mock_input_user_or_group("space_user"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_check_space_sub); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); nss_test_ctx->rctx->override_space = '\0'; assert_int_equal(ret, EOK); } /* * Check that FQDN processing is able to handle arbitrarily sized * delimeter */ struct passwd getpwnam_fancy_fqdn = { .pw_name = discard_const("testuser_fqdn_fancy"), .pw_uid = 125, .pw_gid = 458, .pw_dir = discard_const("/home/testuser"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwnam_check_fancy_fqdn(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); nss_test_ctx->cctx->rctx->domains[0].fqnames = false; ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_int_equal(pwd.pw_uid, 125); assert_int_equal(pwd.pw_gid, 458); assert_string_equal(pwd.pw_name, "testuser_fqdn_fancy@@@@@"TEST_DOM_NAME); assert_string_equal(pwd.pw_shell, "/bin/sh"); return EOK; } void test_nss_getpwnam_fqdn_fancy(void **state) { errno_t ret; /* Prime the cache with a valid user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwnam_fancy_fqdn, NULL, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("testuser_fqdn_fancy@"TEST_DOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_check_fancy_fqdn); nss_test_ctx->cctx->rctx->domains[0].fqnames = true; ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Check getting cached and valid id from cache. Account callback will * not be called and test_nss_getpwuid_check will make sure the id is * the same as the test entered before starting */ struct passwd getpwuid_usr = { .pw_name = discard_const("testuser1"), .pw_uid = 101, .pw_gid = 401, .pw_dir = discard_const("/home/testuser1"), .pw_gecos = discard_const("test user1"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwuid_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwuid_usr); return EOK; } void test_nss_getpwuid(void **state) { errno_t ret; uint32_t id = 101; /* Prime the cache with a valid user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwuid_usr, NULL, 0); assert_int_equal(ret, EOK); mock_input_id(nss_test_ctx, id); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID); mock_fill_user(); /* Query for that id, call a callback when command finishes */ set_cmd_cb(test_nss_getpwuid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Test that searching for a nonexistent id yields ENOENT. * Account callback will be called */ void test_nss_getpwuid_neg(void **state) { errno_t ret; uid_t uid_neg = 102; mock_input_id(nss_test_ctx, uid_neg); mock_account_recv_simple(); assert_int_equal(nss_test_ctx->ncache_hits, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); assert_int_equal(nss_test_ctx->ncache_hits, 0); /* Test that subsequent search for a nonexistent id yields * ENOENT and Account callback is not called, on the other hand * the ncache functions will be called */ nss_test_ctx->tctx->done = false; mock_input_id(nss_test_ctx, uid_neg); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* Negative cache was hit this time */ assert_int_equal(nss_test_ctx->ncache_hits, 1); } /* Test that lookup by UID for a user that does * not exist in the cache fetches the user from DP */ struct passwd getpwuid_srch = { .pw_name = discard_const("exampleuser_search"), .pw_uid = 107, .pw_gid = 987, .pw_dir = discard_const("/home/examplesearch"), .pw_gecos = discard_const("example search"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwuid_search_acct_cb(void *pvt) { struct nss_test_ctx *ctx = talloc_get_type(pvt, struct nss_test_ctx); return store_user(ctx, ctx->tctx->dom, &getpwuid_srch, NULL, 0); } static int test_nss_getpwuid_search_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwuid_srch); return EOK; } void test_nss_getpwuid_search(void **state) { errno_t ret; struct ldb_result *res; mock_input_id(nss_test_ctx, getpwuid_srch.pw_uid); mock_account_recv(0, 0, NULL, test_nss_getpwuid_search_acct_cb, nss_test_ctx); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID); mock_fill_user(); set_cmd_cb(test_nss_getpwuid_search_check); ret = sysdb_getpwuid(nss_test_ctx, nss_test_ctx->tctx->dom, getpwuid_srch.pw_uid, &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); /* test_nss_getpwuid_search_check will check the id attributes */ ret = sysdb_getpwuid(nss_test_ctx, nss_test_ctx->tctx->dom, getpwuid_srch.pw_uid, &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 1); } /* Test that searching for an id that is expired in the cache goes to the DP * which updates the record and the NSS responder returns the updated record * * The user's shell attribute is updated. */ struct passwd getpwuid_update = { .pw_name = discard_const("exampleuser_update"), .pw_uid = 109, .pw_gid = 11000, .pw_dir = discard_const("/home/exampleuser"), .pw_gecos = discard_const("example user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwuid_update_acct_cb(void *pvt) { struct nss_test_ctx *ctx = talloc_get_type(pvt, struct nss_test_ctx); getpwuid_update.pw_shell = discard_const("/bin/ksh"); return store_user(ctx, ctx->tctx->dom, &getpwuid_update, NULL, 0); } static int test_nss_getpwuid_update_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &getpwuid_update); return EOK; } void test_nss_getpwuid_update(void **state) { errno_t ret; struct ldb_result *res; const char *shell; /* Prime the cache with a valid but expired user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &getpwuid_update, NULL, 1); assert_int_equal(ret, EOK); /* Mock client input */ mock_input_id(nss_test_ctx, getpwuid_update.pw_uid); /* Mock client command */ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID); /* Call this function when id is updated by the mock DP request */ mock_account_recv(0, 0, NULL, test_nss_getpwuid_update_acct_cb, nss_test_ctx); /* Call this function to check what the responder returned to the client */ set_cmd_cb(test_nss_getpwuid_update_check); /* Mock output buffer */ mock_fill_user(); /* Fire the command */ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); /* Check the user was updated in the cache */ ret = sysdb_getpwuid(nss_test_ctx, nss_test_ctx->tctx->dom, getpwuid_update.pw_uid, &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 1); shell = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SHELL, NULL); assert_string_equal(shell, "/bin/ksh"); } /* Testsuite setup and teardown */ void test_nss_setup(struct sss_test_conf_param params[], void **state) { errno_t ret; nss_test_ctx = talloc_zero(NULL, struct nss_test_ctx); assert_non_null(nss_test_ctx); nss_test_ctx->tctx = create_dom_test_ctx(nss_test_ctx, TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME, TEST_ID_PROVIDER, params); assert_non_null(nss_test_ctx->tctx); nss_test_ctx->tctx->dom->domain_id = discard_const(TEST_DOM_SID); nss_test_ctx->nss_cmds = get_nss_cmds(); assert_non_null(nss_test_ctx->nss_cmds); /* FIXME - perhaps this should be folded into sssd_domain_init or stricty * used together */ ret = sss_names_init(nss_test_ctx, nss_test_ctx->tctx->confdb, TEST_DOM_NAME, &nss_test_ctx->tctx->dom->names); assert_int_equal(ret, EOK); /* Initialize the NSS responder */ nss_test_ctx->nctx = mock_nctx(nss_test_ctx); assert_non_null(nss_test_ctx->nctx); ret = sss_ad_default_names_ctx(nss_test_ctx->nctx, &nss_test_ctx->nctx->global_names); assert_int_equal(ret, EOK); assert_non_null(nss_test_ctx->nctx->global_names); nss_test_ctx->rctx = mock_rctx(nss_test_ctx, nss_test_ctx->tctx->ev, nss_test_ctx->tctx->dom, nss_test_ctx->nctx); assert_non_null(nss_test_ctx->rctx); nss_test_ctx->rctx->cdb = nss_test_ctx->tctx->confdb; nss_test_ctx->nctx->rctx = nss_test_ctx->rctx; /* Create client context */ nss_test_ctx->cctx = mock_cctx(nss_test_ctx, nss_test_ctx->rctx); assert_non_null(nss_test_ctx->cctx); /* Add nss specific state_ctx */ nss_connection_setup(nss_test_ctx->cctx); assert_non_null(nss_test_ctx->cctx->state_ctx); /* do after previous setup as the former nulls procotol_ctx */ nss_test_ctx->cctx->protocol_ctx = mock_prctx(nss_test_ctx->cctx); assert_non_null(nss_test_ctx->cctx->protocol_ctx); } struct group getgrnam_no_members = { .gr_gid = 1123, .gr_name = discard_const("testgroup"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_getgrnam_no_members_check(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 0); assert_groups_equal(&getgrnam_no_members, &gr, nmem); return EOK; } /* Test that requesting a valid, cached group with no members returns a valid * group structure */ void test_nss_getgrnam_no_members(void **state) { errno_t ret; /* Prime the cache with a valid group */ ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &getgrnam_no_members, 0); assert_int_equal(ret, EOK); mock_input_user_or_group(getgrnam_no_members.gr_name); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(0); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_no_members_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } struct passwd testmember1 = { .pw_name = discard_const("testmember1"), .pw_uid = 2001, .pw_gid = 456, .pw_dir = discard_const("/home/testmember1"), .pw_gecos = discard_const("test member1"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct passwd testmember2 = { .pw_name = discard_const("testmember2"), .pw_uid = 2002, .pw_gid = 456, .pw_dir = discard_const("/home/testmember2"), .pw_gecos = discard_const("test member2"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct group testgroup_members = { .gr_gid = 1124, .gr_name = discard_const("testgroup_members"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_getgrnam_members_check(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; const char *exp_members[] = { testmember1.pw_name, testmember2.pw_name }; struct group expected = { .gr_gid = testgroup_members.gr_gid, .gr_name = testgroup_members.gr_name, .gr_passwd = testgroup_members.gr_passwd, .gr_mem = discard_const(exp_members) }; assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 2); assert_groups_equal(&expected, &gr, nmem); return EOK; } /* Test that requesting a valid, cached group with some members returns a valid * group structure with those members present */ void test_nss_getgrnam_members(void **state) { errno_t ret; ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testgroup_members, 0); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testmember1, NULL, 0); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testmember2, NULL, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testgroup_members.gr_name, nss_test_ctx->tctx->dom, testmember1.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testgroup_members.gr_name, nss_test_ctx->tctx->dom, testmember2.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testgroup_members"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(2); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_members_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getgrnam_members_check_fqdn(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; const char *exp_members[2]; struct group expected = { .gr_gid = testgroup_members.gr_gid, .gr_passwd = testgroup_members.gr_passwd, .gr_mem = discard_const(exp_members) }; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, nss_test_ctx->tctx->dom, testmember1.pw_name); assert_non_null(exp_members[0]); exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, nss_test_ctx->tctx->dom, testmember2.pw_name); assert_non_null(exp_members[1]); expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, nss_test_ctx->tctx->dom, testgroup_members.gr_name); assert_non_null(expected.gr_name); assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 2); assert_groups_equal(&expected, &gr, nmem); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); return EOK; } /* Test that requesting a valid, cached group with some members returns a valid * group structure with those members present as fully qualified names */ void test_nss_getgrnam_members_fqdn(void **state) { errno_t ret; nss_test_ctx->tctx->dom->fqnames = true; mock_input_user_or_group("testgroup_members@"TEST_DOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(2); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_members_check_fqdn); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); /* Restore FQDN settings */ nss_test_ctx->tctx->dom->fqnames = false; assert_int_equal(ret, EOK); } /* Test that requesting a valid, cached group with subdomain members returns * a valid * group structure with those members present as fully * qualified names */ struct passwd submember1 = { .pw_name = discard_const("submember1"), .pw_uid = 4001, .pw_gid = 456, .pw_dir = discard_const("/home/submember1"), .pw_gecos = discard_const("sub member1"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct passwd submember2 = { .pw_name = discard_const("submember2"), .pw_uid = 4002, .pw_gid = 456, .pw_dir = discard_const("/home/submember2"), .pw_gecos = discard_const("sub member2"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct group testsubdomgroup = { .gr_gid = 2002, .gr_name = discard_const("testsubdomgroup"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_getgrnam_members_check_subdom(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; const char *exp_members[2]; struct group expected = { .gr_gid = testsubdomgroup.gr_gid, .gr_passwd = testsubdomgroup.gr_passwd, .gr_mem = discard_const(exp_members) }; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, submember1.pw_name); assert_non_null(exp_members[0]); exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, submember2.pw_name); assert_non_null(exp_members[1]); expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, testsubdomgroup.gr_name); assert_non_null(expected.gr_name); assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 2); assert_groups_equal(&expected, &gr, nmem); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); return EOK; } void test_nss_getgrnam_members_subdom(void **state) { errno_t ret; ret = store_group(nss_test_ctx, nss_test_ctx->subdom, &testsubdomgroup, 0); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->subdom, &submember1, NULL, 0); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->subdom, &submember2, NULL, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testsubdomgroup.gr_name, nss_test_ctx->subdom, submember1.pw_name, nss_test_ctx->subdom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testsubdomgroup.gr_name, nss_test_ctx->subdom, submember2.pw_name, nss_test_ctx->subdom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testsubdomgroup@"TEST_SUBDOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(2); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_members_check_subdom); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getgrnam_check_mix_dom(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; const char *exp_members[3]; struct group expected = { .gr_name = testgroup_members.gr_name, .gr_gid = testgroup_members.gr_gid, .gr_passwd = testgroup_members.gr_passwd, .gr_mem = discard_const(exp_members) }; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); exp_members[0] = testmember1.pw_name; exp_members[1] = testmember2.pw_name; exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, submember1.pw_name); assert_non_null(exp_members[2]); assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 3); assert_groups_equal(&expected, &gr, nmem); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); return EOK; } void test_nss_getgrnam_mix_dom(void **state) { errno_t ret; ret = store_group_member(nss_test_ctx, testgroup_members.gr_name, nss_test_ctx->tctx->dom, submember1.pw_name, nss_test_ctx->subdom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testgroup_members"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(3); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_check_mix_dom); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; const char *exp_members[3]; struct group expected = { .gr_gid = testgroup_members.gr_gid, .gr_passwd = testgroup_members.gr_passwd, .gr_mem = discard_const(exp_members) }; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, nss_test_ctx->tctx->dom, testmember1.pw_name); assert_non_null(exp_members[0]); exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, nss_test_ctx->tctx->dom, testmember2.pw_name); assert_non_null(exp_members[1]); exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, submember1.pw_name); assert_non_null(exp_members[2]); expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, nss_test_ctx->tctx->dom, testgroup_members.gr_name); assert_non_null(expected.gr_name); assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 3); assert_groups_equal(&expected, &gr, nmem); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); return EOK; } void test_nss_getgrnam_mix_dom_fqdn(void **state) { errno_t ret; nss_test_ctx->tctx->dom->fqnames = true; mock_input_user_or_group("testgroup_members@"TEST_DOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(3); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_check_mix_dom_fqdn); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); /* Restore FQDN settings */ nss_test_ctx->tctx->dom->fqnames = false; assert_int_equal(ret, EOK); } static int test_nss_getgrnam_check_mix_subdom(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; const char *exp_members[3]; struct group expected = { .gr_gid = testsubdomgroup.gr_gid, .gr_passwd = testsubdomgroup.gr_passwd, .gr_mem = discard_const(exp_members) }; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, submember1.pw_name); assert_non_null(exp_members[0]); exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, submember2.pw_name); assert_non_null(exp_members[1]); /* Important: this member is from a non-qualified domain, so his name will * not be qualified either */ exp_members[2] = testmember1.pw_name; expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, nss_test_ctx->subdom, testsubdomgroup.gr_name); assert_non_null(expected.gr_name); assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 3); assert_groups_equal(&expected, &gr, nmem); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); return EOK; } void test_nss_getgrnam_mix_subdom(void **state) { errno_t ret; ret = store_group_member(nss_test_ctx, testsubdomgroup.gr_name, nss_test_ctx->subdom, testmember1.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testsubdomgroup@"TEST_SUBDOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(3); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_check_mix_subdom); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } struct group space_group = { .gr_gid = 2123, .gr_name = discard_const("space group"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_getgrnam_space_check(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 0); assert_groups_equal(&space_group, &gr, nmem); assert_int_equal(ret, EOK); return EOK; } /* Test that requesting a valid, cached group with space in its name returns a valid * group structure */ void test_nss_getgrnam_space(void **state) { errno_t ret; /* Prime the cache with a valid group */ ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &space_group, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("space group"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(0); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_space_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getgrnam_space_sub_check(uint32_t status, uint8_t *body, size_t blen) { int ret; uint32_t nmem; struct group gr; assert_int_equal(status, EOK); ret = parse_group_packet(body, blen, &gr, &nmem); assert_int_equal(ret, EOK); assert_int_equal(nmem, 0); space_group.gr_name = discard_const("space_group"); assert_groups_equal(&space_group, &gr, nmem); assert_int_equal(ret, EOK); return EOK; } /* Test that requesting a valid, cached group with space in its name returns a valid * group structure */ void test_nss_getgrnam_space_sub(void **state) { errno_t ret; /* Set whitespace substitution */ nss_test_ctx->rctx->override_space = '_'; mock_input_user_or_group("space group"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); mock_fill_group_with_members(0); /* Query for that group, call a callback when command finishes */ set_cmd_cb(test_nss_getgrnam_space_sub_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); nss_test_ctx->rctx->override_space = '\0'; assert_int_equal(ret, EOK); } static int test_nss_well_known_sid_check(uint32_t status, uint8_t *body, size_t blen) { const char *name; enum sss_id_type type; size_t rp = 2 * sizeof(uint32_t); char *expected_result = sss_mock_ptr_type(char *); if (expected_result == NULL) { assert_int_equal(status, EINVAL); assert_int_equal(blen, 0); } else { assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&type, body+rp, &rp); name = (char *) body+rp; assert_int_equal(type, SSS_ID_TYPE_GID); assert_string_equal(name, expected_result); } return EOK; } void test_nss_well_known_getnamebysid(void **state) { errno_t ret; will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, "S-1-5-32-550"); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); will_return(test_nss_well_known_sid_check, "Print Operators@BUILTIN"); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } void test_nss_well_known_getnamebysid_special(void **state) { errno_t ret; will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, "S-1-2-0"); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); will_return(test_nss_well_known_sid_check, "LOCAL@LOCAL AUTHORITY"); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } void test_nss_well_known_getnamebysid_non_existing(void **state) { errno_t ret; will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, "S-1-5-32-123"); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); will_return(test_nss_well_known_sid_check, NULL); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } void test_nss_well_known_getidbysid_failure(void **state) { errno_t ret; will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, "S-1-5-32-550"); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETIDBYSID); will_return(test_nss_well_known_sid_check, NULL); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETIDBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } void test_nss_well_known_getsidbyname(void **state) { errno_t ret; const char *names[] = { "Cryptographic Operators@BUILTIN", "BUILTIN\\Cryptographic Operators", NULL}; size_t c; for (c = 0; names[c] != NULL; c++) { will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, names[c]); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); will_return(test_nss_well_known_sid_check, "S-1-5-32-569"); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } } void test_nss_well_known_getsidbyname_nonexisting(void **state) { errno_t ret; const char *names[] = { "Abc@BUILTIN", "BUILTIN\\Abc", NULL }; size_t c; for (c = 0; names[c] != NULL; c++) { will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, names[c]); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME); will_return(test_nss_well_known_sid_check, NULL); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } } void test_nss_well_known_getsidbyname_special(void **state) { errno_t ret; const char *names[] = { "CREATOR OWNER@CREATOR AUTHORITY", "CREATOR AUTHORITY\\CREATOR OWNER", NULL }; size_t c; for (c = 0; names[c] != NULL; c++) { will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); will_return(__wrap_sss_packet_get_body, names[c]); will_return(__wrap_sss_packet_get_body, 0); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); will_return(test_nss_well_known_sid_check, "S-1-3-0"); set_cmd_cb(test_nss_well_known_sid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } } static int test_nss_getorigbyname_check(uint32_t status, uint8_t *body, size_t blen) { const char *s; enum sss_id_type id_type; size_t rp = 2 * sizeof(uint32_t); assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp); assert_int_equal(id_type, SSS_ID_TYPE_UID); /* Sequence of null terminated strings */ s = (char *) body+rp; assert_string_equal(s, SYSDB_SID_STR); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "S-1-2-3-4"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_NAME); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "orig_name"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_UIDNUM); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "1234"); rp += strlen(s) + 1; assert_int_equal(rp, blen); return EOK; } struct passwd orig_name = { .pw_name = discard_const("testuserorig"), .pw_uid = 1234, .pw_gid = 5678, .pw_dir = discard_const("/home/testuserorig"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; void test_nss_getorigbyname(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, "S-1-2-3-4"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, ORIGINALAD_PREFIX SYSDB_NAME, "orig_name"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_uint32(attrs, ORIGINALAD_PREFIX SYSDB_UIDNUM, 1234); assert_int_equal(ret, EOK); /* Prime the cache with a valid user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &orig_name, attrs, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("testuserorig"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETORIGBYNAME); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getorigbyname_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETORIGBYNAME, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getorigbyname_extra_check(uint32_t status, uint8_t *body, size_t blen) { const char *s; enum sss_id_type id_type; size_t rp = 2 * sizeof(uint32_t); assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp); assert_int_equal(id_type, SSS_ID_TYPE_UID); /* Sequence of null terminated strings */ s = (char *) body+rp; assert_string_equal(s, SYSDB_SID_STR); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "S-1-2-3-4"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_NAME); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "orig_name"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_UIDNUM); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "1234"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "phone"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "+12-34 56 78"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "mobile"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "+98-76 54 32"); rp += strlen(s) + 1; assert_int_equal(rp, blen); return EOK; } struct passwd orig_extra = { .pw_name = discard_const("testuserorigextra"), .pw_uid = 2345, .pw_gid = 6789, .pw_dir = discard_const("/home/testuserorigextra"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; void test_nss_getorigbyname_extra_attrs(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, "S-1-2-3-4"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, ORIGINALAD_PREFIX SYSDB_NAME, "orig_name"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_uint32(attrs, ORIGINALAD_PREFIX SYSDB_UIDNUM, 1234); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, "phone", "+12-34 56 78"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, "mobile", "+98-76 54 32"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, "not_extra", "abc"); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &orig_extra, attrs, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("testuserorigextra"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETORIGBYNAME); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getorigbyname_extra_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETORIGBYNAME, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } static int test_nss_getorigbyname_multi_check(uint32_t status, uint8_t *body, size_t blen) { const char *s; enum sss_id_type id_type; size_t rp = 2 * sizeof(uint32_t); assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp); assert_int_equal(id_type, SSS_ID_TYPE_UID); /* Sequence of null terminated strings */ s = (char *) body+rp; assert_string_equal(s, SYSDB_SID_STR); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "S-1-2-3-4"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_NAME); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "orig_name"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, ORIGINALAD_PREFIX SYSDB_UIDNUM); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "1234"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, SYSDB_ORIG_MEMBEROF); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "cn=abc"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, SYSDB_ORIG_MEMBEROF); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "cn=def"); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, SYSDB_ORIG_MEMBEROF); rp += strlen(s) + 1; assert_true(rp < blen); s = (char *) body+rp; assert_string_equal(s, "cn=123"); rp += strlen(s) + 1; assert_int_equal(rp, blen); return EOK; } struct passwd orig_multi = { .pw_name = discard_const("testuserorigmulti"), .pw_uid = 3456, .pw_gid = 7890, .pw_dir = discard_const("/home/testuserorigmulti"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; void test_nss_getorigbyname_multi_value_attrs(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, "S-1-2-3-4"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, ORIGINALAD_PREFIX SYSDB_NAME, "orig_name"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_uint32(attrs, ORIGINALAD_PREFIX SYSDB_UIDNUM, 1234); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_MEMBEROF, "cn=abc"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_MEMBEROF, "cn=def"); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_MEMBEROF, "cn=123"); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &orig_multi, attrs, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("testuserorigmulti"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETORIGBYNAME); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getorigbyname_multi_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETORIGBYNAME, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } struct passwd upn_user = { .pw_name = discard_const("upnuser"), .pw_uid = 34567, .pw_gid = 45678, .pw_dir = discard_const("/home/testuserorig"), .pw_gecos = discard_const("test user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getpwnam_upn_check(uint32_t status, uint8_t *body, size_t blen) { struct passwd pwd; errno_t ret; assert_int_equal(status, EOK); ret = parse_user_packet(body, blen, &pwd); assert_int_equal(ret, EOK); assert_users_equal(&pwd, &upn_user); return EOK; } void test_nss_getpwnam_upn(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upnuser@upndomain.test"); assert_int_equal(ret, EOK); /* Prime the cache with a valid user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &upn_user, attrs, 0); assert_int_equal(ret, EOK); mock_input_user_or_group("upnuser@upndomain.test"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM); mock_fill_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_getpwnam_upn_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Test that searching for a nonexistant user yields ENOENT. * Account callback will be called */ void test_nss_getpwnam_upn_neg(void **state) { errno_t ret; mock_input_user_or_group("nosuchupnuser@upndomain.test"); mock_account_recv_simple(); assert_int_equal(nss_test_ctx->ncache_hits, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); assert_int_equal(nss_test_ctx->ncache_hits, 1); /* Test that subsequent search for a nonexistent user yields * ENOENT and Account callback is not called, on the other hand * the ncache functions will be called */ nss_test_ctx->tctx->done = false; nss_test_ctx->ncache_hits = 0; mock_input_user_or_group("nosuchupnuser@upndomain.test"); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* Negative cache was hit this time */ assert_int_equal(nss_test_ctx->ncache_hits, 1); } static int test_nss_initgr_check(uint32_t status, uint8_t *body, size_t blen) { gid_t expected_gids[] = { 3211, 3212 }; assert_int_equal(status, EOK); check_initgr_packet(body, blen, expected_gids, N_ELEMENTS(expected_gids)); return EOK; } struct passwd testinitgr_usr = { .pw_name = discard_const("testinitgr"), .pw_uid = 321, .pw_gid = 654, .pw_dir = discard_const("/home/testinitgr"), .pw_gecos = discard_const("test initgroups"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct group testinitgr_gr1 = { .gr_gid = 3211, .gr_name = discard_const("testinitgr_gr1"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; struct group testinitgr_gr2 = { .gr_gid = 3212, .gr_name = discard_const("testinitgr_gr2"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; void test_nss_initgroups(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, time(NULL) + 300); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upninitgr@upndomain.test"); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_usr, attrs, 0); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_gr1, 0); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_gr2, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_gr1.gr_name, nss_test_ctx->tctx->dom, testinitgr_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_gr2.gr_name, nss_test_ctx->tctx->dom, testinitgr_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testinitgr"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR); mock_fill_initgr_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_initgr_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Test that searching for a nonexistant user yields ENOENT. * Account callback will be called */ void test_initgr_neg_by_name(const char *name, bool is_upn) { errno_t ret; mock_input_user_or_group(name); mock_account_recv_simple(); assert_int_equal(nss_test_ctx->ncache_hits, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* UPN lookup will first hit negcache with the username */ assert_int_equal(nss_test_ctx->ncache_hits, is_upn ? 1 : 0); /* Test that subsequent search for a nonexistent user yields * ENOENT and Account callback is not called, on the other hand * the ncache functions will be called */ nss_test_ctx->tctx->done = false; nss_test_ctx->ncache_hits = 0; mock_input_user_or_group(name); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* Negative cache was hit this time */ assert_int_equal(nss_test_ctx->ncache_hits, 1); } void test_nss_initgr_neg(void **state) { test_initgr_neg_by_name("testinitgr_neg", false); } struct passwd testinitgr_srch_usr = { .pw_name = discard_const("testinitgr_srch"), .pw_uid = 421, .pw_gid = 654, .pw_dir = discard_const("/home/testinitgr_srch"), .pw_gecos = discard_const("test initgroups"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct group testinitgr_srch_gr1 = { .gr_gid = 4211, .gr_name = discard_const("testinitgr_srch_gr1"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; struct group testinitgr_srch_gr2 = { .gr_gid = 4212, .gr_name = discard_const("testinitgr_srch_gr2"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_initgr_search_acct_cb(void *pvt) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, time(NULL) + 300); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_srch_usr, attrs, 0); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_srch_gr1, 0); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_srch_gr2, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_srch_gr1.gr_name, nss_test_ctx->tctx->dom, testinitgr_srch_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_srch_gr2.gr_name, nss_test_ctx->tctx->dom, testinitgr_srch_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); return EOK; } static int test_nss_initgr_search_check(uint32_t status, uint8_t *body, size_t blen) { gid_t expected_gids[] = { 4211, 4212 }; assert_int_equal(status, EOK); check_initgr_packet(body, blen, expected_gids, N_ELEMENTS(expected_gids)); return EOK; } void test_nss_initgr_search(void **state) { errno_t ret; struct ldb_result *res; mock_input_user_or_group("testinitgr_srch"); mock_account_recv(0, 0, NULL, test_nss_initgr_search_acct_cb, nss_test_ctx); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR); mock_fill_initgr_user(); set_cmd_cb(test_nss_initgr_search_check); ret = get_user(nss_test_ctx, nss_test_ctx->tctx->dom, "testinitgr_srch", &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); /* test_nss_getpwnam_search_check will check the user attributes */ ret = get_user(nss_test_ctx, nss_test_ctx->tctx->dom, "testinitgr_srch", &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 1); } struct passwd testinitgr_update_usr = { .pw_name = discard_const("testinitgr_update"), .pw_uid = 521, .pw_gid = 654, .pw_dir = discard_const("/home/testinitgr_update"), .pw_gecos = discard_const("test initgroups"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct group testinitgr_update_gr1 = { .gr_gid = 5211, .gr_name = discard_const("testinitgr_update_gr1"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; struct group testinitgr_update_gr2 = { .gr_gid = 5212, .gr_name = discard_const("testinitgr_update_gr2"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_initgr_update_acct_cb(void *pvt) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, time(NULL) + 300); assert_int_equal(ret, EOK); ret = set_user_attr(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_update_usr, attrs); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_update_gr2, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_update_gr2.gr_name, nss_test_ctx->tctx->dom, testinitgr_update_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); return EOK; } static int test_nss_initgr_update_check(uint32_t status, uint8_t *body, size_t blen) { gid_t expected_gids[] = { 5211, 5212 }; assert_int_equal(status, EOK); check_initgr_packet(body, blen, expected_gids, N_ELEMENTS(expected_gids)); return EOK; } void test_nss_initgr_update(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, time(NULL) - 1); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_update_usr, attrs, 0); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_update_gr1, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_update_gr1.gr_name, nss_test_ctx->tctx->dom, testinitgr_update_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testinitgr_update"); mock_account_recv(0, 0, NULL, test_nss_initgr_update_acct_cb, nss_test_ctx); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR); mock_fill_initgr_user(); set_cmd_cb(test_nss_initgr_update_check); /* Query for that user, call a callback when command finishes */ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } struct passwd testinitgr_2attr_usr = { .pw_name = discard_const("testinitgr_2attr"), .pw_uid = 521, .pw_gid = 654, .pw_dir = discard_const("/home/testinitgr_2attr"), .pw_gecos = discard_const("test initgroups"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; struct group testinitgr_2attr_gr1 = { .gr_gid = 5221, .gr_name = discard_const("testinitgr_2attr_gr11"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; struct group testinitgr_2attr_gr2 = { .gr_gid = 5222, .gr_name = discard_const("testinitgr_2attr_gr12"), .gr_passwd = discard_const("*"), .gr_mem = NULL, }; static int test_nss_initgr_update_acct_2expire_attributes_cb(void *pvt) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, time(NULL) + 300); assert_int_equal(ret, EOK); ret = set_user_attr(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_2attr_usr, attrs); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_2attr_gr2, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_2attr_gr2.gr_name, nss_test_ctx->tctx->dom, testinitgr_2attr_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); return EOK; } static int test_nss_initgr_update_2expire_attributes_check(uint32_t status, uint8_t *body, size_t blen) { gid_t expected_gids[] = { 5221, 5222 }; assert_int_equal(status, EOK); check_initgr_packet(body, blen, expected_gids, N_ELEMENTS(expected_gids)); return EOK; } /* * SYSDB_INITGR_EXPIRE has default value 0 => initgroups was not finished. * SYSDB_CACHE_EXPIRE has value from future => getpwnam finished successfully * * Test result: DP should be contacted for update. */ void test_nss_initgr_update_two_expire_attributes(void **state) { errno_t ret; struct sysdb_attrs *attrs; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, 0); assert_int_equal(ret, EOK); ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE, time(NULL) + 100); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_2attr_usr, attrs, 0); assert_int_equal(ret, EOK); ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom, &testinitgr_2attr_gr1, 0); assert_int_equal(ret, EOK); ret = store_group_member(nss_test_ctx, testinitgr_2attr_gr1.gr_name, nss_test_ctx->tctx->dom, testinitgr_2attr_usr.pw_name, nss_test_ctx->tctx->dom, SYSDB_MEMBER_USER); assert_int_equal(ret, EOK); mock_input_user_or_group("testinitgr_2attr"); mock_account_recv(0, 0, NULL, test_nss_initgr_update_acct_2expire_attributes_cb, nss_test_ctx); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR); mock_fill_initgr_user(); set_cmd_cb(test_nss_initgr_update_2expire_attributes_check); /* Query for that user, call a callback when command finishes */ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } void test_nss_initgroups_upn(void **state) { errno_t ret; mock_input_user_or_group("upninitgr@upndomain.test"); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR); mock_fill_initgr_user(); /* Query for that user, call a callback when command finishes */ set_cmd_cb(test_nss_initgr_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Test that searching for a nonexistant user yields ENOENT. * Account callback will be called */ void test_nss_initgr_neg_upn(void **state) { test_initgr_neg_by_name("upninitgr_neg@upndomain.test", true); } static int nss_test_setup(void **state) { struct sss_test_conf_param params[] = { { "enumerate", "false" }, { NULL, NULL }, /* Sentinel */ }; test_nss_setup(params, state); return 0; } static int nss_fqdn_test_setup(void **state) { struct sss_test_conf_param params[] = { { "enumerate", "false" }, { "full_name_format", "%1$s@%2$s" }, { NULL, NULL }, /* Sentinel */ }; test_nss_setup(params, state); return 0; } static int nss_test_setup_extra_attr(void **state) { struct sss_test_conf_param params[] = { { "enumerate", "false" }, { NULL, NULL }, /* Sentinel */ }; test_nss_setup(params, state); nss_test_ctx->nctx->extra_attributes = global_extra_attrs; return 0; } static int nss_subdom_test_setup(void **state) { const char *const testdom[4] = { TEST_SUBDOM_NAME, "TEST.SUB", "test", "S-3" }; struct sss_domain_info *subdomain; errno_t ret; nss_test_setup(state); subdomain = new_subdomain(nss_test_ctx, nss_test_ctx->tctx->dom, testdom[0], testdom[1], testdom[2], testdom[3], false, false, NULL, 0); assert_non_null(subdomain); ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb, testdom[0], testdom[1], testdom[2], testdom[3], false, false, NULL, 0); assert_int_equal(ret, EOK); ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom); assert_int_equal(ret, EOK); nss_test_ctx->subdom = subdomain; return 0; } static int nss_fqdn_fancy_test_setup(void **state) { struct sss_test_conf_param params[] = { { "enumerate", "false" }, { "full_name_format", "%1$s@@@@@%2$s" }, { NULL, NULL }, /* Sentinel */ }; test_nss_setup(params, state); return 0; } static int nss_test_teardown(void **state) { talloc_free(nss_test_ctx); return 0; } struct passwd testbysid = { .pw_name = discard_const("testsiduser"), .pw_uid = 12345, .pw_gid = 6890, .pw_dir = discard_const("/home/testsiduser"), .pw_gecos = discard_const("test bysid lookup"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getnamebysid_check(uint32_t status, uint8_t *body, size_t blen) { size_t rp = 2 * sizeof(uint32_t); /* num_results and reserved */ uint32_t id_type; const char *name; assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp); assert_int_equal(id_type, SSS_ID_TYPE_UID); name = (const char *) body + rp; assert_string_equal(name, testbysid.pw_name); return EOK; } static void test_nss_getnamebysid(void **state) { errno_t ret; struct sysdb_attrs *attrs; char *user_sid; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); user_sid = talloc_asprintf(attrs, "%s-500", nss_test_ctx->tctx->dom->domain_id); assert_non_null(user_sid); ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, user_sid); assert_int_equal(ret, EOK); ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testbysid, attrs, 0); assert_int_equal(ret, EOK); mock_input_user_or_group(user_sid); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); mock_fill_bysid(); /* Query for that user, call a callback when command finishes */ /* Should go straight to back end, without contacting DP */ set_cmd_cb(test_nss_getnamebysid_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } /* Test that searching for a nonexistant user yields ENOENT. * Account callback will be called */ void test_nss_getnamebysid_neg(void **state) { errno_t ret; char *user_sid; user_sid = talloc_asprintf(nss_test_ctx, "%s-499", nss_test_ctx->tctx->dom->domain_id); assert_non_null(user_sid); mock_input_user_or_group(user_sid); mock_account_recv_simple(); assert_int_equal(nss_test_ctx->ncache_hits, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); assert_int_equal(nss_test_ctx->ncache_hits, 0); /* Test that subsequent search for a nonexistent user yields * ENOENT and Account callback is not called, on the other hand * the ncache functions will be called */ nss_test_ctx->tctx->done = false; mock_input_user_or_group(user_sid); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* Negative cache was hit this time */ assert_int_equal(nss_test_ctx->ncache_hits, 1); } struct passwd testbysid_update = { .pw_name = discard_const("testsidbyname_update"), .pw_uid = 123456, .pw_gid = 789, .pw_dir = discard_const("/home/testsidbyname_update"), .pw_gecos = discard_const("test bysid lookup"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; static int test_nss_getnamebysid_update_check(uint32_t status, uint8_t *body, size_t blen) { size_t rp = 2 * sizeof(uint32_t); /* num_results and reserved */ uint32_t id_type; const char *name; assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp); assert_int_equal(id_type, SSS_ID_TYPE_UID); name = (const char *) body + rp; assert_string_equal(name, "testsidbyname_update"); return EOK; } static int test_nss_getnamebysid_update_acct_cb(void *pvt) { errno_t ret; struct nss_test_ctx *ctx = talloc_get_type(pvt, struct nss_test_ctx); testbysid_update.pw_shell = discard_const("/bin/ksh"); ret = store_user(ctx, nss_test_ctx->tctx->dom, &testbysid_update, NULL, 0); assert_int_equal(ret, EOK); return EOK; } void test_nss_getnamebysid_update(void **state) { errno_t ret; struct ldb_result *res; struct sysdb_attrs *attrs; const char *shell; char *user_sid; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); user_sid = talloc_asprintf(attrs, "%s-123456", nss_test_ctx->tctx->dom->domain_id); assert_non_null(user_sid); ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, user_sid); assert_int_equal(ret, EOK); /* Prime the cache with a valid but expired user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testbysid_update, attrs, 1); assert_int_equal(ret, EOK); /* Mock client input */ mock_input_user_or_group(user_sid); /* Mock client command */ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYSID); /* Call this function when user is updated by the mock DP request */ mock_account_recv(0, 0, NULL, test_nss_getnamebysid_update_acct_cb, nss_test_ctx); /* Call this function to check what the responder returned to the client */ set_cmd_cb(test_nss_getnamebysid_update_check); /* Mock output buffer */ mock_fill_bysid(); /* Fire the command */ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYSID, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); /* Check the user was updated in the cache */ ret = get_user(nss_test_ctx, nss_test_ctx->tctx->dom, testbysid_update.pw_name, &res); assert_int_equal(ret, EOK); assert_int_equal(res->count, 1); shell = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SHELL, NULL); assert_string_equal(shell, "/bin/ksh"); } struct passwd testbycert = { .pw_name = discard_const("testcertuser"), .pw_uid = 23456, .pw_gid = 6890, .pw_dir = discard_const("/home/testcertuser"), .pw_gecos = discard_const("test cert user"), .pw_shell = discard_const("/bin/sh"), .pw_passwd = discard_const("*"), }; #define TEST_TOKEN_CERT \ "MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \ "NjMyMDdaFw0xNzA2MjMxNjMyMDdaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \ "A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \ "ADCCAQoCggEBALXUq56VlY+Z0aWLLpFAjFfbElPBXGQsbZb85J3cGyPjaMHC9wS+" \ "wjB6Ve4HmQyPLx8hbINdDmbawMHYQvTScLYfsqLtj0Lqw20sUUmedk+Es5Oh9VHo" \ "nd8MavYx25Du2u+T0iSgNIDikXguiwCmtAj8VC49ebbgITcjJGzMmiiuJkV3o93Y" \ "vvYF0VjLGDQbQWOy7IxzYJeNVJnZWKo67CHdok6qOrm9rxQt81rzwV/mGLbCMUbr" \ "+N4M8URtd7EmzaYZQmNm//s2owFrCYMxpLiURPj+URZVuB72504/Ix7X0HCbA/AV" \ "26J27fPY5nc8DMwfhUDCbTqPH/JEjd3mvY8CAwEAAaOCASYwggEiMB8GA1UdIwQY" \ "MBaAFJOq+KAQmPEnNp8Wok23eGTdE7aDMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \ "BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \ "BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \ "aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \ "LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \ "IEF1dGhvcml0eTAdBgNVHQ4EFgQUFaDNd5a53QGpaw5m63hnwXicMQ8wDQYJKoZI" \ "hvcNAQELBQADggEBADH7Nj00qqGhGJeXJQAsepqSskz/wooqXh8vgVyb8SS4N0/c" \ "0aQtVmY81xamlXE12ZFpwDX43d+EufBkwCUKFX/+8JFDd2doAyeJxv1xM22kKRpc" \ "AqITPgMsa9ToGMWxjbVpc/X/5YfZixWPF0/eZUTotBj9oaR039UrhGfyN7OguF/G" \ "rzmxtB5y4ZrMpcD/Oe90mkd9HY7sA/fB8OWOUgeRfQoh97HNS0UiDWsPtfxmjQG5" \ "zotpoBIZmdH+ipYsu58HohHVlM9Wi5H4QmiiXl+Soldkq7eXYlafcmT7wv8+cKwz" \ "Nz0Tm3+eYpFqRo3skr6QzXi525Jkg3r6r+kkhxU=" static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t blen) { size_t rp = 2 * sizeof(uint32_t); /* num_results and reserved */ uint32_t id_type; const char *name; assert_int_equal(status, EOK); SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp); assert_int_equal(id_type, SSS_ID_TYPE_UID); name = (const char *)body + rp; assert_string_equal(name, testbycert.pw_name); return EOK; } static void test_nss_getnamebycert(void **state) { errno_t ret; struct sysdb_attrs *attrs; unsigned char *der = NULL; size_t der_size; attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); assert_non_null(der); ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); talloc_free(der); assert_int_equal(ret, EOK); /* Prime the cache with a valid user */ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, &testbycert, attrs, 0); assert_int_equal(ret, EOK); talloc_free(attrs); mock_input_user_or_group(TEST_TOKEN_CERT); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYCERT); mock_fill_bysid(); /* Query for that user, call a callback when command finishes */ /* Should go straight to back end, without contacting DP */ set_cmd_cb(test_nss_getnamebycert_check); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYCERT, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with EOK */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, EOK); } void test_nss_getnamebycert_neg(void **state) { errno_t ret; mock_input_user_or_group(TEST_TOKEN_CERT); mock_account_recv_simple(); assert_int_equal(nss_test_ctx->ncache_hits, 0); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYCERT, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); assert_int_equal(nss_test_ctx->ncache_hits, 0); /* Test that subsequent search for a nonexistent user yields * ENOENT and Account callback is not called, on the other hand * the ncache functions will be called */ nss_test_ctx->tctx->done = false; mock_input_user_or_group(TEST_TOKEN_CERT); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYCERT, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); /* Wait until the test finishes with ENOENT */ ret = test_ev_loop(nss_test_ctx->tctx); assert_int_equal(ret, ENOENT); /* Negative cache was hit this time */ assert_int_equal(nss_test_ctx->ncache_hits, 1); } int main(int argc, const char *argv[]) { int rv; int no_cleanup = 0; poptContext pc; int opt; struct poptOption long_options[] = { POPT_AUTOHELP SSSD_DEBUG_OPTS {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0, _("Do not delete the test database after a test run"), NULL }, POPT_TABLEEND }; const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(test_nss_getpwnam, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwuid, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_neg, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwuid_neg, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_search, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwuid_search, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_update, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwuid_update, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_fqdn, nss_fqdn_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_fqdn_fancy, nss_fqdn_fancy_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_space, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_space_sub, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_space_sub_query, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_no_members, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_members, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_fqdn, nss_fqdn_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom, nss_subdom_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom, nss_subdom_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn, nss_subdom_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, nss_subdom_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getnamebysid, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getnamebysid_special, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getnamebysid_non_existing, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getidbysid_failure, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getsidbyname, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getsidbyname_nonexisting, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_well_known_getsidbyname_special, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getorigbyname, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getorigbyname_extra_attrs, nss_test_setup_extra_attr, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getorigbyname_multi_value_attrs, nss_test_setup_extra_attr, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_upn, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getpwnam_upn_neg, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgroups, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgr_neg, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgr_search, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgr_update, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgr_update_two_expire_attributes, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgroups_upn, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_initgr_neg_upn, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getnamebysid, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getnamebysid_neg, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getnamebysid_update, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getnamebycert_neg, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getnamebycert, nss_test_setup, nss_test_teardown), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ debug_level = SSSDBG_INVALID; pc = poptGetContext(argv[0], argc, argv, long_options, 0); while((opt = poptGetNextOpt(pc)) != -1) { switch(opt) { default: fprintf(stderr, "\nInvalid option %s: %s\n\n", poptBadOption(pc, 0), poptStrerror(opt)); poptPrintUsage(pc, stderr, 0); return 1; } } poptFreeContext(pc); DEBUG_CLI_INIT(debug_level); /* Even though normally the tests should clean up after themselves * they might not after a failed run. Remove the old db to be sure */ tests_set_cwd(); test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); test_dom_suite_setup(TESTS_PATH); rv = cmocka_run_group_tests(tests, NULL, NULL); if (rv == 0 && !no_cleanup) { test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); } #ifdef HAVE_NSS /* Cleanup NSS and NSPR to make valgrind happy. */ nspr_nss_cleanup(); #endif return rv; }