1 /* 2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* 6 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 7 * 8 * Openvision retains the copyright to derivative works of 9 * this source code. Do *NOT* create a derivative of this 10 * source code before consulting with your legal department. 11 * Do *NOT* integrate *ANY* of this source code into another 12 * product before consulting with your legal department. 13 * 14 * For further information, read the top-level Openvision 15 * copyright which is contained in the top-level MIT Kerberos 16 * copyright. 17 * 18 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 19 * 20 */ 21 22 /* 23 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 24 */ 25 26 #include <sys/types.h> 27 #include <sys/time.h> 28 #include <errno.h> 29 #include "server_internal.h" 30 #include <kadm5/admin.h> 31 #include <kdb.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <stdarg.h> 35 #include <stdlib.h> 36 #include <k5-int.h> 37 #include <kadm5/server_internal.h> 38 #include <kadm5/admin.h> 39 #ifdef USE_PASSWORD_SERVER 40 #include <sys/wait.h> 41 #endif 42 43 extern krb5_principal master_princ; 44 extern krb5_principal hist_princ; 45 extern krb5_keyblock hist_key; 46 extern krb5_db_entry master_db; 47 extern krb5_db_entry hist_db; 48 extern krb5_kvno hist_kvno; 49 50 static int decrypt_key_data(krb5_context context, 51 krb5_keyblock *, int n_key_data, krb5_key_data *key_data, 52 krb5_keyblock **keyblocks, int *n_keys); 53 54 static krb5_error_code 55 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc) 56 { 57 register krb5_principal tempprinc; 58 register int i, nelems; 59 60 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data)); 61 62 if (tempprinc == 0) 63 return ENOMEM; 64 65 memcpy(tempprinc, inprinc, sizeof(krb5_principal_data)); 66 67 nelems = (int) krb5_princ_size(context, inprinc); 68 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data)); 69 70 if (tempprinc->data == 0) { 71 krb5_db_free(context, (char *)tempprinc); 72 return ENOMEM; 73 } 74 75 for (i = 0; i < nelems; i++) { 76 unsigned int len = krb5_princ_component(context, inprinc, i)->length; 77 krb5_princ_component(context, tempprinc, i)->length = len; 78 if (((krb5_princ_component(context, tempprinc, i)->data = 79 krb5_db_alloc(context, NULL, len)) == 0) && len) { 80 while (--i >= 0) 81 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); 82 krb5_db_free (context, tempprinc->data); 83 krb5_db_free (context, tempprinc); 84 return ENOMEM; 85 } 86 if (len) 87 memcpy(krb5_princ_component(context, tempprinc, i)->data, 88 krb5_princ_component(context, inprinc, i)->data, len); 89 } 90 91 tempprinc->realm.data = 92 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length); 93 if (!tempprinc->realm.data && tempprinc->realm.length) { 94 for (i = 0; i < nelems; i++) 95 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); 96 krb5_db_free(context, tempprinc->data); 97 krb5_db_free(context, tempprinc); 98 return ENOMEM; 99 } 100 if (tempprinc->realm.length) 101 memcpy(tempprinc->realm.data, inprinc->realm.data, 102 inprinc->realm.length); 103 104 *outprinc = tempprinc; 105 return 0; 106 } 107 108 static void 109 kadm5_free_principal(krb5_context context, krb5_principal val) 110 { 111 register krb5_int32 i; 112 113 if (!val) 114 return; 115 116 if (val->data) { 117 i = krb5_princ_size(context, val); 118 while(--i >= 0) 119 krb5_db_free(context, krb5_princ_component(context, val, i)->data); 120 krb5_db_free(context, val->data); 121 } 122 if (val->realm.data) 123 krb5_db_free(context, val->realm.data); 124 krb5_db_free(context, val); 125 } 126 127 /* 128 * XXX Functions that ought to be in libkrb5.a, but aren't. 129 */ 130 kadm5_ret_t krb5_copy_key_data_contents(context, from, to) 131 krb5_context context; 132 krb5_key_data *from, *to; 133 { 134 int i, idx; 135 136 *to = *from; 137 138 idx = (from->key_data_ver == 1 ? 1 : 2); 139 140 for (i = 0; i < idx; i++) { 141 if ( from->key_data_length[i] ) { 142 to->key_data_contents[i] = malloc(from->key_data_length[i]); 143 if (to->key_data_contents[i] == NULL) { 144 for (i = 0; i < idx; i++) { 145 if (to->key_data_contents[i]) { 146 memset(to->key_data_contents[i], 0, 147 to->key_data_length[i]); 148 free(to->key_data_contents[i]); 149 } 150 } 151 return ENOMEM; 152 } 153 memcpy(to->key_data_contents[i], from->key_data_contents[i], 154 from->key_data_length[i]); 155 } 156 } 157 return 0; 158 } 159 160 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) 161 { 162 krb5_tl_data *n; 163 164 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); 165 if (n == NULL) 166 return NULL; 167 n->tl_data_contents = malloc(tl->tl_data_length); 168 if (n->tl_data_contents == NULL) { 169 free(n); 170 return NULL; 171 } 172 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); 173 n->tl_data_type = tl->tl_data_type; 174 n->tl_data_length = tl->tl_data_length; 175 n->tl_data_next = NULL; 176 return n; 177 } 178 179 /* This is in lib/kdb/kdb_cpw.c, but is static */ 180 static void cleanup_key_data(context, count, data) 181 krb5_context context; 182 int count; 183 krb5_key_data * data; 184 { 185 int i, j; 186 187 for (i = 0; i < count; i++) 188 for (j = 0; j < data[i].key_data_ver; j++) 189 if (data[i].key_data_length[j]) 190 krb5_db_free(context, data[i].key_data_contents[j]); 191 krb5_db_free(context, data); 192 } 193 194 kadm5_ret_t 195 kadm5_create_principal(void *server_handle, 196 kadm5_principal_ent_t entry, long mask, 197 char *password) 198 { 199 return 200 kadm5_create_principal_3(server_handle, entry, mask, 201 0, NULL, password); 202 } 203 kadm5_ret_t 204 kadm5_create_principal_3(void *server_handle, 205 kadm5_principal_ent_t entry, long mask, 206 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 207 char *password) 208 { 209 krb5_db_entry kdb; 210 osa_princ_ent_rec adb; 211 kadm5_policy_ent_rec polent; 212 krb5_int32 now; 213 krb5_tl_data *tl_data_tail; 214 unsigned int ret; 215 kadm5_server_handle_t handle = server_handle; 216 217 CHECK_HANDLE(server_handle); 218 219 krb5_clear_error_message(handle->context); 220 221 /* 222 * Argument sanity checking, and opening up the DB 223 */ 224 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || 225 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || 226 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || 227 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || 228 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || 229 (mask & KADM5_FAIL_AUTH_COUNT)) 230 return KADM5_BAD_MASK; 231 if((mask & ~ALL_PRINC_MASK)) 232 return KADM5_BAD_MASK; 233 if (entry == (kadm5_principal_ent_t) NULL || password == NULL) 234 return EINVAL; 235 236 /* 237 * Check to see if the principal exists 238 */ 239 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 240 241 switch(ret) { 242 case KADM5_UNK_PRINC: 243 /* Solaris Kerberos */ 244 memset(&kdb, 0, sizeof(krb5_db_entry)); 245 memset(&adb, 0, sizeof(osa_princ_ent_rec)); 246 break; 247 case 0: 248 /* 249 * Solaris Kerberos: this allows an addprinc to be done on a mix-in 250 * princ which has no keys initially. 251 */ 252 if (kdb.n_key_data != 0) { 253 /* have a princ with keys, return dupe princ error */ 254 kdb_free_entry(handle, &kdb, &adb); 255 return KADM5_DUP; 256 } else { 257 /* 258 * have a princ with no keys, let's replace it. Note, want to 259 * keep the existing kdb tl_data (specifically the LDAP plugin 260 * adds the DN to the tl_data which is needed to locate the dir. 261 * entry). 262 */ 263 kdb_free_entry(handle, NULL, &adb); 264 memset(&adb, 0, sizeof(osa_princ_ent_rec)); 265 } 266 break; 267 default: 268 return ret; 269 } 270 271 /* 272 * If a policy was specified, load it. 273 * If we can not find the one specified return an error 274 */ 275 if ((mask & KADM5_POLICY)) { 276 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, 277 &polent)) != KADM5_OK) { 278 if(ret == EINVAL) 279 return KADM5_BAD_POLICY; 280 else 281 return ret; 282 } 283 } 284 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY), 285 &polent, entry->principal))) { 286 if (mask & KADM5_POLICY) 287 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 288 return ret; 289 } 290 /* 291 * Start populating the various DB fields, using the 292 * "defaults" for fields that were not specified by the 293 * mask. 294 */ 295 if ((ret = krb5_timeofday(handle->context, &now))) { 296 if (mask & KADM5_POLICY) 297 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 298 return ret; 299 } 300 301 kdb.magic = KRB5_KDB_MAGIC_NUMBER; 302 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ 303 304 /* 305 * Solaris Kerberos: 306 * If KADM5_ATTRIBUTES is set, we want to rope in not only 307 * entry->attributes, but also the generic params.flags 308 * obtained previously via kadm5_get_config_params. 309 */ 310 if ((mask & KADM5_ATTRIBUTES)) { 311 kdb.attributes = handle->params.flags; 312 kdb.attributes |= entry->attributes; 313 } else { 314 kdb.attributes = handle->params.flags; 315 } 316 317 if ((mask & KADM5_MAX_LIFE)) 318 kdb.max_life = entry->max_life; 319 else 320 kdb.max_life = handle->params.max_life; 321 322 if (mask & KADM5_MAX_RLIFE) 323 kdb.max_renewable_life = entry->max_renewable_life; 324 else 325 kdb.max_renewable_life = handle->params.max_rlife; 326 327 if ((mask & KADM5_PRINC_EXPIRE_TIME)) 328 kdb.expiration = entry->princ_expire_time; 329 else 330 kdb.expiration = handle->params.expiration; 331 332 kdb.pw_expiration = 0; 333 if ((mask & KADM5_POLICY)) { 334 if(polent.pw_max_life) 335 kdb.pw_expiration = now + polent.pw_max_life; 336 else 337 kdb.pw_expiration = 0; 338 } 339 if ((mask & KADM5_PW_EXPIRATION)) 340 kdb.pw_expiration = entry->pw_expiration; 341 342 kdb.last_success = 0; 343 kdb.last_failed = 0; 344 kdb.fail_auth_count = 0; 345 346 /* this is kind of gross, but in order to free the tl data, I need 347 to free the entire kdb entry, and that will try to free the 348 principal. */ 349 350 if ((ret = kadm5_copy_principal(handle->context, 351 entry->principal, &(kdb.princ)))) { 352 if (mask & KADM5_POLICY) 353 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 354 return(ret); 355 } 356 357 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) { 358 krb5_db_free_principal(handle->context, &kdb, 1); 359 if (mask & KADM5_POLICY) 360 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 361 return(ret); 362 } 363 364 if (mask & KADM5_TL_DATA) { 365 /* splice entry->tl_data onto the front of kdb.tl_data */ 366 for (tl_data_tail = entry->tl_data; tl_data_tail; 367 tl_data_tail = tl_data_tail->tl_data_next) 368 { 369 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail); 370 if( ret ) 371 { 372 krb5_db_free_principal(handle->context, &kdb, 1); 373 if (mask & KADM5_POLICY) 374 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 375 return ret; 376 } 377 } 378 } 379 380 /* initialize the keys */ 381 382 if ((ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 383 n_ks_tuple?ks_tuple:handle->params.keysalts, 384 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 385 password, 386 (mask & KADM5_KVNO)?entry->kvno:1, 387 FALSE, &kdb))) { 388 krb5_db_free_principal(handle->context, &kdb, 1); 389 if (mask & KADM5_POLICY) 390 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 391 return(ret); 392 } 393 394 /* populate the admin-server-specific fields. In the OV server, 395 this used to be in a separate database. Since there's already 396 marshalling code for the admin fields, to keep things simple, 397 I'm going to keep it, and make all the admin stuff occupy a 398 single tl_data record, */ 399 400 adb.admin_history_kvno = hist_kvno; 401 if ((mask & KADM5_POLICY)) { 402 adb.aux_attributes = KADM5_POLICY; 403 404 /* this does *not* need to be strdup'ed, because adb is xdr */ 405 /* encoded in osa_adb_create_princ, and not ever freed */ 406 407 adb.policy = entry->policy; 408 } 409 410 /* increment the policy ref count, if any */ 411 412 if ((mask & KADM5_POLICY)) { 413 polent.policy_refcnt++; 414 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 415 KADM5_REF_COUNT)) 416 != KADM5_OK) { 417 krb5_db_free_principal(handle->context, &kdb, 1); 418 if (mask & KADM5_POLICY) 419 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 420 return(ret); 421 } 422 } 423 424 /* In all cases key and the principal data is set, let the database provider know */ 425 kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ; 426 427 /* store the new db entry */ 428 ret = kdb_put_entry(handle, &kdb, &adb); 429 430 krb5_db_free_principal(handle->context, &kdb, 1); 431 432 if (ret) { 433 if ((mask & KADM5_POLICY)) { 434 /* decrement the policy ref count */ 435 436 polent.policy_refcnt--; 437 /* 438 * if this fails, there's nothing we can do anyway. the 439 * policy refcount wil be too high. 440 */ 441 (void) kadm5_modify_policy_internal(handle->lhandle, &polent, 442 KADM5_REF_COUNT); 443 } 444 445 if (mask & KADM5_POLICY) 446 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 447 return(ret); 448 } 449 450 if (mask & KADM5_POLICY) 451 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 452 453 return KADM5_OK; 454 } 455 456 457 kadm5_ret_t 458 kadm5_delete_principal(void *server_handle, krb5_principal principal) 459 { 460 unsigned int ret; 461 kadm5_policy_ent_rec polent; 462 krb5_db_entry kdb; 463 osa_princ_ent_rec adb; 464 kadm5_server_handle_t handle = server_handle; 465 466 CHECK_HANDLE(server_handle); 467 468 krb5_clear_error_message(handle->context); 469 470 if (principal == NULL) 471 return EINVAL; 472 473 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 474 return(ret); 475 476 if ((adb.aux_attributes & KADM5_POLICY)) { 477 if ((ret = kadm5_get_policy(handle->lhandle, 478 adb.policy, &polent)) 479 == KADM5_OK) { 480 polent.policy_refcnt--; 481 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, 482 KADM5_REF_COUNT)) 483 != KADM5_OK) { 484 (void) kadm5_free_policy_ent(handle->lhandle, &polent); 485 kdb_free_entry(handle, &kdb, &adb); 486 return(ret); 487 } 488 } 489 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) { 490 kdb_free_entry(handle, &kdb, &adb); 491 return ret; 492 } 493 } 494 495 ret = kdb_delete_entry(handle, principal); 496 497 kdb_free_entry(handle, &kdb, &adb); 498 499 return ret; 500 } 501 502 kadm5_ret_t 503 kadm5_modify_principal(void *server_handle, 504 kadm5_principal_ent_t entry, long mask) 505 { 506 int ret, ret2, i; 507 kadm5_policy_ent_rec npol, opol; 508 int have_npol = 0, have_opol = 0; 509 krb5_db_entry kdb; 510 krb5_tl_data *tl_data_orig; 511 osa_princ_ent_rec adb; 512 kadm5_server_handle_t handle = server_handle; 513 514 CHECK_HANDLE(server_handle); 515 516 krb5_clear_error_message(handle->context); 517 518 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || 519 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || 520 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || 521 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || 522 (mask & KADM5_LAST_FAILED)) 523 return KADM5_BAD_MASK; 524 if((mask & ~ALL_PRINC_MASK)) 525 return KADM5_BAD_MASK; 526 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) 527 return KADM5_BAD_MASK; 528 if(entry == (kadm5_principal_ent_t) NULL) 529 return EINVAL; 530 if (mask & KADM5_TL_DATA) { 531 tl_data_orig = entry->tl_data; 532 while (tl_data_orig) { 533 if (tl_data_orig->tl_data_type < 256) 534 return KADM5_BAD_TL_TYPE; 535 tl_data_orig = tl_data_orig->tl_data_next; 536 } 537 } 538 539 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); 540 if (ret) 541 return(ret); 542 543 /* 544 * This is pretty much the same as create ... 545 */ 546 547 if ((mask & KADM5_POLICY)) { 548 /* get the new policy */ 549 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); 550 if (ret) { 551 switch (ret) { 552 case EINVAL: 553 ret = KADM5_BAD_POLICY; 554 break; 555 case KADM5_UNK_POLICY: 556 case KADM5_BAD_POLICY: 557 ret = KADM5_UNK_POLICY; 558 break; 559 } 560 goto done; 561 } 562 have_npol = 1; 563 564 /* if we already have a policy, get it to decrement the refcnt */ 565 if(adb.aux_attributes & KADM5_POLICY) { 566 /* ... but not if the old and new are the same */ 567 if(strcmp(adb.policy, entry->policy)) { 568 ret = kadm5_get_policy(handle->lhandle, 569 adb.policy, &opol); 570 switch(ret) { 571 case EINVAL: 572 case KADM5_BAD_POLICY: 573 case KADM5_UNK_POLICY: 574 break; 575 case KADM5_OK: 576 have_opol = 1; 577 opol.policy_refcnt--; 578 break; 579 default: 580 goto done; 581 break; 582 } 583 npol.policy_refcnt++; 584 } 585 } else npol.policy_refcnt++; 586 587 /* set us up to use the new policy */ 588 adb.aux_attributes |= KADM5_POLICY; 589 if (adb.policy) 590 free(adb.policy); 591 adb.policy = strdup(entry->policy); 592 593 /* set pw_max_life based on new policy */ 594 if (npol.pw_max_life) { 595 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 596 &(kdb.pw_expiration)); 597 if (ret) 598 goto done; 599 kdb.pw_expiration += npol.pw_max_life; 600 } else { 601 kdb.pw_expiration = 0; 602 } 603 } 604 605 if ((mask & KADM5_POLICY_CLR) && 606 (adb.aux_attributes & KADM5_POLICY)) { 607 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); 608 switch(ret) { 609 case EINVAL: 610 case KADM5_BAD_POLICY: 611 case KADM5_UNK_POLICY: 612 ret = KADM5_BAD_DB; 613 goto done; 614 break; 615 case KADM5_OK: 616 have_opol = 1; 617 if (adb.policy) 618 free(adb.policy); 619 adb.policy = NULL; 620 adb.aux_attributes &= ~KADM5_POLICY; 621 kdb.pw_expiration = 0; 622 opol.policy_refcnt--; 623 break; 624 default: 625 goto done; 626 break; 627 } 628 } 629 630 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) && 631 (((have_opol) && 632 (ret = 633 kadm5_modify_policy_internal(handle->lhandle, &opol, 634 KADM5_REF_COUNT))) || 635 ((have_npol) && 636 (ret = 637 kadm5_modify_policy_internal(handle->lhandle, &npol, 638 KADM5_REF_COUNT))))) 639 goto done; 640 641 if ((mask & KADM5_ATTRIBUTES)) 642 kdb.attributes = entry->attributes; 643 if ((mask & KADM5_MAX_LIFE)) 644 kdb.max_life = entry->max_life; 645 if ((mask & KADM5_PRINC_EXPIRE_TIME)) 646 kdb.expiration = entry->princ_expire_time; 647 if (mask & KADM5_PW_EXPIRATION) 648 kdb.pw_expiration = entry->pw_expiration; 649 if (mask & KADM5_MAX_RLIFE) 650 kdb.max_renewable_life = entry->max_renewable_life; 651 if (mask & KADM5_FAIL_AUTH_COUNT) 652 kdb.fail_auth_count = entry->fail_auth_count; 653 654 if((mask & KADM5_KVNO)) { 655 for (i = 0; i < kdb.n_key_data; i++) 656 kdb.key_data[i].key_data_kvno = entry->kvno; 657 } 658 659 if (mask & KADM5_TL_DATA) { 660 krb5_tl_data *tl; 661 662 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */ 663 664 for (tl = entry->tl_data; tl; 665 tl = tl->tl_data_next) 666 { 667 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl); 668 if( ret ) 669 { 670 goto done; 671 } 672 } 673 } 674 675 /* let the mask propagate to the database provider */ 676 kdb.mask = mask; 677 678 ret = kdb_put_entry(handle, &kdb, &adb); 679 if (ret) goto done; 680 681 ret = KADM5_OK; 682 done: 683 if (have_opol) { 684 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); 685 ret = ret ? ret : ret2; 686 } 687 if (have_npol) { 688 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); 689 ret = ret ? ret : ret2; 690 } 691 kdb_free_entry(handle, &kdb, &adb); 692 return ret; 693 } 694 695 kadm5_ret_t 696 kadm5_rename_principal(void *server_handle, 697 krb5_principal source, krb5_principal target) 698 { 699 krb5_db_entry kdb; 700 osa_princ_ent_rec adb; 701 int ret, i; 702 kadm5_server_handle_t handle = server_handle; 703 704 CHECK_HANDLE(server_handle); 705 706 krb5_clear_error_message(handle->context); 707 708 if (source == NULL || target == NULL) 709 return EINVAL; 710 711 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { 712 kdb_free_entry(handle, &kdb, &adb); 713 return(KADM5_DUP); 714 } 715 716 if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) 717 return ret; 718 719 /* this is kinda gross, but unavoidable */ 720 721 for (i=0; i<kdb.n_key_data; i++) { 722 if ((kdb.key_data[i].key_data_ver == 1) || 723 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) { 724 ret = KADM5_NO_RENAME_SALT; 725 goto done; 726 } 727 } 728 729 kadm5_free_principal(handle->context, kdb.princ); 730 ret = kadm5_copy_principal(handle->context, target, &kdb.princ); 731 if (ret) { 732 kdb.princ = NULL; /* so freeing the dbe doesn't lose */ 733 goto done; 734 } 735 736 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 737 goto done; 738 739 ret = kdb_delete_entry(handle, source); 740 741 done: 742 kdb_free_entry(handle, &kdb, &adb); 743 return ret; 744 } 745 746 kadm5_ret_t 747 kadm5_get_principal(void *server_handle, krb5_principal principal, 748 kadm5_principal_ent_t entry, 749 long in_mask) 750 { 751 krb5_db_entry kdb; 752 osa_princ_ent_rec adb; 753 krb5_error_code ret = 0; 754 long mask; 755 int i; 756 kadm5_server_handle_t handle = server_handle; 757 kadm5_principal_ent_rec entry_local, *entry_orig; 758 759 CHECK_HANDLE(server_handle); 760 761 krb5_clear_error_message(handle->context); 762 763 /* 764 * In version 1, all the defined fields are always returned. 765 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be 766 * filled with allocated memory. 767 */ 768 if (handle->api_version == KADM5_API_VERSION_1) { 769 mask = KADM5_PRINCIPAL_NORMAL_MASK; 770 entry_orig = entry; 771 entry = &entry_local; 772 } else { 773 mask = in_mask; 774 } 775 776 memset((char *) entry, 0, sizeof(*entry)); 777 778 if (principal == NULL) 779 return EINVAL; 780 781 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 782 return ret; 783 784 if ((mask & KADM5_POLICY) && 785 adb.policy && (adb.aux_attributes & KADM5_POLICY)) { 786 if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) { 787 ret = ENOMEM; 788 goto done; 789 } 790 strcpy(entry->policy, adb.policy); 791 } 792 793 if (mask & KADM5_AUX_ATTRIBUTES) 794 entry->aux_attributes = adb.aux_attributes; 795 796 if ((mask & KADM5_PRINCIPAL) && 797 (ret = krb5_copy_principal(handle->context, principal, 798 &entry->principal))) { 799 goto done; 800 } 801 802 if (mask & KADM5_PRINC_EXPIRE_TIME) 803 entry->princ_expire_time = kdb.expiration; 804 805 if ((mask & KADM5_LAST_PWD_CHANGE) && 806 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, 807 &(entry->last_pwd_change)))) { 808 goto done; 809 } 810 811 if (mask & KADM5_PW_EXPIRATION) 812 entry->pw_expiration = kdb.pw_expiration; 813 if (mask & KADM5_MAX_LIFE) 814 entry->max_life = kdb.max_life; 815 816 /* this is a little non-sensical because the function returns two */ 817 /* values that must be checked separately against the mask */ 818 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { 819 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb, 820 &(entry->mod_date), 821 &(entry->mod_name)); 822 if (ret) { 823 goto done; 824 } 825 826 if (! (mask & KADM5_MOD_TIME)) 827 entry->mod_date = 0; 828 if (! (mask & KADM5_MOD_NAME)) { 829 krb5_free_principal(handle->context, entry->principal); 830 entry->principal = NULL; 831 } 832 } 833 834 if (mask & KADM5_ATTRIBUTES) 835 entry->attributes = kdb.attributes; 836 837 if (mask & KADM5_KVNO) 838 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++) 839 if (kdb.key_data[i].key_data_kvno > entry->kvno) 840 entry->kvno = kdb.key_data[i].key_data_kvno; 841 842 if (handle->api_version == KADM5_API_VERSION_2) 843 entry->mkvno = 0; 844 else { 845 /* XXX I'll be damned if I know how to deal with this one --marc */ 846 entry->mkvno = 1; 847 } 848 849 /* 850 * The new fields that only exist in version 2 start here 851 */ 852 if (handle->api_version == KADM5_API_VERSION_2) { 853 if (mask & KADM5_MAX_RLIFE) 854 entry->max_renewable_life = kdb.max_renewable_life; 855 if (mask & KADM5_LAST_SUCCESS) 856 entry->last_success = kdb.last_success; 857 if (mask & KADM5_LAST_FAILED) 858 entry->last_failed = kdb.last_failed; 859 if (mask & KADM5_FAIL_AUTH_COUNT) 860 entry->fail_auth_count = kdb.fail_auth_count; 861 if (mask & KADM5_TL_DATA) { 862 krb5_tl_data *tl, *tl2; 863 864 entry->tl_data = NULL; 865 866 tl = kdb.tl_data; 867 while (tl) { 868 if (tl->tl_data_type > 255) { 869 if ((tl2 = dup_tl_data(tl)) == NULL) { 870 ret = ENOMEM; 871 goto done; 872 } 873 tl2->tl_data_next = entry->tl_data; 874 entry->tl_data = tl2; 875 entry->n_tl_data++; 876 } 877 878 tl = tl->tl_data_next; 879 } 880 } 881 if (mask & KADM5_KEY_DATA) { 882 entry->n_key_data = kdb.n_key_data; 883 if(entry->n_key_data) { 884 entry->key_data = (krb5_key_data *) 885 malloc(entry->n_key_data*sizeof(krb5_key_data)); 886 if (entry->key_data == NULL) { 887 ret = ENOMEM; 888 goto done; 889 } 890 } else 891 entry->key_data = NULL; 892 893 for (i = 0; i < entry->n_key_data; i++) 894 ret = krb5_copy_key_data_contents(handle->context, 895 &kdb.key_data[i], 896 &entry->key_data[i]); 897 if (ret) 898 goto done; 899 } 900 } 901 902 /* 903 * If KADM5_API_VERSION_1, we return an allocated structure, and 904 * we need to convert the new structure back into the format the 905 * caller is expecting. 906 */ 907 if (handle->api_version == KADM5_API_VERSION_1) { 908 kadm5_principal_ent_t_v1 newv1; 909 910 newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1))); 911 if (newv1 == NULL) { 912 ret = ENOMEM; 913 goto done; 914 } 915 916 newv1->principal = entry->principal; 917 newv1->princ_expire_time = entry->princ_expire_time; 918 newv1->last_pwd_change = entry->last_pwd_change; 919 newv1->pw_expiration = entry->pw_expiration; 920 newv1->max_life = entry->max_life; 921 newv1->mod_name = entry->mod_name; 922 newv1->mod_date = entry->mod_date; 923 newv1->attributes = entry->attributes; 924 newv1->kvno = entry->kvno; 925 newv1->mkvno = entry->mkvno; 926 newv1->policy = entry->policy; 927 newv1->aux_attributes = entry->aux_attributes; 928 929 *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1; 930 } 931 932 ret = KADM5_OK; 933 934 done: 935 if (ret && entry->principal) 936 krb5_free_principal(handle->context, entry->principal); 937 kdb_free_entry(handle, &kdb, &adb); 938 939 return ret; 940 } 941 942 /* 943 * Function: check_pw_reuse 944 * 945 * Purpose: Check if a key appears in a list of keys, in order to 946 * enforce password history. 947 * 948 * Arguments: 949 * 950 * context (r) the krb5 context 951 * hist_keyblock (r) the key that hist_key_data is 952 * encrypted in 953 * n_new_key_data (r) length of new_key_data 954 * new_key_data (r) keys to check against 955 * pw_hist_data, encrypted in hist_keyblock 956 * n_pw_hist_data (r) length of pw_hist_data 957 * pw_hist_data (r) passwords to check new_key_data against 958 * 959 * Effects: 960 * For each new_key in new_key_data: 961 * decrypt new_key with the master_keyblock 962 * for each password in pw_hist_data: 963 * for each hist_key in password: 964 * decrypt hist_key with hist_keyblock 965 * compare the new_key and hist_key 966 * 967 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in 968 * new_key_data is the same as a key in pw_hist_data, or 0. 969 */ 970 static kadm5_ret_t 971 check_pw_reuse(krb5_context context, 972 krb5_keyblock *master_keyblock, 973 krb5_keyblock *hist_keyblock, 974 int n_new_key_data, krb5_key_data *new_key_data, 975 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) 976 { 977 int x, y, z; 978 krb5_keyblock newkey, histkey; 979 krb5_error_code ret; 980 981 for (x = 0; x < n_new_key_data; x++) { 982 ret = krb5_dbekd_decrypt_key_data(context, 983 master_keyblock, 984 &(new_key_data[x]), 985 &newkey, NULL); 986 if (ret) 987 return(ret); 988 for (y = 0; y < n_pw_hist_data; y++) { 989 for (z = 0; z < pw_hist_data[y].n_key_data; z++) { 990 ret = krb5_dbekd_decrypt_key_data(context, 991 hist_keyblock, 992 &pw_hist_data[y].key_data[z], 993 &histkey, NULL); 994 if (ret) 995 return(ret); 996 997 if ((newkey.length == histkey.length) && 998 (newkey.enctype == histkey.enctype) && 999 (memcmp(newkey.contents, histkey.contents, 1000 histkey.length) == 0)) { 1001 krb5_free_keyblock_contents(context, &histkey); 1002 krb5_free_keyblock_contents(context, &newkey); 1003 1004 return(KADM5_PASS_REUSE); 1005 } 1006 krb5_free_keyblock_contents(context, &histkey); 1007 } 1008 } 1009 krb5_free_keyblock_contents(context, &newkey); 1010 } 1011 1012 return(0); 1013 } 1014 1015 /* 1016 * Function: create_history_entry 1017 * 1018 * Purpose: Creates a password history entry from an array of 1019 * key_data. 1020 * 1021 * Arguments: 1022 * 1023 * context (r) krb5_context to use 1024 * master_keyblcok (r) master key block 1025 * n_key_data (r) number of elements in key_data 1026 * key_data (r) keys to add to the history entry 1027 * hist (w) history entry to fill in 1028 * 1029 * Effects: 1030 * 1031 * hist->key_data is allocated to store n_key_data key_datas. Each 1032 * element of key_data is decrypted with master_keyblock, re-encrypted 1033 * in hist_key, and added to hist->key_data. hist->n_key_data is 1034 * set to n_key_data. 1035 */ 1036 static 1037 int create_history_entry(krb5_context context, 1038 krb5_keyblock *master_keyblock, int n_key_data, 1039 krb5_key_data *key_data, osa_pw_hist_ent *hist) 1040 { 1041 int i, ret; 1042 krb5_keyblock key; 1043 krb5_keysalt salt; 1044 1045 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); 1046 if (hist->key_data == NULL) 1047 return ENOMEM; 1048 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); 1049 1050 for (i = 0; i < n_key_data; i++) { 1051 ret = krb5_dbekd_decrypt_key_data(context, 1052 master_keyblock, 1053 &key_data[i], 1054 &key, &salt); 1055 if (ret) 1056 return ret; 1057 1058 ret = krb5_dbekd_encrypt_key_data(context, &hist_key, 1059 &key, &salt, 1060 key_data[i].key_data_kvno, 1061 &hist->key_data[i]); 1062 if (ret) 1063 return ret; 1064 1065 krb5_free_keyblock_contents(context, &key); 1066 /* krb5_free_keysalt(context, &salt); */ 1067 } 1068 1069 hist->n_key_data = n_key_data; 1070 return 0; 1071 } 1072 1073 static 1074 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) 1075 { 1076 int i; 1077 1078 for (i = 0; i < hist->n_key_data; i++) 1079 krb5_free_key_data_contents(context, &hist->key_data[i]); 1080 free(hist->key_data); 1081 } 1082 1083 /* 1084 * Function: add_to_history 1085 * 1086 * Purpose: Adds a password to a principal's password history. 1087 * 1088 * Arguments: 1089 * 1090 * context (r) krb5_context to use 1091 * adb (r/w) admin principal entry to add keys to 1092 * pol (r) adb's policy 1093 * pw (r) keys for the password to add to adb's key history 1094 * 1095 * Effects: 1096 * 1097 * add_to_history adds a single password to adb's password history. 1098 * pw contains n_key_data keys in its key_data, in storage should be 1099 * allocated but not freed by the caller (XXX blech!). 1100 * 1101 * This function maintains adb->old_keys as a circular queue. It 1102 * starts empty, and grows each time this function is called until it 1103 * is pol->pw_history_num items long. adb->old_key_len holds the 1104 * number of allocated entries in the array, and must therefore be [0, 1105 * pol->pw_history_num). adb->old_key_next is the index into the 1106 * array where the next element should be written, and must be [0, 1107 * adb->old_key_len). 1108 */ 1109 #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len 1110 static kadm5_ret_t add_to_history(krb5_context context, 1111 osa_princ_ent_t adb, 1112 kadm5_policy_ent_t pol, 1113 osa_pw_hist_ent *pw) 1114 { 1115 osa_pw_hist_ent *histp; 1116 uint32_t nhist; 1117 unsigned int i, knext, nkeys; 1118 1119 nhist = pol->pw_history_num; 1120 /* A history of 1 means just check the current password */ 1121 if (nhist <= 1) 1122 return 0; 1123 1124 nkeys = adb->old_key_len; 1125 knext = adb->old_key_next; 1126 /* resize the adb->old_keys array if necessary */ 1127 if (nkeys + 1 < nhist) { 1128 if (adb->old_keys == NULL) { 1129 adb->old_keys = (osa_pw_hist_ent *) 1130 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent)); 1131 } else { 1132 adb->old_keys = (osa_pw_hist_ent *) 1133 realloc(adb->old_keys, 1134 (nkeys + 1) * sizeof (osa_pw_hist_ent)); 1135 } 1136 if (adb->old_keys == NULL) 1137 return(ENOMEM); 1138 1139 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent)); 1140 nkeys = ++adb->old_key_len; 1141 /* 1142 * To avoid losing old keys, shift forward each entry after 1143 * knext. 1144 */ 1145 for (i = nkeys - 1; i > knext; i--) { 1146 adb->old_keys[i] = adb->old_keys[i - 1]; 1147 } 1148 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent)); 1149 } else if (nkeys + 1 > nhist) { 1150 /* 1151 * The policy must have changed! Shrink the array. 1152 * Can't simply realloc() down, since it might be wrapped. 1153 * To understand the arithmetic below, note that we are 1154 * copying into new positions 0 .. N-1 from old positions 1155 * old_key_next-N .. old_key_next-1, modulo old_key_len, 1156 * where N = pw_history_num - 1 is the length of the 1157 * shortened list. Matt Crawford, FNAL 1158 */ 1159 /* 1160 * M = adb->old_key_len, N = pol->pw_history_num - 1 1161 * 1162 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M] 1163 */ 1164 int j; 1165 osa_pw_hist_t tmp; 1166 1167 tmp = (osa_pw_hist_ent *) 1168 malloc((nhist - 1) * sizeof (osa_pw_hist_ent)); 1169 if (tmp == NULL) 1170 return ENOMEM; 1171 for (i = 0; i < nhist - 1; i++) { 1172 /* 1173 * Add nkeys once before taking remainder to avoid 1174 * negative values. 1175 */ 1176 j = (i + nkeys + knext - (nhist - 1)) % nkeys; 1177 tmp[i] = adb->old_keys[j]; 1178 } 1179 /* Now free the ones we don't keep (the oldest ones) */ 1180 for (i = 0; i < nkeys - (nhist - 1); i++) { 1181 j = (i + nkeys + knext) % nkeys; 1182 histp = &adb->old_keys[j]; 1183 for (j = 0; j < histp->n_key_data; j++) { 1184 krb5_free_key_data_contents(context, &histp->key_data[j]); 1185 } 1186 free(histp->key_data); 1187 } 1188 free((void *)adb->old_keys); 1189 adb->old_keys = tmp; 1190 nkeys = adb->old_key_len = nhist - 1; 1191 knext = adb->old_key_next = 0; 1192 } 1193 1194 /* 1195 * If nhist decreased since the last password change, and nkeys+1 1196 * is less than the previous nhist, it is possible for knext to 1197 * index into unallocated space. This condition would not be 1198 * caught by the resizing code above. 1199 */ 1200 if (knext + 1 > nkeys) 1201 knext = adb->old_key_next = 0; 1202 /* free the old pw history entry if it contains data */ 1203 histp = &adb->old_keys[knext]; 1204 for (i = 0; i < histp->n_key_data; i++) 1205 krb5_free_key_data_contents(context, &histp->key_data[i]); 1206 free(histp->key_data); 1207 1208 /* store the new entry */ 1209 adb->old_keys[knext] = *pw; 1210 1211 /* update the next pointer */ 1212 if (++adb->old_key_next == nhist - 1) 1213 adb->old_key_next = 0; 1214 1215 return(0); 1216 } 1217 #undef KADM_MOD 1218 1219 #ifdef USE_PASSWORD_SERVER 1220 /* FIXME: don't use global variable for this */ 1221 krb5_boolean use_password_server = 0; 1222 1223 static krb5_boolean 1224 kadm5_use_password_server (void) 1225 { 1226 return use_password_server; 1227 } 1228 1229 void 1230 kadm5_set_use_password_server (void) 1231 { 1232 use_password_server = 1; 1233 } 1234 #endif 1235 1236 #ifdef USE_PASSWORD_SERVER 1237 1238 /* 1239 * kadm5_launch_task () runs a program (task_path) to synchronize the 1240 * Apple password server with the Kerberos database. Password server 1241 * programs can receive arguments on the command line (task_argv) 1242 * and a block of data via stdin (data_buffer). 1243 * 1244 * Because a failure to communicate with the tool results in the 1245 * password server falling out of sync with the database, 1246 * kadm5_launch_task() always fails if it can't talk to the tool. 1247 */ 1248 1249 static kadm5_ret_t 1250 kadm5_launch_task (krb5_context context, 1251 const char *task_path, char * const task_argv[], 1252 const char *data_buffer) 1253 { 1254 kadm5_ret_t ret = 0; 1255 int data_pipe[2]; 1256 1257 if (data_buffer != NULL) { 1258 ret = pipe (data_pipe); 1259 if (ret) { ret = errno; } 1260 } 1261 1262 if (!ret) { 1263 pid_t pid = fork (); 1264 if (pid == -1) { 1265 ret = errno; 1266 } else if (pid == 0) { 1267 /* The child: */ 1268 1269 if (data_buffer != NULL) { 1270 if (dup2 (data_pipe[0], STDIN_FILENO) == -1) { 1271 _exit (1); 1272 } 1273 } else { 1274 close (data_pipe[0]); 1275 } 1276 1277 close (data_pipe[1]); 1278 1279 execv (task_path, task_argv); 1280 1281 _exit (1); /* Fail if execv fails */ 1282 } else { 1283 /* The parent: */ 1284 int status; 1285 1286 if (data_buffer != NULL) { 1287 /* Write out the buffer to the child */ 1288 if (krb5_net_write (context, data_pipe[1], 1289 data_buffer, strlen (data_buffer)) < 0) { 1290 /* kill the child to make sure waitpid() won't hang later */ 1291 ret = errno; 1292 kill (pid, SIGKILL); 1293 } 1294 } 1295 1296 close (data_buffer[0]); 1297 close (data_buffer[1]); 1298 1299 waitpid (pid, &status, 0); 1300 1301 if (!ret) { 1302 if (WIFEXITED (status)) { 1303 /* child read password and exited. Check the return value. */ 1304 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) { 1305 ret = KRB5KDC_ERR_POLICY; /* password change rejected */ 1306 } 1307 } else { 1308 /* child read password but crashed or was killed */ 1309 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */ 1310 } 1311 } 1312 } 1313 } 1314 1315 return ret; 1316 } 1317 1318 #endif 1319 1320 kadm5_ret_t 1321 kadm5_chpass_principal(void *server_handle, 1322 krb5_principal principal, char *password) 1323 { 1324 return 1325 kadm5_chpass_principal_3(server_handle, principal, FALSE, 1326 0, NULL, password); 1327 } 1328 1329 kadm5_ret_t 1330 kadm5_chpass_principal_3(void *server_handle, 1331 krb5_principal principal, krb5_boolean keepold, 1332 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1333 char *password) 1334 { 1335 krb5_int32 now; 1336 kadm5_policy_ent_rec pol; 1337 osa_princ_ent_rec adb; 1338 krb5_db_entry kdb, kdb_save; 1339 int ret, ret2, last_pwd, hist_added; 1340 int have_pol = 0; 1341 kadm5_server_handle_t handle = server_handle; 1342 osa_pw_hist_ent hist; 1343 1344 CHECK_HANDLE(server_handle); 1345 1346 /* Solaris Kerberos - kadm5_check_min_life checks for null principal. */ 1347 ret = kadm5_check_min_life(server_handle,principal,NULL,0); 1348 if (ret) 1349 return (ret); 1350 krb5_clear_error_message(handle->context); 1351 1352 hist_added = 0; 1353 memset(&hist, 0, sizeof(hist)); 1354 1355 if (principal == NULL || password == NULL) 1356 return EINVAL; 1357 if ((krb5_principal_compare(handle->context, 1358 principal, hist_princ)) == TRUE) 1359 return KADM5_PROTECT_PRINCIPAL; 1360 1361 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1362 return(ret); 1363 1364 /* we are going to need the current keys after the new keys are set */ 1365 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { 1366 kdb_free_entry(handle, &kdb, &adb); 1367 return(ret); 1368 } 1369 1370 if ((adb.aux_attributes & KADM5_POLICY)) { 1371 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) 1372 goto done; 1373 have_pol = 1; 1374 } 1375 1376 if ((ret = passwd_check(handle, password, adb.aux_attributes & 1377 KADM5_POLICY, &pol, principal))) 1378 goto done; 1379 1380 ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 1381 n_ks_tuple?ks_tuple:handle->params.keysalts, 1382 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1383 password, 0 /* increment kvno */, 1384 keepold, &kdb); 1385 if (ret) 1386 goto done; 1387 1388 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1389 1390 ret = krb5_timeofday(handle->context, &now); 1391 if (ret) 1392 goto done; 1393 1394 if ((adb.aux_attributes & KADM5_POLICY)) { 1395 /* the policy was loaded before */ 1396 1397 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1398 &kdb, &last_pwd); 1399 if (ret) 1400 goto done; 1401 1402 #if 0 1403 /* 1404 * The spec says this check is overridden if the caller has 1405 * modify privilege. The admin server therefore makes this 1406 * check itself (in chpass_principal_wrapper, misc.c). A 1407 * local caller implicitly has all authorization bits. 1408 */ 1409 if ((now - last_pwd) < pol.pw_min_life && 1410 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1411 ret = KADM5_PASS_TOOSOON; 1412 goto done; 1413 } 1414 #endif 1415 1416 ret = create_history_entry(handle->context, 1417 &handle->master_keyblock, kdb_save.n_key_data, 1418 kdb_save.key_data, &hist); 1419 if (ret) 1420 goto done; 1421 1422 ret = check_pw_reuse(handle->context, 1423 &handle->master_keyblock, 1424 &hist_key, 1425 kdb.n_key_data, kdb.key_data, 1426 1, &hist); 1427 if (ret) 1428 goto done; 1429 1430 if (pol.pw_history_num > 1) { 1431 if (adb.admin_history_kvno != hist_kvno) { 1432 ret = KADM5_BAD_HIST_KEY; 1433 goto done; 1434 } 1435 1436 ret = check_pw_reuse(handle->context, 1437 &handle->master_keyblock, 1438 &hist_key, 1439 kdb.n_key_data, kdb.key_data, 1440 adb.old_key_len, adb.old_keys); 1441 if (ret) 1442 goto done; 1443 1444 ret = add_to_history(handle->context, &adb, &pol, &hist); 1445 if (ret) 1446 goto done; 1447 hist_added = 1; 1448 } 1449 1450 if (pol.pw_max_life) 1451 kdb.pw_expiration = now + pol.pw_max_life; 1452 else 1453 kdb.pw_expiration = 0; 1454 } else { 1455 kdb.pw_expiration = 0; 1456 } 1457 1458 #ifdef USE_PASSWORD_SERVER 1459 if (kadm5_use_password_server () && 1460 (krb5_princ_size (handle->context, principal) == 1)) { 1461 krb5_data *princ = krb5_princ_component (handle->context, principal, 0); 1462 const char *path = "/usr/sbin/mkpassdb"; 1463 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL }; 1464 char *pstring = NULL; 1465 char pwbuf[256]; 1466 int pwlen = strlen (password); 1467 1468 if (pwlen > 254) pwlen = 254; 1469 strncpy (pwbuf, password, pwlen); 1470 pwbuf[pwlen] = '\n'; 1471 pwbuf[pwlen + 1] = '\0'; 1472 1473 if (!ret) { 1474 pstring = malloc ((princ->length + 1) * sizeof (char)); 1475 if (pstring == NULL) { ret = errno; } 1476 } 1477 1478 if (!ret) { 1479 memcpy (pstring, princ->data, princ->length); 1480 pstring [princ->length] = '\0'; 1481 argv[2] = pstring; 1482 1483 ret = kadm5_launch_task (handle->context, path, argv, pwbuf); 1484 } 1485 1486 if (pstring != NULL) 1487 free (pstring); 1488 1489 if (ret) 1490 goto done; 1491 } 1492 #endif 1493 1494 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1495 if (ret) 1496 goto done; 1497 1498 /* key data and attributes changed, let the database provider know */ 1499 /* Solaris Kerberos: adding support for key history in LDAP KDB */ 1500 if (hist_added == 1) 1501 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_KEY_HIST 1502 /* | KADM5_CPW_FUNCTION */; 1503 else 1504 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES /* | KADM5_CPW_FUNCTION */; 1505 1506 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1507 goto done; 1508 1509 ret = KADM5_OK; 1510 done: 1511 if (!hist_added && hist.key_data) 1512 free_history_entry(handle->context, &hist); 1513 kdb_free_entry(handle, &kdb, &adb); 1514 kdb_free_entry(handle, &kdb_save, NULL); 1515 krb5_db_free_principal(handle->context, &kdb, 1); 1516 1517 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) 1518 && !ret) 1519 ret = ret2; 1520 1521 return ret; 1522 } 1523 1524 kadm5_ret_t 1525 kadm5_randkey_principal(void *server_handle, 1526 krb5_principal principal, 1527 krb5_keyblock **keyblocks, 1528 int *n_keys) 1529 { 1530 /* Solaris Kerberos: */ 1531 krb5_key_salt_tuple keysalts[2]; 1532 1533 /* 1534 * Anyone calling this routine is forced to use only DES 1535 * enctypes to be compatible with earlier releases that 1536 * did not support stronger crypto. 1537 * 1538 * S10 (and later) kadmin clients will not use this API, 1539 * so we can assume the request is from an older version. 1540 */ 1541 keysalts[0].ks_enctype = ENCTYPE_DES_CBC_MD5; 1542 keysalts[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 1543 keysalts[1].ks_enctype = ENCTYPE_DES_CBC_CRC; 1544 keysalts[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 1545 1546 return (kadm5_randkey_principal_3(server_handle, principal, 1547 FALSE, 2, keysalts, keyblocks, n_keys)); 1548 } 1549 kadm5_ret_t 1550 kadm5_randkey_principal_3(void *server_handle, 1551 krb5_principal principal, 1552 krb5_boolean keepold, 1553 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1554 krb5_keyblock **keyblocks, 1555 int *n_keys) 1556 { 1557 krb5_db_entry kdb; 1558 osa_princ_ent_rec adb; 1559 krb5_int32 now; 1560 kadm5_policy_ent_rec pol; 1561 krb5_key_data *key_data; 1562 int ret, last_pwd, have_pol = 0; 1563 kadm5_server_handle_t handle = server_handle; 1564 1565 if (keyblocks) 1566 *keyblocks = NULL; 1567 1568 CHECK_HANDLE(server_handle); 1569 1570 krb5_clear_error_message(handle->context); 1571 1572 if (principal == NULL) 1573 return EINVAL; 1574 if (hist_princ && /* this will be NULL when initializing the databse */ 1575 ((krb5_principal_compare(handle->context, 1576 principal, hist_princ)) == TRUE)) 1577 return KADM5_PROTECT_PRINCIPAL; 1578 1579 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1580 return(ret); 1581 1582 ret = krb5_dbe_crk(handle->context, &handle->master_keyblock, 1583 n_ks_tuple?ks_tuple:handle->params.keysalts, 1584 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1585 keepold, 1586 &kdb); 1587 if (ret) 1588 goto done; 1589 1590 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1591 1592 ret = krb5_timeofday(handle->context, &now); 1593 if (ret) 1594 goto done; 1595 1596 if ((adb.aux_attributes & KADM5_POLICY)) { 1597 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1598 &pol)) != KADM5_OK) 1599 goto done; 1600 have_pol = 1; 1601 1602 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1603 &kdb, &last_pwd); 1604 if (ret) 1605 goto done; 1606 1607 #if 0 1608 /* 1609 * The spec says this check is overridden if the caller has 1610 * modify privilege. The admin server therefore makes this 1611 * check itself (in chpass_principal_wrapper, misc.c). A 1612 * local caller implicitly has all authorization bits. 1613 */ 1614 if((now - last_pwd) < pol.pw_min_life && 1615 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1616 ret = KADM5_PASS_TOOSOON; 1617 goto done; 1618 } 1619 #endif 1620 1621 if(pol.pw_history_num > 1) { 1622 if(adb.admin_history_kvno != hist_kvno) { 1623 ret = KADM5_BAD_HIST_KEY; 1624 goto done; 1625 } 1626 1627 ret = check_pw_reuse(handle->context, 1628 &handle->master_keyblock, 1629 &hist_key, 1630 kdb.n_key_data, kdb.key_data, 1631 adb.old_key_len, adb.old_keys); 1632 if (ret) 1633 goto done; 1634 } 1635 if (pol.pw_max_life) 1636 kdb.pw_expiration = now + pol.pw_max_life; 1637 else 1638 kdb.pw_expiration = 0; 1639 } else { 1640 kdb.pw_expiration = 0; 1641 } 1642 1643 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1644 if (ret) 1645 goto done; 1646 1647 if (keyblocks) { 1648 if (handle->api_version == KADM5_API_VERSION_1) { 1649 /* Version 1 clients will expect to see a DES_CRC enctype. */ 1650 ret = krb5_dbe_find_enctype(handle->context, &kdb, 1651 ENCTYPE_DES_CBC_CRC, 1652 -1, -1, &key_data); 1653 if (ret) 1654 goto done; 1655 1656 ret = decrypt_key_data(handle->context, 1657 &handle->master_keyblock, 1, key_data, 1658 keyblocks, NULL); 1659 if (ret) 1660 goto done; 1661 } else { 1662 ret = decrypt_key_data(handle->context, 1663 &handle->master_keyblock, 1664 kdb.n_key_data, kdb.key_data, 1665 keyblocks, n_keys); 1666 if (ret) 1667 goto done; 1668 } 1669 } 1670 1671 /* key data changed, let the database provider know */ 1672 kdb.mask = KADM5_KEY_DATA /* | KADM5_RANDKEY_USED */; 1673 1674 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1675 goto done; 1676 1677 ret = KADM5_OK; 1678 done: 1679 kdb_free_entry(handle, &kdb, &adb); 1680 if (have_pol) 1681 kadm5_free_policy_ent(handle->lhandle, &pol); 1682 1683 return ret; 1684 } 1685 1686 #if 0 /* Solaris Kerberos */ 1687 /* 1688 * kadm5_setv4key_principal: 1689 * 1690 * Set only ONE key of the principal, removing all others. This key 1691 * must have the DES_CBC_CRC enctype and is entered as having the 1692 * krb4 salttype. This is to enable things like kadmind4 to work. 1693 */ 1694 kadm5_ret_t 1695 kadm5_setv4key_principal(void *server_handle, 1696 krb5_principal principal, 1697 krb5_keyblock *keyblock) 1698 { 1699 krb5_db_entry kdb; 1700 osa_princ_ent_rec adb; 1701 krb5_int32 now; 1702 kadm5_policy_ent_rec pol; 1703 krb5_keysalt keysalt; 1704 int i, k, kvno, ret, have_pol = 0; 1705 #if 0 1706 int last_pwd; 1707 #endif 1708 kadm5_server_handle_t handle = server_handle; 1709 krb5_key_data tmp_key_data; 1710 1711 memset( &tmp_key_data, 0, sizeof(tmp_key_data)); 1712 1713 CHECK_HANDLE(server_handle); 1714 1715 krb5_clear_error_message(handle->context); 1716 1717 if (principal == NULL || keyblock == NULL) 1718 return EINVAL; 1719 if (hist_princ && /* this will be NULL when initializing the databse */ 1720 ((krb5_principal_compare(handle->context, 1721 principal, hist_princ)) == TRUE)) 1722 return KADM5_PROTECT_PRINCIPAL; 1723 1724 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC) 1725 return KADM5_SETV4KEY_INVAL_ENCTYPE; 1726 1727 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1728 return(ret); 1729 1730 for (kvno = 0, i=0; i<kdb.n_key_data; i++) 1731 if (kdb.key_data[i].key_data_kvno > kvno) 1732 kvno = kdb.key_data[i].key_data_kvno; 1733 1734 if (kdb.key_data != NULL) 1735 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1736 1737 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data)); 1738 if (kdb.key_data == NULL) 1739 return ENOMEM; 1740 memset(kdb.key_data, 0, sizeof(krb5_key_data)); 1741 kdb.n_key_data = 1; 1742 keysalt.type = KRB5_KDB_SALTTYPE_V4; 1743 /* XXX data.magic? */ 1744 keysalt.data.length = 0; 1745 keysalt.data.data = NULL; 1746 1747 /* use tmp_key_data as temporary location and reallocate later */ 1748 ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock, 1749 keyblock, &keysalt, kvno + 1, 1750 &tmp_key_data); 1751 if (ret) { 1752 goto done; 1753 } 1754 1755 for (k = 0; k < tmp_key_data.key_data_ver; k++) { 1756 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k]; 1757 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k]; 1758 if (tmp_key_data.key_data_contents[k]) { 1759 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); 1760 if (kdb.key_data->key_data_contents[k] == NULL) { 1761 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1762 kdb.key_data = NULL; 1763 kdb.n_key_data = 0; 1764 ret = ENOMEM; 1765 goto done; 1766 } 1767 memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 1768 1769 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 1770 free (tmp_key_data.key_data_contents[k]); 1771 tmp_key_data.key_data_contents[k] = NULL; 1772 } 1773 } 1774 1775 1776 1777 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1778 1779 ret = krb5_timeofday(handle->context, &now); 1780 if (ret) 1781 goto done; 1782 1783 if ((adb.aux_attributes & KADM5_POLICY)) { 1784 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1785 &pol)) != KADM5_OK) 1786 goto done; 1787 have_pol = 1; 1788 1789 #if 0 1790 /* 1791 * The spec says this check is overridden if the caller has 1792 * modify privilege. The admin server therefore makes this 1793 * check itself (in chpass_principal_wrapper, misc.c). A 1794 * local caller implicitly has all authorization bits. 1795 */ 1796 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1797 &kdb, &last_pwd)) 1798 goto done; 1799 if((now - last_pwd) < pol.pw_min_life && 1800 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1801 ret = KADM5_PASS_TOOSOON; 1802 goto done; 1803 } 1804 #endif 1805 #if 0 1806 /* 1807 * Should we be checking/updating pw history here? 1808 */ 1809 if(pol.pw_history_num > 1) { 1810 if(adb.admin_history_kvno != hist_kvno) { 1811 ret = KADM5_BAD_HIST_KEY; 1812 goto done; 1813 } 1814 1815 if (ret = check_pw_reuse(handle->context, 1816 &hist_key, 1817 kdb.n_key_data, kdb.key_data, 1818 adb.old_key_len, adb.old_keys)) 1819 goto done; 1820 } 1821 #endif 1822 1823 if (pol.pw_max_life) 1824 kdb.pw_expiration = now + pol.pw_max_life; 1825 else 1826 kdb.pw_expiration = 0; 1827 } else { 1828 kdb.pw_expiration = 0; 1829 } 1830 1831 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1832 if (ret) 1833 goto done; 1834 1835 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1836 goto done; 1837 1838 ret = KADM5_OK; 1839 done: 1840 for (i = 0; i < tmp_key_data.key_data_ver; i++) { 1841 if (tmp_key_data.key_data_contents[i]) { 1842 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); 1843 free (tmp_key_data.key_data_contents[i]); 1844 } 1845 } 1846 1847 kdb_free_entry(handle, &kdb, &adb); 1848 if (have_pol) 1849 kadm5_free_policy_ent(handle->lhandle, &pol); 1850 1851 return ret; 1852 } 1853 #endif 1854 1855 kadm5_ret_t 1856 kadm5_setkey_principal(void *server_handle, 1857 krb5_principal principal, 1858 krb5_keyblock *keyblocks, 1859 int n_keys) 1860 { 1861 return 1862 kadm5_setkey_principal_3(server_handle, principal, 1863 FALSE, 0, NULL, 1864 keyblocks, n_keys); 1865 } 1866 1867 kadm5_ret_t 1868 kadm5_setkey_principal_3(void *server_handle, 1869 krb5_principal principal, 1870 krb5_boolean keepold, 1871 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1872 krb5_keyblock *keyblocks, 1873 int n_keys) 1874 { 1875 krb5_db_entry kdb; 1876 osa_princ_ent_rec adb; 1877 krb5_int32 now; 1878 kadm5_policy_ent_rec pol; 1879 krb5_key_data *old_key_data; 1880 int n_old_keys; 1881 int i, j, k, kvno, ret, have_pol = 0; 1882 #if 0 1883 int last_pwd; 1884 #endif 1885 kadm5_server_handle_t handle = server_handle; 1886 krb5_boolean similar; 1887 krb5_keysalt keysalt; 1888 krb5_key_data tmp_key_data; 1889 krb5_key_data *tptr; 1890 1891 CHECK_HANDLE(server_handle); 1892 1893 krb5_clear_error_message(handle->context); 1894 1895 if (principal == NULL || keyblocks == NULL) 1896 return EINVAL; 1897 if (hist_princ && /* this will be NULL when initializing the databse */ 1898 ((krb5_principal_compare(handle->context, 1899 principal, hist_princ)) == TRUE)) 1900 return KADM5_PROTECT_PRINCIPAL; 1901 1902 for (i = 0; i < n_keys; i++) { 1903 for (j = i+1; j < n_keys; j++) { 1904 if ((ret = krb5_c_enctype_compare(handle->context, 1905 keyblocks[i].enctype, 1906 keyblocks[j].enctype, 1907 &similar))) 1908 return(ret); 1909 if (similar) { 1910 if (n_ks_tuple) { 1911 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) 1912 return KADM5_SETKEY_DUP_ENCTYPES; 1913 } else 1914 return KADM5_SETKEY_DUP_ENCTYPES; 1915 } 1916 } 1917 } 1918 1919 if (n_ks_tuple && n_ks_tuple != n_keys) 1920 return KADM5_SETKEY3_ETYPE_MISMATCH; 1921 1922 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1923 return(ret); 1924 1925 for (kvno = 0, i=0; i<kdb.n_key_data; i++) 1926 if (kdb.key_data[i].key_data_kvno > kvno) 1927 kvno = kdb.key_data[i].key_data_kvno; 1928 1929 if (keepold) { 1930 old_key_data = kdb.key_data; 1931 n_old_keys = kdb.n_key_data; 1932 } else { 1933 if (kdb.key_data != NULL) 1934 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1935 n_old_keys = 0; 1936 old_key_data = NULL; 1937 } 1938 1939 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys) 1940 *sizeof(krb5_key_data)); 1941 if (kdb.key_data == NULL) { 1942 ret = ENOMEM; 1943 goto done; 1944 } 1945 1946 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); 1947 kdb.n_key_data = 0; 1948 1949 for (i = 0; i < n_keys; i++) { 1950 if (n_ks_tuple) { 1951 keysalt.type = ks_tuple[i].ks_salttype; 1952 keysalt.data.length = 0; 1953 keysalt.data.data = NULL; 1954 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { 1955 ret = KADM5_SETKEY3_ETYPE_MISMATCH; 1956 goto done; 1957 } 1958 } 1959 memset (&tmp_key_data, 0, sizeof(tmp_key_data)); 1960 1961 ret = krb5_dbekd_encrypt_key_data(handle->context, 1962 &handle->master_keyblock, 1963 &keyblocks[i], 1964 n_ks_tuple ? &keysalt : NULL, 1965 kvno + 1, 1966 &tmp_key_data); 1967 if (ret) { 1968 goto done; 1969 } 1970 tptr = &kdb.key_data[i]; 1971 for (k = 0; k < tmp_key_data.key_data_ver; k++) { 1972 tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; 1973 tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; 1974 if (tmp_key_data.key_data_contents[k]) { 1975 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); 1976 if (tptr->key_data_contents[k] == NULL) { 1977 int i1; 1978 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) { 1979 if (tmp_key_data.key_data_contents[i1]) { 1980 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]); 1981 free (tmp_key_data.key_data_contents[i1]); 1982 } 1983 } 1984 1985 ret = ENOMEM; 1986 goto done; 1987 } 1988 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 1989 1990 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 1991 free (tmp_key_data.key_data_contents[k]); 1992 tmp_key_data.key_data_contents[k] = NULL; 1993 } 1994 } 1995 kdb.n_key_data++; 1996 } 1997 1998 /* copy old key data if necessary */ 1999 for (i = 0; i < n_old_keys; i++) { 2000 kdb.key_data[i+n_keys] = old_key_data[i]; 2001 memset(&old_key_data[i], 0, sizeof (krb5_key_data)); 2002 kdb.n_key_data++; 2003 } 2004 2005 if (old_key_data) 2006 krb5_db_free(handle->context, old_key_data); 2007 2008 /* assert(kdb.n_key_data == n_keys + n_old_keys) */ 2009 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 2010 2011 if ((ret = krb5_timeofday(handle->context, &now))) 2012 goto done; 2013 2014 if ((adb.aux_attributes & KADM5_POLICY)) { 2015 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 2016 &pol)) != KADM5_OK) 2017 goto done; 2018 have_pol = 1; 2019 2020 #if 0 2021 /* 2022 * The spec says this check is overridden if the caller has 2023 * modify privilege. The admin server therefore makes this 2024 * check itself (in chpass_principal_wrapper, misc.c). A 2025 * local caller implicitly has all authorization bits. 2026 */ 2027 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 2028 &kdb, &last_pwd)) 2029 goto done; 2030 if((now - last_pwd) < pol.pw_min_life && 2031 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 2032 ret = KADM5_PASS_TOOSOON; 2033 goto done; 2034 } 2035 #endif 2036 #if 0 2037 /* 2038 * Should we be checking/updating pw history here? 2039 */ 2040 if (pol.pw_history_num > 1) { 2041 if(adb.admin_history_kvno != hist_kvno) { 2042 ret = KADM5_BAD_HIST_KEY; 2043 goto done; 2044 } 2045 2046 if (ret = check_pw_reuse(handle->context, 2047 &handle->master_keyblock, 2048 &hist_key, 2049 kdb.n_key_data, kdb.key_data, 2050 adb.old_key_len, adb.old_keys)) 2051 goto done; 2052 } 2053 #endif 2054 2055 if (pol.pw_max_life) 2056 kdb.pw_expiration = now + pol.pw_max_life; 2057 else 2058 kdb.pw_expiration = 0; 2059 } else { 2060 kdb.pw_expiration = 0; 2061 } 2062 2063 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) 2064 goto done; 2065 2066 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 2067 goto done; 2068 2069 ret = KADM5_OK; 2070 done: 2071 kdb_free_entry(handle, &kdb, &adb); 2072 if (have_pol) 2073 kadm5_free_policy_ent(handle->lhandle, &pol); 2074 2075 return ret; 2076 } 2077 2078 /* 2079 * Allocate an array of n_key_data krb5_keyblocks, fill in each 2080 * element with the results of decrypting the nth key in key_data with 2081 * master_keyblock, and if n_keys is not NULL fill it in with the 2082 * number of keys decrypted. 2083 */ 2084 static int decrypt_key_data(krb5_context context, 2085 krb5_keyblock *master_keyblock, 2086 int n_key_data, krb5_key_data *key_data, 2087 krb5_keyblock **keyblocks, int *n_keys) 2088 { 2089 krb5_keyblock *keys; 2090 int ret, i; 2091 2092 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); 2093 if (keys == NULL) 2094 return ENOMEM; 2095 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 2096 2097 for (i = 0; i < n_key_data; i++) { 2098 ret = krb5_dbekd_decrypt_key_data(context, 2099 master_keyblock, 2100 &key_data[i], 2101 &keys[i], NULL); 2102 if (ret) { 2103 for (; i >= 0; i--) { 2104 if (keys[i].contents) { 2105 memset (keys[i].contents, 0, keys[i].length); 2106 free( keys[i].contents ); 2107 } 2108 } 2109 2110 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 2111 free(keys); 2112 return ret; 2113 } 2114 } 2115 2116 *keyblocks = keys; 2117 if (n_keys) 2118 *n_keys = n_key_data; 2119 2120 return 0; 2121 } 2122 2123 /* 2124 * Function: kadm5_decrypt_key 2125 * 2126 * Purpose: Retrieves and decrypts a principal key. 2127 * 2128 * Arguments: 2129 * 2130 * server_handle (r) kadm5 handle 2131 * entry (r) principal retrieved with kadm5_get_principal 2132 * ktype (r) enctype to search for, or -1 to ignore 2133 * stype (r) salt type to search for, or -1 to ignore 2134 * kvno (r) kvno to search for, -1 for max, 0 for max 2135 * only if it also matches ktype and stype 2136 * keyblock (w) keyblock to fill in 2137 * keysalt (w) keysalt to fill in, or NULL 2138 * kvnop (w) kvno to fill in, or NULL 2139 * 2140 * Effects: Searches the key_data array of entry, which must have been 2141 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to 2142 * find a key with a specified enctype, salt type, and kvno in a 2143 * principal entry. If not found, return ENOENT. Otherwise, decrypt 2144 * it with the master key, and return the key in keyblock, the salt 2145 * in salttype, and the key version number in kvno. 2146 * 2147 * If ktype or stype is -1, it is ignored for the search. If kvno is 2148 * -1, ktype and stype are ignored and the key with the max kvno is 2149 * returned. If kvno is 0, only the key with the max kvno is returned 2150 * and only if it matches the ktype and stype; otherwise, ENOENT is 2151 * returned. 2152 */ 2153 kadm5_ret_t kadm5_decrypt_key(void *server_handle, 2154 kadm5_principal_ent_t entry, krb5_int32 2155 ktype, krb5_int32 stype, krb5_int32 2156 kvno, krb5_keyblock *keyblock, 2157 krb5_keysalt *keysalt, int *kvnop) 2158 { 2159 kadm5_server_handle_t handle = server_handle; 2160 krb5_db_entry dbent; 2161 krb5_key_data *key_data; 2162 int ret; 2163 2164 CHECK_HANDLE(server_handle); 2165 2166 if (entry->n_key_data == 0 || entry->key_data == NULL) 2167 return EINVAL; 2168 2169 /* find_enctype only uses these two fields */ 2170 dbent.n_key_data = entry->n_key_data; 2171 dbent.key_data = entry->key_data; 2172 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, 2173 stype, kvno, &key_data))) 2174 return ret; 2175 2176 if ((ret = krb5_dbekd_decrypt_key_data(handle->context, 2177 &handle->master_keyblock, key_data, 2178 keyblock, keysalt))) 2179 return ret; 2180 2181 /* 2182 * Coerce the enctype of the output keyblock in case we got an 2183 * inexact match on the enctype; this behavior will go away when 2184 * the key storage architecture gets redesigned for 1.3. 2185 */ 2186 keyblock->enctype = ktype; 2187 2188 if (kvnop) 2189 *kvnop = key_data->key_data_kvno; 2190 2191 return KADM5_OK; 2192 } 2193 2194 /* Solaris Kerberos */ 2195 kadm5_ret_t 2196 kadm5_check_min_life(void *server_handle, krb5_principal principal, 2197 char *msg_ret, unsigned int msg_len) 2198 { 2199 krb5_int32 now; 2200 kadm5_ret_t ret; 2201 kadm5_policy_ent_rec pol; 2202 kadm5_principal_ent_rec princ; 2203 kadm5_server_handle_t handle = server_handle; 2204 2205 if (msg_ret != NULL) 2206 *msg_ret = '\0'; 2207 2208 ret = krb5_timeofday(handle->context, &now); 2209 if (ret) 2210 return ret; 2211 2212 ret = kadm5_get_principal(handle->lhandle, principal, 2213 &princ, KADM5_PRINCIPAL_NORMAL_MASK); 2214 if(ret) 2215 return ret; 2216 if(princ.aux_attributes & KADM5_POLICY) { 2217 if((ret=kadm5_get_policy(handle->lhandle, 2218 princ.policy, &pol)) != KADM5_OK) { 2219 (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2220 return ret; 2221 } 2222 if((now - princ.last_pwd_change) < pol.pw_min_life && 2223 !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 2224 if (msg_ret != NULL) { 2225 time_t until; 2226 char *time_string, *ptr, *errstr; 2227 2228 until = princ.last_pwd_change + pol.pw_min_life; 2229 2230 time_string = ctime(&until); 2231 errstr = (char *)error_message(CHPASS_UTIL_PASSWORD_TOO_SOON); 2232 2233 if (strlen(errstr) + strlen(time_string) >= msg_len) { 2234 *errstr = '\0'; 2235 } else { 2236 if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') 2237 *ptr = '\0'; 2238 sprintf(msg_ret, errstr, time_string); 2239 } 2240 } 2241 2242 (void) kadm5_free_policy_ent(handle->lhandle, &pol); 2243 (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2244 return KADM5_PASS_TOOSOON; 2245 } 2246 2247 ret = kadm5_free_policy_ent(handle->lhandle, &pol); 2248 if (ret) { 2249 (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2250 return ret; 2251 } 2252 } 2253 2254 return kadm5_free_principal_ent(handle->lhandle, &princ); 2255 } 2256