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