>From 42b7e7ce5b1d5877480cf15e720a8dbc654f3f0e Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 4 Jun 2015 10:51:05 +0200 Subject: [PATCH 20/29] IPA: Fetch keytab for 1way trusts Uses the ipa-getkeytab call to retrieve keytabs for one-way trust relationships. https://fedorahosted.org/sssd/ticket/2636 --- Makefile.am | 3 + configure.ac | 1 + contrib/sssd.spec.in | 1 + src/conf_macros.m4 | 14 + src/providers/ipa/ipa_subdomains.h | 5 + src/providers/ipa/ipa_subdomains_server.c | 410 ++++++++++++++++++++++++-- src/tests/cmocka/test_ipa_subdomains_server.c | 162 +++++++++- src/util/util_errors.c | 2 + src/util/util_errors.h | 2 + 9 files changed, 571 insertions(+), 29 deletions(-) diff --git a/Makefile.am b/Makefile.am index 4eed1069b982d35b4dc27ea5cfad7c2dad291097..bdb5c8a4f827034397545308deb546367242709a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2455,9 +2455,11 @@ test_ipa_subdom_server_SOURCES = \ test_ipa_subdom_server_CFLAGS = \ $(AM_CFLAGS) \ -DUNIT_TESTING \ + -DIPA_TRUST_KEYTAB_DIR=TEST_DIR \ $(NULL) test_ipa_subdom_server_LDFLAGS = \ -Wl,-wrap,krb5_kt_default \ + -Wl,-wrap,execl \ $(NULL) test_ipa_subdom_server_LDADD = \ $(PAM_LIBS) \ @@ -3283,6 +3285,7 @@ src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile SSSD_USER_DIRS = \ $(DESTDIR)$(dbpath) \ + $(DESTDIR)$(dbpath)/keytabs \ $(DESTDIR)$(mcpath) \ $(DESTDIR)$(pipepath) \ $(DESTDIR)$(pipepath)/private \ diff --git a/configure.ac b/configure.ac index a127d0bd57ee4149f664e193a65271d50d95f83b..339dd8b68056e747244a90897c742a31366721a1 100644 --- a/configure.ac +++ b/configure.ac @@ -122,6 +122,7 @@ WITH_PYTHON3_BINDINGS WITH_CIFS_PLUGIN_PATH WITH_SELINUX WITH_NSCD +WITH_IPA_GETKEYTAB WITH_SEMANAGE WITH_AD_GPO_DEFAULT WITH_GPO_CACHE_PATH diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index d4b2a93000ffa03cb135a4595a9669d008313836..bfee8f8c2a2174e269b194b58f17ddfce2d4ffa1 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -765,6 +765,7 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root,-) %doc COPYING %attr(755,root,root) %dir %{pubconfpath}/krb5.include.d +%attr(700,sssd,sssd) %dir %{dbpath}/keytabs %{_libdir}/%{name}/libsss_ipa.so %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child %{_mandir}/man5/sssd-ipa.5* diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 index 0ed1694cb6b8ebf54fc4488826fbb64b050fa3bb..eeba01e1b81ceb70766544ef2d3c004e8595658d 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 @@ -424,6 +424,20 @@ AC_DEFUN([WITH_TEST_DIR], AC_DEFINE_UNQUOTED(TEST_DIR, "$TEST_DIR", [Directory used for 'make check' temporary files]) ]) +AC_DEFUN([WITH_IPA_GETKEYTAB], + [ AC_ARG_WITH([ipa_getkeytab], + [AC_HELP_STRING([--with-ipa-getkeytab=PATH], + [Path to ipa_getkeytab binary to retrieve keytabs from FreeIPA server [/usr/sbin/ipa-getkeytab]] + ) + ] + ) + IPA_GETKEYTAB_PATH="/usr/sbin/ipa-getkeytab" + if test x"$with_ipa_getkeytab" != x; then + IPA_GETKEYTAB_PATH=$with_ipa_getkeytab + fi + AC_DEFINE_UNQUOTED(IPA_GETKEYTAB_PATH, "$IPA_GETKEYTAB_PATH", [The path to the ipa-getkeytab utility]) + ]) + AC_DEFUN([WITH_NSCD], [ AC_ARG_WITH([nscd], [AC_HELP_STRING([--with-nscd=PATH], diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h index a2acb7887cf4156fd20944fcc82df320ae588e98..a4da5af06fec0a3c60e00f04213425da802ae8b8 100644 --- a/src/providers/ipa/ipa_subdomains.h +++ b/src/providers/ipa/ipa_subdomains.h @@ -27,6 +27,11 @@ #include "providers/dp_backend.h" #include "providers/ipa/ipa_common.h" +#include "config.h" + +#ifndef IPA_TRUST_KEYTAB_DIR +#define IPA_TRUST_KEYTAB_DIR DB_PATH"/keytabs" +#endif /* IPA_TRUST_KEYTAB_DIR */ /* ==Sid2Name Extended Operation============================================= */ #define EXOP_SID2NAME_OID "2.16.840.1.113730.3.8.10.4" diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c index e9d1184a32000a0b8f411ad5fc77ef952c601ddd..eb4867c2665084ac17472b3370ef3007a9140607 100644 --- a/src/providers/ipa/ipa_subdomains_server.c +++ b/src/providers/ipa/ipa_subdomains_server.c @@ -31,6 +31,25 @@ #define LSA_TRUST_DIRECTION_INBOUND 0x00000001 #define LSA_TRUST_DIRECTION_OUTBOUND 0x00000002 +static char *forest_keytab(TALLOC_CTX *mem_ctx, const char *forest) +{ + return talloc_asprintf(mem_ctx, + "%s/%s.keytab", IPA_TRUST_KEYTAB_DIR, forest); +} + +static char *subdomain_trust_princ(TALLOC_CTX *mem_ctx, + const char *forest, + struct sss_domain_info *sd) +{ + if (sd->parent->flat_name == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Unknown flat name for parent %s\n", sd->parent->name); + return NULL; + } + + return talloc_asprintf(mem_ctx, "%s$@%s", sd->parent->flat_name, forest); +} + static enum trust_direction default_direction(TALLOC_CTX *mem_ctx, struct ldb_context *ldb_ctx, struct sysdb_attrs *attrs) @@ -105,6 +124,11 @@ const char *ipa_trust_dir2str(enum trust_direction direction) } } +#ifndef IPA_GETKEYTAB_TIMEOUT +#define IPA_GETKEYTAB_TIMEOUT 5 +#endif /* IPA_GETKEYTAB_TIMEOUT */ + + static errno_t ipa_ad_ctx_new(struct be_ctx *be_ctx, struct ipa_id_ctx *id_ctx, @@ -253,9 +277,218 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, return EOK; } +struct ipa_getkeytab_state { + int child_status; + struct sss_child_ctx_old *child_ctx; + struct tevent_timer *timeout_handler; +}; + +static void ipa_getkeytab_exec(const char *server, + const char *principal, + const char *keytab_path); +static void ipa_getkeytab_done(int child_status, + struct tevent_signal *sige, + void *pvt); +static void ipa_getkeytab_timeout(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *pvt); + +static struct tevent_req *ipa_getkeytab_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *server, + const char *principal, + const char *keytab) + + +{ + errno_t ret; + struct tevent_req *req = NULL; + struct ipa_getkeytab_state *state; + pid_t child_pid; + struct timeval tv; + + req = tevent_req_create(mem_ctx, &state, struct ipa_getkeytab_state); + if (req == NULL) { + return NULL; + } + state->child_status = 0; + + if (server == NULL || principal == NULL || keytab == NULL) { + ret = EINVAL; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Retrieving keytab for %s from %s into %s\n", + principal, server, keytab); + + child_pid = fork(); + if (child_pid == 0) { /* child */ + ipa_getkeytab_exec(server, principal, keytab); + } else if (child_pid > 0) { /* parent */ + /* Set up SIGCHLD handler */ + ret = child_handler_setup(ev, child_pid, ipa_getkeytab_done, req, + &state->child_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n", + ret, sss_strerror(ret)); + ret = ERR_IPA_GETKEYTAB_FAILED; + goto done; + } + + /* Set up timeout handler */ + tv = tevent_timeval_current_ofs(IPA_GETKEYTAB_TIMEOUT, 0); + state->timeout_handler = tevent_add_timer(ev, req, tv, + ipa_getkeytab_timeout, req); + if(state->timeout_handler == NULL) { + ret = ERR_IPA_GETKEYTAB_FAILED; + goto done; + } + + /* Now either wait for the timeout to fire or the child + * to finish + */ + } else { /* error */ + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "fork failed [%d][%s].\n", ret, sss_strerror(ret)); + goto done; + } + + ret = EOK; +done: + if (ret != EOK) { + tevent_req_error(req, ret); + tevent_req_post(req, ev); + } + return req; +} + +static void ipa_getkeytab_exec(const char *server, + const char *principal, + const char *keytab_path) +{ + errno_t ret; + int debug_fd; + + if (debug_level >= SSSDBG_TRACE_LIBS) { + debug_fd = get_fd_from_debug_file(); + ret = dup2(debug_fd, STDERR_FILENO); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, + "dup2 failed [%d][%s].\n", ret, sss_strerror(ret)); + /* stderr is not fatal */ + } + } + + errno = 0; + execl(IPA_GETKEYTAB_PATH, IPA_GETKEYTAB_PATH, + "-r", "-s", server, "-p", principal, "-k", keytab_path, NULL); + + /* The child should never end up here */ + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "execv failed [%d][%s].\n", ret, sss_strerror(ret)); + exit(1); +} + +static void ipa_getkeytab_done(int child_status, + struct tevent_signal *sige, + void *pvt) +{ + struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); + struct ipa_getkeytab_state *state = + tevent_req_data(req, struct ipa_getkeytab_state); + + state->child_status = child_status; + + if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) { + DEBUG(SSSDBG_OP_FAILURE, + "ipa-getkeytab failed with status [%d]\n", child_status); + tevent_req_error(req, ERR_IPA_GETKEYTAB_FAILED); + return; + } + + if (WIFSIGNALED(child_status)) { + DEBUG(SSSDBG_OP_FAILURE, + "ipa-getkeytab was terminated by signal [%d]\n", + WTERMSIG(child_status)); + tevent_req_error(req, ERR_IPA_GETKEYTAB_FAILED); + return; + } + + tevent_req_done(req); +} + +static void ipa_getkeytab_timeout(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *pvt) +{ + struct tevent_req *req = + talloc_get_type(pvt, struct tevent_req); + struct ipa_getkeytab_state *state = + tevent_req_data(req, struct ipa_getkeytab_state); + + DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for retrieving keytab from IPA server\n"); + child_handler_destroy(state->child_ctx); + state->child_ctx = NULL; + state->child_status = ETIMEDOUT; + tevent_req_error(req, ERR_IPA_GETKEYTAB_FAILED); +} + +static errno_t ipa_getkeytab_recv(struct tevent_req *req, int *child_status) +{ + struct ipa_getkeytab_state *state = + tevent_req_data(req, struct ipa_getkeytab_state); + + DEBUG(SSSDBG_TRACE_INTERNAL, + "ipa-getkeytab status %d\n", state->child_status); + if (child_status) { + *child_status = state->child_status; + } + + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + +static errno_t ipa_check_keytab(const char *keytab) +{ + errno_t ret; + + ret = check_file(keytab, getuid(), getgid(), S_IFREG|0600, 0, NULL, false); + if (ret != EOK) { + if (ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to check for %s\n", keytab); + } else { + DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab); + } + goto done; + } + + DEBUG(SSSDBG_TRACE_ALL, "keytab %s already exists\n", keytab); + ret = EOK; +done: + return ret; +} + struct ipa_server_trust_add_state { + struct tevent_context *ev; + struct be_ctx *be_ctx; + struct ipa_id_ctx *id_ctx; + struct sss_domain_info *subdom; + + enum trust_direction direction; + const char *forest; + const char *keytab; + const char *principal; }; +static errno_t ipa_server_trust_add_1way(struct tevent_req *req); +static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq); +static errno_t ipa_server_trust_add_step(struct tevent_req *req); + static struct tevent_req * ipa_server_trust_add_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -265,44 +498,173 @@ ipa_server_trust_add_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req = NULL; struct ipa_server_trust_add_state *state = NULL; - struct ipa_ad_server_ctx *trust_ctx; - struct ad_id_ctx *ad_id_ctx; errno_t ret; req = tevent_req_create(mem_ctx, &state, struct ipa_server_trust_add_state); if (req == NULL) { return NULL; } + state->ev = ev; + state->be_ctx = be_ctx; + state->id_ctx = id_ctx; + state->subdom = subdom; - ret = ipa_ad_ctx_new(be_ctx, id_ctx, subdom, &ad_id_ctx); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Cannot create ad_id_ctx for subdomain %s\n", subdom->name); + /* Trusts are only established with forest roots */ + if (subdom->forest_root == NULL) { + ret = ERR_TRUST_FOREST_UNKNOWN; goto immediate; } - trust_ctx = talloc(id_ctx->server_mode, struct ipa_ad_server_ctx); + state->direction = subdom->forest_root->trust_direction; + state->forest = subdom->forest_root->realm; + + DEBUG(SSSDBG_TRACE_LIBS, + "Trust direction of subdom %s from forest %s is: %s\n", + subdom->name, state->forest, + ipa_trust_dir2str(state->direction)); + + switch (state->direction) { + case SD_TRUST_DIRECTION_OUTBOUND: + /* Need special keytab */ + ret = ipa_server_trust_add_1way(req); + if (ret == EAGAIN) { + /* In progress.. */ + return req; + } else if (ret == EOK) { + ret = ipa_server_trust_add_step(req); + } + break; + case SD_TRUST_DIRECTION_TWOWAY: + /* Use system keytab */ + ret = ipa_server_trust_add_step(req); + break; + default: + /* Even unset is an error at this point */ + ret = ERR_TRUST_NOT_SUPPORTED; + break; + } + +immediate: + if (ret != EOK) { + tevent_req_error(req, ret); + } else { + tevent_req_done(req); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ipa_server_trust_add_1way(struct tevent_req *req) +{ + errno_t ret; + struct tevent_req *subreq = NULL; + struct ipa_server_trust_add_state *state = + tevent_req_data(req, struct ipa_server_trust_add_state); + const char *hostname; + + state->keytab = forest_keytab(state, state->forest); + if (state->keytab == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n"); + return EIO; + } + + ret = ipa_check_keytab(state->keytab); + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_FUNC, + "Keytab already present, can add the trust\n"); + return EOK; + } else if (ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to check for keytab: %d\n", ret); + return ret; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "No keytab for %s\n", state->subdom->name); + + hostname = dp_opt_get_string(state->id_ctx->ipa_options->basic, + IPA_HOSTNAME); + + state->principal = subdomain_trust_princ(state, state->forest, state->subdom); + if (state->principal == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n"); + return EIO; + } + + subreq = ipa_getkeytab_send(state->be_ctx, state->be_ctx->ev, + hostname, + state->principal, + state->keytab); + if (subreq == NULL) { + return ENOMEM; + } + tevent_req_set_callback(subreq, ipa_server_trust_1way_kt_done, req); + return EAGAIN; +} + +static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_server_trust_add_state *state = + tevent_req_data(req, struct ipa_server_trust_add_state); + + ret = ipa_getkeytab_recv(subreq, NULL); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_getkeytab_recv failed: %d\n", ret); + tevent_req_error(req, ret); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Keytab successfully retrieved to %s\n", state->keytab); + + ret = ipa_check_keytab(state->keytab); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_check_keytab failed: %d\n", ret); + tevent_req_error(req, ret); + return; + } + + ret = ipa_server_trust_add_step(req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "ipa_server_trust_add_step failed: %d\n", ret); + tevent_req_error(req, ret); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Established trust context for %s\n", state->subdom->name); + tevent_req_done(req); +} + +static errno_t ipa_server_trust_add_step(struct tevent_req *req) +{ + struct ipa_ad_server_ctx *trust_ctx; + struct ad_id_ctx *ad_id_ctx; + errno_t ret; + struct ipa_server_trust_add_state *state = + tevent_req_data(req, struct ipa_server_trust_add_state); + + ret = ipa_ad_ctx_new(state->be_ctx, state->id_ctx, state->subdom, &ad_id_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot create ad_id_ctx for subdomain %s\n", state->subdom->name); + return ret; + } + + trust_ctx = talloc(state->id_ctx->server_mode, struct ipa_ad_server_ctx); if (trust_ctx == NULL) { - ret = ENOMEM; - goto immediate; + return ENOMEM; } - trust_ctx->dom = subdom; + trust_ctx->dom = state->subdom; trust_ctx->ad_id_ctx = ad_id_ctx; - DLIST_ADD(id_ctx->server_mode->trusts, trust_ctx); - ret = EOK; - goto immediate; - - return req; - -immediate: - if (ret != EOK) { - tevent_req_error(req, ret); - } else { - tevent_req_done(req); - } - tevent_req_post(req, ev); - return req; + DLIST_ADD(state->id_ctx->server_mode->trusts, trust_ctx); + return EOK; } static errno_t ipa_server_trust_add_recv(struct tevent_req *req) diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c index 279784cfc3639a76cd72bd3669fa040e7ba9e6a3..96a0c3621c8234e3356e8aae2b9b7ecbf01edd9e 100644 --- a/src/tests/cmocka/test_ipa_subdomains_server.c +++ b/src/tests/cmocka/test_ipa_subdomains_server.c @@ -41,6 +41,7 @@ #define DOM_REALM "DOM.MAIN" #define HOSTNAME "ipaserver.dom.main" +#define DOM_FLAT "DOM" #define TEST_AUTHID "host/"HOSTNAME #define KEYTAB_TEST_PRINC TEST_AUTHID"@"DOM_REALM @@ -61,11 +62,34 @@ #define TEST_DOM_NAME "ipa_subdom_server_test" #define TEST_ID_PROVIDER "ipa" +#define ONEWAY_KEYTAB TEST_DIR"/"SUBDOM_REALM".keytab" +#define ONEWAY_AUTHID DOM_FLAT"$@"SUBDOM_REALM + krb5_error_code __wrap_krb5_kt_default(krb5_context context, krb5_keytab *id) { return krb5_kt_resolve(context, KEYTAB_PATH, id); } +static void create_dummy_keytab(void) +{ + int fd; + errno_t ret; + + assert_non_null(ONEWAY_KEYTAB); + fd = open(ONEWAY_KEYTAB, O_WRONLY | O_CREAT | O_TRUNC, 0600); + assert_int_not_equal(fd, -1); + close(fd); + + ret = access(ONEWAY_KEYTAB, R_OK); + assert_int_equal(ret, 0); +} + +int __wrap_execl(const char *path, const char *arg, ...) +{ + create_dummy_keytab(); + _exit(0); +} + struct trust_test_ctx { struct sss_test_ctx *tctx; struct be_ctx *be_ctx; @@ -140,7 +164,8 @@ static struct ipa_server_mode_ctx *mock_server_mode(TALLOC_CTX *mem_ctx) return server_mode; } -static void add_test_subdomains(struct trust_test_ctx *test_ctx) +static void add_test_subdomains(struct trust_test_ctx *test_ctx, + enum trust_direction direction) { errno_t @@ -149,14 +174,14 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx) SUBDOM_NAME, SUBDOM_REALM, NULL, SUBDOM_SID, true, false, SUBDOM_REALM, - SD_TRUST_DIRECTION_TWOWAY); + direction); assert_int_equal(ret, EOK); ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, CHILD_NAME, CHILD_REALM, CHILD_FLAT, CHILD_SID, true, false, SUBDOM_REALM, - SD_TRUST_DIRECTION_TWOWAY); + direction); assert_int_equal(ret, EOK); ret = sysdb_update_subdomains(test_ctx->tctx->dom); @@ -180,6 +205,8 @@ static int test_ipa_server_create_trusts_setup(void **state) TEST_CONF_DB, TEST_DOM_NAME, TEST_ID_PROVIDER, params); assert_non_null(test_ctx->tctx); + test_ctx->tctx->dom->flat_name = discard_const(DOM_FLAT); + test_ctx->tctx->dom->realm = discard_const(DOM_REALM); test_ctx->be_ctx = mock_be_ctx(test_ctx, test_ctx->tctx); assert_non_null(test_ctx->be_ctx); @@ -209,6 +236,9 @@ static int test_ipa_server_create_trusts_teardown(void **state) ret = unlink(KEYTAB_PATH); assert_int_equal(ret, 0); + unlink(ONEWAY_KEYTAB); + /* Ignore failures */ + talloc_free(test_ctx); return 0; } @@ -248,7 +278,7 @@ static void test_ipa_server_create_trusts_none(struct tevent_req *req) assert_int_equal(ret, EOK); /* Add two subdomains */ - add_test_subdomains(test_ctx); + add_test_subdomains(test_ctx, SD_TRUST_DIRECTION_TWOWAY); req = ipa_server_create_trusts_send(test_ctx, test_ctx->tctx->ev, @@ -404,7 +434,7 @@ static void test_ipa_server_trust_init(void **state) struct tevent_timer *timeout_handler; struct timeval tv; - add_test_subdomains(test_ctx); + add_test_subdomains(test_ctx, SD_TRUST_DIRECTION_TWOWAY); ret = ipa_ad_subdom_init(test_ctx->be_ctx, test_ctx->ipa_ctx); assert_int_equal(ret, EOK); @@ -553,6 +583,116 @@ static void test_get_trust_direction_notset_member(void **state) assert_int_equal(dir, SD_TRUST_DIRECTION_NOT_SET); } +static void test_ipa_server_create_trusts_oneway(struct tevent_req *req); + +static void test_ipa_server_create_oneway(void **state) +{ + struct trust_test_ctx *test_ctx = + talloc_get_type(*state, struct trust_test_ctx); + struct tevent_req *req; + errno_t ret; + + add_test_subdomains(test_ctx, SD_TRUST_DIRECTION_OUTBOUND); + + ret = access(ONEWAY_KEYTAB, R_OK); + assert_int_not_equal(ret, 0); + + assert_null(test_ctx->ipa_ctx->server_mode->trusts); + + req = ipa_server_create_trusts_send(test_ctx, + test_ctx->tctx->ev, + test_ctx->be_ctx, + test_ctx->ipa_ctx, + test_ctx->be_ctx->domain); + assert_non_null(req); + + tevent_req_set_callback(req, test_ipa_server_create_trusts_oneway, test_ctx); + + ret = test_ev_loop(test_ctx->tctx); + assert_int_equal(ret, ERR_OK); +} + +static void test_ipa_server_create_trusts_oneway(struct tevent_req *req) +{ + struct trust_test_ctx *test_ctx = \ + tevent_req_callback_data(req, struct trust_test_ctx); + errno_t ret; + + ret = ipa_server_create_trusts_recv(req); + talloc_zfree(req); + assert_int_equal(ret, EOK); + + ret = access(ONEWAY_KEYTAB, R_OK); + assert_int_equal(ret, 0); + + /* Trust object should be around now */ + assert_non_null(test_ctx->ipa_ctx->server_mode->trusts); + assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next); + + test_ipa_server_create_trusts_finish(test_ctx); +} + +static void test_ipa_server_create_oneway_kt_exists(void **state) +{ + struct trust_test_ctx *test_ctx = + talloc_get_type(*state, struct trust_test_ctx); + struct tevent_req *req; + errno_t ret; + + add_test_subdomains(test_ctx, SD_TRUST_DIRECTION_OUTBOUND); + + create_dummy_keytab(); + ret = access(ONEWAY_KEYTAB, R_OK); + assert_int_equal(ret, 0); + + assert_null(test_ctx->ipa_ctx->server_mode->trusts); + + req = ipa_server_create_trusts_send(test_ctx, + test_ctx->tctx->ev, + test_ctx->be_ctx, + test_ctx->ipa_ctx, + test_ctx->be_ctx->domain); + assert_non_null(req); + + tevent_req_set_callback(req, test_ipa_server_create_trusts_oneway, test_ctx); + + ret = test_ev_loop(test_ctx->tctx); + assert_int_equal(ret, ERR_OK); +} + +static void test_ipa_server_trust_oneway_init(void **state) +{ + struct trust_test_ctx *test_ctx = + talloc_get_type(*state, struct trust_test_ctx); + errno_t ret; + struct tevent_timer *timeout_handler; + struct timeval tv; + + add_test_subdomains(test_ctx, SD_TRUST_DIRECTION_OUTBOUND); + + ret = ipa_ad_subdom_init(test_ctx->be_ctx, test_ctx->ipa_ctx); + assert_int_equal(ret, EOK); + + tv = tevent_timeval_current_ofs(1, 0); + timeout_handler = tevent_add_timer(test_ctx->tctx->ev, test_ctx, tv, + ipa_server_init_done, test_ctx); + assert_non_null(timeout_handler); + + ret = test_ev_loop(test_ctx->tctx); + assert_int_equal(ret, ERR_OK); + + assert_non_null(test_ctx->ipa_ctx->server_mode->trusts); +} + +static void test_ipa_trust_dir2str(void **state) +{ + /* Just make sure the caller can rely on getting a valid string.. */ + assert_non_null(ipa_trust_dir2str(SD_TRUST_DIRECTION_NOT_SET)); + assert_non_null(ipa_trust_dir2str(SD_TRUST_DIRECTION_OUTBOUND)); + assert_non_null(ipa_trust_dir2str(SD_TRUST_DIRECTION_TWOWAY)); + assert_non_null(ipa_trust_dir2str(999)); +} + int main(int argc, const char *argv[]) { int rv; @@ -565,6 +705,18 @@ int main(int argc, const char *argv[]) }; const struct CMUnitTest tests[] = { + cmocka_unit_test(test_ipa_trust_dir2str), + + cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway, + test_ipa_server_create_trusts_setup, + test_ipa_server_create_trusts_teardown), + cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_exists, + test_ipa_server_create_trusts_setup, + test_ipa_server_create_trusts_teardown), + cmocka_unit_test_setup_teardown(test_ipa_server_trust_oneway_init, + test_ipa_server_create_trusts_setup, + test_ipa_server_create_trusts_teardown), + cmocka_unit_test_setup_teardown(test_ipa_server_trust_init, test_ipa_server_create_trusts_setup, test_ipa_server_create_trusts_teardown), diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 2323d2f0ede9ad9c1f3246cde7c286aeef211449..9d94fb624e21568f33d8979b04244fc83c1b918c 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -75,6 +75,8 @@ struct err_string error_to_str[] = { { "Unexpected cache entry type" }, /* ERR_UNEXPECTED_ENTRY_TYPE */ { "Failed to resolve one of user groups" }, /* ERR_SIMPLE_GROUPS_MISSING */ { "Unsupported trust direction" }, /* ERR_TRUST_NOT_SUPPORTED */ + { "Retrieving keytab failed" }, /* ERR_IPA_GETKEYTAB_FAILED */ + { "Trusted forest root unknown" }, /* ERR_TRUST_FOREST_UNKNOWN */ { "ERR_LAST" } /* ERR_LAST */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index 154006fa124ce1eab6fa3034586af0c60d03be1f..35a730bed98fb8e482cbd94443c93e67bdb50d71 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -97,6 +97,8 @@ enum sssd_errors { ERR_UNEXPECTED_ENTRY_TYPE, ERR_SIMPLE_GROUPS_MISSING, ERR_TRUST_NOT_SUPPORTED, + ERR_IPA_GETKEYTAB_FAILED, + ERR_TRUST_FOREST_UNKNOWN, ERR_LAST /* ALWAYS LAST */ }; -- 2.1.0