From 165f58ab7fb22c7e82aca2be3eeb76377a955d2f Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Jun 05 2018 19:11:33 +0000 Subject: tests: add SSH responder tests Related to https://pagure.io/SSSD/sssd/issue/3489 Reviewed-by: Jakub Hrozek --- diff --git a/Makefile.am b/Makefile.am index 42d565c..b6c60ec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -275,6 +275,7 @@ if HAVE_CMOCKA test_sbus_opath \ test_fo_srv \ pam-srv-tests \ + ssh-srv-tests \ test_ipa_subdom_util \ test_tools_colondb \ test_krb5_wait_queue \ @@ -2425,6 +2426,41 @@ pam_srv_tests_LDADD = \ libsss_certmap.la \ $(NULL) +EXTRA_ssh_srv_tests_DEPENDENCIES = \ + $(ldblib_LTLIBRARIES) \ + $(NULL) +if HAVE_NSS +EXTRA_ssh_srv_tests_DEPENDENCIES += p11_child +endif +ssh_srv_tests_SOURCES = \ + $(TEST_MOCK_RESP_OBJ) \ + src/tests/cmocka/test_ssh_srv.c \ + src/responder/ssh/ssh_cmd.c \ + src/responder/ssh/ssh_known_hosts.c \ + src/responder/ssh/ssh_protocol.c \ + src/responder/ssh/ssh_reply.c \ + src/util/cert/cert_common_p11_child.c \ + $(NULL) +ssh_srv_tests_CFLAGS = \ + -U SSSD_LIBEXEC_PATH -DSSSD_LIBEXEC_PATH=\"$(abs_builddir)\" \ + -I$(abs_builddir)/src \ + $(AM_CFLAGS) \ + $(NULL) +ssh_srv_tests_LDFLAGS = \ + -Wl,-wrap,sss_packet_get_body \ + -Wl,-wrap,sss_packet_get_cmd \ + -Wl,-wrap,sss_cmd_send_empty \ + -Wl,-wrap,sss_cmd_done \ + -Wl,-wrap,ssh_dp_send_req \ + $(NULL) +ssh_srv_tests_LDADD = \ + $(CMOCKA_LIBS) \ + $(SSSD_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + $(SYSTEMD_DAEMON_LIBS) \ + libsss_test_common.la \ + $(NULL) + EXTRA_responder_get_domains_tests_DEPENDENCIES = \ $(ldblib_LTLIBRARIES) responder_get_domains_tests_SOURCES = \ diff --git a/src/tests/cmocka/test_ssh_srv.c b/src/tests/cmocka/test_ssh_srv.c new file mode 100644 index 0000000..dd9a523 --- /dev/null +++ b/src/tests/cmocka/test_ssh_srv.c @@ -0,0 +1,655 @@ +/* + Authors: + Sumit Bose + + Copyright (C) 2015 Red Hat + + SSSD tests: PAM 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 "tests/cmocka/common_mock.h" +#include "tests/cmocka/common_mock_resp.h" +#include "responder/common/responder_packet.h" +#include "responder/common/negcache.h" +#include "responder/ssh/ssh_private.h" +#include "confdb/confdb.h" + +#include "util/crypto/sss_crypto.h" +#ifdef HAVE_NSS +#include "util/crypto/nss/nss_util.h" +#endif + +#ifdef HAVE_TEST_CA +#include "tests/test_CA/SSSD_test_cert_x509_0001.h" +#include "tests/test_CA/SSSD_test_cert_pubsshkey_0001.h" +#include "tests/test_CA/SSSD_test_cert_x509_0002.h" +#include "tests/test_CA/SSSD_test_cert_pubsshkey_0002.h" +#else +#define SSSD_TEST_CERT_0001 "" +#define SSSD_TEST_CERT_SSH_KEY_0001 "" +#define SSSD_TEST_CERT_0002 "" +#define SSSD_TEST_CERT_SSH_KEY_0002 "" +#endif + +#define TESTS_PATH "tp_" BASE_FILE_STEM +#define TEST_CONF_DB "test_ssh_conf.ldb" +#define TEST_DOM_NAME "ssh_test" +#define TEST_SUBDOM_NAME "test.subdomain" +#define TEST_ID_PROVIDER "ldap" + +#define TEST_SSH_PUBKEY \ +"AAAAB3NzaC1yc2EAAAADAQABAAABAQC1" \ +"OlYGkYw8JyhKQrlNBGbZC2az9TJhUWNn" \ +"/kS26OOI9hXCZgz4eHyZnCS1bY1/0ptG" \ +"ByQAk2qvF9uYV2plxULoiOUYAWCnnqx/" \ +"bnhQ4SxmCcA5RPy3h8FX2OrxMlQEadH6" \ +"wz3ZTnOvsw57/ZV8yXjzVexJeeO1A59g" \ +"pLD43f3v056zSF/Jo1NwAZUzCJuzpFAy" \ +"Ale6mZ/1rpGN+ah6rN70wz3brwEOi4f2" \ +"HQNbKAL4idVyRYbA7oU+htCLEd6YsSdy" \ +"murxDMAEEQbLeMbF1DXNt1OunoeprXrU" \ +"UE1U9Rxi6xvPt7s3h9NbZiaLRPJU6due" \ +"+nqwn8En7mesd7LnRQST" + +struct ssh_test_ctx { + struct sss_test_ctx *tctx; + struct sss_domain_info *subdom; + + struct resp_ctx *rctx; + struct cli_ctx *cctx; + struct sss_cmd_table *ssh_cmds; + struct ssh_ctx *ssh_ctx; + + int ncache_hits; + bool provider_contacted; + + const char *ssh_user_fqdn; + const char *wrong_user_fqdn; +}; + +/* Must be global because it is needed in some wrappers */ +struct ssh_test_ctx *ssh_test_ctx; + +struct ssh_ctx *mock_ssh_ctx(TALLOC_CTX *mem_ctx) +{ + struct ssh_ctx *ssh_ctx; + + ssh_ctx = talloc_zero(mem_ctx, struct ssh_ctx); + assert_non_null(ssh_ctx); + + return ssh_ctx; +} + +static int add_confdb_params(struct sss_test_conf_param params[], + struct confdb_ctx *cdb, const char *section) +{ + const char *val[2]; + int ret; + + val[1] = NULL; + + for (int i = 0; params[i].key; i++) { + val[0] = params[i].value; + ret = confdb_add_param(cdb, true, section, params[i].key, val); + assert_int_equal(ret, EOK); + } + + return EOK; +} + +static int add_ssh_params(struct sss_test_conf_param ssh_params[], + struct confdb_ctx *cdb) +{ + return add_confdb_params(ssh_params, cdb, CONFDB_SSH_CONF_ENTRY); +} + +static int add_monitor_params(struct sss_test_conf_param monitor_params[], + struct confdb_ctx *cdb) +{ + return add_confdb_params(monitor_params, cdb, CONFDB_MONITOR_CONF_ENTRY); +} + +void test_ssh_setup(struct sss_test_conf_param dom_params[], + struct sss_test_conf_param ssh_params[], + struct sss_test_conf_param monitor_params[], + void **state) +{ + struct cli_protocol *prctx; + errno_t ret; + + ssh_test_ctx = talloc_zero(NULL, struct ssh_test_ctx); + assert_non_null(ssh_test_ctx); + + ssh_test_ctx->tctx = create_dom_test_ctx(ssh_test_ctx, TESTS_PATH, + TEST_CONF_DB, TEST_DOM_NAME, + TEST_ID_PROVIDER, dom_params); + assert_non_null(ssh_test_ctx->tctx); + + ssh_test_ctx->ssh_cmds = get_ssh_cmds(); + assert_non_null(ssh_test_ctx->ssh_cmds); + + /* FIXME - perhaps this should be folded into sssd_domain_init or strictly + * used together + */ + ret = sss_names_init(ssh_test_ctx, ssh_test_ctx->tctx->confdb, + TEST_DOM_NAME, &ssh_test_ctx->tctx->dom->names); + assert_int_equal(ret, EOK); + + /* Initialize the SSH responder */ + ssh_test_ctx->ssh_ctx = mock_ssh_ctx(ssh_test_ctx); + assert_non_null(ssh_test_ctx->ssh_ctx); + + ssh_test_ctx->rctx = mock_rctx(ssh_test_ctx, ssh_test_ctx->tctx->ev, + ssh_test_ctx->tctx->dom, + ssh_test_ctx->ssh_ctx); + assert_non_null(ssh_test_ctx->rctx); + ssh_test_ctx->rctx->cdb = ssh_test_ctx->tctx->confdb; + ssh_test_ctx->ssh_ctx->rctx = ssh_test_ctx->rctx; + + ret = add_ssh_params(ssh_params, ssh_test_ctx->rctx->cdb); + assert_int_equal(ret, EOK); + + ret = add_monitor_params(monitor_params, ssh_test_ctx->rctx->cdb); + assert_int_equal(ret, EOK); + + /* Create client context */ + ssh_test_ctx->cctx = mock_cctx(ssh_test_ctx, ssh_test_ctx->rctx); + assert_non_null(ssh_test_ctx->cctx); + ssh_test_ctx->cctx->ev = ssh_test_ctx->tctx->ev; + + prctx = mock_prctx(ssh_test_ctx->cctx); + assert_non_null(prctx); + ssh_test_ctx->cctx->protocol_ctx = prctx; + prctx->cli_protocol_version = register_cli_protocol_version(); +} + +static void ssh_test_setup_common(void) +{ + errno_t ret; + + ssh_test_ctx->ssh_user_fqdn = \ + sss_create_internal_fqname(ssh_test_ctx, + "sshuser", + ssh_test_ctx->tctx->dom->name); + assert_non_null(ssh_test_ctx->ssh_user_fqdn); + + ssh_test_ctx->wrong_user_fqdn = \ + sss_create_internal_fqname(ssh_test_ctx, + "wrongsshuser", + ssh_test_ctx->tctx->dom->name); + assert_non_null(ssh_test_ctx->wrong_user_fqdn); + + /* Prime the cache with a valid user */ + ret = sysdb_add_user(ssh_test_ctx->tctx->dom, + ssh_test_ctx->ssh_user_fqdn, + 123, 456, "ssh user", + "/home/sshuser", "/bin/sh", NULL, + NULL, 300, 0); + assert_int_equal(ret, EOK); + + /* Prime the cache with a user for wrong matches */ + ret = sysdb_add_user(ssh_test_ctx->tctx->dom, + ssh_test_ctx->wrong_user_fqdn, + 321, 654, "wrong ssh user", + "/home/wrongsshuser", "/bin/sh", NULL, + NULL, 300, 0); + assert_int_equal(ret, EOK); +} + +static int ssh_test_setup(void **state) +{ + struct sss_test_conf_param dom_params[] = { + { "enumerate", "false" }, + { "cache_credentials", "true" }, + { NULL, NULL }, /* Sentinel */ + }; + + /* When run under valgrind with --trace-children=yes we have to increase + * the timeout not because p11_child needs much more time under valgrind + * but because of the way valgrind handles the children. */ + struct sss_test_conf_param ssh_params[] = { + { "p11_child_timeout", "40" }, + { NULL, NULL }, /* Sentinel */ + }; + + struct sss_test_conf_param monitor_params[] = { + { "certificate_verification", "no_ocsp"}, + { NULL, NULL }, /* Sentinel */ + }; + + test_ssh_setup(dom_params, ssh_params, monitor_params, state); + + ssh_test_setup_common(); + return 0; +} + +static int ssh_test_teardown(void **state) +{ + int ret; + + ret = sysdb_delete_user(ssh_test_ctx->tctx->dom, + ssh_test_ctx->ssh_user_fqdn, 0); + assert_int_equal(ret, EOK); + + ret = sysdb_delete_user(ssh_test_ctx->tctx->dom, + ssh_test_ctx->wrong_user_fqdn, 0); + assert_int_equal(ret, EOK); + + talloc_free(ssh_test_ctx); + return 0; +} + +typedef int (*cmd_cb_fn_t)(uint32_t, uint8_t *, size_t); + + +int __real_read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint8_t **buf, ssize_t *len); + +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; +} + +void __real_sss_packet_get_body(struct sss_packet *packet, + uint8_t **body, size_t *blen); + +void __wrap_sss_cmd_done(struct cli_ctx *cctx, void *freectx) +{ + struct cli_protocol *prctx; + struct sss_packet *packet; + uint8_t *body; + size_t blen; + cmd_cb_fn_t check_cb; + + prctx = talloc_get_type(cctx->protocol_ctx, struct cli_protocol); + packet = prctx->creq->out; + assert_non_null(packet); + + check_cb = sss_mock_ptr_type(cmd_cb_fn_t); + + __real_sss_packet_get_body(packet, &body, &blen); + + ssh_test_ctx->tctx->error = check_cb(sss_packet_get_status(packet), + body, blen); + ssh_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) +{ + ssh_test_ctx->tctx->done = true; + ssh_test_ctx->tctx->error = ENOENT; + return EOK; +} + +static void set_cmd_cb(cmd_cb_fn_t fn) +{ + will_return(__wrap_sss_cmd_done, fn); +} + +static void mock_input_user(TALLOC_CTX *mem_ctx, const char *username) +{ + uint8_t *buf; + size_t len = strlen(username); + size_t buf_len = len + 1 + 2 * sizeof(uint32_t); + + buf = talloc_size(mem_ctx, buf_len); + SAFEALIGN_SET_UINT32(&buf[0], 0, NULL); + SAFEALIGN_SET_UINT32(&buf[4], len + 1, NULL); + memcpy(&buf[8], username, len + 1); + + will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER); + will_return(__wrap_sss_packet_get_body, buf); + will_return(__wrap_sss_packet_get_body, buf_len); + mock_parse_inp("sshuser", TEST_DOM_NAME, EOK); +} + +static int test_ssh_user_no_pubkeys_check(uint32_t status, + uint8_t *body, size_t blen) +{ + uint32_t val; + + assert_int_equal(status, EOK); + assert_int_equal(blen, 8); + + SAFEALIGN_COPY_UINT32(&val, &body[0], NULL); + assert_int_equal(val, 0); + + SAFEALIGN_COPY_UINT32(&val, &body[4], NULL); + assert_int_equal(val, 0); + + return EOK; +} + +void test_ssh_user_no_pubkeys(void **state) { + int ret; + + mock_input_user(ssh_test_ctx, ssh_test_ctx->ssh_user_fqdn); + will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + set_cmd_cb(test_ssh_user_no_pubkeys_check); + ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS, + ssh_test_ctx->ssh_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(ssh_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +static int test_ssh_user_one_pubkey_check(uint32_t status, + uint8_t *body, size_t blen) +{ + uint32_t val; + size_t exp_len; + size_t name_len; + size_t key_len; + uint8_t *key; + size_t rp = 0; + + key = sss_base64_decode(ssh_test_ctx, TEST_SSH_PUBKEY, &key_len); + name_len = strlen(ssh_test_ctx->ssh_user_fqdn) + 1; + + exp_len = 5 * sizeof(uint32_t) + name_len + key_len; + + assert_int_equal(status, EOK); + assert_int_equal(blen, exp_len); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, 1); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, 0); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, 0); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, name_len); + + assert_memory_equal(body + rp, ssh_test_ctx->ssh_user_fqdn, name_len); + rp += name_len; + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, key_len); + + assert_memory_equal(body + rp, key, key_len); + rp += key_len; + + assert_int_equal(rp, blen); + + return EOK; +} + +void test_ssh_user_pubkey(void **state) +{ + int ret; + struct sysdb_attrs *attrs; + + attrs = sysdb_new_attrs(ssh_test_ctx); + assert_non_null(attrs); + ret = sysdb_attrs_add_string(attrs, SYSDB_SSH_PUBKEY, TEST_SSH_PUBKEY); + assert_int_equal(ret, EOK); + + ret = sysdb_set_user_attr(ssh_test_ctx->tctx->dom, + ssh_test_ctx->ssh_user_fqdn, + attrs, + LDB_FLAG_MOD_ADD); + talloc_free(attrs); + assert_int_equal(ret, EOK); + + mock_input_user(ssh_test_ctx, ssh_test_ctx->ssh_user_fqdn); + will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + set_cmd_cb(test_ssh_user_one_pubkey_check); + ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS, + ssh_test_ctx->ssh_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(ssh_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +void test_ssh_user_pubkey_cert_disabled(void **state) +{ + int ret; + struct sysdb_attrs *attrs; + + attrs = sysdb_new_attrs(ssh_test_ctx); + assert_non_null(attrs); + ret = sysdb_attrs_add_string(attrs, SYSDB_SSH_PUBKEY, TEST_SSH_PUBKEY); + assert_int_equal(ret, EOK); + ret = sysdb_attrs_add_string(attrs, SYSDB_USER_CERT, SSSD_TEST_CERT_0001); + assert_int_equal(ret, EOK); + ret = sysdb_attrs_add_string(attrs, SYSDB_USER_CERT, SSSD_TEST_CERT_0002); + assert_int_equal(ret, EOK); + + ret = sysdb_set_user_attr(ssh_test_ctx->tctx->dom, + ssh_test_ctx->ssh_user_fqdn, + attrs, + LDB_FLAG_MOD_ADD); + talloc_free(attrs); + assert_int_equal(ret, EOK); + + mock_input_user(ssh_test_ctx, ssh_test_ctx->ssh_user_fqdn); + will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + set_cmd_cb(test_ssh_user_one_pubkey_check); + ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS, + ssh_test_ctx->ssh_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(ssh_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + +static int test_ssh_user_pubkey_cert_check(uint32_t status, + uint8_t *body, size_t blen) +{ + uint32_t val; + size_t exp_len; + size_t name_len; + size_t key_len[3]; + uint8_t *key[3]; + size_t rp = 0; + size_t c; + + key[0] = sss_base64_decode(ssh_test_ctx, TEST_SSH_PUBKEY, &key_len[0]); + assert_non_null(key[0]); + + key[1] = sss_base64_decode(ssh_test_ctx, SSSD_TEST_CERT_SSH_KEY_0001, + &key_len[1]); + assert_non_null(key[1]); + + key[2] = sss_base64_decode(ssh_test_ctx, SSSD_TEST_CERT_SSH_KEY_0002, + &key_len[2]); + assert_non_null(key[2]); + + name_len = strlen(ssh_test_ctx->ssh_user_fqdn) + 1; + + exp_len = 2 * sizeof(uint32_t) + 3* 3* sizeof(uint32_t) + 3 * name_len + + key_len[0] + key_len[1] + key_len[2]; + + assert_int_equal(status, EOK); + assert_int_equal(blen, exp_len); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, 3); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, 0); + + for (c = 0; c < 3; c++) { + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, 0); + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, name_len); + + assert_memory_equal(body + rp, ssh_test_ctx->ssh_user_fqdn, name_len); + rp += name_len; + + SAFEALIGN_COPY_UINT32(&val, &body[rp], &rp); + assert_int_equal(val, key_len[c]); + + assert_memory_equal(body + rp, key[c], key_len[c]); + rp += key_len[c]; + } + + assert_int_equal(rp, blen); + + return EOK; +} + +void test_ssh_user_pubkey_cert(void **state) +{ + int ret; + struct sysdb_attrs *attrs; + + attrs = sysdb_new_attrs(ssh_test_ctx); + assert_non_null(attrs); + ret = sysdb_attrs_add_string(attrs, SYSDB_SSH_PUBKEY, TEST_SSH_PUBKEY); + assert_int_equal(ret, EOK); + ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT, + SSSD_TEST_CERT_0001); + assert_int_equal(ret, EOK); + ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT, + SSSD_TEST_CERT_0002); + assert_int_equal(ret, EOK); + + ret = sysdb_set_user_attr(ssh_test_ctx->tctx->dom, + ssh_test_ctx->ssh_user_fqdn, + attrs, + LDB_FLAG_MOD_ADD); + talloc_free(attrs); + assert_int_equal(ret, EOK); + + mock_input_user(ssh_test_ctx, ssh_test_ctx->ssh_user_fqdn); + will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Enable certificate support */ + ssh_test_ctx->ssh_ctx->use_cert_keys = true; + ssh_test_ctx->ssh_ctx->ca_db = discard_const("sql:" ABS_BUILD_DIR + "/src/tests/test_CA/p11_nssdb"); + + set_cmd_cb(test_ssh_user_pubkey_cert_check); + ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS, + ssh_test_ctx->ssh_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(ssh_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_ssh_user_no_pubkeys, + ssh_test_setup, ssh_test_teardown), + cmocka_unit_test_setup_teardown(test_ssh_user_pubkey, + ssh_test_setup, ssh_test_teardown), +#ifdef HAVE_TEST_CA + cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert_disabled, + ssh_test_setup, ssh_test_teardown), +#ifdef HAVE_NSS + cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert, + ssh_test_setup, ssh_test_teardown), +#endif +#endif + }; + + /* Set debug level to invalid value so we can decide 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; +}