#include "k5-int.h"
#include <kadm5/admin.h>
static uint32_t api;
static krb5_boolean rpc;
static krb5_context context;
#define ADMIN_PASSWORD "admin"
#define USER_PASSWORD "us3r"
static krb5_enctype
default_supported_enctypes[] = {
ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
ENCTYPE_NULL
};
static void
check(krb5_error_code code)
{
assert(code == 0);
}
static void
check_fail(krb5_error_code code, krb5_error_code expected)
{
assert(code == expected);
}
static void *
get_handle(char *client)
{
void *handle;
char *service, *pass;
if (client == NULL)
return NULL;
if (*client == '$') {
service = KADM5_CHANGEPW_SERVICE;
client++;
} else {
service = KADM5_ADMIN_SERVICE;
}
pass = (strcmp(client, "user") == 0) ? USER_PASSWORD : ADMIN_PASSWORD;
check(kadm5_init(context, client, pass, service, NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle));
return handle;
}
static void
free_handle(void *handle)
{
if (handle != NULL)
check(kadm5_destroy(handle));
}
static krb5_principal
parse_princ(const char *str)
{
krb5_principal princ;
check(krb5_parse_name(context, str, &princ));
return princ;
}
static void
create_simple_policy(char *name)
{
void *handle = get_handle("admin");
kadm5_policy_ent_rec ent;
memset(&ent, 0, sizeof(ent));
ent.policy = name;
check(kadm5_create_policy(handle, &ent, KADM5_POLICY));
free_handle(handle);
}
static void
delete_policy(char *name)
{
void *handle = get_handle("admin");
check(kadm5_delete_policy(handle, name));
free_handle(handle);
}
static void
compare_policy(kadm5_policy_ent_t x, uint32_t mask)
{
kadm5_policy_ent_rec g;
void *handle = get_handle("admin");
check(kadm5_get_policy(handle, x->policy, &g));
assert(strcmp(g.policy, x->policy) == 0);
if (mask & KADM5_PW_MAX_LIFE)
assert(g.pw_max_life == x->pw_max_life);
if (mask & KADM5_PW_MIN_LIFE)
assert(g.pw_min_life == x->pw_min_life);
if (mask & KADM5_PW_MIN_LENGTH)
assert(g.pw_min_length == x->pw_min_length);
if (mask & KADM5_PW_MIN_CLASSES)
assert(g.pw_min_classes == x->pw_min_classes);
if (mask & KADM5_PW_HISTORY_NUM)
assert(g.pw_history_num == x->pw_history_num);
if (mask & KADM5_PW_MAX_FAILURE)
assert(g.pw_max_fail == x->pw_max_fail);
if (mask & KADM5_PW_FAILURE_COUNT_INTERVAL)
assert(g.pw_failcnt_interval == x->pw_failcnt_interval);
if (mask & KADM5_PW_LOCKOUT_DURATION)
assert(g.pw_lockout_duration == x->pw_lockout_duration);
check(kadm5_free_policy_ent(handle, &g));
free_handle(handle);
}
static void
create_simple_princ(krb5_principal princ, char *policy)
{
void *handle = get_handle("admin");
kadm5_principal_ent_rec ent;
uint32_t mask = KADM5_PRINCIPAL;
memset(&ent, 0, sizeof(ent));
ent.principal = princ;
ent.policy = policy;
if (policy != NULL)
mask |= KADM5_POLICY;
check(kadm5_create_principal(handle, &ent, mask, "pw"));
free_handle(handle);
}
static void
delete_princ(krb5_principal princ)
{
void *handle = get_handle("admin");
check(kadm5_delete_principal(handle, princ));
free_handle(handle);
}
static void
compare_key_data(kadm5_principal_ent_t ent, const krb5_enctype *etypes)
{
int i;
for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
assert(i < ent->n_key_data);
assert(ent->key_data[i].key_data_ver >= 1);
assert(ent->key_data[i].key_data_type[0] == etypes[i]);
}
}
static void
compare_princ(kadm5_principal_ent_t x, uint32_t mask)
{
void *handle = get_handle("admin");
kadm5_principal_ent_rec g;
kadm5_policy_ent_rec pol;
check(kadm5_get_principal(handle, x->principal, &g,
KADM5_PRINCIPAL_NORMAL_MASK));
assert(krb5_principal_compare(context, g.principal, x->principal));
if (mask & KADM5_POLICY)
assert(strcmp(g.policy, x->policy) == 0);
if (mask & KADM5_PRINC_EXPIRE_TIME)
assert(g.princ_expire_time == x->princ_expire_time);
if (mask & KADM5_MAX_LIFE)
assert(g.max_life == x->max_life);
if (mask & KADM5_MAX_RLIFE)
assert(g.max_renewable_life == x->max_renewable_life);
if (mask & KADM5_FAIL_AUTH_COUNT)
assert(g.fail_auth_count == x->fail_auth_count);
if (mask & KADM5_ATTRIBUTES)
assert(g.attributes == x->attributes);
if (mask & KADM5_KVNO)
assert(g.kvno == x->kvno);
if (mask & KADM5_PW_EXPIRATION) {
assert(g.pw_expiration == x->pw_expiration);
} else if ((mask & KADM5_POLICY) &&
kadm5_get_policy(handle, g.policy, &pol) == 0) {
if (pol.pw_max_life != 0) {
assert(ts_incr(g.last_pwd_change, pol.pw_max_life) ==
g.pw_expiration);
} else {
assert(g.pw_expiration == 0);
}
check(kadm5_free_policy_ent(handle, &pol));
}
if (mask & KADM5_POLICY_CLR) {
assert(g.policy == NULL);
if (!(mask & KADM5_PW_EXPIRATION))
assert(g.pw_expiration == 0);
}
check(kadm5_free_principal_ent(handle, &g));
free_handle(handle);
}
static void
kinit(krb5_ccache cc, const char *user, const char *pass, const char *service)
{
krb5_get_init_creds_opt *opt;
krb5_principal client = parse_princ(user);
krb5_creds creds;
check(krb5_get_init_creds_opt_alloc(context, &opt));
check(krb5_get_init_creds_opt_set_out_ccache(context, opt, cc));
check(krb5_get_init_creds_password(context, &creds, client, pass, NULL,
NULL, 0, service, opt));
krb5_get_init_creds_opt_free(context, opt);
krb5_free_cred_contents(context, &creds);
krb5_free_principal(context, client);
}
static void
cpw_test_fail(char *user, krb5_principal princ, char *pass,
krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_chpass_principal(handle, princ, pass), code);
free_handle(handle);
}
static void
cpw_test_succeed(char *user, krb5_principal princ, char *pass)
{
cpw_test_fail(user, princ, pass, 0);
}
static void
test_chpass(void)
{
krb5_principal princ = parse_princ("chpass-test");
krb5_principal hist_princ = parse_princ("kadmin/history");
kadm5_principal_ent_rec ent;
void *handle;
create_simple_princ(princ, "minlife-pol");
handle = get_handle("admin");
check(kadm5_chpass_principal(handle, princ, "newpassword"));
check(kadm5_get_principal(handle, princ, &ent, KADM5_KEY_DATA));
compare_key_data(&ent, default_supported_enctypes);
assert(ent.key_data[0].key_data_kvno == 2);
check(kadm5_free_principal_ent(handle, &ent));
free_handle(handle);
cpw_test_fail("admin", hist_princ, "pw", KADM5_PROTECT_PRINCIPAL);
if (rpc) {
cpw_test_succeed("admin/modify", princ, "pw2");
cpw_test_fail("admin/none", princ, "pw3", KADM5_AUTH_CHANGEPW);
cpw_test_fail("$admin", princ, "pw3", KADM5_AUTH_CHANGEPW);
}
cpw_test_fail(NULL, princ, "pw", KADM5_BAD_SERVER_HANDLE);
cpw_test_fail("admin", NULL, "pw", EINVAL);
delete_princ(princ);
krb5_free_principal(context, princ);
krb5_free_principal(context, hist_princ);
}
static void
cpol_test_fail(char *user, kadm5_policy_ent_t ent, uint32_t mask,
krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_create_policy(handle, ent, mask | KADM5_POLICY), code);
free_handle(handle);
}
static void
cpol_test_compare(char *user, kadm5_policy_ent_t ent, uint32_t mask)
{
cpol_test_fail(user, ent, mask, 0);
compare_policy(ent, mask);
delete_policy(ent->policy);
}
static void
test_create_policy(void)
{
void *handle;
kadm5_policy_ent_rec ent;
memset(&ent, 0, sizeof(ent));
ent.policy = "create-policy-test";
cpol_test_fail("admin", &ent, 0x10000000, KADM5_BAD_MASK);
handle = get_handle("admin");
check_fail(kadm5_create_policy(handle, &ent, 0), KADM5_BAD_MASK);
free_handle(handle);
cpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
ent.pw_min_life = 32;
cpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
cpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
ent.pw_max_life = 32;
cpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
cpol_test_fail("admin", &ent, KADM5_PW_MIN_LENGTH, KADM5_BAD_LENGTH);
ent.pw_min_length = 32;
cpol_test_compare("admin", &ent, KADM5_PW_MIN_LENGTH);
cpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
ent.pw_min_classes = 1;
cpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
ent.pw_min_classes = 5;
cpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
ent.pw_min_classes = 6;
cpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
cpol_test_fail("admin", &ent, KADM5_PW_HISTORY_NUM, KADM5_BAD_HISTORY);
ent.pw_history_num = 1;
cpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
ent.pw_history_num = 10;
cpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
if (api >= KADM5_API_VERSION_3) {
ent.pw_max_fail = 2;
cpol_test_compare("admin", &ent, KADM5_PW_MAX_FAILURE);
ent.pw_failcnt_interval = 90;
cpol_test_compare("admin", &ent,
KADM5_PW_FAILURE_COUNT_INTERVAL);
ent.pw_lockout_duration = 180;
cpol_test_compare("admin", &ent, KADM5_PW_LOCKOUT_DURATION);
}
if (rpc) {
cpol_test_fail("$admin", &ent, 0, KADM5_AUTH_ADD);
cpol_test_fail("admin/none", &ent, 0, KADM5_AUTH_ADD);
cpol_test_fail("admin/get", &ent, 0, KADM5_AUTH_ADD);
cpol_test_fail("admin/modify", &ent, 0, KADM5_AUTH_ADD);
cpol_test_fail("admin/delete", &ent, 0, KADM5_AUTH_ADD);
cpol_test_compare("admin/add", &ent, 0);
}
ent.policy = "test-pol";
cpol_test_fail("admin", &ent, 0, KADM5_DUP);
ent.policy = NULL;
cpol_test_fail("admin", &ent, 0, EINVAL);
ent.policy = "";
cpol_test_fail("admin", &ent, 0, KADM5_BAD_POLICY);
ent.policy = "pol\7";
cpol_test_fail("admin", &ent, 0, KADM5_BAD_POLICY);
cpol_test_fail(NULL, &ent, 0, KADM5_BAD_SERVER_HANDLE);
cpol_test_fail("admin", NULL, 0, EINVAL);
}
static void
cprinc_test_fail(char *user, kadm5_principal_ent_t ent, uint32_t mask,
char *pass, krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_create_principal(handle, ent, mask | KADM5_PRINCIPAL,
pass), code);
free_handle(handle);
}
static void
cprinc_test_compare(char *user, kadm5_principal_ent_t ent, uint32_t mask,
char *pass)
{
cprinc_test_fail(user, ent, mask, pass, 0);
compare_princ(ent, mask);
delete_princ(ent->principal);
}
static void
test_create_principal(void)
{
void *handle;
kadm5_principal_ent_rec ent;
krb5_principal princ = parse_princ("create-principal-test");
krb5_principal user_princ = parse_princ("user");
memset(&ent, 0, sizeof(ent));
ent.principal = princ;
cprinc_test_fail("admin", &ent, 0x100000, "", KADM5_BAD_MASK);
cprinc_test_fail("admin", &ent, KADM5_LAST_PWD_CHANGE, "pw",
KADM5_BAD_MASK);
cprinc_test_fail("admin", &ent, KADM5_MOD_TIME, "pw", KADM5_BAD_MASK);
cprinc_test_fail("admin", &ent, KADM5_MOD_NAME, "pw", KADM5_BAD_MASK);
cprinc_test_fail("admin", &ent, KADM5_MKVNO, "pw", KADM5_BAD_MASK);
cprinc_test_fail("admin", &ent, KADM5_AUX_ATTRIBUTES, "pw",
KADM5_BAD_MASK);
handle = get_handle("admin");
check_fail(kadm5_create_principal(handle, &ent, 0, "pw"), KADM5_BAD_MASK);
free_handle(handle);
cprinc_test_fail("admin", &ent, 0, "", KADM5_PASS_Q_TOOSHORT);
ent.policy = "test-pol";
cprinc_test_fail("admin", &ent, KADM5_POLICY, "tP", KADM5_PASS_Q_TOOSHORT);
cprinc_test_fail("admin", &ent, KADM5_POLICY, "testpassword",
KADM5_PASS_Q_CLASS);
cprinc_test_fail("admin", &ent, KADM5_POLICY, "Abyssinia",
KADM5_PASS_Q_DICT);
cprinc_test_compare("admin", &ent, 0, "pw");
ent.policy = "nonexistent-pol";
cprinc_test_compare("admin", &ent, KADM5_POLICY, "pw");
cprinc_test_compare("admin/rename", &ent, KADM5_POLICY, "pw");
ent.policy = "test-pol";
cprinc_test_compare("admin", &ent, KADM5_POLICY, "NotinTheDictionary");
cprinc_test_compare("admin", &ent, KADM5_PRINC_EXPIRE_TIME, "pw");
cprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION, "pw");
cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
"NotinTheDictionary");
ent.pw_expiration = 1234;
cprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION, "pw");
cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
"NotinTheDictionary");
ent.pw_expiration = 999999999;
cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
"NotinTheDictionary");
ent.policy = "dict-only-pol";
cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
"pw");
if (rpc) {
cprinc_test_fail("$admin", &ent, 0, "pw", KADM5_AUTH_ADD);
cprinc_test_fail("admin/none", &ent, 0, "pw", KADM5_AUTH_ADD);
cprinc_test_fail("admin/get", &ent, 0, "pw", KADM5_AUTH_ADD);
cprinc_test_fail("admin/modify", &ent, 0, "pw", KADM5_AUTH_ADD);
cprinc_test_fail("admin/delete", &ent, 0, "pw", KADM5_AUTH_ADD);
}
ent.principal = user_princ;
cprinc_test_fail("admin", &ent, 0, "pw", KADM5_DUP);
cprinc_test_fail(NULL, &ent, 0, "pw", KADM5_BAD_SERVER_HANDLE);
cprinc_test_fail("admin", NULL, 0, "pw", EINVAL);
krb5_free_principal(context, princ);
krb5_free_principal(context, user_princ);
}
static void
dpol_test_fail(char *user, char *name, krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_delete_policy(handle, name), code);
free_handle(handle);
}
static void
dpol_test_succeed(char *user, char *name)
{
dpol_test_fail(user, name, 0);
}
static void
test_delete_policy(void)
{
krb5_principal princ = parse_princ("delete-policy-test-princ");
dpol_test_fail("admin", "delete-policy-test", KADM5_UNK_POLICY);
dpol_test_fail("admin", "", KADM5_BAD_POLICY);
create_simple_policy("delete-policy-test");
dpol_test_succeed("admin/delete", "delete-policy-test");
create_simple_policy("delete-policy-test");
create_simple_princ(princ, "delete-policy-test");
dpol_test_succeed("admin", "delete-policy-test");
delete_princ(princ);
if (rpc) {
dpol_test_fail("$admin", "test-pol", KADM5_AUTH_DELETE);
dpol_test_fail("admin/none", "test-pol", KADM5_AUTH_DELETE);
dpol_test_fail("admin/add", "test-pol", KADM5_AUTH_DELETE);
}
dpol_test_fail(NULL, "test-pol", KADM5_BAD_SERVER_HANDLE);
dpol_test_fail("admin", NULL, EINVAL);
krb5_free_principal(context, princ);
}
static void
dprinc_test_fail(char *user, krb5_principal princ, krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_delete_principal(handle, princ), code);
free_handle(handle);
}
static void
dprinc_test_succeed(char *user, krb5_principal princ)
{
dprinc_test_fail(user, princ, 0);
}
static void
test_delete_principal(void)
{
krb5_principal princ = parse_princ("delete-principal-test");
dprinc_test_fail("admin", princ, KADM5_UNK_PRINC);
create_simple_princ(princ, NULL);
dprinc_test_succeed("admin/delete", princ);
if (rpc) {
dprinc_test_fail("$admin", princ, KADM5_AUTH_DELETE);
dprinc_test_fail("admin/add", princ, KADM5_AUTH_DELETE);
dprinc_test_fail("admin/modify", princ, KADM5_AUTH_DELETE);
dprinc_test_fail("admin/get", princ, KADM5_AUTH_DELETE);
dprinc_test_fail("admin/none", princ, KADM5_AUTH_DELETE);
}
dprinc_test_fail(NULL, princ, KADM5_BAD_SERVER_HANDLE);
dprinc_test_fail("admin", NULL, EINVAL);
krb5_free_principal(context, princ);
}
static void
gpol_test_succeed(char *user, char *name)
{
void *handle = get_handle(user);
kadm5_policy_ent_rec ent;
check(kadm5_get_policy(handle, name, &ent));
assert(strcmp(ent.policy, name) == 0);
check(kadm5_free_policy_ent(handle, &ent));
free_handle(handle);
}
static void
gpol_test_fail(char *user, char *name, krb5_error_code code)
{
void *handle = get_handle(user);
kadm5_policy_ent_rec ent;
check_fail(kadm5_get_policy(handle, name, &ent), code);
free_handle(handle);
}
static void
test_get_policy(void)
{
dpol_test_fail("admin", "unknown-policy", KADM5_UNK_POLICY);
gpol_test_fail("admin", "", KADM5_BAD_POLICY);
gpol_test_fail("admin", NULL, EINVAL);
gpol_test_fail(NULL, "", KADM5_BAD_SERVER_HANDLE);
if (rpc) {
gpol_test_fail("admin/none", "test-pol", KADM5_AUTH_GET);
gpol_test_fail("admin/add", "test-pol", KADM5_AUTH_GET);
gpol_test_succeed("admin/get", "test-pol");
gpol_test_succeed("user", "minlife-pol");
gpol_test_succeed("$user", "minlife-pol");
}
}
static void
gprinc_test_succeed(char *user, krb5_principal princ)
{
void *handle = get_handle(user);
kadm5_principal_ent_rec ent;
check(kadm5_get_principal(handle, princ, &ent,
KADM5_PRINCIPAL_NORMAL_MASK));
assert(krb5_principal_compare(context, ent.principal, princ));
check(kadm5_free_principal_ent(handle, &ent));
free_handle(handle);
}
static void
gprinc_test_fail(char *user, krb5_principal princ, krb5_error_code code)
{
void *handle = get_handle(user);
kadm5_principal_ent_rec ent;
check_fail(kadm5_get_principal(handle, princ, &ent,
KADM5_PRINCIPAL_NORMAL_MASK), code);
free_handle(handle);
}
static void
test_get_principal(void)
{
void *handle;
kadm5_principal_ent_rec ent;
krb5_principal princ = parse_princ("get-principal-test");
krb5_principal admin_princ = parse_princ("admin");
krb5_principal admin_none_princ = parse_princ("admin/none");
int i;
gprinc_test_fail("admin", princ, KADM5_UNK_PRINC);
create_simple_princ(princ, NULL);
gprinc_test_succeed("admin/none", admin_none_princ);
gprinc_test_succeed("$admin", admin_princ);
gprinc_test_succeed("admin/get", princ);
if (rpc) {
gprinc_test_fail("$admin", princ, KADM5_AUTH_GET);
gprinc_test_fail("admin/none", princ, KADM5_AUTH_GET);
gprinc_test_fail("admin/add", princ, KADM5_AUTH_GET);
gprinc_test_fail("admin/modify", princ, KADM5_AUTH_GET);
gprinc_test_fail("admin/delete", princ, KADM5_AUTH_GET);
}
handle = get_handle("admin");
check(kadm5_get_principal(handle, princ, &ent,
KADM5_PRINCIPAL_NORMAL_MASK));
assert(ent.n_tl_data == 0);
assert(ent.n_key_data == 0);
assert(ent.tl_data == NULL);
check(kadm5_free_principal_ent(handle, &ent));
check(kadm5_get_principal(handle, princ, &ent,
KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA));
assert(ent.n_key_data == 2);
for (i = 0; i < ent.n_key_data; i++)
assert(rpc == (ent.key_data[i].key_data_length[0] == 0));
check(kadm5_free_principal_ent(handle, &ent));
free_handle(handle);
gprinc_test_fail(NULL, princ, KADM5_BAD_SERVER_HANDLE);
gprinc_test_fail("admin", NULL, EINVAL);
delete_princ(princ);
krb5_free_principal(context, princ);
krb5_free_principal(context, admin_princ);
krb5_free_principal(context, admin_none_princ);
}
static void
test_init_destroy(void)
{
krb5_context ctx;
kadm5_ret_t ret;
kadm5_config_params params;
kadm5_principal_ent_rec ent, gent;
krb5_principal princ = parse_princ("init-test");
krb5_ccache cc;
void *handle;
char hostname[MAXHOSTNAMELEN];
int r;
memset(¶ms, 0, sizeof(params));
memset(&ent, 0, sizeof(ent));
ent.principal = princ;
r = gethostname(hostname, sizeof(hostname));
assert(r == 0);
check_fail(kadm5_destroy(NULL), KADM5_BAD_SERVER_HANDLE);
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
0x65432101, api, NULL, &handle),
KADM5_BAD_STRUCT_VERSION);
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
1, api, NULL, &handle), KADM5_BAD_STRUCT_VERSION);
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION_MASK, api, NULL, &handle),
KADM5_OLD_STRUCT_VERSION);
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION_MASK | 0xca, api, NULL,
&handle), KADM5_NEW_STRUCT_VERSION);
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, 0x65432100, NULL, &handle),
KADM5_BAD_API_VERSION);
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, 4, NULL, &handle),
KADM5_BAD_API_VERSION);
ret = kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, KADM5_API_VERSION_MASK, NULL,
&handle);
assert(ret == (rpc ? KADM5_OLD_LIB_API_VERSION :
KADM5_OLD_SERVER_API_VERSION));
ret = kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, KADM5_API_VERSION_MASK | 0xca, NULL,
&handle);
assert(ret == (rpc ? KADM5_NEW_LIB_API_VERSION :
KADM5_NEW_SERVER_API_VERSION));
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
api, KADM5_STRUCT_VERSION, NULL, &handle),
KADM5_BAD_STRUCT_VERSION);
handle = get_handle("admin");
check(kadm5_create_principal(handle, &ent, KADM5_PRINCIPAL, "pw"));
check(kadm5_get_principal(handle, princ, &gent,
KADM5_PRINCIPAL_NORMAL_MASK));
assert(gent.max_life == KRB5_KDB_MAX_LIFE);
check(kadm5_delete_principal(handle, princ));
check(kadm5_free_principal_ent(handle, &gent));
free_handle(handle);
check(kadm5_init_krb5_context(&ctx));
params.realm = "";
params.mask = KADM5_CONFIG_REALM;
ret = kadm5_init(ctx, "admin", "admin", KADM5_ADMIN_SERVICE, ¶ms,
KADM5_STRUCT_VERSION, api, NULL, &handle);
assert(ret == (rpc ? KADM5_MISSING_KRB5_CONF_PARAMS : ENOENT));
krb5_free_context(ctx);
check(kadm5_init_krb5_context(&ctx));
params.realm = "@";
ret = kadm5_init(ctx, "admin", "admin", KADM5_ADMIN_SERVICE, ¶ms,
KADM5_STRUCT_VERSION, api, NULL, &handle);
assert(ret == (rpc ? KADM5_MISSING_KRB5_CONF_PARAMS : ENOENT));
krb5_free_context(ctx);
check(kadm5_init_krb5_context(&ctx));
params.realm = "BAD.REALM";
ret = kadm5_init(ctx, "admin", "admin", KADM5_ADMIN_SERVICE, ¶ms,
KADM5_STRUCT_VERSION, api, NULL, &handle);
assert(ret == (rpc ? KADM5_MISSING_KRB5_CONF_PARAMS : ENOENT));
krb5_free_context(ctx);
check(kadm5_init_krb5_context(&ctx));
params.realm = "KRBTEST.COM";
check(kadm5_init(ctx, "admin@KRBTEST.COM", "admin", KADM5_ADMIN_SERVICE,
¶ms, KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_destroy(handle));
krb5_free_context(ctx);
check(kadm5_init(context, "admin@KRBTEST.COM", "admin",
KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION, api,
NULL, &handle));
check(kadm5_destroy(handle));
if (rpc) {
check(krb5_cc_default(context, &cc));
params.admin_server = hostname;
params.kadmind_port = 61001;
params.mask = KADM5_CONFIG_ADMIN_SERVER | KADM5_CONFIG_KADMIND_PORT;
check(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
¶ms, KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_destroy(handle));
params.kadmind_port = 4;
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
¶ms, KADM5_STRUCT_VERSION, api, NULL,
&handle), KADM5_RPC_ERROR);
params.admin_server = "does.not.exist";
params.mask = KADM5_CONFIG_ADMIN_SERVER;
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
¶ms, KADM5_STRUCT_VERSION, api, NULL,
&handle), KADM5_CANT_RESOLVE);
check_fail(kadm5_init_with_creds(context, "admin", cc,
KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, api, NULL,
&handle), KRB5_FCC_NOFILE);
kinit(cc, "admin", "admin", KADM5_ADMIN_SERVICE);
check(kadm5_init_with_creds(context, "admin", cc, KADM5_ADMIN_SERVICE,
NULL, KADM5_STRUCT_VERSION, api, NULL,
&handle));
check(kadm5_destroy(handle));
kinit(cc, "admin", "admin", KADM5_CHANGEPW_SERVICE);
check(kadm5_init_with_creds(context, "admin", cc,
KADM5_CHANGEPW_SERVICE, NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_destroy(handle));
kinit(cc, "admin", "admin", NULL);
check_fail(kadm5_init_with_creds(context, "admin", cc,
KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, api, NULL,
&handle), KRB5_CC_NOTFOUND);
check_fail(kadm5_init(context, "admin", "admin", "user", NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle),
KADM5_RPC_ERROR);
check_fail(kadm5_init(context, "admin", "admin", "noexist", NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle),
KADM5_SECURE_PRINC_MISSING);
check_fail(kadm5_init(context, "admin", "admin", "admin", NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle),
KADM5_RPC_ERROR);
check_fail(kadm5_init(context, "admin", "wrong", KADM5_ADMIN_SERVICE,
NULL, KADM5_STRUCT_VERSION, api, NULL, &handle),
KADM5_BAD_PASSWORD);
check_fail(kadm5_init(context, NULL, "admin", KADM5_ADMIN_SERVICE,
NULL, KADM5_STRUCT_VERSION, api, NULL, &handle),
EINVAL);
check_fail(kadm5_init(context, "noexist", "admin", KADM5_ADMIN_SERVICE,
NULL, KADM5_STRUCT_VERSION, api, NULL, &handle),
KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
check_fail(kadm5_init(context, "noexist@KRBTEST.COM", "admin",
KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION,
api, NULL, &handle),
KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
check_fail(kadm5_init(context, "noexist@BAD.REALM", "admin",
KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION,
api, NULL, &handle), KRB5_REALM_UNKNOWN);
check_fail(kadm5_init(context, "admin@BAD.REALM", "admin",
KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION,
api, NULL, &handle), KRB5_REALM_UNKNOWN);
check(krb5_cc_destroy(context, cc));
} else {
params.stash_file = "does/not/exist";
params.mask = KADM5_CONFIG_STASH_FILE;
check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
¶ms, KADM5_STRUCT_VERSION, api, NULL,
&handle), KRB5_KDB_CANTREAD_STORED);
params.max_life = 10;
params.max_rlife = 20;
params.expiration = 30;
params.num_keysalts = 0;
params.mask = KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE |
KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES;
check(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
¶ms, KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_create_principal(handle, &ent, KADM5_PRINCIPAL, "pw"));
check(kadm5_get_principal(handle, princ, &gent,
KADM5_PRINCIPAL_NORMAL_MASK |
KADM5_KEY_DATA));
assert(gent.max_life == 10);
assert(gent.max_renewable_life == 20);
assert(gent.princ_expire_time == 30);
assert(gent.n_key_data == 0);
check(kadm5_delete_principal(handle, princ));
check(kadm5_free_principal_ent(handle, &gent));
check(kadm5_destroy(handle));
check(kadm5_init(context, "admin", "wrong", KADM5_ADMIN_SERVICE, NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_destroy(handle));
check(kadm5_init(context, "admin", "admin", NULL, NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_destroy(handle));
check(kadm5_init(context, "admin", "admin", "foobar", NULL,
KADM5_STRUCT_VERSION, api, NULL, &handle));
check(kadm5_destroy(handle));
}
krb5_free_principal(context, princ);
}
static void
mpol_test_fail(char *user, kadm5_policy_ent_t ent, uint32_t mask,
krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_modify_policy(handle, ent, mask), code);
free_handle(handle);
}
static void
mpol_test_compare(void *handle, kadm5_policy_ent_t ent, uint32_t mask)
{
mpol_test_fail(handle, ent, mask, 0);
compare_policy(ent, mask);
}
static void
test_modify_policy(void)
{
kadm5_policy_ent_rec ent;
memset(&ent, 0, sizeof(ent));
ent.policy = "modify-policy-test";
create_simple_policy(ent.policy);
mpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
ent.pw_min_life = 32;
mpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
mpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
ent.pw_max_life = 32;
mpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
mpol_test_fail("admin", &ent, KADM5_PW_MIN_LENGTH, KADM5_BAD_LENGTH);
ent.pw_min_length = 8;
mpol_test_compare("admin", &ent, KADM5_PW_MIN_LENGTH);
mpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
ent.pw_min_classes = 1;
mpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
ent.pw_min_classes = 5;
mpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
ent.pw_min_classes = 6;
mpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
mpol_test_fail("admin", &ent, KADM5_PW_HISTORY_NUM, KADM5_BAD_HISTORY);
ent.pw_history_num = 1;
mpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
ent.pw_history_num = 10;
mpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
if (api >= KADM5_API_VERSION_3) {
ent.pw_max_fail = 2;
mpol_test_compare("admin", &ent, KADM5_PW_MAX_FAILURE);
ent.pw_failcnt_interval = 90;
mpol_test_compare("admin", &ent, KADM5_PW_FAILURE_COUNT_INTERVAL);
ent.pw_lockout_duration = 180;
mpol_test_compare("admin", &ent, KADM5_PW_LOCKOUT_DURATION);
}
if (rpc) {
mpol_test_fail("$admin", &ent, KADM5_PW_MAX_LIFE, KADM5_AUTH_MODIFY);
mpol_test_fail("admin/none", &ent, KADM5_PW_MAX_LIFE,
KADM5_AUTH_MODIFY);
mpol_test_fail("admin/get", &ent, KADM5_PW_MAX_LIFE,
KADM5_AUTH_MODIFY);
mpol_test_compare("admin/modify", &ent, KADM5_PW_MAX_LIFE);
}
delete_policy(ent.policy);
ent.policy = NULL;
mpol_test_fail("admin", &ent, KADM5_PW_MAX_LIFE, EINVAL);
ent.policy = "";
mpol_test_fail("admin", &ent, KADM5_PW_MAX_LIFE, KADM5_BAD_POLICY);
mpol_test_fail(NULL, &ent, KADM5_PW_MAX_LIFE, KADM5_BAD_SERVER_HANDLE);
mpol_test_fail("admin", NULL, KADM5_PW_MAX_LIFE, EINVAL);
}
static void
mprinc_test_fail(char *user, kadm5_principal_ent_t ent, uint32_t mask,
krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_modify_principal(handle, ent, mask), code);
free_handle(handle);
}
static void
mprinc_test_compare(char *user, kadm5_principal_ent_t ent, uint32_t mask)
{
mprinc_test_fail(user, ent, mask, 0);
compare_princ(ent, mask);
}
static void
test_modify_principal(void)
{
void *handle;
krb5_principal princ = parse_princ("modify-principal-test");
kadm5_principal_ent_rec ent;
krb5_tl_data tl = { NULL, 1, 1, (uint8_t *)"x" };
krb5_tl_data tl2 = { NULL, 999, 6, (uint8_t *)"foobar" };
memset(&ent, 0, sizeof(ent));
ent.principal = princ;
mprinc_test_fail("admin", &ent, KADM5_KVNO, KADM5_UNK_PRINC);
create_simple_princ(princ, NULL);
mprinc_test_fail("admin", &ent, KADM5_AUX_ATTRIBUTES, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_KEY_DATA, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_LAST_FAILED, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_LAST_SUCCESS, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_LAST_PWD_CHANGE, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_MKVNO, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_MOD_NAME, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_MOD_TIME, KADM5_BAD_MASK);
mprinc_test_fail("admin", &ent, KADM5_PRINCIPAL, KADM5_BAD_MASK);
ent.n_tl_data = 1;
ent.tl_data = &tl;
mprinc_test_fail("admin", &ent, KADM5_TL_DATA, KADM5_BAD_TL_TYPE);
ent.fail_auth_count = 1234;
mprinc_test_fail("admin", &ent, KADM5_FAIL_AUTH_COUNT,
KADM5_BAD_SERVER_PARAMS);
ent.fail_auth_count = 0;
mprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION);
mprinc_test_compare("admin", &ent, KADM5_MAX_LIFE);
mprinc_test_compare("admin", &ent, KADM5_MAX_RLIFE);
mprinc_test_compare("admin", &ent, KADM5_FAIL_AUTH_COUNT);
mprinc_test_compare("admin/modify", &ent, KADM5_PRINC_EXPIRE_TIME);
mprinc_test_compare("admin", &ent, KADM5_POLICY_CLR);
ent.pw_expiration = 1234;
mprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION);
ent.policy = "dict-only-pol";
mprinc_test_compare("admin", &ent, KADM5_POLICY);
ent.policy = "test-pol";
mprinc_test_compare("admin", &ent, KADM5_POLICY);
ent.pw_expiration = 999999999;
mprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION);
mprinc_test_compare("admin", &ent, KADM5_POLICY_CLR);
ent.princ_expire_time = 1234;
mprinc_test_compare("admin", &ent, KADM5_PRINC_EXPIRE_TIME);
ent.attributes = KRB5_KDB_DISALLOW_ALL_TIX;
mprinc_test_compare("admin", &ent, KADM5_ATTRIBUTES);
ent.attributes = KRB5_KDB_REQUIRES_PWCHANGE;
mprinc_test_compare("admin", &ent, KADM5_ATTRIBUTES);
ent.attributes = KRB5_KDB_DISALLOW_TGT_BASED;
mprinc_test_compare("admin", &ent, KADM5_ATTRIBUTES);
ent.max_life = 3456;
mprinc_test_compare("admin", &ent, KADM5_MAX_LIFE);
ent.kvno = 7;
mprinc_test_compare("admin", &ent, KADM5_KVNO);
if (rpc) {
mprinc_test_fail("$admin", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
mprinc_test_fail("admin/none", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
mprinc_test_fail("admin/get", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
mprinc_test_fail("admin/add", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
mprinc_test_fail("admin/delete", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
}
handle = get_handle("admin");
ent.max_renewable_life = 88;
ent.tl_data = &tl2;
check(kadm5_modify_principal(handle, &ent,
KADM5_MAX_RLIFE | KADM5_TL_DATA));
memset(&ent, 0, sizeof(ent));
check(kadm5_get_principal(handle, princ, &ent,
KADM5_PRINCIPAL_NORMAL_MASK | KADM5_TL_DATA));
assert(ent.max_renewable_life == 88);
assert(ent.n_tl_data == 1);
assert(ent.tl_data->tl_data_type == tl2.tl_data_type);
assert(ent.tl_data->tl_data_length == tl2.tl_data_length);
assert(memcmp(ent.tl_data->tl_data_contents, tl2.tl_data_contents,
tl2.tl_data_length) == 0);
check(kadm5_free_principal_ent(handle, &ent));
free_handle(handle);
mprinc_test_fail(NULL, &ent, KADM5_KVNO, KADM5_BAD_SERVER_HANDLE);
mprinc_test_fail("admin", NULL, KADM5_KVNO, EINVAL);
delete_princ(princ);
krb5_free_principal(context, princ);
}
static void
rnd_test_fail(char *user, krb5_principal princ, krb5_error_code code)
{
void *handle = get_handle(user);
check_fail(kadm5_randkey_principal(handle, princ, NULL, NULL), code);
free_handle(handle);
}
static void
rnd_test_succeed(char *user, krb5_principal princ)
{
rnd_test_fail(user, princ, 0);
}
static void
test_randkey(void)
{
void *handle;
krb5_principal princ = parse_princ("randkey-principal-test");
krb5_principal user_princ = parse_princ("user");
krb5_principal admin_princ = parse_princ("admin");
kadm5_principal_ent_rec ent;
krb5_keyblock *keys;
int n_keys, i;
create_simple_princ(princ, NULL);
handle = get_handle("admin");
check(kadm5_randkey_principal(handle, princ, &keys, &n_keys));
check(kadm5_get_principal(handle, princ, &ent, KADM5_KEY_DATA));
compare_key_data(&ent, default_supported_enctypes);
assert(ent.key_data[0].key_data_kvno == 2);
assert(n_keys == ent.n_key_data);
for (i = 0; i < n_keys; i++)
krb5_free_keyblock_contents(context, &keys[i]);
free(keys);
check(kadm5_free_principal_ent(handle, &ent));
free_handle(handle);
if (rpc) {
rnd_test_fail("$admin", user_princ, KADM5_AUTH_CHANGEPW);
rnd_test_fail("admin/none", user_princ, KADM5_AUTH_CHANGEPW);
rnd_test_fail("admin/delete", user_princ, KADM5_AUTH_CHANGEPW);
rnd_test_succeed("admin/modify", user_princ);
cpw_test_succeed("admin", user_princ, USER_PASSWORD);
rnd_test_fail("user", user_princ, KADM5_PASS_TOOSOON);
rnd_test_fail("$user", user_princ, KADM5_PASS_TOOSOON);
}
rnd_test_succeed("admin/modify", user_princ);
cpw_test_succeed("admin", user_princ, USER_PASSWORD);
handle = get_handle("$admin");
check(kadm5_randkey_principal(handle, admin_princ, NULL, NULL));
check(kadm5_chpass_principal(handle, admin_princ, ADMIN_PASSWORD));
free_handle(handle);
rnd_test_fail(NULL, princ, KADM5_BAD_SERVER_HANDLE);
rnd_test_fail("admin", NULL, EINVAL);
delete_princ(princ);
krb5_free_principal(context, princ);
krb5_free_principal(context, user_princ);
krb5_free_principal(context, admin_princ);
}
int
main(int argc, char **argv)
{
assert(argc == 2);
rpc = (strcmp(argv[1], "clnt") == 0);
check(kadm5_init_krb5_context(&context));
api = KADM5_API_VERSION_2;
test_create_policy();
test_get_policy();
test_modify_policy();
api = KADM5_API_VERSION_4;
test_chpass();
test_create_policy();
test_create_principal();
test_delete_policy();
test_delete_principal();
test_get_policy();
test_get_principal();
test_init_destroy();
test_modify_policy();
test_modify_principal();
test_randkey();
krb5_free_context(context);
return 0;
}