1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/kadm5/t_kadm5.c - API tests for libkadm5 */
3 /*
4 * Copyright (C) 2021 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "k5-int.h"
34 #include <kadm5/admin.h>
35
36 static uint32_t api;
37 static krb5_boolean rpc;
38
39 static krb5_context context;
40
41 /* These must match the creation commands in t_kadm5.py. */
42 #define ADMIN_PASSWORD "admin"
43 #define USER_PASSWORD "us3r"
44
45 /* This list must match the supported_enctypes setting in t_kadm5.py. */
46 static krb5_enctype
47 default_supported_enctypes[] = {
48 ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
49 ENCTYPE_NULL
50 };
51
52 static void
check(krb5_error_code code)53 check(krb5_error_code code)
54 {
55 assert(code == 0);
56 }
57
58 static void
check_fail(krb5_error_code code,krb5_error_code expected)59 check_fail(krb5_error_code code, krb5_error_code expected)
60 {
61 assert(code == expected);
62 }
63
64 /*
65 * Initialize a handle using the global context. The caller must destroy this
66 * handle before initializing another one. If the client name begins with '$',
67 * authenticate to kadmin/changepw; otherwise authenticate to kadmin/admin. If
68 * client is null, return a null handle.
69 */
70 static void *
get_handle(char * client)71 get_handle(char *client)
72 {
73 void *handle;
74 char *service, *pass;
75
76 if (client == NULL)
77 return NULL;
78
79 if (*client == '$') {
80 service = KADM5_CHANGEPW_SERVICE;
81 client++;
82 } else {
83 service = KADM5_ADMIN_SERVICE;
84 }
85 pass = (strcmp(client, "user") == 0) ? USER_PASSWORD : ADMIN_PASSWORD;
86
87 check(kadm5_init(context, client, pass, service, NULL,
88 KADM5_STRUCT_VERSION, api, NULL, &handle));
89 return handle;
90 }
91
92 static void
free_handle(void * handle)93 free_handle(void *handle)
94 {
95 if (handle != NULL)
96 check(kadm5_destroy(handle));
97 }
98
99 static krb5_principal
parse_princ(const char * str)100 parse_princ(const char *str)
101 {
102 krb5_principal princ;
103
104 check(krb5_parse_name(context, str, &princ));
105 return princ;
106 }
107
108 static void
create_simple_policy(char * name)109 create_simple_policy(char *name)
110 {
111 void *handle = get_handle("admin");
112 kadm5_policy_ent_rec ent;
113
114 memset(&ent, 0, sizeof(ent));
115 ent.policy = name;
116 check(kadm5_create_policy(handle, &ent, KADM5_POLICY));
117 free_handle(handle);
118 }
119
120 static void
delete_policy(char * name)121 delete_policy(char *name)
122 {
123 void *handle = get_handle("admin");
124
125 check(kadm5_delete_policy(handle, name));
126 free_handle(handle);
127 }
128
129 static void
compare_policy(kadm5_policy_ent_t x,uint32_t mask)130 compare_policy(kadm5_policy_ent_t x, uint32_t mask)
131 {
132 kadm5_policy_ent_rec g;
133 void *handle = get_handle("admin");
134
135 check(kadm5_get_policy(handle, x->policy, &g));
136
137 assert(strcmp(g.policy, x->policy) == 0);
138 if (mask & KADM5_PW_MAX_LIFE)
139 assert(g.pw_max_life == x->pw_max_life);
140 if (mask & KADM5_PW_MIN_LIFE)
141 assert(g.pw_min_life == x->pw_min_life);
142 if (mask & KADM5_PW_MIN_LENGTH)
143 assert(g.pw_min_length == x->pw_min_length);
144 if (mask & KADM5_PW_MIN_CLASSES)
145 assert(g.pw_min_classes == x->pw_min_classes);
146 if (mask & KADM5_PW_HISTORY_NUM)
147 assert(g.pw_history_num == x->pw_history_num);
148 if (mask & KADM5_PW_MAX_FAILURE)
149 assert(g.pw_max_fail == x->pw_max_fail);
150 if (mask & KADM5_PW_FAILURE_COUNT_INTERVAL)
151 assert(g.pw_failcnt_interval == x->pw_failcnt_interval);
152 if (mask & KADM5_PW_LOCKOUT_DURATION)
153 assert(g.pw_lockout_duration == x->pw_lockout_duration);
154
155 check(kadm5_free_policy_ent(handle, &g));
156 free_handle(handle);
157 }
158
159 static void
create_simple_princ(krb5_principal princ,char * policy)160 create_simple_princ(krb5_principal princ, char *policy)
161 {
162 void *handle = get_handle("admin");
163 kadm5_principal_ent_rec ent;
164 uint32_t mask = KADM5_PRINCIPAL;
165
166 memset(&ent, 0, sizeof(ent));
167 ent.principal = princ;
168 ent.policy = policy;
169 if (policy != NULL)
170 mask |= KADM5_POLICY;
171 check(kadm5_create_principal(handle, &ent, mask, "pw"));
172 free_handle(handle);
173 }
174
175 static void
delete_princ(krb5_principal princ)176 delete_princ(krb5_principal princ)
177 {
178 void *handle = get_handle("admin");
179
180 check(kadm5_delete_principal(handle, princ));
181 free_handle(handle);
182 }
183
184 static void
compare_key_data(kadm5_principal_ent_t ent,const krb5_enctype * etypes)185 compare_key_data(kadm5_principal_ent_t ent, const krb5_enctype *etypes)
186 {
187 int i;
188
189 for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
190 assert(i < ent->n_key_data);
191 assert(ent->key_data[i].key_data_ver >= 1);
192 assert(ent->key_data[i].key_data_type[0] == etypes[i]);
193 }
194 }
195
196 static void
compare_princ(kadm5_principal_ent_t x,uint32_t mask)197 compare_princ(kadm5_principal_ent_t x, uint32_t mask)
198 {
199 void *handle = get_handle("admin");
200 kadm5_principal_ent_rec g;
201 kadm5_policy_ent_rec pol;
202
203 check(kadm5_get_principal(handle, x->principal, &g,
204 KADM5_PRINCIPAL_NORMAL_MASK));
205
206 assert(krb5_principal_compare(context, g.principal, x->principal));
207 if (mask & KADM5_POLICY)
208 assert(strcmp(g.policy, x->policy) == 0);
209 if (mask & KADM5_PRINC_EXPIRE_TIME)
210 assert(g.princ_expire_time == x->princ_expire_time);
211 if (mask & KADM5_MAX_LIFE)
212 assert(g.max_life == x->max_life);
213 if (mask & KADM5_MAX_RLIFE)
214 assert(g.max_renewable_life == x->max_renewable_life);
215 if (mask & KADM5_FAIL_AUTH_COUNT)
216 assert(g.fail_auth_count == x->fail_auth_count);
217 if (mask & KADM5_ATTRIBUTES)
218 assert(g.attributes == x->attributes);
219 if (mask & KADM5_KVNO)
220 assert(g.kvno == x->kvno);
221
222 if (mask & KADM5_PW_EXPIRATION) {
223 assert(g.pw_expiration == x->pw_expiration);
224 } else if ((mask & KADM5_POLICY) &&
225 kadm5_get_policy(handle, g.policy, &pol) == 0) {
226 /* Check the policy pw_max_life computation. */
227 if (pol.pw_max_life != 0) {
228 assert(ts_incr(g.last_pwd_change, pol.pw_max_life) ==
229 g.pw_expiration);
230 } else {
231 assert(g.pw_expiration == 0);
232 }
233 check(kadm5_free_policy_ent(handle, &pol));
234 }
235
236 if (mask & KADM5_POLICY_CLR) {
237 assert(g.policy == NULL);
238 if (!(mask & KADM5_PW_EXPIRATION))
239 assert(g.pw_expiration == 0);
240 }
241
242 check(kadm5_free_principal_ent(handle, &g));
243 free_handle(handle);
244 }
245
246 static void
kinit(krb5_ccache cc,const char * user,const char * pass,const char * service)247 kinit(krb5_ccache cc, const char *user, const char *pass, const char *service)
248 {
249 krb5_get_init_creds_opt *opt;
250 krb5_principal client = parse_princ(user);
251 krb5_creds creds;
252
253 check(krb5_get_init_creds_opt_alloc(context, &opt));
254 check(krb5_get_init_creds_opt_set_out_ccache(context, opt, cc));
255 check(krb5_get_init_creds_password(context, &creds, client, pass, NULL,
256 NULL, 0, service, opt));
257 krb5_get_init_creds_opt_free(context, opt);
258 krb5_free_cred_contents(context, &creds);
259 krb5_free_principal(context, client);
260 }
261
262 static void
cpw_test_fail(char * user,krb5_principal princ,char * pass,krb5_error_code code)263 cpw_test_fail(char *user, krb5_principal princ, char *pass,
264 krb5_error_code code)
265 {
266 void *handle = get_handle(user);
267
268 check_fail(kadm5_chpass_principal(handle, princ, pass), code);
269 free_handle(handle);
270 }
271
272 static void
cpw_test_succeed(char * user,krb5_principal princ,char * pass)273 cpw_test_succeed(char *user, krb5_principal princ, char *pass)
274 {
275 cpw_test_fail(user, princ, pass, 0);
276 }
277
278 static void
test_chpass()279 test_chpass()
280 {
281 krb5_principal princ = parse_princ("chpass-test");
282 krb5_principal hist_princ = parse_princ("kadmin/history");
283 kadm5_principal_ent_rec ent;
284 void *handle;
285
286 /* Specify a policy so that kadmin/history is created. */
287 create_simple_princ(princ, "minlife-pol");
288
289 /* Check kvno and enctypes after a password change. */
290 handle = get_handle("admin");
291 check(kadm5_chpass_principal(handle, princ, "newpassword"));
292 check(kadm5_get_principal(handle, princ, &ent, KADM5_KEY_DATA));
293 compare_key_data(&ent, default_supported_enctypes);
294 assert(ent.key_data[0].key_data_kvno == 2);
295 check(kadm5_free_principal_ent(handle, &ent));
296 free_handle(handle);
297
298 /* Fails for protected principal. */
299 cpw_test_fail("admin", hist_princ, "pw", KADM5_PROTECT_PRINCIPAL);
300
301 /* Fails over RPC if "change" ACL is not granted, or if we authenticated to
302 * kadmin/changepw and are changing another principal's password. */
303 if (rpc) {
304 cpw_test_succeed("admin/modify", princ, "pw2");
305 cpw_test_fail("admin/none", princ, "pw3", KADM5_AUTH_CHANGEPW);
306 cpw_test_fail("$admin", princ, "pw3", KADM5_AUTH_CHANGEPW);
307 }
308
309 /* Fails with null handle or principal name. */
310 cpw_test_fail(NULL, princ, "pw", KADM5_BAD_SERVER_HANDLE);
311 cpw_test_fail("admin", NULL, "pw", EINVAL);
312
313 delete_princ(princ);
314 krb5_free_principal(context, princ);
315 krb5_free_principal(context, hist_princ);
316 }
317
318 static void
cpol_test_fail(char * user,kadm5_policy_ent_t ent,uint32_t mask,krb5_error_code code)319 cpol_test_fail(char *user, kadm5_policy_ent_t ent, uint32_t mask,
320 krb5_error_code code)
321 {
322 void *handle = get_handle(user);
323
324 check_fail(kadm5_create_policy(handle, ent, mask | KADM5_POLICY), code);
325 free_handle(handle);
326 }
327
328 static void
cpol_test_compare(char * user,kadm5_policy_ent_t ent,uint32_t mask)329 cpol_test_compare(char *user, kadm5_policy_ent_t ent, uint32_t mask)
330 {
331 cpol_test_fail(user, ent, mask, 0);
332 compare_policy(ent, mask);
333 delete_policy(ent->policy);
334 }
335
336 static void
test_create_policy()337 test_create_policy()
338 {
339 void *handle;
340 kadm5_policy_ent_rec ent;
341
342 memset(&ent, 0, sizeof(ent));
343
344 /* Fails with undefined mask bit. */
345 ent.policy = "create-policy-test";
346 cpol_test_fail("admin", &ent, 0x10000000, KADM5_BAD_MASK);
347
348 /* Fails without KADM5_POLICY mask bit. */
349 handle = get_handle("admin");
350 check_fail(kadm5_create_policy(handle, &ent, 0), KADM5_BAD_MASK);
351 free_handle(handle);
352
353 /* pw_min_life = 0 and pw_min_life != 0 */
354 cpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
355 ent.pw_min_life = 32;
356 cpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
357
358 /* pw_max_life = 0 and pw_max_life != 0 */
359 cpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
360 ent.pw_max_life = 32;
361 cpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
362
363 /* pw_min_length = 0 (rejected) and pw_min_length != 0 */
364 cpol_test_fail("admin", &ent, KADM5_PW_MIN_LENGTH, KADM5_BAD_LENGTH);
365 ent.pw_min_length = 32;
366 cpol_test_compare("admin", &ent, KADM5_PW_MIN_LENGTH);
367
368 /* pw_min_classes = 0 (rejected), 1, 5, 6 (rejected) */
369 cpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
370 ent.pw_min_classes = 1;
371 cpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
372 ent.pw_min_classes = 5;
373 cpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
374 ent.pw_min_classes = 6;
375 cpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
376
377 /* pw_history_num = 0 (rejected), 1, 10 */
378 cpol_test_fail("admin", &ent, KADM5_PW_HISTORY_NUM, KADM5_BAD_HISTORY);
379 ent.pw_history_num = 1;
380 cpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
381 ent.pw_history_num = 10;
382 cpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
383
384 if (api >= KADM5_API_VERSION_3) {
385 ent.pw_max_fail = 2;
386 cpol_test_compare("admin", &ent, KADM5_PW_MAX_FAILURE);
387 ent.pw_failcnt_interval = 90;
388 cpol_test_compare("admin", &ent,
389 KADM5_PW_FAILURE_COUNT_INTERVAL);
390 ent.pw_lockout_duration = 180;
391 cpol_test_compare("admin", &ent, KADM5_PW_LOCKOUT_DURATION);
392 }
393
394 /* Fails over RPC if "add" ACL is not granted, or if we authenticated to
395 * kadmin/changepw. */
396 if (rpc) {
397 cpol_test_fail("$admin", &ent, 0, KADM5_AUTH_ADD);
398 cpol_test_fail("admin/none", &ent, 0, KADM5_AUTH_ADD);
399 cpol_test_fail("admin/get", &ent, 0, KADM5_AUTH_ADD);
400 cpol_test_fail("admin/modify", &ent, 0, KADM5_AUTH_ADD);
401 cpol_test_fail("admin/delete", &ent, 0, KADM5_AUTH_ADD);
402 cpol_test_compare("admin/add", &ent, 0);
403 }
404
405 /* Fails with existing policy name. */
406 ent.policy = "test-pol";
407 cpol_test_fail("admin", &ent, 0, KADM5_DUP);
408
409 /* Fails with null or empty policy name, or invalid character in name. */
410 ent.policy = NULL;
411 cpol_test_fail("admin", &ent, 0, EINVAL);
412 ent.policy = "";
413 cpol_test_fail("admin", &ent, 0, KADM5_BAD_POLICY);
414 ent.policy = "pol\7";
415 cpol_test_fail("admin", &ent, 0, KADM5_BAD_POLICY);
416
417 /* Fails with null handle or policy ent. */
418 cpol_test_fail(NULL, &ent, 0, KADM5_BAD_SERVER_HANDLE);
419 cpol_test_fail("admin", NULL, 0, EINVAL);
420 }
421
422 static void
cprinc_test_fail(char * user,kadm5_principal_ent_t ent,uint32_t mask,char * pass,krb5_error_code code)423 cprinc_test_fail(char *user, kadm5_principal_ent_t ent, uint32_t mask,
424 char *pass, krb5_error_code code)
425 {
426 void *handle = get_handle(user);
427
428 check_fail(kadm5_create_principal(handle, ent, mask | KADM5_PRINCIPAL,
429 pass), code);
430 free_handle(handle);
431 }
432
433 static void
cprinc_test_compare(char * user,kadm5_principal_ent_t ent,uint32_t mask,char * pass)434 cprinc_test_compare(char *user, kadm5_principal_ent_t ent, uint32_t mask,
435 char *pass)
436 {
437 cprinc_test_fail(user, ent, mask, pass, 0);
438 compare_princ(ent, mask);
439 delete_princ(ent->principal);
440 }
441
442 static void
test_create_principal()443 test_create_principal()
444 {
445 void *handle;
446 kadm5_principal_ent_rec ent;
447 krb5_principal princ = parse_princ("create-principal-test");
448 krb5_principal user_princ = parse_princ("user");
449
450 memset(&ent, 0, sizeof(ent));
451 ent.principal = princ;
452
453 /* Fails with undefined or prohibited mask bit. */
454 cprinc_test_fail("admin", &ent, 0x100000, "", KADM5_BAD_MASK);
455 cprinc_test_fail("admin", &ent, KADM5_LAST_PWD_CHANGE, "pw",
456 KADM5_BAD_MASK);
457 cprinc_test_fail("admin", &ent, KADM5_MOD_TIME, "pw", KADM5_BAD_MASK);
458 cprinc_test_fail("admin", &ent, KADM5_MOD_NAME, "pw", KADM5_BAD_MASK);
459 cprinc_test_fail("admin", &ent, KADM5_MKVNO, "pw", KADM5_BAD_MASK);
460 cprinc_test_fail("admin", &ent, KADM5_AUX_ATTRIBUTES, "pw",
461 KADM5_BAD_MASK);
462
463 /* Fails without KADM5_PRINCIPAL mask bit. */
464 handle = get_handle("admin");
465 check_fail(kadm5_create_principal(handle, &ent, 0, "pw"), KADM5_BAD_MASK);
466 free_handle(handle);
467
468 /* Fails with empty password or password prohibited by policy. */
469 cprinc_test_fail("admin", &ent, 0, "", KADM5_PASS_Q_TOOSHORT);
470 ent.policy = "test-pol";
471 cprinc_test_fail("admin", &ent, KADM5_POLICY, "tP", KADM5_PASS_Q_TOOSHORT);
472 cprinc_test_fail("admin", &ent, KADM5_POLICY, "testpassword",
473 KADM5_PASS_Q_CLASS);
474 cprinc_test_fail("admin", &ent, KADM5_POLICY, "Abyssinia",
475 KADM5_PASS_Q_DICT);
476
477 cprinc_test_compare("admin", &ent, 0, "pw");
478 ent.policy = "nonexistent-pol";
479 cprinc_test_compare("admin", &ent, KADM5_POLICY, "pw");
480 cprinc_test_compare("admin/rename", &ent, KADM5_POLICY, "pw");
481
482 /* Test pw_expiration explicit specifications vs. policy pw_max_life. */
483 ent.policy = "test-pol";
484 cprinc_test_compare("admin", &ent, KADM5_POLICY, "NotinTheDictionary");
485 cprinc_test_compare("admin", &ent, KADM5_PRINC_EXPIRE_TIME, "pw");
486 cprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION, "pw");
487 cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
488 "NotinTheDictionary");
489 ent.pw_expiration = 1234;
490 cprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION, "pw");
491 cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
492 "NotinTheDictionary");
493 ent.pw_expiration = 999999999;
494 cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
495 "NotinTheDictionary");
496 ent.policy = "dict-only-pol";
497 cprinc_test_compare("admin", &ent, KADM5_POLICY | KADM5_PW_EXPIRATION,
498 "pw");
499
500 /* Fails over RPC if "add" ACL is not granted, or if we authenticated to
501 * kadmin/changepw. */
502 if (rpc) {
503 cprinc_test_fail("$admin", &ent, 0, "pw", KADM5_AUTH_ADD);
504 cprinc_test_fail("admin/none", &ent, 0, "pw", KADM5_AUTH_ADD);
505 cprinc_test_fail("admin/get", &ent, 0, "pw", KADM5_AUTH_ADD);
506 cprinc_test_fail("admin/modify", &ent, 0, "pw", KADM5_AUTH_ADD);
507 cprinc_test_fail("admin/delete", &ent, 0, "pw", KADM5_AUTH_ADD);
508 }
509
510 /* Fails with existing policy name. */
511 ent.principal = user_princ;
512 cprinc_test_fail("admin", &ent, 0, "pw", KADM5_DUP);
513
514 /* Fails with null handle or principal ent. */
515 cprinc_test_fail(NULL, &ent, 0, "pw", KADM5_BAD_SERVER_HANDLE);
516 cprinc_test_fail("admin", NULL, 0, "pw", EINVAL);
517
518 krb5_free_principal(context, princ);
519 krb5_free_principal(context, user_princ);
520 }
521
522 static void
dpol_test_fail(char * user,char * name,krb5_error_code code)523 dpol_test_fail(char *user, char *name, krb5_error_code code)
524 {
525 void *handle = get_handle(user);
526
527 check_fail(kadm5_delete_policy(handle, name), code);
528 free_handle(handle);
529 }
530
531 static void
dpol_test_succeed(char * user,char * name)532 dpol_test_succeed(char *user, char *name)
533 {
534 dpol_test_fail(user, name, 0);
535 }
536
537 static void
test_delete_policy()538 test_delete_policy()
539 {
540 krb5_principal princ = parse_princ("delete-policy-test-princ");
541
542 /* Fails with unknown policy. */
543 dpol_test_fail("admin", "delete-policy-test", KADM5_UNK_POLICY);
544
545 /* Fails with empty policy name. */
546 dpol_test_fail("admin", "", KADM5_BAD_POLICY);
547
548 /* Succeeds with "delete" ACL (or local authentication). */
549 create_simple_policy("delete-policy-test");
550 dpol_test_succeed("admin/delete", "delete-policy-test");
551
552 /* Succeeds even if a principal references the policy, since we now allow
553 * principals to reference nonexistent policies. */
554 create_simple_policy("delete-policy-test");
555 create_simple_princ(princ, "delete-policy-test");
556 dpol_test_succeed("admin", "delete-policy-test");
557 delete_princ(princ);
558
559 /* Fails over RPC if "delete" ACL is not granted, or if we authenticated to
560 * kadmin/changepw. */
561 if (rpc) {
562 dpol_test_fail("$admin", "test-pol", KADM5_AUTH_DELETE);
563 dpol_test_fail("admin/none", "test-pol", KADM5_AUTH_DELETE);
564 dpol_test_fail("admin/add", "test-pol", KADM5_AUTH_DELETE);
565 }
566
567 /* Fails with null handle or principal ent. */
568 dpol_test_fail(NULL, "test-pol", KADM5_BAD_SERVER_HANDLE);
569 dpol_test_fail("admin", NULL, EINVAL);
570
571 krb5_free_principal(context, princ);
572 }
573
574 static void
dprinc_test_fail(char * user,krb5_principal princ,krb5_error_code code)575 dprinc_test_fail(char *user, krb5_principal princ, krb5_error_code code)
576 {
577 void *handle = get_handle(user);
578
579 check_fail(kadm5_delete_principal(handle, princ), code);
580 free_handle(handle);
581 }
582
583 static void
dprinc_test_succeed(char * user,krb5_principal princ)584 dprinc_test_succeed(char *user, krb5_principal princ)
585 {
586 dprinc_test_fail(user, princ, 0);
587 }
588
589 static void
test_delete_principal()590 test_delete_principal()
591 {
592 krb5_principal princ = parse_princ("delete-principal-test");
593
594 /* Fails with unknown principal. */
595 dprinc_test_fail("admin", princ, KADM5_UNK_PRINC);
596
597 /* Succeeds with "delete" ACL (or local authentication). */
598 create_simple_princ(princ, NULL);
599 dprinc_test_succeed("admin/delete", princ);
600
601 /* Fails over RPC if "delete" ACL is not granted, or if we authenticated to
602 * kadmin/changepw. */
603 if (rpc) {
604 dprinc_test_fail("$admin", princ, KADM5_AUTH_DELETE);
605 dprinc_test_fail("admin/add", princ, KADM5_AUTH_DELETE);
606 dprinc_test_fail("admin/modify", princ, KADM5_AUTH_DELETE);
607 dprinc_test_fail("admin/get", princ, KADM5_AUTH_DELETE);
608 dprinc_test_fail("admin/none", princ, KADM5_AUTH_DELETE);
609 }
610
611 /* Fails with null handle or principal ent. */
612 dprinc_test_fail(NULL, princ, KADM5_BAD_SERVER_HANDLE);
613 dprinc_test_fail("admin", NULL, EINVAL);
614
615 krb5_free_principal(context, princ);
616 }
617
618 static void
gpol_test_succeed(char * user,char * name)619 gpol_test_succeed(char *user, char *name)
620 {
621 void *handle = get_handle(user);
622 kadm5_policy_ent_rec ent;
623
624 check(kadm5_get_policy(handle, name, &ent));
625 assert(strcmp(ent.policy, name) == 0);
626 check(kadm5_free_policy_ent(handle, &ent));
627 free_handle(handle);
628 }
629
630 static void
gpol_test_fail(char * user,char * name,krb5_error_code code)631 gpol_test_fail(char *user, char *name, krb5_error_code code)
632 {
633 void *handle = get_handle(user);
634 kadm5_policy_ent_rec ent;
635
636 check_fail(kadm5_get_policy(handle, name, &ent), code);
637 free_handle(handle);
638 }
639
640 static void
test_get_policy()641 test_get_policy()
642 {
643 /* Fails with unknown policy. */
644 dpol_test_fail("admin", "unknown-policy", KADM5_UNK_POLICY);
645
646 /* Fails with empty or null policy name or a null handle. */
647 gpol_test_fail("admin", "", KADM5_BAD_POLICY);
648 gpol_test_fail("admin", NULL, EINVAL);
649 gpol_test_fail(NULL, "", KADM5_BAD_SERVER_HANDLE);
650
651 /* Fails over RPC unless "get" ACL is granted or the principal's own policy
652 * is retrieved. */
653 if (rpc) {
654 gpol_test_fail("admin/none", "test-pol", KADM5_AUTH_GET);
655 gpol_test_fail("admin/add", "test-pol", KADM5_AUTH_GET);
656 gpol_test_succeed("admin/get", "test-pol");
657 gpol_test_succeed("user", "minlife-pol");
658 gpol_test_succeed("$user", "minlife-pol");
659 }
660 }
661
662 static void
gprinc_test_succeed(char * user,krb5_principal princ)663 gprinc_test_succeed(char *user, krb5_principal princ)
664 {
665 void *handle = get_handle(user);
666 kadm5_principal_ent_rec ent;
667
668 check(kadm5_get_principal(handle, princ, &ent,
669 KADM5_PRINCIPAL_NORMAL_MASK));
670 assert(krb5_principal_compare(context, ent.principal, princ));
671 check(kadm5_free_principal_ent(handle, &ent));
672 free_handle(handle);
673 }
674
675 static void
gprinc_test_fail(char * user,krb5_principal princ,krb5_error_code code)676 gprinc_test_fail(char *user, krb5_principal princ, krb5_error_code code)
677 {
678 void *handle = get_handle(user);
679 kadm5_principal_ent_rec ent;
680
681 check_fail(kadm5_get_principal(handle, princ, &ent,
682 KADM5_PRINCIPAL_NORMAL_MASK), code);
683 free_handle(handle);
684 }
685
686 static void
test_get_principal()687 test_get_principal()
688 {
689 void *handle;
690 kadm5_principal_ent_rec ent;
691 krb5_principal princ = parse_princ("get-principal-test");
692 krb5_principal admin_princ = parse_princ("admin");
693 krb5_principal admin_none_princ = parse_princ("admin/none");
694 int i;
695
696 /* Fails with unknown principal. */
697 gprinc_test_fail("admin", princ, KADM5_UNK_PRINC);
698
699 create_simple_princ(princ, NULL);
700
701 /* Succeeds with "get" ACL (or local authentication), or operating on
702 * self. */
703 gprinc_test_succeed("admin/none", admin_none_princ);
704 gprinc_test_succeed("$admin", admin_princ);
705 gprinc_test_succeed("admin/get", princ);
706
707 /* Fails over RPC if "get" ACL is not granted, or if we authenticated to
708 * kadmin/changepw and getting another principal entry. */
709 if (rpc) {
710 gprinc_test_fail("$admin", princ, KADM5_AUTH_GET);
711 gprinc_test_fail("admin/none", princ, KADM5_AUTH_GET);
712 gprinc_test_fail("admin/add", princ, KADM5_AUTH_GET);
713 gprinc_test_fail("admin/modify", princ, KADM5_AUTH_GET);
714 gprinc_test_fail("admin/delete", princ, KADM5_AUTH_GET);
715 }
716
717 /* Entry contains no key data or tl-data unless asked for. */
718 handle = get_handle("admin");
719 check(kadm5_get_principal(handle, princ, &ent,
720 KADM5_PRINCIPAL_NORMAL_MASK));
721 assert(ent.n_tl_data == 0);
722 assert(ent.n_key_data == 0);
723 assert(ent.tl_data == NULL);
724 check(kadm5_free_principal_ent(handle, &ent));
725
726 /* Key data (without the actual keys over RPC) is provided if asked for. */
727 check(kadm5_get_principal(handle, princ, &ent,
728 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA));
729 assert(ent.n_key_data == 2);
730 for (i = 0; i < ent.n_key_data; i++)
731 assert(rpc == (ent.key_data[i].key_data_length[0] == 0));
732 check(kadm5_free_principal_ent(handle, &ent));
733 free_handle(handle);
734
735 /* Fails with null handle or principal. */
736 gprinc_test_fail(NULL, princ, KADM5_BAD_SERVER_HANDLE);
737 gprinc_test_fail("admin", NULL, EINVAL);
738
739 delete_princ(princ);
740 krb5_free_principal(context, princ);
741 krb5_free_principal(context, admin_princ);
742 krb5_free_principal(context, admin_none_princ);
743 }
744
745 static void
test_init_destroy()746 test_init_destroy()
747 {
748 krb5_context ctx;
749 kadm5_ret_t ret;
750 kadm5_config_params params;
751 kadm5_principal_ent_rec ent, gent;
752 krb5_principal princ = parse_princ("init-test");
753 krb5_ccache cc;
754 void *handle;
755 char hostname[MAXHOSTNAMELEN];
756 int r;
757
758 memset(¶ms, 0, sizeof(params));
759 memset(&ent, 0, sizeof(ent));
760 ent.principal = princ;
761
762 r = gethostname(hostname, sizeof(hostname));
763 assert(r == 0);
764
765 /* Destroy fails with no server handle. */
766 check_fail(kadm5_destroy(NULL), KADM5_BAD_SERVER_HANDLE);
767
768 /* Fails with bad structure version mask. */
769 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
770 0x65432101, api, NULL, &handle),
771 KADM5_BAD_STRUCT_VERSION);
772 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
773 1, api, NULL, &handle), KADM5_BAD_STRUCT_VERSION);
774
775 /* Fails with too-old or too-new structure version. */
776 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
777 KADM5_STRUCT_VERSION_MASK, api, NULL, &handle),
778 KADM5_OLD_STRUCT_VERSION);
779 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
780 KADM5_STRUCT_VERSION_MASK | 0xca, api, NULL,
781 &handle), KADM5_NEW_STRUCT_VERSION);
782
783 /* Fails with bad API version mask. */
784 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
785 KADM5_STRUCT_VERSION, 0x65432100, NULL, &handle),
786 KADM5_BAD_API_VERSION);
787 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
788 KADM5_STRUCT_VERSION, 4, NULL, &handle),
789 KADM5_BAD_API_VERSION);
790
791 /* Fails with too-old or too-new API version.*/
792 ret = kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
793 KADM5_STRUCT_VERSION, KADM5_API_VERSION_MASK, NULL,
794 &handle);
795 assert(ret == (rpc ? KADM5_OLD_LIB_API_VERSION :
796 KADM5_OLD_SERVER_API_VERSION));
797 ret = kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
798 KADM5_STRUCT_VERSION, KADM5_API_VERSION_MASK | 0xca, NULL,
799 &handle);
800 assert(ret == (rpc ? KADM5_NEW_LIB_API_VERSION :
801 KADM5_NEW_SERVER_API_VERSION));
802
803 /* Fails with structure and API version reversed. */
804 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE, NULL,
805 api, KADM5_STRUCT_VERSION, NULL, &handle),
806 KADM5_BAD_STRUCT_VERSION);
807
808 /* Hardcoded default max lifetime is used when no handle or krb5.conf
809 * setting is given. */
810 handle = get_handle("admin");
811 check(kadm5_create_principal(handle, &ent, KADM5_PRINCIPAL, "pw"));
812 check(kadm5_get_principal(handle, princ, &gent,
813 KADM5_PRINCIPAL_NORMAL_MASK));
814 assert(gent.max_life == KRB5_KDB_MAX_LIFE);
815 check(kadm5_delete_principal(handle, princ));
816 check(kadm5_free_principal_ent(handle, &gent));
817 free_handle(handle);
818
819 /* Fails with configured unknown realm. Do these tests in separate krb5
820 * contexts since the realm setting sticks to the context. */
821 check(kadm5_init_krb5_context(&ctx));
822 params.realm = "";
823 params.mask = KADM5_CONFIG_REALM;
824 ret = kadm5_init(ctx, "admin", "admin", KADM5_ADMIN_SERVICE, ¶ms,
825 KADM5_STRUCT_VERSION, api, NULL, &handle);
826 assert(ret == (rpc ? KADM5_MISSING_KRB5_CONF_PARAMS : ENOENT));
827 krb5_free_context(ctx);
828
829 check(kadm5_init_krb5_context(&ctx));
830 params.realm = "@";
831 ret = kadm5_init(ctx, "admin", "admin", KADM5_ADMIN_SERVICE, ¶ms,
832 KADM5_STRUCT_VERSION, api, NULL, &handle);
833 assert(ret == (rpc ? KADM5_MISSING_KRB5_CONF_PARAMS : ENOENT));
834 krb5_free_context(ctx);
835
836 check(kadm5_init_krb5_context(&ctx));
837 params.realm = "BAD.REALM";
838 ret = kadm5_init(ctx, "admin", "admin", KADM5_ADMIN_SERVICE, ¶ms,
839 KADM5_STRUCT_VERSION, api, NULL, &handle);
840 assert(ret == (rpc ? KADM5_MISSING_KRB5_CONF_PARAMS : ENOENT));
841 krb5_free_context(ctx);
842
843 /* Succeeds with explicit client realm and configured realm. */
844 check(kadm5_init_krb5_context(&ctx));
845 params.realm = "KRBTEST.COM";
846 check(kadm5_init(ctx, "admin@KRBTEST.COM", "admin", KADM5_ADMIN_SERVICE,
847 ¶ms, KADM5_STRUCT_VERSION, api, NULL, &handle));
848 check(kadm5_destroy(handle));
849 krb5_free_context(ctx);
850
851 /* Succeeds with explicit client realm. */
852 check(kadm5_init(context, "admin@KRBTEST.COM", "admin",
853 KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION, api,
854 NULL, &handle));
855 check(kadm5_destroy(handle));
856
857
858 if (rpc) {
859 check(krb5_cc_default(context, &cc));
860
861 /* Succeeds with configured host and port. */
862 params.admin_server = hostname;
863 params.kadmind_port = 61001;
864 params.mask = KADM5_CONFIG_ADMIN_SERVER | KADM5_CONFIG_KADMIND_PORT;
865 check(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
866 ¶ms, KADM5_STRUCT_VERSION, api, NULL, &handle));
867 check(kadm5_destroy(handle));
868
869 /* Fails with wrong configured port. */
870 params.kadmind_port = 4;
871 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
872 ¶ms, KADM5_STRUCT_VERSION, api, NULL,
873 &handle), KADM5_RPC_ERROR);
874
875 /* Fails with non-resolving hostname. */
876 params.admin_server = "does.not.exist";
877 params.mask = KADM5_CONFIG_ADMIN_SERVER;
878 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
879 ¶ms, KADM5_STRUCT_VERSION, api, NULL,
880 &handle), KADM5_CANT_RESOLVE);
881
882 /* Fails with uninitialized cache. */
883 check_fail(kadm5_init_with_creds(context, "admin", cc,
884 KADM5_ADMIN_SERVICE, NULL,
885 KADM5_STRUCT_VERSION, api, NULL,
886 &handle), KRB5_FCC_NOFILE);
887
888 /* Succeeds with cache containing kadmin/admin cred. */
889 kinit(cc, "admin", "admin", KADM5_ADMIN_SERVICE);
890 check(kadm5_init_with_creds(context, "admin", cc, KADM5_ADMIN_SERVICE,
891 NULL, KADM5_STRUCT_VERSION, api, NULL,
892 &handle));
893 check(kadm5_destroy(handle));
894
895 /* Succeeds with cache containing kadmin/changepw cred. */
896 kinit(cc, "admin", "admin", KADM5_CHANGEPW_SERVICE);
897 check(kadm5_init_with_creds(context, "admin", cc,
898 KADM5_CHANGEPW_SERVICE, NULL,
899 KADM5_STRUCT_VERSION, api, NULL, &handle));
900 check(kadm5_destroy(handle));
901
902 /* Fails with cache containing only a TGT. */
903 kinit(cc, "admin", "admin", NULL);
904 check_fail(kadm5_init_with_creds(context, "admin", cc,
905 KADM5_ADMIN_SERVICE, NULL,
906 KADM5_STRUCT_VERSION, api, NULL,
907 &handle), KRB5_CC_NOTFOUND);
908
909 /* Fails authenticating to non-kadmin princ. */
910 check_fail(kadm5_init(context, "admin", "admin", "user", NULL,
911 KADM5_STRUCT_VERSION, api, NULL, &handle),
912 KADM5_RPC_ERROR);
913
914 /* Fails authenticating to nonexistent princ. */
915 check_fail(kadm5_init(context, "admin", "admin", "noexist", NULL,
916 KADM5_STRUCT_VERSION, api, NULL, &handle),
917 KADM5_SECURE_PRINC_MISSING);
918
919 /* Fails authenticating to client princ (which is non-kadmin). */
920 check_fail(kadm5_init(context, "admin", "admin", "admin", NULL,
921 KADM5_STRUCT_VERSION, api, NULL, &handle),
922 KADM5_RPC_ERROR);
923
924 /* Fails with wrong password. */
925 check_fail(kadm5_init(context, "admin", "wrong", KADM5_ADMIN_SERVICE,
926 NULL, KADM5_STRUCT_VERSION, api, NULL, &handle),
927 KADM5_BAD_PASSWORD);
928
929 /* Fails with null client name. */
930 check_fail(kadm5_init(context, NULL, "admin", KADM5_ADMIN_SERVICE,
931 NULL, KADM5_STRUCT_VERSION, api, NULL, &handle),
932 EINVAL);
933
934 /* Fails with nonexistent client name. */
935 check_fail(kadm5_init(context, "noexist", "admin", KADM5_ADMIN_SERVICE,
936 NULL, KADM5_STRUCT_VERSION, api, NULL, &handle),
937 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
938
939 /* Fails with nonexistent client name with explicit realm. */
940 check_fail(kadm5_init(context, "noexist@KRBTEST.COM", "admin",
941 KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION,
942 api, NULL, &handle),
943 KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
944
945 /* Fails with nonexistent client name with unknown realm. */
946 check_fail(kadm5_init(context, "noexist@BAD.REALM", "admin",
947 KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION,
948 api, NULL, &handle), KRB5_REALM_UNKNOWN);
949
950 /* Fails with known name but unknown realm. */
951 check_fail(kadm5_init(context, "admin@BAD.REALM", "admin",
952 KADM5_ADMIN_SERVICE, NULL, KADM5_STRUCT_VERSION,
953 api, NULL, &handle), KRB5_REALM_UNKNOWN);
954
955 check(krb5_cc_destroy(context, cc));
956 } else {
957 /* Fails with nonexistent stash file. */
958 params.stash_file = "does/not/exist";
959 params.mask = KADM5_CONFIG_STASH_FILE;
960 check_fail(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
961 ¶ms, KADM5_STRUCT_VERSION, api, NULL,
962 &handle), KRB5_KDB_CANTREAD_STORED);
963
964 /* Uses configured defaults for principal creation. */
965 params.max_life = 10;
966 params.max_rlife = 20;
967 params.expiration = 30;
968 params.num_keysalts = 0;
969 params.mask = KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE |
970 KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES;
971 check(kadm5_init(context, "admin", "admin", KADM5_ADMIN_SERVICE,
972 ¶ms, KADM5_STRUCT_VERSION, api, NULL, &handle));
973 check(kadm5_create_principal(handle, &ent, KADM5_PRINCIPAL, "pw"));
974 check(kadm5_get_principal(handle, princ, &gent,
975 KADM5_PRINCIPAL_NORMAL_MASK |
976 KADM5_KEY_DATA));
977 assert(gent.max_life == 10);
978 assert(gent.max_renewable_life == 20);
979 assert(gent.princ_expire_time == 30);
980 assert(gent.n_key_data == 0);
981 check(kadm5_delete_principal(handle, princ));
982 check(kadm5_free_principal_ent(handle, &gent));
983 check(kadm5_destroy(handle));
984
985 /* Succeeds with incorrect password using local auth. */
986 check(kadm5_init(context, "admin", "wrong", KADM5_ADMIN_SERVICE, NULL,
987 KADM5_STRUCT_VERSION, api, NULL, &handle));
988 check(kadm5_destroy(handle));
989
990 /* Succeeds with null service using local auth. */
991 check(kadm5_init(context, "admin", "admin", NULL, NULL,
992 KADM5_STRUCT_VERSION, api, NULL, &handle));
993 check(kadm5_destroy(handle));
994
995 /* Succeeds with nonexistent, non-kadmin service using local auth. */
996 check(kadm5_init(context, "admin", "admin", "foobar", NULL,
997 KADM5_STRUCT_VERSION, api, NULL, &handle));
998 check(kadm5_destroy(handle));
999 }
1000
1001 krb5_free_principal(context, princ);
1002 }
1003
1004 static void
mpol_test_fail(char * user,kadm5_policy_ent_t ent,uint32_t mask,krb5_error_code code)1005 mpol_test_fail(char *user, kadm5_policy_ent_t ent, uint32_t mask,
1006 krb5_error_code code)
1007 {
1008 void *handle = get_handle(user);
1009
1010 check_fail(kadm5_modify_policy(handle, ent, mask), code);
1011 free_handle(handle);
1012 }
1013
1014 static void
mpol_test_compare(void * handle,kadm5_policy_ent_t ent,uint32_t mask)1015 mpol_test_compare(void *handle, kadm5_policy_ent_t ent, uint32_t mask)
1016 {
1017 mpol_test_fail(handle, ent, mask, 0);
1018 compare_policy(ent, mask);
1019 }
1020
1021 static void
test_modify_policy()1022 test_modify_policy()
1023 {
1024 kadm5_policy_ent_rec ent;
1025
1026 memset(&ent, 0, sizeof(ent));
1027 ent.policy = "modify-policy-test";
1028 create_simple_policy(ent.policy);
1029
1030 /* pw_min_life = 0 and pw_min_life != 0 */
1031 mpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
1032 ent.pw_min_life = 32;
1033 mpol_test_compare("admin", &ent, KADM5_PW_MIN_LIFE);
1034
1035 /* pw_max_life = 0 and pw_max_life != 0 */
1036 mpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
1037 ent.pw_max_life = 32;
1038 mpol_test_compare("admin", &ent, KADM5_PW_MAX_LIFE);
1039
1040 /* pw_min_length = 0 (rejected) and pw_min_length != 0 */
1041 mpol_test_fail("admin", &ent, KADM5_PW_MIN_LENGTH, KADM5_BAD_LENGTH);
1042 ent.pw_min_length = 8;
1043 mpol_test_compare("admin", &ent, KADM5_PW_MIN_LENGTH);
1044
1045 /* pw_min_classes = 0 (rejected), 1, 5, 6 (rejected) */
1046 mpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
1047 ent.pw_min_classes = 1;
1048 mpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
1049 ent.pw_min_classes = 5;
1050 mpol_test_compare("admin", &ent, KADM5_PW_MIN_CLASSES);
1051 ent.pw_min_classes = 6;
1052 mpol_test_fail("admin", &ent, KADM5_PW_MIN_CLASSES, KADM5_BAD_CLASS);
1053
1054 /* pw_history_num = 0 (rejected), 1, 10 */
1055 mpol_test_fail("admin", &ent, KADM5_PW_HISTORY_NUM, KADM5_BAD_HISTORY);
1056 ent.pw_history_num = 1;
1057 mpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
1058 ent.pw_history_num = 10;
1059 mpol_test_compare("admin", &ent, KADM5_PW_HISTORY_NUM);
1060
1061 if (api >= KADM5_API_VERSION_3) {
1062 ent.pw_max_fail = 2;
1063 mpol_test_compare("admin", &ent, KADM5_PW_MAX_FAILURE);
1064 ent.pw_failcnt_interval = 90;
1065 mpol_test_compare("admin", &ent, KADM5_PW_FAILURE_COUNT_INTERVAL);
1066 ent.pw_lockout_duration = 180;
1067 mpol_test_compare("admin", &ent, KADM5_PW_LOCKOUT_DURATION);
1068 }
1069
1070 /* Fails over RPC if "modify" ACL is not granted, or if we authenticated to
1071 * kadmin/changepw. */
1072 if (rpc) {
1073 mpol_test_fail("$admin", &ent, KADM5_PW_MAX_LIFE, KADM5_AUTH_MODIFY);
1074 mpol_test_fail("admin/none", &ent, KADM5_PW_MAX_LIFE,
1075 KADM5_AUTH_MODIFY);
1076 mpol_test_fail("admin/get", &ent, KADM5_PW_MAX_LIFE,
1077 KADM5_AUTH_MODIFY);
1078 mpol_test_compare("admin/modify", &ent, KADM5_PW_MAX_LIFE);
1079 }
1080
1081 delete_policy(ent.policy);
1082
1083 /* Fails with empty or null policy name. */
1084 ent.policy = NULL;
1085 mpol_test_fail("admin", &ent, KADM5_PW_MAX_LIFE, EINVAL);
1086 ent.policy = "";
1087 mpol_test_fail("admin", &ent, KADM5_PW_MAX_LIFE, KADM5_BAD_POLICY);
1088
1089 /* Fails with null handle or policy ent. */
1090 mpol_test_fail(NULL, &ent, KADM5_PW_MAX_LIFE, KADM5_BAD_SERVER_HANDLE);
1091 mpol_test_fail("admin", NULL, KADM5_PW_MAX_LIFE, EINVAL);
1092 }
1093
1094 static void
mprinc_test_fail(char * user,kadm5_principal_ent_t ent,uint32_t mask,krb5_error_code code)1095 mprinc_test_fail(char *user, kadm5_principal_ent_t ent, uint32_t mask,
1096 krb5_error_code code)
1097 {
1098 void *handle = get_handle(user);
1099
1100 check_fail(kadm5_modify_principal(handle, ent, mask), code);
1101 free_handle(handle);
1102 }
1103
1104 static void
mprinc_test_compare(char * user,kadm5_principal_ent_t ent,uint32_t mask)1105 mprinc_test_compare(char *user, kadm5_principal_ent_t ent, uint32_t mask)
1106 {
1107 mprinc_test_fail(user, ent, mask, 0);
1108 compare_princ(ent, mask);
1109 }
1110
1111 static void
test_modify_principal()1112 test_modify_principal()
1113 {
1114 void *handle;
1115 krb5_principal princ = parse_princ("modify-principal-test");
1116 kadm5_principal_ent_rec ent;
1117 krb5_tl_data tl = { NULL, 1, 1, (uint8_t *)"x" };
1118 krb5_tl_data tl2 = { NULL, 999, 6, (uint8_t *)"foobar" };
1119
1120 memset(&ent, 0, sizeof(ent));
1121 ent.principal = princ;
1122
1123 /* Fails with unknown principal. */
1124 mprinc_test_fail("admin", &ent, KADM5_KVNO, KADM5_UNK_PRINC);
1125
1126 create_simple_princ(princ, NULL);
1127
1128 /* Fails with prohibited mask bit or tl-data type. */
1129 mprinc_test_fail("admin", &ent, KADM5_AUX_ATTRIBUTES, KADM5_BAD_MASK);
1130 mprinc_test_fail("admin", &ent, KADM5_KEY_DATA, KADM5_BAD_MASK);
1131 mprinc_test_fail("admin", &ent, KADM5_LAST_FAILED, KADM5_BAD_MASK);
1132 mprinc_test_fail("admin", &ent, KADM5_LAST_SUCCESS, KADM5_BAD_MASK);
1133 mprinc_test_fail("admin", &ent, KADM5_LAST_PWD_CHANGE, KADM5_BAD_MASK);
1134 mprinc_test_fail("admin", &ent, KADM5_MKVNO, KADM5_BAD_MASK);
1135 mprinc_test_fail("admin", &ent, KADM5_MOD_NAME, KADM5_BAD_MASK);
1136 mprinc_test_fail("admin", &ent, KADM5_MOD_TIME, KADM5_BAD_MASK);
1137 mprinc_test_fail("admin", &ent, KADM5_PRINCIPAL, KADM5_BAD_MASK);
1138
1139 /* Fails with tl-data type below 256. */
1140 ent.n_tl_data = 1;
1141 ent.tl_data = &tl;
1142 mprinc_test_fail("admin", &ent, KADM5_TL_DATA, KADM5_BAD_TL_TYPE);
1143
1144 /* Fails with fail_auth_count other than zero. */
1145 ent.fail_auth_count = 1234;
1146 mprinc_test_fail("admin", &ent, KADM5_FAIL_AUTH_COUNT,
1147 KADM5_BAD_SERVER_PARAMS);
1148 ent.fail_auth_count = 0;
1149
1150 /* Succeeds with zero values of various fields. */
1151 mprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION);
1152 mprinc_test_compare("admin", &ent, KADM5_MAX_LIFE);
1153 mprinc_test_compare("admin", &ent, KADM5_MAX_RLIFE);
1154 mprinc_test_compare("admin", &ent, KADM5_FAIL_AUTH_COUNT);
1155 mprinc_test_compare("admin/modify", &ent, KADM5_PRINC_EXPIRE_TIME);
1156 mprinc_test_compare("admin", &ent, KADM5_POLICY_CLR);
1157
1158 /* Setting a policy causes a pw_expiration computation. Explicit
1159 * PW_EXPIRATION overrides the policy. */
1160 ent.pw_expiration = 1234;
1161 mprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION);
1162 ent.policy = "dict-only-pol";
1163 mprinc_test_compare("admin", &ent, KADM5_POLICY);
1164 ent.policy = "test-pol";
1165 mprinc_test_compare("admin", &ent, KADM5_POLICY);
1166 ent.pw_expiration = 999999999;
1167 mprinc_test_compare("admin", &ent, KADM5_PW_EXPIRATION);
1168 mprinc_test_compare("admin", &ent, KADM5_POLICY_CLR);
1169
1170 /* Succeeds with non-zero values of various fields. */
1171 ent.princ_expire_time = 1234;
1172 mprinc_test_compare("admin", &ent, KADM5_PRINC_EXPIRE_TIME);
1173 ent.attributes = KRB5_KDB_DISALLOW_ALL_TIX;
1174 mprinc_test_compare("admin", &ent, KADM5_ATTRIBUTES);
1175 ent.attributes = KRB5_KDB_REQUIRES_PWCHANGE;
1176 mprinc_test_compare("admin", &ent, KADM5_ATTRIBUTES);
1177 ent.attributes = KRB5_KDB_DISALLOW_TGT_BASED;
1178 mprinc_test_compare("admin", &ent, KADM5_ATTRIBUTES);
1179 ent.max_life = 3456;
1180 mprinc_test_compare("admin", &ent, KADM5_MAX_LIFE);
1181 ent.kvno = 7;
1182 mprinc_test_compare("admin", &ent, KADM5_KVNO);
1183
1184 /* Fails over RPC if "modify" ACL is not granted, or if we authenticated to
1185 * kadmin/changepw. */
1186 if (rpc) {
1187 mprinc_test_fail("$admin", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
1188 mprinc_test_fail("admin/none", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
1189 mprinc_test_fail("admin/get", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
1190 mprinc_test_fail("admin/add", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
1191 mprinc_test_fail("admin/delete", &ent, KADM5_KVNO, KADM5_AUTH_MODIFY);
1192 }
1193
1194 /* tl-data of type > 255 is accepted. */
1195 handle = get_handle("admin");
1196 ent.max_renewable_life = 88;
1197 ent.tl_data = &tl2;
1198 check(kadm5_modify_principal(handle, &ent,
1199 KADM5_MAX_RLIFE | KADM5_TL_DATA));
1200 memset(&ent, 0, sizeof(ent));
1201 check(kadm5_get_principal(handle, princ, &ent,
1202 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_TL_DATA));
1203 assert(ent.max_renewable_life == 88);
1204 assert(ent.n_tl_data == 1);
1205 assert(ent.tl_data->tl_data_type == tl2.tl_data_type);
1206 assert(ent.tl_data->tl_data_length == tl2.tl_data_length);
1207 assert(memcmp(ent.tl_data->tl_data_contents, tl2.tl_data_contents,
1208 tl2.tl_data_length) == 0);
1209 check(kadm5_free_principal_ent(handle, &ent));
1210 free_handle(handle);
1211
1212 /* Fails with null handle or principal ent. */
1213 mprinc_test_fail(NULL, &ent, KADM5_KVNO, KADM5_BAD_SERVER_HANDLE);
1214 mprinc_test_fail("admin", NULL, KADM5_KVNO, EINVAL);
1215
1216 delete_princ(princ);
1217 krb5_free_principal(context, princ);
1218 }
1219
1220 static void
rnd_test_fail(char * user,krb5_principal princ,krb5_error_code code)1221 rnd_test_fail(char *user, krb5_principal princ, krb5_error_code code)
1222 {
1223 void *handle = get_handle(user);
1224
1225 check_fail(kadm5_randkey_principal(handle, princ, NULL, NULL), code);
1226 free_handle(handle);
1227 }
1228
1229 static void
rnd_test_succeed(char * user,krb5_principal princ)1230 rnd_test_succeed(char *user, krb5_principal princ)
1231 {
1232 rnd_test_fail(user, princ, 0);
1233 }
1234
1235 static void
test_randkey()1236 test_randkey()
1237 {
1238 void *handle;
1239 krb5_principal princ = parse_princ("randkey-principal-test");
1240 krb5_principal user_princ = parse_princ("user");
1241 krb5_principal admin_princ = parse_princ("admin");
1242 kadm5_principal_ent_rec ent;
1243 krb5_keyblock *keys;
1244 int n_keys, i;
1245
1246 create_simple_princ(princ, NULL);
1247
1248 /* Check kvno and enctypes after randkey. */
1249 handle = get_handle("admin");
1250 check(kadm5_randkey_principal(handle, princ, &keys, &n_keys));
1251 check(kadm5_get_principal(handle, princ, &ent, KADM5_KEY_DATA));
1252 compare_key_data(&ent, default_supported_enctypes);
1253 assert(ent.key_data[0].key_data_kvno == 2);
1254 assert(n_keys == ent.n_key_data);
1255 for (i = 0; i < n_keys; i++)
1256 krb5_free_keyblock_contents(context, &keys[i]);
1257 free(keys);
1258 check(kadm5_free_principal_ent(handle, &ent));
1259 free_handle(handle);
1260
1261 /*
1262 * Fails over RPC if "change" ACL is not granted, or if we authenticated to
1263 * kadmin/changepw and are changing another principal's password, or for
1264 * self-service if the policy minimum life has not elapsed since the last
1265 * key change.
1266 */
1267 if (rpc) {
1268 rnd_test_fail("$admin", user_princ, KADM5_AUTH_CHANGEPW);
1269 rnd_test_fail("admin/none", user_princ, KADM5_AUTH_CHANGEPW);
1270 rnd_test_fail("admin/delete", user_princ, KADM5_AUTH_CHANGEPW);
1271 rnd_test_succeed("admin/modify", user_princ);
1272 cpw_test_succeed("admin", user_princ, USER_PASSWORD);
1273 rnd_test_fail("user", user_princ, KADM5_PASS_TOOSOON);
1274 rnd_test_fail("$user", user_princ, KADM5_PASS_TOOSOON);
1275 }
1276
1277 /* Succeeds with change privilege in spite of policy minimum life. */
1278 rnd_test_succeed("admin/modify", user_princ);
1279 cpw_test_succeed("admin", user_princ, USER_PASSWORD);
1280
1281 /* Succeeds for self-service when authenticating to kadmin/changepw. */
1282 handle = get_handle("$admin");
1283 check(kadm5_randkey_principal(handle, admin_princ, NULL, NULL));
1284 check(kadm5_chpass_principal(handle, admin_princ, ADMIN_PASSWORD));
1285 free_handle(handle);
1286
1287 /* Fails with null handle or principal name. */
1288 rnd_test_fail(NULL, princ, KADM5_BAD_SERVER_HANDLE);
1289 rnd_test_fail("admin", NULL, EINVAL);
1290
1291 delete_princ(princ);
1292 krb5_free_principal(context, princ);
1293 krb5_free_principal(context, user_princ);
1294 krb5_free_principal(context, admin_princ);
1295 }
1296
1297 int
main(int argc,char ** argv)1298 main(int argc, char **argv)
1299 {
1300 assert(argc == 2);
1301 rpc = (strcmp(argv[1], "clnt") == 0);
1302
1303 check(kadm5_init_krb5_context(&context));
1304
1305 api = KADM5_API_VERSION_2;
1306 test_create_policy();
1307 test_get_policy();
1308 test_modify_policy();
1309
1310 api = KADM5_API_VERSION_4;
1311 test_chpass();
1312 test_create_policy();
1313 test_create_principal();
1314 test_delete_policy();
1315 test_delete_principal();
1316 test_get_policy();
1317 test_get_principal();
1318 test_init_destroy();
1319 test_modify_policy();
1320 test_modify_principal();
1321 test_randkey();
1322
1323 krb5_free_context(context);
1324
1325 return 0;
1326 }
1327