# Automake makefile for krb5-sync.
#
# Written by Russ Allbery <rra@stanford.edu>
-# Copyright 2006, 2007, 2010, 2012
+# Copyright 2006, 2007, 2010, 2012, 2013
# The Board of Trustees of the Leland Stanford Junior University
#
# See LICENSE for licensing terms.
EXTRA_DIST = .gitignore LICENSE autogen patches/README \
patches/heimdal-1.3.1 patches/mit-krb5-1.4.4 patches/mit-krb5-1.8.3 \
tests/README tests/TESTS tests/data/empty.conf tests/data/krb5.conf \
- tests/docs/pod-spelling-t tests/docs/pod-t tests/tap/libtap.sh \
- tests/util/xmalloc-t tools/krb5-sync.pod
+ tests/data/queue.conf tests/docs/pod-spelling-t tests/docs/pod-t \
+ tests/tap/libtap.sh tests/util/xmalloc-t tools/krb5-sync.pod
AM_CPPFLAGS = $(KRB5_CPPFLAGS)
$(MAKE) V=0 CFLAGS='$(WARNINGS)' $(check_PROGRAMS)
# The bits below are for the test suite, not for the main package.
-check_PROGRAMS = tests/runtests tests/plugin/heimdal-t tests/plugin/mit-t \
- tests/plugin/queuing-t tests/portable/asprintf-t \
- tests/portable/snprintf-t tests/portable/strlcat-t \
- tests/portable/strlcpy-t tests/portable/strndup-t \
- tests/util/messages-krb5-t tests/util/messages-t tests/util/xmalloc
+check_PROGRAMS = tests/runtests tests/plugin/heimdal-t tests/plugin/mit-t \
+ tests/plugin/queue-only-t tests/plugin/queuing-t \
+ tests/portable/asprintf-t tests/portable/snprintf-t \
+ tests/portable/strlcat-t tests/portable/strlcpy-t \
+ tests/portable/strndup-t tests/util/messages-krb5-t \
+ tests/util/messages-t tests/util/xmalloc
check_LIBRARIES = tests/tap/libtap.a
tests_runtests_CPPFLAGS = -DSOURCE='"$(abs_top_srcdir)/tests"' \
-DBUILD='"$(abs_top_builddir)/tests"'
$(DL_LIBS)
tests_plugin_mit_t_LDADD = tests/tap/libtap.a portable/libportable.la \
$(DL_LIBS)
+tests_plugin_queue_only_t_SOURCES = tests/plugin/queue-only-t.c \
+ $(plugin_krb5_sync_la_SOURCES)
+tests_plugin_queue_only_t_CPPFLAGS = $(LDAP_CPPFLAGS) $(AM_CPPFLAGS)
+tests_plugin_queue_only_t_LDFLAGS = $(LDAP_LDFLAGS) $(KRB5_LDFLAGS)
+tests_plugin_queue_only_t_LDADD = tests/tap/libtap.a portable/libportable.la \
+ $(LDAP_LIBS) $(KRB5_LIBS)
tests_plugin_queuing_t_SOURCES = tests/plugin/queuing-t.c \
$(plugin_krb5_sync_la_SOURCES)
tests_plugin_queuing_t_CPPFLAGS = $(LDAP_CPPFLAGS) $(AM_CPPFLAGS)
* Written by Russ Allbery <rra@stanford.edu>
* Based on code developed by Derrick Brashear and Ken Hornstein of Sine
* Nomine Associates, on behalf of Stanford University.
- * Copyright 2006, 2007, 2010
+ * Copyright 2006, 2007, 2010, 2013
* The Board of Trustees of the Leland Stanford Junior University
*
* See LICENSE for licensing terms.
}
+/*
+ * Load a boolean option from Kerberos appdefaults, setting the default to
+ * false if the setting was not found.
+ */
+static void
+config_boolean(krb5_context ctx, const char *opt, bool *result)
+{
+ int tmp;
+
+ /*
+ * The MIT version of krb5_appdefault_boolean takes an int * and the
+ * Heimdal version takes a krb5_boolean *, so hope that Heimdal always
+ * defines krb5_boolean to int or this will require more portability work.
+ */
+ krb5_appdefault_boolean(ctx, "krb5-strength", NULL, opt, *result, &tmp);
+ *result = tmp;
+}
+
+
/*
* Initialize the module. This consists solely of loading our configuration
* options from krb5.conf into a newly allocated struct stored in the second
config_string(ctx, "ad_admin_server", &config->ad_admin_server);
config_string(ctx, "ad_ldap_base", &config->ad_ldap_base);
config_string(ctx, "ad_instances", &config->ad_instances);
+ config_boolean(ctx, "ad_queue_only", &config->ad_queue_only);
config_string(ctx, "queue_dir", &config->queue_dir);
*data = config;
return 0;
return 0;
if (pwupdate_queue_conflict(config, ctx, principal, "ad", "password"))
goto queue;
+ if (config->ad_queue_only)
+ goto queue;
status = pwupdate_ad_change(config, ctx, principal, password, pwlen,
errstr, errstrlen);
if (status == 3) {
return 0;
if (pwupdate_queue_conflict(config, ctx, principal, "ad", "enable"))
goto queue;
+ if (config->ad_queue_only)
+ goto queue;
status = pwupdate_ad_status(config, ctx, principal, enabled, errstr,
errstrlen);
if (status != 0)
--- /dev/null
+/*
+ * Tests for forced queuing in the krb5-sync plugin.
+ *
+ * Disable immediate changes and force queuing, and test that this works
+ * correctly.
+ *
+ * Written by Russ Allbery <eagle@eyrie.org>
+ * Copyright 2013
+ * The Board of Trustees of the Leland Stanford Junior University
+ *
+ * See LICENSE for licensing terms.
+ */
+
+#include <config.h>
+#include <portable/krb5.h>
+#include <portable/system.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <plugin/internal.h>
+#include <tests/tap/basic.h>
+#include <tests/tap/string.h>
+
+
+int
+main(void)
+{
+ char *tmpdir, *krb5conf, *env, *queue;
+ krb5_context ctx;
+ krb5_principal princ;
+ krb5_error_code code;
+ void *data;
+ char errstr[BUFSIZ], buffer[BUFSIZ];
+ time_t now, try;
+ struct tm *date;
+ FILE *file;
+ struct stat st;
+
+ tmpdir = test_tmpdir();
+ if (chdir(tmpdir) < 0)
+ sysbail("cannot cd to %s", tmpdir);
+ krb5conf = test_file_path("data/queue.conf");
+ if (krb5conf == NULL)
+ bail("cannot find tests/data/queue.conf");
+ if (mkdir("queue", 0777) < 0)
+ sysbail("cannot mkdir queue");
+ basprintf(&env, "KRB5_CONFIG=%s", krb5conf);
+ if (putenv(env) < 0)
+ sysbail("cannot set KRB5CCNAME");
+ code = krb5_init_context(&ctx);
+ if (code != 0)
+ bail("cannot create Kerberos context (%d)", (int) code);
+ code = krb5_parse_name(ctx, "test@EXAMPLE.COM", &princ);
+ if (code != 0)
+ bail("cannot parse principal: %s", krb5_get_error_message(ctx, code));
+
+ plan(26);
+
+ /* Test init. */
+ is_int(0, pwupdate_init(ctx, &data), "pwupdate_init succeeds");
+ ok(data != NULL, "...and data is non-NULL");
+
+ /* Create a password change and be sure it's queued. */
+ code = pwupdate_precommit_password(data, princ, "foobar", strlen("foobar"),
+ errstr, sizeof(errstr));
+ is_int(0, code, "pwupdate_precommit_password succeeds");
+ queue = NULL;
+ now = time(NULL);
+ for (try = now - 1; try <= now; try++) {
+ date = gmtime(&try);
+ basprintf(&queue,
+ "queue/test-ad-password-%04d%02d%02dT%02d%02d%02dZ-00",
+ date->tm_year + 1900, date->tm_mon + 1, date->tm_mday,
+ date->tm_hour, date->tm_min, date->tm_sec);
+ if (access(queue, F_OK) == 0)
+ break;
+ free(queue);
+ queue = NULL;
+ }
+ ok(queue != NULL, "...password change was queued");
+ if (queue == NULL)
+ ok_block(5, false, "No queued change to check");
+ else {
+ if (stat(queue, &st) < 0)
+ sysbail("cannot stat %s", queue);
+ is_int(0600, st.st_mode & 0777, "...mode of queue file is correct");
+ file = fopen(queue, "r");
+ if (file == NULL)
+ sysbail("cannot open %s", queue);
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("test\n", buffer, "...queued user is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("ad\n", buffer, "...queued domain is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("password\n", buffer, "...queued operation is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("foobar\n", buffer, "...queued password is correct");
+ fclose(file);
+ }
+ ok(unlink(queue) == 0, "Remove queued password change");
+ free(queue);
+
+ /* Test queuing of enable. */
+ errstr[0] = '\0';
+ code = pwupdate_postcommit_status(data, princ, 1, errstr, sizeof(errstr));
+ is_int(0, code, "pwupdate_postcommit_status enable succeeds");
+ is_string("", errstr, "...and there is no error");
+ queue = NULL;
+ now = time(NULL);
+ for (try = now - 1; try <= now; try++) {
+ date = gmtime(&try);
+ basprintf(&queue, "queue/test-ad-enable-%04d%02d%02dT%02d%02d%02dZ-00",
+ date->tm_year + 1900, date->tm_mon + 1, date->tm_mday,
+ date->tm_hour, date->tm_min, date->tm_sec);
+ if (access(queue, F_OK) == 0)
+ break;
+ free(queue);
+ queue = NULL;
+ }
+ ok(queue != NULL, "...enable was queued");
+ if (queue == NULL)
+ ok_block(3, false, "No queued change to check");
+ else {
+ file = fopen(queue, "r");
+ if (file == NULL)
+ sysbail("cannot open %s", queue);
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("test\n", buffer, "...queued user is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("ad\n", buffer, "...queued domain is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("enable\n", buffer, "...queued operation is correct");
+ fclose(file);
+ }
+ ok(unlink(queue) == 0, "Remove queued enable");
+
+ /* Test queuing of disable. */
+ errstr[0] = '\0';
+ code = pwupdate_postcommit_status(data, princ, 0, errstr, sizeof(errstr));
+ is_int(0, code, "pwupdate_postcommit_status disable succeeds");
+ is_string("", errstr, "...and there is no error");
+ queue = NULL;
+ now = time(NULL);
+ for (try = now - 1; try <= now; try++) {
+ date = gmtime(&try);
+ basprintf(&queue, "queue/test-ad-enable-%04d%02d%02dT%02d%02d%02dZ-00",
+ date->tm_year + 1900, date->tm_mon + 1, date->tm_mday,
+ date->tm_hour, date->tm_min, date->tm_sec);
+ if (access(queue, F_OK) == 0)
+ break;
+ free(queue);
+ queue = NULL;
+ }
+ ok(queue != NULL, "...enable was queued");
+ if (queue == NULL)
+ ok_block(3, false, "No queued change to check");
+ else {
+ file = fopen(queue, "r");
+ if (file == NULL)
+ sysbail("cannot open %s", queue);
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("test\n", buffer, "...queued user is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("ad\n", buffer, "...queued domain is correct");
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ buffer[0] = '\0';
+ is_string("disable\n", buffer, "...queued operation is correct");
+ fclose(file);
+ }
+ ok(unlink(queue) == 0, "Remove queued disable");
+ free(queue);
+
+ /* Unwind the queue and be sure all the right files exist. */
+ ok(unlink("queue/.lock") == 0, "Lock file still exists");
+ ok(rmdir("queue") == 0, "No other files in queue directory");
+
+ /* Shut down the plugin. */
+ pwupdate_close(data);
+
+ /* Clean up. */
+ krb5_free_principal(ctx, princ);
+ krb5_free_context(ctx);
+ test_file_path_free(krb5conf);
+ if (chdir("..") < 0)
+ sysbail("cannot chdir to parent directory");
+ test_tmpdir_free(tmpdir);
+ free(env);
+ return 0;
+}