summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2015-06-04 10:51:05 +0200
committerJakub Hrozek <jhrozek@redhat.com>2015-06-14 21:47:20 +0200
commit64ea4127f463798410a2c20e0261c6b15f60257f (patch)
tree35591187021deb529f91fb069b3cca7fb225ea71
parentf4025ea817b3467be1c2e6092014a11fe4547c0d (diff)
downloadsssd-64ea4127f463798410a2c20e0261c6b15f60257f.tar.gz
sssd-64ea4127f463798410a2c20e0261c6b15f60257f.tar.xz
sssd-64ea4127f463798410a2c20e0261c6b15f60257f.zip
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 Reviewed-by: Sumit Bose <sbose@redhat.com>
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac1
-rw-r--r--contrib/ci/sssd.supp18
-rw-r--r--contrib/sssd.spec.in1
-rw-r--r--src/conf_macros.m414
-rw-r--r--src/providers/ipa/ipa_subdomains.h5
-rw-r--r--src/providers/ipa/ipa_subdomains_server.c425
-rw-r--r--src/tests/cmocka/test_ipa_subdomains_server.c172
-rw-r--r--src/util/util_errors.c2
-rw-r--r--src/util/util_errors.h2
10 files changed, 618 insertions, 26 deletions
diff --git a/Makefile.am b/Makefile.am
index 4eed1069b..ae44549ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2455,15 +2455,18 @@ 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,execle \
$(NULL)
test_ipa_subdom_server_LDADD = \
$(PAM_LIBS) \
$(CMOCKA_LIBS) \
$(SSSD_LIBS) \
$(CARES_LIBS) \
+ $(KEYUTILS_LIBS) \
$(KRB5_LIBS) \
$(SSSD_INTERNAL_LTLIBS) \
libsss_ldap_common.la \
@@ -3283,6 +3286,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 a127d0bd5..339dd8b68 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/ci/sssd.supp b/contrib/ci/sssd.supp
index b9d13cdd6..06cf64088 100644
--- a/contrib/ci/sssd.supp
+++ b/contrib/ci/sssd.supp
@@ -151,3 +151,21 @@
fun:poptGetNextOpt
fun:main
}
+
+# Some tests initialize c-ares context, then fork a child that just exits
+# without a proper teardown, which means the ares destructor is not called.
+# Suppress those errors.
+{
+ c-ares-suppress-leak-from-init
+ Memcheck:Leak
+ ...
+ fun:ares_init_options
+ fun:recreate_ares_channel
+ fun:resolv_init
+ fun:be_res_init
+ fun:be_init_failover
+ fun:test_ipa_server_create_trusts_setup
+ ...
+ fun:_cmocka_run_group_tests
+ fun:main
+}
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index d4b2a9300..bfee8f8c2 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 0ed1694cb..eeba01e1b 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 8dc3b78f3..281e975e7 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 6e43bbc2d..03a2c579e 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -34,6 +34,26 @@
#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_realm,
+ 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_realm);
+}
+
static uint32_t default_direction(TALLOC_CTX *mem_ctx,
struct ldb_context *ldb_ctx,
struct sysdb_attrs *attrs)
@@ -103,6 +123,11 @@ const char *ipa_trust_dir2str(uint32_t direction)
return "unknown";
}
+#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,
@@ -255,9 +280,234 @@ 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 *ccache,
+ 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 *ccache,
+ 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 = EFAULT;
+
+ if (server == NULL || principal == NULL || keytab == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Retrieving keytab for %s from %s into %s using ccache %s\n",
+ principal, server, keytab, ccache);
+
+ child_pid = fork();
+ if (child_pid == 0) { /* child */
+ ipa_getkeytab_exec(ccache, 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 *ccache,
+ const char *server,
+ const char *principal,
+ const char *keytab_path)
+{
+ errno_t ret;
+ int debug_fd;
+ const char *gkt_env[2] = { NULL, NULL };
+
+ 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 */
+ }
+ }
+
+ gkt_env[0] = talloc_asprintf(NULL, "KRB5CCNAME=%s", ccache);
+ if (gkt_env[0] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to format KRB5CCNAME\n");
+ exit(1);
+ }
+
+ errno = 0;
+ ret = execle(IPA_GETKEYTAB_PATH, IPA_GETKEYTAB_PATH,
+ "-r", "-s", server, "-p", principal, "-k", keytab_path, NULL,
+ gkt_env);
+
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "execle returned %d, this shouldn't happen!\n", ret);
+
+ /* The child should never end up here */
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "execle 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;
+
+ uint32_t direction;
+ const char *forest;
+ const char *keytab;
+ const char *principal;
+ const char *forest_realm;
+ const char *ccache;
};
+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,
@@ -267,42 +517,59 @@ 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) {
+ /* Trusts are only established with forest roots */
+ if (subdom->forest_root == NULL) {
DEBUG(SSSDBG_OP_FAILURE,
- "Cannot create ad_id_ctx for subdomain %s\n", subdom->name);
+ "Subdomain %s has no forest root?\n", subdom->name);
+ ret = ERR_TRUST_FOREST_UNKNOWN;
goto immediate;
}
- trust_ctx = talloc(id_ctx->server_mode, struct ipa_ad_server_ctx);
- if (trust_ctx == NULL) {
+ state->direction = subdom->forest_root->trust_direction;
+ state->forest = subdom->forest_root->realm;
+ state->forest_realm = subdom->forest_root->realm;
+ state->ccache = talloc_asprintf(state, "%s/ccache_%s",
+ DB_PATH, subdom->parent->realm);
+ if (state->ccache == NULL) {
ret = ENOMEM;
goto immediate;
}
- trust_ctx->dom = subdom;
- trust_ctx->ad_id_ctx = ad_id_ctx;
-
- DLIST_ADD(id_ctx->server_mode->trusts, trust_ctx);
- /* In this particular patch, we just want to fake the async interface
- * for an otherwise synchronous operation of creating two-way trusts,
- * so currently the request is just marked as done and terminated. We
- * will convert the request to fully async in a subsequent patch that
- * adds support for one-way trusts.
- */
- ret = EOK;
- goto immediate;
-
- return req;
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "Trust direction of subdom %s from forest %s is: %s\n",
+ subdom->name, state->forest,
+ ipa_trust_dir2str(state->direction));
+
+ if (state->direction & LSA_TRUST_DIRECTION_OUTBOUND) {
+ /* Use system keytab */
+ ret = ipa_server_trust_add_step(req);
+ } else if (state->direction & LSA_TRUST_DIRECTION_INBOUND) {
+ /* 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);
+ }
+ } else {
+ /* Even unset is an error at this point */
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Subdomain %s has trust direction %d\n",
+ subdom->name, subdom->trust_direction);
+ ret = ERR_TRUST_NOT_SUPPORTED;
+ }
immediate:
if (ret != EOK) {
@@ -314,6 +581,122 @@ immediate:
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_realm,
+ 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,
+ state->ccache,
+ 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) {
+ return ENOMEM;
+ }
+ trust_ctx->dom = state->subdom;
+ trust_ctx->ad_id_ctx = ad_id_ctx;
+
+ DLIST_ADD(state->id_ctx->server_mode->trusts, trust_ctx);
+ return EOK;
+}
+
static errno_t ipa_server_trust_add_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c
index 9ec5d720a..9d9c9dd8f 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_execle(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;
@@ -146,7 +170,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,
+ uint32_t direction)
{
errno_t
@@ -155,14 +180,14 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx)
SUBDOM_NAME, SUBDOM_REALM,
NULL, SUBDOM_SID,
true, false, SUBDOM_REALM,
- 0);
+ 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,
- 0);
+ direction);
assert_int_equal(ret, EOK);
ret = sysdb_update_subdomains(test_ctx->tctx->dom);
@@ -170,6 +195,16 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx)
}
+static void add_test_2way_subdomains(struct trust_test_ctx *test_ctx)
+{
+ return add_test_subdomains(test_ctx, 0x1 | 0x2);
+}
+
+static void add_test_1way_subdomains(struct trust_test_ctx *test_ctx)
+{
+ return add_test_subdomains(test_ctx, 0x1);
+}
+
static int test_ipa_server_create_trusts_setup(void **state)
{
errno_t ret;
@@ -186,6 +221,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);
@@ -215,6 +252,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;
}
@@ -254,7 +294,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_2way_subdomains(test_ctx);
req = ipa_server_create_trusts_send(test_ctx,
test_ctx->tctx->ev,
@@ -410,7 +450,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_2way_subdomains(test_ctx);
ret = ipa_ad_subdom_init(test_ctx->be_ctx, test_ctx->ipa_ctx);
assert_int_equal(ret, EOK);
@@ -557,6 +597,116 @@ static void test_get_trust_direction_notset_member(void **state)
assert_int_equal(dir, 0);
}
+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_1way_subdomains(test_ctx);
+
+ 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_1way_subdomains(test_ctx);
+
+ 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_1way_subdomains(test_ctx);
+
+ 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(0x00));
+ assert_non_null(ipa_trust_dir2str(0x01));
+ assert_non_null(ipa_trust_dir2str(0x02));
+ assert_non_null(ipa_trust_dir2str(0x80));
+}
+
int main(int argc, const char *argv[])
{
int rv;
@@ -569,6 +719,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 6bf3566f7..61818c9fc 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -76,6 +76,8 @@ struct err_string error_to_str[] = {
{ "Failed to resolve one of user groups" }, /* ERR_SIMPLE_GROUPS_MISSING */
{ "Home directory is NULL" }, /* ERR_HOMEDIR_IS_NULL */
{ "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 86f6fa13b..7e03f00e8 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -98,6 +98,8 @@ enum sssd_errors {
ERR_SIMPLE_GROUPS_MISSING,
ERR_HOMEDIR_IS_NULL,
ERR_TRUST_NOT_SUPPORTED,
+ ERR_IPA_GETKEYTAB_FAILED,
+ ERR_TRUST_FOREST_UNKNOWN,
ERR_LAST /* ALWAYS LAST */
};