1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
/*
* Tests for queuing behavior in the krb5-sync plugin.
*
* It's difficult to test actions that make actual LDAP or set_password calls,
* since one then needs an Active Directory test environment to point at. But
* we can test all plugin behavior that involves queuing, by forcing changes
* to queue.
*
* Written by Russ Allbery <eagle@eyrie.org>
* Copyright 2012, 2013
* The Board of Trustees of the Leland Stanford Junior University
*
* See LICENSE for licensing terms.
*/
#include <config.h>
#include <portable/kadmin.h>
#include <portable/krb5.h>
#include <portable/system.h>
#include <errno.h>
#include <sys/stat.h>
#include <plugin/internal.h>
#include <tests/tap/basic.h>
#include <tests/tap/kerberos.h>
#include <tests/tap/string.h>
#include <tests/tap/sync.h>
int
main(void)
{
char *path, *tmpdir, *krb5_config, *old_krb5_config;
krb5_context ctx;
krb5_principal princ;
krb5_error_code code;
kadm5_hook_modinfo *data;
const char *message;
char *wanted;
/* Define the plan. */
plan(47);
/* Set up a temporary directory and queue relative to it. */
tmpdir = test_tmpdir();
if (chdir(tmpdir) < 0)
sysbail("cannot cd to %s", tmpdir);
if (mkdir("queue", 0777) < 0)
sysbail("cannot mkdir queue");
/* Point KRB5_CONFIG at the correct krb5.conf file. */
path = test_file_path("data/krb5.conf");
if (path == NULL)
bail("cannot find data/krb5.conf in the test suite");
basprintf(&krb5_config, "KRB5_CONFIG=%s", path);
if (putenv(krb5_config) < 0)
sysbail("cannot set KRB5_CONFIG in the environment");
/* Obtain a new Kerberos context with that krb5.conf file. */
code = krb5_init_context(&ctx);
if (code != 0)
bail_krb5(ctx, code, "cannot create Kerberos context");
/* Test init. */
is_int(0, sync_init(ctx, &data), "sync_init succeeds");
ok(data != NULL, "...and data is non-NULL");
/* Block processing for our test user and then test password change. */
code = krb5_parse_name(ctx, "test@EXAMPLE.COM", &princ);
if (code != 0)
bail_krb5(ctx, code, "cannot parse principal test@EXAMPLE.COM");
sync_queue_block("queue", "test", "password");
code = sync_chpass(data, ctx, princ, "foobar");
is_int(0, code, "sync_chpass succeeds");
ok(access("queue/.lock", F_OK) == 0, "...lock file now exists");
sync_queue_check_password("queue", "test", "foobar");
sync_queue_unblock("queue", "test", "password");
/* Block processing for our test user and then test enable. */
sync_queue_block("queue", "test", "enable");
code = sync_status(data, ctx, princ, true);
is_int(0, code, "sync_status enable succeeds");
sync_queue_check_enable("queue", "test", true);
/* Do the same thing for disables, which should still be blocked. */
code = sync_status(data, ctx, princ, false);
is_int(0, code, "sync_status disable succeeds");
sync_queue_check_enable("queue", "test", false);
sync_queue_unblock("queue", "test", "enable");
/* Queue a password change for a root instance. */
krb5_free_principal(ctx, princ);
code = krb5_parse_name(ctx, "test/root@EXAMPLE.COM", &princ);
if (code != 0)
bail_krb5(ctx, code, "cannot parse principal test/root@EXAMPLE.COM");
sync_queue_block("queue", "test/root", "password");
code = sync_chpass(data, ctx, princ, "foobar");
is_int(0, code, "sync_chpass of root instance succeeds");
sync_queue_check_password("queue", "test/root", "foobar");
sync_queue_unblock("queue", "test/root", "password");
/* Queue an account disable for an ipass instance. */
krb5_free_principal(ctx, princ);
code = krb5_parse_name(ctx, "test/ipass@EXAMPLE.COM", &princ);
if (code != 0)
bail_krb5(ctx, code, "cannot parse principal test/ipass@EXAMPLE.COM");
sync_queue_block("queue", "test/ipass", "enable");
code = sync_status(data, ctx, princ, true);
is_int(0, code, "sync_status of root instance succeeds");
sync_queue_check_enable("queue", "test/ipass", true);
sync_queue_unblock("queue", "test/ipass", "enable");
/*
* Try queuing a change for an admin instance, which should do nothing,
* successfully. We'll test there's no queued changes by deleting the
* queue file.
*/
krb5_free_principal(ctx, princ);
code = krb5_parse_name(ctx, "test/admin@EXAMPLE.COM", &princ);
if (code != 0)
bail_krb5(ctx, code, "cannot parse principal test/admin@EXAMPLE.COM");
code = sync_chpass(data, ctx, princ, "foobar");
is_int(0, code, "sync_chpass of admin instance succeeds");
code = sync_status(data, ctx, princ, true);
is_int(0, code, "sync_status enable of admin instance succeeds");
/* 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");
/* Check failure when there's no queue directory. */
krb5_free_principal(ctx, princ);
code = krb5_parse_name(ctx, "test/root@EXAMPLE.COM", &princ);
if (code != 0)
bail_krb5(ctx, code, "cannot parse principal test/root@EXAMPLE.COM");
basprintf(&wanted, "cannot open lock file queue/.lock: %s",
strerror(ENOENT));
code = sync_chpass(data, ctx, princ, "foobar");
is_int(ENOENT, code, "sync_chpass fails with no queue");
message = krb5_get_error_message(ctx, code);
is_string(wanted, message, "...with correct error message");
krb5_free_error_message(ctx, message);
code = sync_status(data, ctx, princ, false);
is_int(ENOENT, code, "sync_status disable fails with no queue");
message = krb5_get_error_message(ctx, code);
is_string(wanted, message, "...with correct error message");
krb5_free_error_message(ctx, message);
/* Shut down the plugin. */
sync_close(ctx, data);
free(wanted);
krb5_free_principal(ctx, princ);
krb5_free_context(ctx);
test_file_path_free(path);
/* Change to an empty Kerberos configuration file. */
path = test_file_path("data/krb5-empty.conf");
if (path == NULL)
bail("cannot find data/krb5-empty.conf in the test suite");
old_krb5_config = krb5_config;
basprintf(&krb5_config, "KRB5_CONFIG=%s", path);
if (putenv(krb5_config) < 0)
sysbail("cannot set KRB5CCNAME");
free(old_krb5_config);
code = krb5_init_context(&ctx);
if (code != 0)
bail_krb5(ctx, code, "cannot create Kerberos context");
/* Make sure the plugin does nothing when there's no configuration. */
is_int(0, sync_init(ctx, &data), "sync_init succeeds");
ok(data != NULL, "...and data is non-NULL");
code = krb5_parse_name(ctx, "test@EXAMPLE.COM", &princ);
if (code != 0)
bail_krb5(ctx, code, "cannot parse principal test@EXAMPLE.COM");
code = sync_chpass(data, ctx, princ, "foobar");
is_int(0, code, "sync_chpass succeeds");
code = sync_status(data, ctx, princ, false);
is_int(0, code, "sync_status disable succeeds");
sync_close(ctx, data);
/* Clean up. */
krb5_free_principal(ctx, princ);
krb5_free_context(ctx);
putenv((char *) "KRB5_CONFIG=");
if (chdir("..") < 0)
sysbail("cannot chdir to parent directory");
test_tmpdir_free(tmpdir);
free(krb5_config);
test_file_path_free(path);
return 0;
}
|