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 * $Header$ 26 */ 27 28 #if !defined(lint) && !defined(__CODECENTER__) 29 static char *rcsid = "$Header$"; 30 #endif 31 32 #include <sys/types.h> 33 #include <sys/time.h> 34 #include <errno.h> 35 #include "server_internal.h" 36 #include <kadm5/admin.h> 37 #include <kdb.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <stdarg.h> 41 #include <stdlib.h> 42 #include <k5-int.h> 43 #include <kadm5/server_internal.h> 44 #include <kadm5/admin.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 /* Solaris Kerberos - kadm5_check_min_life checks for null principal. */ 1354 ret = kadm5_check_min_life(server_handle,principal,NULL,0); 1355 if (ret) 1356 return (ret); 1357 krb5_clear_error_message(handle->context); 1358 1359 hist_added = 0; 1360 memset(&hist, 0, sizeof(hist)); 1361 1362 if (principal == NULL || password == NULL) 1363 return EINVAL; 1364 if ((krb5_principal_compare(handle->context, 1365 principal, hist_princ)) == TRUE) 1366 return KADM5_PROTECT_PRINCIPAL; 1367 1368 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1369 return(ret); 1370 1371 /* we are going to need the current keys after the new keys are set */ 1372 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { 1373 kdb_free_entry(handle, &kdb, &adb); 1374 return(ret); 1375 } 1376 1377 if ((adb.aux_attributes & KADM5_POLICY)) { 1378 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) 1379 goto done; 1380 have_pol = 1; 1381 } 1382 1383 if ((ret = passwd_check(handle, password, adb.aux_attributes & 1384 KADM5_POLICY, &pol, principal))) 1385 goto done; 1386 1387 ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, 1388 n_ks_tuple?ks_tuple:handle->params.keysalts, 1389 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1390 password, 0 /* increment kvno */, 1391 keepold, &kdb); 1392 if (ret) 1393 goto done; 1394 1395 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1396 1397 ret = krb5_timeofday(handle->context, &now); 1398 if (ret) 1399 goto done; 1400 1401 if ((adb.aux_attributes & KADM5_POLICY)) { 1402 /* the policy was loaded before */ 1403 1404 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1405 &kdb, &last_pwd); 1406 if (ret) 1407 goto done; 1408 1409 #if 0 1410 /* 1411 * The spec says this check is overridden if the caller has 1412 * modify privilege. The admin server therefore makes this 1413 * check itself (in chpass_principal_wrapper, misc.c). A 1414 * local caller implicitly has all authorization bits. 1415 */ 1416 if ((now - last_pwd) < pol.pw_min_life && 1417 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1418 ret = KADM5_PASS_TOOSOON; 1419 goto done; 1420 } 1421 #endif 1422 1423 ret = create_history_entry(handle->context, 1424 &handle->master_keyblock, kdb_save.n_key_data, 1425 kdb_save.key_data, &hist); 1426 if (ret) 1427 goto done; 1428 1429 ret = check_pw_reuse(handle->context, 1430 &handle->master_keyblock, 1431 &hist_key, 1432 kdb.n_key_data, kdb.key_data, 1433 1, &hist); 1434 if (ret) 1435 goto done; 1436 1437 if (pol.pw_history_num > 1) { 1438 if (adb.admin_history_kvno != hist_kvno) { 1439 ret = KADM5_BAD_HIST_KEY; 1440 goto done; 1441 } 1442 1443 ret = check_pw_reuse(handle->context, 1444 &handle->master_keyblock, 1445 &hist_key, 1446 kdb.n_key_data, kdb.key_data, 1447 adb.old_key_len, adb.old_keys); 1448 if (ret) 1449 goto done; 1450 1451 ret = add_to_history(handle->context, &adb, &pol, &hist); 1452 if (ret) 1453 goto done; 1454 hist_added = 1; 1455 } 1456 1457 if (pol.pw_max_life) 1458 kdb.pw_expiration = now + pol.pw_max_life; 1459 else 1460 kdb.pw_expiration = 0; 1461 } else { 1462 kdb.pw_expiration = 0; 1463 } 1464 1465 #ifdef USE_PASSWORD_SERVER 1466 if (kadm5_use_password_server () && 1467 (krb5_princ_size (handle->context, principal) == 1)) { 1468 krb5_data *princ = krb5_princ_component (handle->context, principal, 0); 1469 const char *path = "/usr/sbin/mkpassdb"; 1470 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL }; 1471 char *pstring = NULL; 1472 char pwbuf[256]; 1473 int pwlen = strlen (password); 1474 1475 if (pwlen > 254) pwlen = 254; 1476 strncpy (pwbuf, password, pwlen); 1477 pwbuf[pwlen] = '\n'; 1478 pwbuf[pwlen + 1] = '\0'; 1479 1480 if (!ret) { 1481 pstring = malloc ((princ->length + 1) * sizeof (char)); 1482 if (pstring == NULL) { ret = errno; } 1483 } 1484 1485 if (!ret) { 1486 memcpy (pstring, princ->data, princ->length); 1487 pstring [princ->length] = '\0'; 1488 argv[2] = pstring; 1489 1490 ret = kadm5_launch_task (handle->context, path, argv, pwbuf); 1491 } 1492 1493 if (pstring != NULL) 1494 free (pstring); 1495 1496 if (ret) 1497 goto done; 1498 } 1499 #endif 1500 1501 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1502 if (ret) 1503 goto done; 1504 1505 /* key data and attributes changed, let the database provider know */ 1506 /* Solaris Kerberos: adding support for key history in LDAP KDB */ 1507 if (hist_added == 1) 1508 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_KEY_HIST 1509 /* | KADM5_CPW_FUNCTION */; 1510 else 1511 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES /* | KADM5_CPW_FUNCTION */; 1512 1513 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1514 goto done; 1515 1516 ret = KADM5_OK; 1517 done: 1518 if (!hist_added && hist.key_data) 1519 free_history_entry(handle->context, &hist); 1520 kdb_free_entry(handle, &kdb, &adb); 1521 kdb_free_entry(handle, &kdb_save, NULL); 1522 krb5_db_free_principal(handle->context, &kdb, 1); 1523 1524 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) 1525 && !ret) 1526 ret = ret2; 1527 1528 return ret; 1529 } 1530 1531 kadm5_ret_t 1532 kadm5_randkey_principal(void *server_handle, 1533 krb5_principal principal, 1534 krb5_keyblock **keyblocks, 1535 int *n_keys) 1536 { 1537 /* Solaris Kerberos: */ 1538 krb5_key_salt_tuple keysalts[2]; 1539 1540 /* 1541 * Anyone calling this routine is forced to use only DES 1542 * enctypes to be compatible with earlier releases that 1543 * did not support stronger crypto. 1544 * 1545 * S10 (and later) kadmin clients will not use this API, 1546 * so we can assume the request is from an older version. 1547 */ 1548 keysalts[0].ks_enctype = ENCTYPE_DES_CBC_MD5; 1549 keysalts[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 1550 keysalts[1].ks_enctype = ENCTYPE_DES_CBC_CRC; 1551 keysalts[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; 1552 1553 return (kadm5_randkey_principal_3(server_handle, principal, 1554 FALSE, 2, keysalts, keyblocks, n_keys)); 1555 } 1556 kadm5_ret_t 1557 kadm5_randkey_principal_3(void *server_handle, 1558 krb5_principal principal, 1559 krb5_boolean keepold, 1560 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1561 krb5_keyblock **keyblocks, 1562 int *n_keys) 1563 { 1564 krb5_db_entry kdb; 1565 osa_princ_ent_rec adb; 1566 krb5_int32 now; 1567 kadm5_policy_ent_rec pol; 1568 krb5_key_data *key_data; 1569 int ret, last_pwd, have_pol = 0; 1570 kadm5_server_handle_t handle = server_handle; 1571 1572 if (keyblocks) 1573 *keyblocks = NULL; 1574 1575 CHECK_HANDLE(server_handle); 1576 1577 krb5_clear_error_message(handle->context); 1578 1579 if (principal == NULL) 1580 return EINVAL; 1581 if (hist_princ && /* this will be NULL when initializing the databse */ 1582 ((krb5_principal_compare(handle->context, 1583 principal, hist_princ)) == TRUE)) 1584 return KADM5_PROTECT_PRINCIPAL; 1585 1586 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1587 return(ret); 1588 1589 ret = krb5_dbe_crk(handle->context, &handle->master_keyblock, 1590 n_ks_tuple?ks_tuple:handle->params.keysalts, 1591 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, 1592 keepold, 1593 &kdb); 1594 if (ret) 1595 goto done; 1596 1597 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1598 1599 ret = krb5_timeofday(handle->context, &now); 1600 if (ret) 1601 goto done; 1602 1603 if ((adb.aux_attributes & KADM5_POLICY)) { 1604 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1605 &pol)) != KADM5_OK) 1606 goto done; 1607 have_pol = 1; 1608 1609 ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1610 &kdb, &last_pwd); 1611 if (ret) 1612 goto done; 1613 1614 #if 0 1615 /* 1616 * The spec says this check is overridden if the caller has 1617 * modify privilege. The admin server therefore makes this 1618 * check itself (in chpass_principal_wrapper, misc.c). A 1619 * local caller implicitly has all authorization bits. 1620 */ 1621 if((now - last_pwd) < pol.pw_min_life && 1622 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1623 ret = KADM5_PASS_TOOSOON; 1624 goto done; 1625 } 1626 #endif 1627 1628 if(pol.pw_history_num > 1) { 1629 if(adb.admin_history_kvno != hist_kvno) { 1630 ret = KADM5_BAD_HIST_KEY; 1631 goto done; 1632 } 1633 1634 ret = check_pw_reuse(handle->context, 1635 &handle->master_keyblock, 1636 &hist_key, 1637 kdb.n_key_data, kdb.key_data, 1638 adb.old_key_len, adb.old_keys); 1639 if (ret) 1640 goto done; 1641 } 1642 if (pol.pw_max_life) 1643 kdb.pw_expiration = now + pol.pw_max_life; 1644 else 1645 kdb.pw_expiration = 0; 1646 } else { 1647 kdb.pw_expiration = 0; 1648 } 1649 1650 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1651 if (ret) 1652 goto done; 1653 1654 if (keyblocks) { 1655 if (handle->api_version == KADM5_API_VERSION_1) { 1656 /* Version 1 clients will expect to see a DES_CRC enctype. */ 1657 ret = krb5_dbe_find_enctype(handle->context, &kdb, 1658 ENCTYPE_DES_CBC_CRC, 1659 -1, -1, &key_data); 1660 if (ret) 1661 goto done; 1662 1663 ret = decrypt_key_data(handle->context, 1664 &handle->master_keyblock, 1, key_data, 1665 keyblocks, NULL); 1666 if (ret) 1667 goto done; 1668 } else { 1669 ret = decrypt_key_data(handle->context, 1670 &handle->master_keyblock, 1671 kdb.n_key_data, kdb.key_data, 1672 keyblocks, n_keys); 1673 if (ret) 1674 goto done; 1675 } 1676 } 1677 1678 /* key data changed, let the database provider know */ 1679 kdb.mask = KADM5_KEY_DATA /* | KADM5_RANDKEY_USED */; 1680 1681 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1682 goto done; 1683 1684 ret = KADM5_OK; 1685 done: 1686 kdb_free_entry(handle, &kdb, &adb); 1687 if (have_pol) 1688 kadm5_free_policy_ent(handle->lhandle, &pol); 1689 1690 return ret; 1691 } 1692 1693 #if 0 /* Solaris Kerberos */ 1694 /* 1695 * kadm5_setv4key_principal: 1696 * 1697 * Set only ONE key of the principal, removing all others. This key 1698 * must have the DES_CBC_CRC enctype and is entered as having the 1699 * krb4 salttype. This is to enable things like kadmind4 to work. 1700 */ 1701 kadm5_ret_t 1702 kadm5_setv4key_principal(void *server_handle, 1703 krb5_principal principal, 1704 krb5_keyblock *keyblock) 1705 { 1706 krb5_db_entry kdb; 1707 osa_princ_ent_rec adb; 1708 krb5_int32 now; 1709 kadm5_policy_ent_rec pol; 1710 krb5_keysalt keysalt; 1711 int i, k, kvno, ret, have_pol = 0; 1712 #if 0 1713 int last_pwd; 1714 #endif 1715 kadm5_server_handle_t handle = server_handle; 1716 krb5_key_data tmp_key_data; 1717 1718 memset( &tmp_key_data, 0, sizeof(tmp_key_data)); 1719 1720 CHECK_HANDLE(server_handle); 1721 1722 krb5_clear_error_message(handle->context); 1723 1724 if (principal == NULL || keyblock == NULL) 1725 return EINVAL; 1726 if (hist_princ && /* this will be NULL when initializing the databse */ 1727 ((krb5_principal_compare(handle->context, 1728 principal, hist_princ)) == TRUE)) 1729 return KADM5_PROTECT_PRINCIPAL; 1730 1731 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC) 1732 return KADM5_SETV4KEY_INVAL_ENCTYPE; 1733 1734 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1735 return(ret); 1736 1737 for (kvno = 0, i=0; i<kdb.n_key_data; i++) 1738 if (kdb.key_data[i].key_data_kvno > kvno) 1739 kvno = kdb.key_data[i].key_data_kvno; 1740 1741 if (kdb.key_data != NULL) 1742 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1743 1744 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data)); 1745 if (kdb.key_data == NULL) 1746 return ENOMEM; 1747 memset(kdb.key_data, 0, sizeof(krb5_key_data)); 1748 kdb.n_key_data = 1; 1749 keysalt.type = KRB5_KDB_SALTTYPE_V4; 1750 /* XXX data.magic? */ 1751 keysalt.data.length = 0; 1752 keysalt.data.data = NULL; 1753 1754 /* use tmp_key_data as temporary location and reallocate later */ 1755 ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock, 1756 keyblock, &keysalt, kvno + 1, 1757 &tmp_key_data); 1758 if (ret) { 1759 goto done; 1760 } 1761 1762 for (k = 0; k < tmp_key_data.key_data_ver; k++) { 1763 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k]; 1764 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k]; 1765 if (tmp_key_data.key_data_contents[k]) { 1766 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); 1767 if (kdb.key_data->key_data_contents[k] == NULL) { 1768 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1769 kdb.key_data = NULL; 1770 kdb.n_key_data = 0; 1771 ret = ENOMEM; 1772 goto done; 1773 } 1774 memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 1775 1776 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 1777 free (tmp_key_data.key_data_contents[k]); 1778 tmp_key_data.key_data_contents[k] = NULL; 1779 } 1780 } 1781 1782 1783 1784 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 1785 1786 ret = krb5_timeofday(handle->context, &now); 1787 if (ret) 1788 goto done; 1789 1790 if ((adb.aux_attributes & KADM5_POLICY)) { 1791 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 1792 &pol)) != KADM5_OK) 1793 goto done; 1794 have_pol = 1; 1795 1796 #if 0 1797 /* 1798 * The spec says this check is overridden if the caller has 1799 * modify privilege. The admin server therefore makes this 1800 * check itself (in chpass_principal_wrapper, misc.c). A 1801 * local caller implicitly has all authorization bits. 1802 */ 1803 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 1804 &kdb, &last_pwd)) 1805 goto done; 1806 if((now - last_pwd) < pol.pw_min_life && 1807 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 1808 ret = KADM5_PASS_TOOSOON; 1809 goto done; 1810 } 1811 #endif 1812 #if 0 1813 /* 1814 * Should we be checking/updating pw history here? 1815 */ 1816 if(pol.pw_history_num > 1) { 1817 if(adb.admin_history_kvno != hist_kvno) { 1818 ret = KADM5_BAD_HIST_KEY; 1819 goto done; 1820 } 1821 1822 if (ret = check_pw_reuse(handle->context, 1823 &hist_key, 1824 kdb.n_key_data, kdb.key_data, 1825 adb.old_key_len, adb.old_keys)) 1826 goto done; 1827 } 1828 #endif 1829 1830 if (pol.pw_max_life) 1831 kdb.pw_expiration = now + pol.pw_max_life; 1832 else 1833 kdb.pw_expiration = 0; 1834 } else { 1835 kdb.pw_expiration = 0; 1836 } 1837 1838 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); 1839 if (ret) 1840 goto done; 1841 1842 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 1843 goto done; 1844 1845 ret = KADM5_OK; 1846 done: 1847 for (i = 0; i < tmp_key_data.key_data_ver; i++) { 1848 if (tmp_key_data.key_data_contents[i]) { 1849 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); 1850 free (tmp_key_data.key_data_contents[i]); 1851 } 1852 } 1853 1854 kdb_free_entry(handle, &kdb, &adb); 1855 if (have_pol) 1856 kadm5_free_policy_ent(handle->lhandle, &pol); 1857 1858 return ret; 1859 } 1860 #endif 1861 1862 kadm5_ret_t 1863 kadm5_setkey_principal(void *server_handle, 1864 krb5_principal principal, 1865 krb5_keyblock *keyblocks, 1866 int n_keys) 1867 { 1868 return 1869 kadm5_setkey_principal_3(server_handle, principal, 1870 FALSE, 0, NULL, 1871 keyblocks, n_keys); 1872 } 1873 1874 kadm5_ret_t 1875 kadm5_setkey_principal_3(void *server_handle, 1876 krb5_principal principal, 1877 krb5_boolean keepold, 1878 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 1879 krb5_keyblock *keyblocks, 1880 int n_keys) 1881 { 1882 krb5_db_entry kdb; 1883 osa_princ_ent_rec adb; 1884 krb5_int32 now; 1885 kadm5_policy_ent_rec pol; 1886 krb5_key_data *old_key_data; 1887 int n_old_keys; 1888 int i, j, k, kvno, ret, have_pol = 0; 1889 #if 0 1890 int last_pwd; 1891 #endif 1892 kadm5_server_handle_t handle = server_handle; 1893 krb5_boolean similar; 1894 krb5_keysalt keysalt; 1895 krb5_key_data tmp_key_data; 1896 krb5_key_data *tptr; 1897 1898 CHECK_HANDLE(server_handle); 1899 1900 krb5_clear_error_message(handle->context); 1901 1902 if (principal == NULL || keyblocks == NULL) 1903 return EINVAL; 1904 if (hist_princ && /* this will be NULL when initializing the databse */ 1905 ((krb5_principal_compare(handle->context, 1906 principal, hist_princ)) == TRUE)) 1907 return KADM5_PROTECT_PRINCIPAL; 1908 1909 for (i = 0; i < n_keys; i++) { 1910 for (j = i+1; j < n_keys; j++) { 1911 if ((ret = krb5_c_enctype_compare(handle->context, 1912 keyblocks[i].enctype, 1913 keyblocks[j].enctype, 1914 &similar))) 1915 return(ret); 1916 if (similar) { 1917 if (n_ks_tuple) { 1918 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) 1919 return KADM5_SETKEY_DUP_ENCTYPES; 1920 } else 1921 return KADM5_SETKEY_DUP_ENCTYPES; 1922 } 1923 } 1924 } 1925 1926 if (n_ks_tuple && n_ks_tuple != n_keys) 1927 return KADM5_SETKEY3_ETYPE_MISMATCH; 1928 1929 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) 1930 return(ret); 1931 1932 for (kvno = 0, i=0; i<kdb.n_key_data; i++) 1933 if (kdb.key_data[i].key_data_kvno > kvno) 1934 kvno = kdb.key_data[i].key_data_kvno; 1935 1936 if (keepold) { 1937 old_key_data = kdb.key_data; 1938 n_old_keys = kdb.n_key_data; 1939 } else { 1940 if (kdb.key_data != NULL) 1941 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); 1942 n_old_keys = 0; 1943 old_key_data = NULL; 1944 } 1945 1946 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys) 1947 *sizeof(krb5_key_data)); 1948 if (kdb.key_data == NULL) { 1949 ret = ENOMEM; 1950 goto done; 1951 } 1952 1953 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); 1954 kdb.n_key_data = 0; 1955 1956 for (i = 0; i < n_keys; i++) { 1957 if (n_ks_tuple) { 1958 keysalt.type = ks_tuple[i].ks_salttype; 1959 keysalt.data.length = 0; 1960 keysalt.data.data = NULL; 1961 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { 1962 ret = KADM5_SETKEY3_ETYPE_MISMATCH; 1963 goto done; 1964 } 1965 } 1966 memset (&tmp_key_data, 0, sizeof(tmp_key_data)); 1967 1968 ret = krb5_dbekd_encrypt_key_data(handle->context, 1969 &handle->master_keyblock, 1970 &keyblocks[i], 1971 n_ks_tuple ? &keysalt : NULL, 1972 kvno + 1, 1973 &tmp_key_data); 1974 if (ret) { 1975 goto done; 1976 } 1977 tptr = &kdb.key_data[i]; 1978 for (k = 0; k < tmp_key_data.key_data_ver; k++) { 1979 tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; 1980 tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; 1981 if (tmp_key_data.key_data_contents[k]) { 1982 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); 1983 if (tptr->key_data_contents[k] == NULL) { 1984 int i1; 1985 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) { 1986 if (tmp_key_data.key_data_contents[i1]) { 1987 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]); 1988 free (tmp_key_data.key_data_contents[i1]); 1989 } 1990 } 1991 1992 ret = ENOMEM; 1993 goto done; 1994 } 1995 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); 1996 1997 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); 1998 free (tmp_key_data.key_data_contents[k]); 1999 tmp_key_data.key_data_contents[k] = NULL; 2000 } 2001 } 2002 kdb.n_key_data++; 2003 } 2004 2005 /* copy old key data if necessary */ 2006 for (i = 0; i < n_old_keys; i++) { 2007 kdb.key_data[i+n_keys] = old_key_data[i]; 2008 memset(&old_key_data[i], 0, sizeof (krb5_key_data)); 2009 kdb.n_key_data++; 2010 } 2011 2012 if (old_key_data) 2013 krb5_db_free(handle->context, old_key_data); 2014 2015 /* assert(kdb.n_key_data == n_keys + n_old_keys) */ 2016 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; 2017 2018 if ((ret = krb5_timeofday(handle->context, &now))) 2019 goto done; 2020 2021 if ((adb.aux_attributes & KADM5_POLICY)) { 2022 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, 2023 &pol)) != KADM5_OK) 2024 goto done; 2025 have_pol = 1; 2026 2027 #if 0 2028 /* 2029 * The spec says this check is overridden if the caller has 2030 * modify privilege. The admin server therefore makes this 2031 * check itself (in chpass_principal_wrapper, misc.c). A 2032 * local caller implicitly has all authorization bits. 2033 */ 2034 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, 2035 &kdb, &last_pwd)) 2036 goto done; 2037 if((now - last_pwd) < pol.pw_min_life && 2038 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 2039 ret = KADM5_PASS_TOOSOON; 2040 goto done; 2041 } 2042 #endif 2043 #if 0 2044 /* 2045 * Should we be checking/updating pw history here? 2046 */ 2047 if (pol.pw_history_num > 1) { 2048 if(adb.admin_history_kvno != hist_kvno) { 2049 ret = KADM5_BAD_HIST_KEY; 2050 goto done; 2051 } 2052 2053 if (ret = check_pw_reuse(handle->context, 2054 &handle->master_keyblock, 2055 &hist_key, 2056 kdb.n_key_data, kdb.key_data, 2057 adb.old_key_len, adb.old_keys)) 2058 goto done; 2059 } 2060 #endif 2061 2062 if (pol.pw_max_life) 2063 kdb.pw_expiration = now + pol.pw_max_life; 2064 else 2065 kdb.pw_expiration = 0; 2066 } else { 2067 kdb.pw_expiration = 0; 2068 } 2069 2070 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) 2071 goto done; 2072 2073 if ((ret = kdb_put_entry(handle, &kdb, &adb))) 2074 goto done; 2075 2076 ret = KADM5_OK; 2077 done: 2078 kdb_free_entry(handle, &kdb, &adb); 2079 if (have_pol) 2080 kadm5_free_policy_ent(handle->lhandle, &pol); 2081 2082 return ret; 2083 } 2084 2085 /* 2086 * Allocate an array of n_key_data krb5_keyblocks, fill in each 2087 * element with the results of decrypting the nth key in key_data with 2088 * master_keyblock, and if n_keys is not NULL fill it in with the 2089 * number of keys decrypted. 2090 */ 2091 static int decrypt_key_data(krb5_context context, 2092 krb5_keyblock *master_keyblock, 2093 int n_key_data, krb5_key_data *key_data, 2094 krb5_keyblock **keyblocks, int *n_keys) 2095 { 2096 krb5_keyblock *keys; 2097 int ret, i; 2098 2099 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); 2100 if (keys == NULL) 2101 return ENOMEM; 2102 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 2103 2104 for (i = 0; i < n_key_data; i++) { 2105 ret = krb5_dbekd_decrypt_key_data(context, 2106 master_keyblock, 2107 &key_data[i], 2108 &keys[i], NULL); 2109 if (ret) { 2110 for (; i >= 0; i--) { 2111 if (keys[i].contents) { 2112 memset (keys[i].contents, 0, keys[i].length); 2113 free( keys[i].contents ); 2114 } 2115 } 2116 2117 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); 2118 free(keys); 2119 return ret; 2120 } 2121 } 2122 2123 *keyblocks = keys; 2124 if (n_keys) 2125 *n_keys = n_key_data; 2126 2127 return 0; 2128 } 2129 2130 /* 2131 * Function: kadm5_decrypt_key 2132 * 2133 * Purpose: Retrieves and decrypts a principal key. 2134 * 2135 * Arguments: 2136 * 2137 * server_handle (r) kadm5 handle 2138 * entry (r) principal retrieved with kadm5_get_principal 2139 * ktype (r) enctype to search for, or -1 to ignore 2140 * stype (r) salt type to search for, or -1 to ignore 2141 * kvno (r) kvno to search for, -1 for max, 0 for max 2142 * only if it also matches ktype and stype 2143 * keyblock (w) keyblock to fill in 2144 * keysalt (w) keysalt to fill in, or NULL 2145 * kvnop (w) kvno to fill in, or NULL 2146 * 2147 * Effects: Searches the key_data array of entry, which must have been 2148 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to 2149 * find a key with a specified enctype, salt type, and kvno in a 2150 * principal entry. If not found, return ENOENT. Otherwise, decrypt 2151 * it with the master key, and return the key in keyblock, the salt 2152 * in salttype, and the key version number in kvno. 2153 * 2154 * If ktype or stype is -1, it is ignored for the search. If kvno is 2155 * -1, ktype and stype are ignored and the key with the max kvno is 2156 * returned. If kvno is 0, only the key with the max kvno is returned 2157 * and only if it matches the ktype and stype; otherwise, ENOENT is 2158 * returned. 2159 */ 2160 kadm5_ret_t kadm5_decrypt_key(void *server_handle, 2161 kadm5_principal_ent_t entry, krb5_int32 2162 ktype, krb5_int32 stype, krb5_int32 2163 kvno, krb5_keyblock *keyblock, 2164 krb5_keysalt *keysalt, int *kvnop) 2165 { 2166 kadm5_server_handle_t handle = server_handle; 2167 krb5_db_entry dbent; 2168 krb5_key_data *key_data; 2169 int ret; 2170 2171 CHECK_HANDLE(server_handle); 2172 2173 if (entry->n_key_data == 0 || entry->key_data == NULL) 2174 return EINVAL; 2175 2176 /* find_enctype only uses these two fields */ 2177 dbent.n_key_data = entry->n_key_data; 2178 dbent.key_data = entry->key_data; 2179 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, 2180 stype, kvno, &key_data))) 2181 return ret; 2182 2183 if ((ret = krb5_dbekd_decrypt_key_data(handle->context, 2184 &handle->master_keyblock, key_data, 2185 keyblock, keysalt))) 2186 return ret; 2187 2188 /* 2189 * Coerce the enctype of the output keyblock in case we got an 2190 * inexact match on the enctype; this behavior will go away when 2191 * the key storage architecture gets redesigned for 1.3. 2192 */ 2193 keyblock->enctype = ktype; 2194 2195 if (kvnop) 2196 *kvnop = key_data->key_data_kvno; 2197 2198 return KADM5_OK; 2199 } 2200 2201 /* Solaris Kerberos */ 2202 kadm5_ret_t 2203 kadm5_check_min_life(void *server_handle, krb5_principal principal, 2204 char *msg_ret, unsigned int msg_len) 2205 { 2206 krb5_int32 now; 2207 kadm5_ret_t ret; 2208 kadm5_policy_ent_rec pol; 2209 kadm5_principal_ent_rec princ; 2210 kadm5_server_handle_t handle = server_handle; 2211 2212 if (msg_ret != NULL) 2213 *msg_ret = '\0'; 2214 2215 ret = krb5_timeofday(handle->context, &now); 2216 if (ret) 2217 return ret; 2218 2219 ret = kadm5_get_principal(handle->lhandle, principal, 2220 &princ, KADM5_PRINCIPAL_NORMAL_MASK); 2221 if(ret) 2222 return ret; 2223 if(princ.aux_attributes & KADM5_POLICY) { 2224 if((ret=kadm5_get_policy(handle->lhandle, 2225 princ.policy, &pol)) != KADM5_OK) { 2226 (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2227 return ret; 2228 } 2229 if((now - princ.last_pwd_change) < pol.pw_min_life && 2230 !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { 2231 if (msg_ret != NULL) { 2232 time_t until; 2233 char *time_string, *ptr, *errstr; 2234 2235 until = princ.last_pwd_change + pol.pw_min_life; 2236 2237 time_string = ctime(&until); 2238 errstr = (char *)error_message(CHPASS_UTIL_PASSWORD_TOO_SOON); 2239 2240 if (strlen(errstr) + strlen(time_string) >= msg_len) { 2241 *errstr = '\0'; 2242 } else { 2243 if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') 2244 *ptr = '\0'; 2245 sprintf(msg_ret, errstr, time_string); 2246 } 2247 } 2248 2249 (void) kadm5_free_policy_ent(handle->lhandle, &pol); 2250 (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2251 return KADM5_PASS_TOOSOON; 2252 } 2253 2254 ret = kadm5_free_policy_ent(handle->lhandle, &pol); 2255 if (ret) { 2256 (void) kadm5_free_principal_ent(handle->lhandle, &princ); 2257 return ret; 2258 } 2259 } 2260 2261 return kadm5_free_principal_ent(handle->lhandle, &princ); 2262 } 2263