>From a0043e064cf60a2df53ff544fc9c88eb85af6853 Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Mon, 10 Aug 2015 12:43:22 +0200 Subject: [PATCH] test_nss_srv_multi: Subject Explanation Resolves: https://fedorahosted.org/sssd/ticket/XXXX --- Makefile.am | 28 +++ src/tests/cmocka/test_nss_srv_multi.c | 437 ++++++++++++++++++++++++++++++++++ 2 files changed, 465 insertions(+) create mode 100644 src/tests/cmocka/test_nss_srv_multi.c diff --git a/Makefile.am b/Makefile.am index 8b64317d6dce9a1ee8614916395b9afd9f11f382..01e5c6c9c1af21d60a0d4922b327dada94f87704 100644 --- a/Makefile.am +++ b/Makefile.am @@ -201,6 +201,7 @@ endif # HAVE_CHECK if HAVE_CMOCKA non_interactive_cmocka_based_tests = \ nss-srv-tests \ + nss-srv-multi-tests \ test-find-uid \ test-io \ test-negcache \ @@ -1850,6 +1851,33 @@ TEST_MOCK_PROVIDER_OBJ = \ src/tests/cmocka/common_mock_sdap.c \ src/tests/cmocka/common_mock_sysdb_objects.c +EXTRA_nss_srv_multi_tests_DEPENDENCIES = \ + $(ldblib_LTLIBRARIES) +nss_srv_multi_tests_SOURCES = \ + $(TEST_MOCK_RESP_OBJ) \ + src/tests/cmocka/test_nss_srv_multi.c \ + src/responder/nss/nsssrv_cmd.c \ + src/responder/nss/nsssrv_netgroup.c \ + src/responder/nss/nsssrv_services.c \ + src/responder/nss/nsssrv_mmap_cache.c +nss_srv_multi_tests_CFLAGS = \ + $(AM_CFLAGS) +nss_srv_multi_tests_LDFLAGS = \ + -Wl,-wrap,sss_dp_get_account_send \ + -Wl,-wrap,sss_ncache_check_user \ + -Wl,-wrap,sss_ncache_check_uid \ + -Wl,-wrap,sss_ncache_check_sid \ + -Wl,-wrap,sss_packet_get_body \ + -Wl,-wrap,sss_packet_get_cmd \ + -Wl,-wrap,sss_cmd_send_empty \ + -Wl,-wrap,sss_cmd_done +nss_srv_multi_tests_LDADD = \ + $(CMOCKA_LIBS) \ + $(SSSD_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la \ + libsss_idmap.la + EXTRA_nss_srv_tests_DEPENDENCIES = \ $(ldblib_LTLIBRARIES) nss_srv_tests_SOURCES = \ diff --git a/src/tests/cmocka/test_nss_srv_multi.c b/src/tests/cmocka/test_nss_srv_multi.c new file mode 100644 index 0000000000000000000000000000000000000000..6320255978b3f8056e0e63d502b9617477d4b042 --- /dev/null +++ b/src/tests/cmocka/test_nss_srv_multi.c @@ -0,0 +1,437 @@ +/* + 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 "db/sysdb_private.h" /* new_subdomain() */ + +#define TESTS_PATH "tests_nss_multi" +#define TEST_CONF_DB "test_nss_multi_conf.ldb" +#define TEST_DOM_NAME "nss_test" +#define TEST_DOM_NAME1 "nss_test_a" +#define TEST_DOM_NAME2 "nss_test_b" +#define TEST_SUBDOM_NAME "test.subdomain" +#define TEST_ID_PROVIDER "ldap" +#define TEST_DOM_SID "S-1-5-21-444379608-1639770488-2995963434" + +static const char *domains[] = { TEST_DOM_NAME1, TEST_DOM_NAME2, NULL }; + +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; + errno_t ret; + enum idmap_error_code err; + + nctx = talloc_zero(mem_ctx, struct nss_ctx); + if (!nctx) { + return NULL; + } + + ret = sss_ncache_init(nctx, &nctx->ncache); + if (ret != EOK) { + talloc_free(nctx); + return NULL; + } + nctx->neg_timeout = 10; + 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; +} + +struct tevent_req * +__wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *dom, + bool fast_reply, + enum sss_dp_acct_type type, + const char *opt_name, + uint32_t opt_id, + const char *extra) +{ + bool dp_called = false; + + dp_called = sss_mock_type(bool); + assert_true(dp_called); + + return test_req_succeed_send(mem_ctx, rctx->ev); +} + +/* 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 sss_packet *packet = cctx->creq->out; + uint8_t *body; + size_t blen; + cmd_cb_fn_t check_cb; + + check_cb = sss_mock_ptr_type(cmd_cb_fn_t); + + __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; +} + +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; +} + +/* 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_fill_initgr_user(void) +{ + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +} + +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]); + } +} + +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_multidom_test_ctx(nss_test_ctx, TESTS_PATH, + TEST_CONF_DB, domains, + 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_names_init(nss_test_ctx->nctx, nss_test_ctx->tctx->confdb, + NULL, &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); +} + +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_test_teardown(void **state) +{ + talloc_free(nss_test_ctx); + return 0; +} + +/* ====================== The tests =============================== */ + +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; +} + +void test_nss_initgroups(void **state) +{ + errno_t ret; + struct sysdb_attrs *attrs; + struct sss_domain_info *domain; + + domain = find_domain_by_name(nss_test_ctx->tctx->dom, + TEST_DOM_NAME2, false); + + 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 = sysdb_add_user(domain, + "testinitgr", 321, 654, "test initgroups", + "/home/testinitgr", "/bin/sh", NULL, + attrs, 300, 0); + assert_int_equal(ret, EOK); + + ret = sysdb_add_group(domain, + "testinitgr_gr1", 3211, + NULL, 300, 0); + assert_int_equal(ret, EOK); + + ret = sysdb_add_group(domain, + "testinitgr_gr2", 3212, + NULL, 300, 0); + assert_int_equal(ret, EOK); + + ret = sysdb_add_group_member(domain, + "testinitgr_gr1", "testinitgr", + SYSDB_MEMBER_USER, false); + assert_int_equal(ret, EOK); + + ret = sysdb_add_group_member(domain, + "testinitgr_gr2", "testinitgr", + SYSDB_MEMBER_USER, false); + assert_int_equal(ret, EOK); + + will_return(__wrap_sss_dp_get_account_send, true); + will_return_always(sss_dp_get_account_recv, 0); + + 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); +} + +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_initgroups, + 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_multidom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, domains); + test_dom_suite_setup(TESTS_PATH); + + rv = cmocka_run_group_tests(tests, NULL, NULL); + if (rv == 0 && !no_cleanup) { + test_multidom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, domains); + } + return rv; +} -- 2.5.0