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 53 check(krb5_error_code code) 54 { 55 assert(code == 0); 56 } 57 58 static void 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 * 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 93 free_handle(void *handle) 94 { 95 if (handle != NULL) 96 check(kadm5_destroy(handle)); 97 } 98 99 static krb5_principal 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 532 dpol_test_succeed(char *user, char *name) 533 { 534 dpol_test_fail(user, name, 0); 535 } 536 537 static void 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 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 584 dprinc_test_succeed(char *user, krb5_principal princ) 585 { 586 dprinc_test_fail(user, princ, 0); 587 } 588 589 static void 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1230 rnd_test_succeed(char *user, krb5_principal princ) 1231 { 1232 rnd_test_fail(user, princ, 0); 1233 } 1234 1235 static void 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 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