1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2006, 2009, 2010, 2016 by the Massachusetts Institute of 4 * Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 /* 28 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 29 * Use is subject to license terms. 30 */ 31 32 /* 33 * This code was based on code donated to MIT by Novell for 34 * distribution under the MIT license. 35 */ 36 37 /* 38 * Include files 39 */ 40 41 #include <k5-int.h> 42 #include "kdb5.h" 43 #include "kdb_log.h" 44 #include "kdb5int.h" 45 46 /* Currently DB2 policy related errors are exported from DAL. But 47 other databases should set_err function to return string. */ 48 #include "adb_err.h" 49 50 /* 51 * internal static variable 52 */ 53 54 static k5_mutex_t db_lock = K5_MUTEX_PARTIAL_INITIALIZER; 55 56 static db_library lib_list; 57 58 /* 59 * Helper Functions 60 */ 61 62 MAKE_INIT_FUNCTION(kdb_init_lock_list); 63 MAKE_FINI_FUNCTION(kdb_fini_lock_list); 64 65 static void 66 free_mkey_list(krb5_context context, krb5_keylist_node *mkey_list) 67 { 68 krb5_keylist_node *cur, *next; 69 70 for (cur = mkey_list; cur != NULL; cur = next) { 71 next = cur->next; 72 krb5_free_keyblock_contents(context, &cur->keyblock); 73 free(cur); 74 } 75 } 76 77 int 78 kdb_init_lock_list(void) 79 { 80 return k5_mutex_finish_init(&db_lock); 81 } 82 83 static int 84 kdb_lock_list(void) 85 { 86 int err; 87 err = CALL_INIT_FUNCTION (kdb_init_lock_list); 88 if (err) 89 return err; 90 k5_mutex_lock(&db_lock); 91 return 0; 92 } 93 94 void 95 kdb_fini_lock_list(void) 96 { 97 if (INITIALIZER_RAN(kdb_init_lock_list)) 98 k5_mutex_destroy(&db_lock); 99 } 100 101 static void 102 kdb_unlock_list(void) 103 { 104 k5_mutex_unlock(&db_lock); 105 } 106 107 /* Return true if the ulog is mapped in the primary role. */ 108 static inline krb5_boolean 109 logging(krb5_context context) 110 { 111 kdb_log_context *log_ctx = context->kdblog_context; 112 113 return log_ctx != NULL && log_ctx->iproprole == IPROP_PRIMARY && 114 log_ctx->ulog != NULL; 115 } 116 117 void 118 krb5_dbe_free_key_data_contents(krb5_context context, krb5_key_data *key) 119 { 120 int i, idx; 121 122 if (key) { 123 idx = (key->key_data_ver == 1 ? 1 : 2); 124 for (i = 0; i < idx; i++) { 125 if (key->key_data_contents[i]) { 126 zap(key->key_data_contents[i], key->key_data_length[i]); 127 free(key->key_data_contents[i]); 128 } 129 } 130 } 131 return; 132 } 133 134 void 135 krb5_dbe_free_key_list(krb5_context context, krb5_keylist_node *val) 136 { 137 krb5_keylist_node *temp = val, *prev; 138 139 while (temp != NULL) { 140 prev = temp; 141 temp = temp->next; 142 krb5_free_keyblock_contents(context, &(prev->keyblock)); 143 free(prev); 144 } 145 } 146 147 void 148 krb5_dbe_free_actkvno_list(krb5_context context, krb5_actkvno_node *val) 149 { 150 krb5_actkvno_node *temp = val, *prev; 151 152 while (temp != NULL) { 153 prev = temp; 154 temp = temp->next; 155 free(prev); 156 } 157 } 158 159 void 160 krb5_dbe_free_mkey_aux_list(krb5_context context, krb5_mkey_aux_node *val) 161 { 162 krb5_mkey_aux_node *temp = val, *prev; 163 164 while (temp != NULL) { 165 prev = temp; 166 temp = temp->next; 167 krb5_dbe_free_key_data_contents(context, &prev->latest_mkey); 168 free(prev); 169 } 170 } 171 172 void 173 krb5_dbe_free_tl_data(krb5_context context, krb5_tl_data *tl_data) 174 { 175 if (tl_data) { 176 if (tl_data->tl_data_contents) 177 free(tl_data->tl_data_contents); 178 free(tl_data); 179 } 180 } 181 182 void 183 krb5_dbe_free_strings(krb5_context context, krb5_string_attr *strings, 184 int count) 185 { 186 int i; 187 188 if (strings == NULL) 189 return; 190 for (i = 0; i < count; i++) { 191 free(strings[i].key); 192 free(strings[i].value); 193 } 194 free(strings); 195 } 196 197 void 198 krb5_dbe_free_string(krb5_context context, char *string) 199 { 200 free(string); 201 } 202 203 /* Set *section to the appropriate section to use for a database module's 204 * profile queries. The caller must free the result. */ 205 static krb5_error_code 206 get_conf_section(krb5_context context, char **section) 207 { 208 krb5_error_code status; 209 char *result = NULL, *value = NULL, *defrealm; 210 211 *section = NULL; 212 213 status = krb5_get_default_realm(context, &defrealm); 214 if (status) { 215 k5_setmsg(context, KRB5_KDB_SERVER_INTERNAL_ERR, 216 _("No default realm set; cannot initialize KDB")); 217 return KRB5_KDB_SERVER_INTERNAL_ERR; 218 } 219 status = profile_get_string(context->profile, 220 /* realms */ 221 KDB_REALM_SECTION, 222 defrealm, 223 /* under the realm name, database_module */ 224 KDB_MODULE_POINTER, 225 /* default value is the realm name itself */ 226 defrealm, 227 &value); 228 krb5_free_default_realm(context, defrealm); 229 if (status) 230 return status; 231 result = strdup(value); 232 profile_release_string(value); 233 if (result == NULL) 234 return ENOMEM; 235 *section = result; 236 return 0; 237 } 238 239 static krb5_error_code 240 kdb_get_library_name(krb5_context kcontext, char **libname_out) 241 { 242 krb5_error_code status = 0; 243 char *value = NULL, *lib = NULL, *defrealm = NULL; 244 245 *libname_out = NULL; 246 247 status = krb5_get_default_realm(kcontext, &defrealm); 248 if (status) 249 goto clean_n_exit; 250 status = profile_get_string(kcontext->profile, 251 /* realms */ 252 KDB_REALM_SECTION, 253 defrealm, 254 /* under the realm name, database_module */ 255 KDB_MODULE_POINTER, 256 /* default value is the realm name itself */ 257 defrealm, 258 &value); 259 if (status) 260 goto clean_n_exit; 261 262 #define DB2_NAME "db2" 263 /* we got the module section. Get the library name from the module */ 264 status = profile_get_string(kcontext->profile, KDB_MODULE_SECTION, value, 265 KDB_LIB_POINTER, 266 /* default to db2 */ 267 DB2_NAME, 268 &lib); 269 270 if (status) { 271 goto clean_n_exit; 272 } 273 274 *libname_out = strdup(lib); 275 if (*libname_out == NULL) 276 status = ENOMEM; 277 278 clean_n_exit: 279 krb5_free_default_realm(kcontext, defrealm); 280 profile_release_string(value); 281 profile_release_string(lib); 282 return status; 283 } 284 285 static void 286 copy_vtable(const kdb_vftabl *in, kdb_vftabl *out) 287 { 288 /* Copy fields for minor version 0. */ 289 out->maj_ver = in->maj_ver; 290 out->min_ver = in->min_ver; 291 out->init_library = in->init_library; 292 out->fini_library = in->fini_library; 293 out->init_module = in->init_module; 294 out->fini_module = in->fini_module; 295 out->create = in->create; 296 out->destroy = in->destroy; 297 out->get_age = in->get_age; 298 out->lock = in->lock; 299 out->unlock = in->unlock; 300 out->get_principal = in->get_principal; 301 out->put_principal = in->put_principal; 302 out->delete_principal = in->delete_principal; 303 out->rename_principal = in->rename_principal; 304 out->iterate = in->iterate; 305 out->create_policy = in->create_policy; 306 out->get_policy = in->get_policy; 307 out->put_policy = in->put_policy; 308 out->iter_policy = in->iter_policy; 309 out->delete_policy = in->delete_policy; 310 out->fetch_master_key = in->fetch_master_key; 311 out->fetch_master_key_list = in->fetch_master_key_list; 312 out->store_master_key_list = in->store_master_key_list; 313 out->dbe_search_enctype = in->dbe_search_enctype; 314 out->change_pwd = in->change_pwd; 315 out->promote_db = in->promote_db; 316 out->decrypt_key_data = in->decrypt_key_data; 317 out->encrypt_key_data = in->encrypt_key_data; 318 out->check_transited_realms = in->check_transited_realms; 319 out->check_policy_as = in->check_policy_as; 320 out->check_policy_tgs = in->check_policy_tgs; 321 out->audit_as_req = in->audit_as_req; 322 out->refresh_config = in->refresh_config; 323 out->check_allowed_to_delegate = in->check_allowed_to_delegate; 324 out->free_principal_e_data = in->free_principal_e_data; 325 out->get_s4u_x509_principal = in->get_s4u_x509_principal; 326 out->allowed_to_delegate_from = in->allowed_to_delegate_from; 327 out->issue_pac = in->issue_pac; 328 329 /* Set defaults for optional fields. */ 330 if (out->fetch_master_key == NULL) 331 out->fetch_master_key = krb5_db_def_fetch_mkey; 332 if (out->fetch_master_key_list == NULL) 333 out->fetch_master_key_list = krb5_def_fetch_mkey_list; 334 if (out->store_master_key_list == NULL) 335 out->store_master_key_list = krb5_def_store_mkey_list; 336 if (out->dbe_search_enctype == NULL) 337 out->dbe_search_enctype = krb5_dbe_def_search_enctype; 338 if (out->change_pwd == NULL) 339 out->change_pwd = krb5_dbe_def_cpw; 340 if (out->decrypt_key_data == NULL) 341 out->decrypt_key_data = krb5_dbe_def_decrypt_key_data; 342 if (out->encrypt_key_data == NULL) 343 out->encrypt_key_data = krb5_dbe_def_encrypt_key_data; 344 if (out->rename_principal == NULL) 345 out->rename_principal = krb5_db_def_rename_principal; 346 } 347 348 #ifdef STATIC_PLUGINS 349 350 extern kdb_vftabl krb5_db2_kdb_function_table; 351 #ifdef ENABLE_LDAP 352 extern kdb_vftabl krb5_ldap_kdb_function_table; 353 #endif 354 355 static krb5_error_code 356 load_library(krb5_context kcontext, const char *lib_name, db_library *libptr) 357 { 358 krb5_error_code status; 359 db_library lib; 360 kdb_vftabl *vftabl_addr = NULL; 361 362 if (strcmp(lib_name, "db2") == 0) 363 vftabl_addr = &krb5_db2_kdb_function_table; 364 #ifdef ENABLE_LDAP 365 if (strcmp(lib_name, "kldap") == 0) 366 vftabl_addr = &krb5_ldap_kdb_function_table; 367 #endif 368 if (!vftabl_addr) { 369 k5_setmsg(kcontext, KRB5_KDB_DBTYPE_NOTFOUND, 370 _("Unable to find requested database type: %s"), lib_name); 371 return KRB5_PLUGIN_OP_NOTSUPP; 372 } 373 374 lib = calloc(1, sizeof(*lib)); 375 if (lib == NULL) 376 return ENOMEM; 377 378 strlcpy(lib->name, lib_name, sizeof(lib->name)); 379 copy_vtable(vftabl_addr, &lib->vftabl); 380 381 status = lib->vftabl.init_library(); 382 if (status) 383 goto cleanup; 384 385 *libptr = lib; 386 return 0; 387 388 cleanup: 389 free(lib); 390 return status; 391 } 392 393 #else /* KDB5_STATIC_LINK*/ 394 395 static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH; 396 #define db_dl_n_locations (sizeof(db_dl_location) / sizeof(db_dl_location[0])) 397 398 static krb5_error_code 399 load_library(krb5_context kcontext, const char *lib_name, db_library *lib) 400 { 401 krb5_error_code status = 0; 402 int ndx; 403 void **vftabl_addrs = NULL; 404 /* N.B.: If this is "const" but not "static", the Solaris 10 405 native compiler has trouble building the library because of 406 absolute relocations needed in read-only section ".rodata". 407 When it's static, it goes into ".picdata", which is 408 read-write. */ 409 static const char *const dbpath_names[] = { 410 KDB_MODULE_SECTION, KRB5_CONF_DB_MODULE_DIR, NULL, 411 }; 412 const char *filebases[2]; 413 char **profpath = NULL; 414 char **path = NULL; 415 416 filebases[0] = lib_name; 417 filebases[1] = NULL; 418 419 *lib = calloc((size_t) 1, sizeof(**lib)); 420 if (*lib == NULL) 421 return ENOMEM; 422 423 strlcpy((*lib)->name, lib_name, sizeof((*lib)->name)); 424 425 /* Fetch the list of directories specified in the config 426 file(s) first. */ 427 status = profile_get_values(kcontext->profile, dbpath_names, &profpath); 428 if (status != 0 && status != PROF_NO_RELATION) 429 goto clean_n_exit; 430 ndx = 0; 431 if (profpath) 432 while (profpath[ndx] != NULL) 433 ndx++; 434 435 path = calloc(ndx + db_dl_n_locations, sizeof (char *)); 436 if (path == NULL) { 437 status = ENOMEM; 438 goto clean_n_exit; 439 } 440 if (ndx) 441 memcpy(path, profpath, ndx * sizeof(profpath[0])); 442 memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *)); 443 status = 0; 444 445 if ((status = krb5int_open_plugin_dirs ((const char **) path, 446 filebases, 447 &(*lib)->dl_dir_handle, &kcontext->err))) { 448 status = KRB5_KDB_DBTYPE_NOTFOUND; 449 k5_prependmsg(kcontext, status, 450 _("Unable to find requested database type")); 451 goto clean_n_exit; 452 } 453 454 if ((status = krb5int_get_plugin_dir_data (&(*lib)->dl_dir_handle, "kdb_function_table", 455 &vftabl_addrs, &kcontext->err))) { 456 status = KRB5_KDB_DBTYPE_INIT; 457 k5_prependmsg(kcontext, status, 458 _("plugin symbol 'kdb_function_table' lookup failed")); 459 goto clean_n_exit; 460 } 461 462 if (vftabl_addrs[0] == NULL) { 463 /* No plugins! */ 464 status = KRB5_KDB_DBTYPE_NOTFOUND; 465 k5_setmsg(kcontext, status, 466 _("Unable to load requested database module '%s': plugin " 467 "symbol 'kdb_function_table' not found"), lib_name); 468 goto clean_n_exit; 469 } 470 471 if (((kdb_vftabl *)vftabl_addrs[0])->maj_ver != 472 KRB5_KDB_DAL_MAJOR_VERSION) { 473 status = KRB5_KDB_DBTYPE_MISMATCH; 474 goto clean_n_exit; 475 } 476 477 copy_vtable(vftabl_addrs[0], &(*lib)->vftabl); 478 479 if ((status = (*lib)->vftabl.init_library())) 480 goto clean_n_exit; 481 482 clean_n_exit: 483 krb5int_free_plugin_dir_data(vftabl_addrs); 484 /* Both of these DTRT with NULL. */ 485 profile_free_list(profpath); 486 free(path); 487 if (status && *lib) { 488 if (PLUGIN_DIR_OPEN((&(*lib)->dl_dir_handle))) 489 krb5int_close_plugin_dirs (&(*lib)->dl_dir_handle); 490 free(*lib); 491 *lib = NULL; 492 } 493 return status; 494 } 495 496 #endif /* end of _KDB5_STATIC_LINK */ 497 498 static krb5_error_code 499 find_library(krb5_context kcontext, const char *lib_name, db_library *lib) 500 { 501 /* lock here so that no two threads try to do the same at the same time */ 502 krb5_error_code status = 0; 503 int locked = 0; 504 db_library curr_elt, prev_elt = NULL; 505 static int kdb_db2_pol_err_loaded = 0; 506 507 if (!strcmp(DB2_NAME, lib_name) && (kdb_db2_pol_err_loaded == 0)) { 508 initialize_adb_error_table(); 509 kdb_db2_pol_err_loaded = 1; 510 } 511 512 if ((status = kdb_lock_list()) != 0) 513 goto clean_n_exit; 514 locked = 1; 515 516 curr_elt = lib_list; 517 while (curr_elt != NULL) { 518 if (strcmp(lib_name, curr_elt->name) == 0) { 519 *lib = curr_elt; 520 goto clean_n_exit; 521 } 522 prev_elt = curr_elt; 523 curr_elt = curr_elt->next; 524 } 525 526 /* module not found. create and add to list */ 527 status = load_library(kcontext, lib_name, lib); 528 if (status) 529 goto clean_n_exit; 530 531 if (prev_elt) { 532 /* prev_elt points to the last element in the list */ 533 prev_elt->next = *lib; 534 (*lib)->prev = prev_elt; 535 } else { 536 lib_list = *lib; 537 } 538 539 clean_n_exit: 540 if (*lib) 541 (*lib)->reference_cnt++; 542 543 if (locked) 544 kdb_unlock_list(); 545 546 return status; 547 } 548 549 static krb5_error_code 550 kdb_free_library(db_library lib) 551 { 552 krb5_error_code status = 0; 553 int locked = 0; 554 555 if ((status = kdb_lock_list()) != 0) 556 goto clean_n_exit; 557 locked = 1; 558 559 lib->reference_cnt--; 560 561 if (lib->reference_cnt == 0) { 562 status = lib->vftabl.fini_library(); 563 if (status) 564 goto clean_n_exit; 565 566 /* close the library */ 567 if (PLUGIN_DIR_OPEN((&lib->dl_dir_handle))) 568 krb5int_close_plugin_dirs (&lib->dl_dir_handle); 569 570 if (lib->prev == NULL) 571 lib_list = lib->next; /* first element in the list */ 572 else 573 lib->prev->next = lib->next; 574 575 if (lib->next) 576 lib->next->prev = lib->prev; 577 free(lib); 578 } 579 580 clean_n_exit: 581 if (locked) 582 kdb_unlock_list(); 583 584 return status; 585 } 586 587 krb5_error_code 588 krb5_db_load_module(krb5_context kcontext, const char *name) 589 { 590 krb5_error_code ret; 591 db_library lib = NULL; 592 kdb5_dal_handle *dal_handle = NULL; 593 594 if (name == NULL) 595 return EINVAL; 596 if (kcontext->dal_handle != NULL) 597 return EEXIST; 598 599 dal_handle = k5alloc(sizeof(*dal_handle), &ret); 600 if (dal_handle == NULL) 601 goto cleanup; 602 603 ret = find_library(kcontext, name, &lib); 604 if (ret) 605 goto cleanup; 606 607 dal_handle->lib_handle = lib; 608 kcontext->dal_handle = dal_handle; 609 lib = NULL; 610 dal_handle = NULL; 611 612 cleanup: 613 free(dal_handle); 614 if (lib != NULL) 615 kdb_free_library(lib); 616 return ret; 617 } 618 619 krb5_error_code 620 krb5_db_setup_lib_handle(krb5_context kcontext) 621 { 622 char *library = NULL; 623 krb5_error_code ret; 624 625 ret = kdb_get_library_name(kcontext, &library); 626 if (library == NULL) { 627 k5_prependmsg(kcontext, ret, _("Cannot initialize database library")); 628 return ret; 629 } 630 631 ret = krb5_db_load_module(kcontext, library); 632 free(library); 633 return ret; 634 } 635 636 static krb5_error_code 637 kdb_free_lib_handle(krb5_context kcontext) 638 { 639 krb5_error_code status = 0; 640 641 status = kdb_free_library(kcontext->dal_handle->lib_handle); 642 if (status) 643 return status; 644 645 free_mkey_list(kcontext, kcontext->dal_handle->master_keylist); 646 krb5_free_principal(kcontext, kcontext->dal_handle->master_princ); 647 free(kcontext->dal_handle); 648 kcontext->dal_handle = NULL; 649 return 0; 650 } 651 652 static krb5_error_code 653 get_vftabl(krb5_context kcontext, kdb_vftabl **vftabl_ptr) 654 { 655 krb5_error_code status; 656 657 *vftabl_ptr = NULL; 658 if (kcontext->dal_handle == NULL) { 659 status = krb5_db_setup_lib_handle(kcontext); 660 if (status) 661 return status; 662 } 663 *vftabl_ptr = &kcontext->dal_handle->lib_handle->vftabl; 664 return 0; 665 } 666 667 /* 668 * External functions... DAL API 669 */ 670 krb5_error_code 671 krb5_db_open(krb5_context kcontext, char **db_args, int mode) 672 { 673 krb5_error_code status; 674 char *section; 675 kdb_vftabl *v; 676 677 status = get_vftabl(kcontext, &v); 678 if (status) 679 return status; 680 status = get_conf_section(kcontext, §ion); 681 if (status) 682 return status; 683 status = v->init_module(kcontext, section, db_args, mode); 684 free(section); 685 if (status) 686 (void)krb5_db_fini(kcontext); 687 return status; 688 } 689 690 krb5_error_code 691 krb5_db_inited(krb5_context kcontext) 692 { 693 return !(kcontext && kcontext->dal_handle && 694 kcontext->dal_handle->db_context); 695 } 696 697 krb5_error_code 698 krb5_db_create(krb5_context kcontext, char **db_args) 699 { 700 krb5_error_code status; 701 char *section; 702 kdb_vftabl *v; 703 704 status = get_vftabl(kcontext, &v); 705 if (status) 706 return status; 707 if (v->create == NULL) 708 return KRB5_PLUGIN_OP_NOTSUPP; 709 status = get_conf_section(kcontext, §ion); 710 if (status) 711 return status; 712 status = v->create(kcontext, section, db_args); 713 free(section); 714 if (status) 715 (void)krb5_db_fini(kcontext); 716 return status; 717 } 718 719 krb5_error_code 720 krb5_db_fini(krb5_context kcontext) 721 { 722 krb5_error_code status = 0; 723 kdb_vftabl *v; 724 725 /* Do nothing if module was never loaded. */ 726 if (kcontext->dal_handle == NULL) 727 return 0; 728 729 v = &kcontext->dal_handle->lib_handle->vftabl; 730 status = v->fini_module(kcontext); 731 732 if (status) 733 return status; 734 735 return kdb_free_lib_handle(kcontext); 736 } 737 738 krb5_error_code 739 krb5_db_destroy(krb5_context kcontext, char **db_args) 740 { 741 krb5_error_code status; 742 char *section; 743 kdb_vftabl *v; 744 745 status = get_vftabl(kcontext, &v); 746 if (status) 747 return status; 748 if (v->destroy == NULL) 749 return KRB5_PLUGIN_OP_NOTSUPP; 750 status = get_conf_section(kcontext, §ion); 751 if (status) 752 return status; 753 status = v->destroy(kcontext, section, db_args); 754 free(section); 755 return status; 756 } 757 758 krb5_error_code 759 krb5_db_get_age(krb5_context kcontext, char *db_name, time_t *t) 760 { 761 krb5_error_code status = 0; 762 kdb_vftabl *v; 763 764 status = get_vftabl(kcontext, &v); 765 if (status) 766 return status; 767 if (v->get_age == NULL) 768 return KRB5_PLUGIN_OP_NOTSUPP; 769 return v->get_age(kcontext, db_name, t); 770 } 771 772 krb5_error_code 773 krb5_db_lock(krb5_context kcontext, int lock_mode) 774 { 775 krb5_error_code status = 0; 776 kdb_vftabl *v; 777 778 status = get_vftabl(kcontext, &v); 779 if (status) 780 return status; 781 if (v->lock == NULL) 782 return KRB5_PLUGIN_OP_NOTSUPP; 783 return v->lock(kcontext, lock_mode); 784 } 785 786 krb5_error_code 787 krb5_db_unlock(krb5_context kcontext) 788 { 789 krb5_error_code status = 0; 790 kdb_vftabl *v; 791 792 status = get_vftabl(kcontext, &v); 793 if (status) 794 return status; 795 if (v->unlock == NULL) 796 return KRB5_PLUGIN_OP_NOTSUPP; 797 return v->unlock(kcontext); 798 } 799 800 #define MAX_ALIAS_DEPTH 10 801 802 krb5_error_code 803 krb5_db_get_principal(krb5_context kcontext, krb5_const_principal search_for, 804 unsigned int flags, krb5_db_entry **entry_out) 805 { 806 krb5_error_code status = 0; 807 kdb_vftabl *v; 808 krb5_db_entry *entry; 809 krb5_principal alias_target; 810 int alias_depth = 0; 811 812 *entry_out = NULL; 813 status = get_vftabl(kcontext, &v); 814 if (status) 815 return status; 816 if (v->get_principal == NULL) 817 return KRB5_PLUGIN_OP_NOTSUPP; 818 819 status = v->get_principal(kcontext, search_for, flags, &entry); 820 if (status) 821 return status; 822 823 /* Resolve any aliases up to the maximum depth. */ 824 for (;;) { 825 status = krb5_dbe_read_alias(kcontext, entry, &alias_target); 826 if (status) 827 return status; 828 if (alias_target == NULL) 829 break; 830 krb5_db_free_principal(kcontext, entry); 831 status = (++alias_depth > MAX_ALIAS_DEPTH) ? KRB5_KDB_NOENTRY : 832 v->get_principal(kcontext, alias_target, flags, &entry); 833 krb5_free_principal(kcontext, alias_target); 834 if (status) 835 return status; 836 } 837 838 /* Sort the keys in the db entry as some parts of krb5 expect it to be. */ 839 if (entry->key_data != NULL) 840 krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data); 841 842 *entry_out = entry; 843 return 0; 844 } 845 846 static void 847 free_tl_data(krb5_tl_data *list) 848 { 849 krb5_tl_data *next; 850 851 for (; list != NULL; list = next) { 852 next = list->tl_data_next; 853 free(list->tl_data_contents); 854 free(list); 855 } 856 } 857 858 void 859 krb5_db_free_principal(krb5_context kcontext, krb5_db_entry *entry) 860 { 861 kdb_vftabl *v; 862 int i; 863 864 if (entry == NULL) 865 return; 866 if (entry->e_data != NULL) { 867 if (get_vftabl(kcontext, &v) == 0 && v->free_principal_e_data != NULL) 868 v->free_principal_e_data(kcontext, entry->e_data); 869 else 870 free(entry->e_data); 871 } 872 krb5_free_principal(kcontext, entry->princ); 873 free_tl_data(entry->tl_data); 874 for (i = 0; i < entry->n_key_data; i++) 875 krb5_dbe_free_key_data_contents(kcontext, &entry->key_data[i]); 876 free(entry->key_data); 877 free(entry); 878 } 879 880 static void 881 free_db_args(char **db_args) 882 { 883 size_t i; 884 885 if (db_args) { 886 for (i = 0; db_args[i]; i++) 887 free(db_args[i]); 888 free(db_args); 889 } 890 } 891 892 static krb5_error_code 893 extract_db_args_from_tl_data(krb5_context kcontext, krb5_tl_data **start, 894 krb5_int16 *count, char ***db_argsp) 895 { 896 char **db_args = NULL; 897 size_t db_args_size = 0; 898 krb5_tl_data *prev, *curr, *next; 899 krb5_error_code status; 900 901 /* Giving db_args as part of tl data causes db2 to store the 902 tl_data as such. To prevent this, tl_data is collated and 903 passed as a separate argument. Currently supports only one 904 principal, but passing it as a separate argument makes it 905 difficult for kadmin remote to pass arguments to server. */ 906 prev = NULL, curr = *start; 907 while (curr) { 908 if (curr->tl_data_type == KRB5_TL_DB_ARGS) { 909 char **t; 910 /* Since this is expected to be NULL terminated string and 911 this could come from any client, do a check before 912 passing it to db. */ 913 if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] != 914 '\0') { 915 /* Not null terminated. Dangerous input. */ 916 status = EINVAL; 917 goto clean_n_exit; 918 } 919 920 db_args_size++; 921 t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */ 922 if (t == NULL) { 923 status = ENOMEM; 924 goto clean_n_exit; 925 } 926 927 db_args = t; 928 db_args[db_args_size - 1] = (char *) curr->tl_data_contents; 929 db_args[db_args_size] = NULL; 930 931 next = curr->tl_data_next; 932 if (prev == NULL) { 933 /* current node is the first in the linked list. remove it */ 934 *start = curr->tl_data_next; 935 } else { 936 prev->tl_data_next = curr->tl_data_next; 937 } 938 (*count)--; 939 free(curr); 940 941 /* previous does not change */ 942 curr = next; 943 } else { 944 prev = curr; 945 curr = curr->tl_data_next; 946 } 947 } 948 status = 0; 949 clean_n_exit: 950 if (status != 0) { 951 free_db_args(db_args); 952 db_args = NULL; 953 } 954 *db_argsp = db_args; 955 return status; 956 } 957 958 krb5_error_code 959 krb5int_put_principal_no_log(krb5_context kcontext, krb5_db_entry *entry) 960 { 961 kdb_vftabl *v; 962 krb5_error_code status; 963 char **db_args; 964 965 status = get_vftabl(kcontext, &v); 966 if (status) 967 return status; 968 if (v->put_principal == NULL) 969 return KRB5_PLUGIN_OP_NOTSUPP; 970 status = extract_db_args_from_tl_data(kcontext, &entry->tl_data, 971 &entry->n_tl_data, 972 &db_args); 973 if (status) 974 return status; 975 status = v->put_principal(kcontext, entry, db_args); 976 free_db_args(db_args); 977 return status; 978 } 979 980 krb5_error_code 981 krb5_db_put_principal(krb5_context kcontext, krb5_db_entry *entry) 982 { 983 krb5_error_code status = 0; 984 kdb_incr_update_t *upd = NULL; 985 char *princ_name = NULL; 986 987 if (logging(kcontext)) { 988 upd = k5alloc(sizeof(*upd), &status); 989 if (upd == NULL) 990 goto cleanup; 991 if ((status = ulog_conv_2logentry(kcontext, entry, upd))) 992 goto cleanup; 993 994 status = krb5_unparse_name(kcontext, entry->princ, &princ_name); 995 if (status != 0) 996 goto cleanup; 997 998 upd->kdb_princ_name.utf8str_t_val = princ_name; 999 upd->kdb_princ_name.utf8str_t_len = strlen(princ_name); 1000 } 1001 1002 status = krb5int_put_principal_no_log(kcontext, entry); 1003 if (status) 1004 goto cleanup; 1005 1006 if (logging(kcontext)) 1007 status = ulog_add_update(kcontext, upd); 1008 1009 cleanup: 1010 ulog_free_entries(upd, 1); 1011 return status; 1012 } 1013 1014 krb5_error_code 1015 krb5int_delete_principal_no_log(krb5_context kcontext, 1016 krb5_principal search_for) 1017 { 1018 kdb_vftabl *v; 1019 krb5_error_code status; 1020 1021 status = get_vftabl(kcontext, &v); 1022 if (status) 1023 return status; 1024 if (v->delete_principal == NULL) 1025 return KRB5_PLUGIN_OP_NOTSUPP; 1026 return v->delete_principal(kcontext, search_for); 1027 } 1028 1029 krb5_error_code 1030 krb5_db_delete_principal(krb5_context kcontext, krb5_principal search_for) 1031 { 1032 krb5_error_code status = 0; 1033 kdb_incr_update_t upd; 1034 char *princ_name = NULL; 1035 1036 status = krb5int_delete_principal_no_log(kcontext, search_for); 1037 if (status || !logging(kcontext)) 1038 return status; 1039 1040 status = krb5_unparse_name(kcontext, search_for, &princ_name); 1041 if (status) 1042 return status; 1043 1044 memset(&upd, 0, sizeof(kdb_incr_update_t)); 1045 upd.kdb_princ_name.utf8str_t_val = princ_name; 1046 upd.kdb_princ_name.utf8str_t_len = strlen(princ_name); 1047 upd.kdb_deleted = TRUE; 1048 1049 status = ulog_add_update(kcontext, &upd); 1050 free(princ_name); 1051 return status; 1052 } 1053 1054 krb5_error_code 1055 krb5_db_rename_principal(krb5_context kcontext, krb5_principal source, 1056 krb5_principal target) 1057 { 1058 kdb_vftabl *v; 1059 krb5_error_code status; 1060 krb5_db_entry *entry; 1061 krb5_boolean eq; 1062 1063 status = get_vftabl(kcontext, &v); 1064 if (status) 1065 return status; 1066 1067 /* 1068 * If the default rename function isn't used and logging is enabled, iprop 1069 * would fail since it doesn't formally support renaming. In that case 1070 * return KRB5_PLUGIN_OP_NOTSUPP. 1071 */ 1072 if (v->rename_principal != krb5_db_def_rename_principal && 1073 logging(kcontext)) 1074 return KRB5_PLUGIN_OP_NOTSUPP; 1075 1076 /* Disallow the operation if source is an alias. */ 1077 status = krb5_db_get_principal(kcontext, source, 0, &entry); 1078 if (status) 1079 return status; 1080 eq = krb5_principal_compare(kcontext, entry->princ, source); 1081 krb5_db_free_principal(kcontext, entry); 1082 if (!eq) 1083 return KRB5_KDB_ALIAS_UNSUPPORTED; 1084 1085 status = krb5_db_get_principal(kcontext, target, 0, &entry); 1086 if (status == 0) { 1087 krb5_db_free_principal(kcontext, entry); 1088 return KRB5_KDB_INUSE; 1089 } 1090 1091 return v->rename_principal(kcontext, source, target); 1092 } 1093 1094 /* 1095 * Use a proxy function for iterate so that we can sort the keys before sending 1096 * them to the callback. 1097 */ 1098 struct callback_proxy_args { 1099 int (*func)(krb5_pointer, krb5_db_entry *); 1100 krb5_pointer func_arg; 1101 }; 1102 1103 static int 1104 sort_entry_callback_proxy(krb5_pointer func_arg, krb5_db_entry *entry) 1105 { 1106 struct callback_proxy_args *args = (struct callback_proxy_args *)func_arg; 1107 1108 /* Sort the keys in the db entry as some parts of krb5 expect it to be. */ 1109 if (entry && entry->key_data) 1110 krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data); 1111 return args->func(args->func_arg, entry); 1112 } 1113 1114 krb5_error_code 1115 krb5_db_iterate(krb5_context kcontext, char *match_entry, 1116 int (*func)(krb5_pointer, krb5_db_entry *), 1117 krb5_pointer func_arg, krb5_flags iterflags) 1118 { 1119 krb5_error_code status = 0; 1120 kdb_vftabl *v; 1121 struct callback_proxy_args proxy_args; 1122 1123 status = get_vftabl(kcontext, &v); 1124 if (status) 1125 return status; 1126 if (v->iterate == NULL) 1127 return KRB5_PLUGIN_OP_NOTSUPP; 1128 1129 /* Use the proxy function to sort key data before passing entries to 1130 * callback. */ 1131 proxy_args.func = func; 1132 proxy_args.func_arg = func_arg; 1133 return v->iterate(kcontext, match_entry, sort_entry_callback_proxy, 1134 &proxy_args, iterflags); 1135 } 1136 1137 /* Return a read only pointer alias to mkey list. Do not free this! */ 1138 krb5_keylist_node * 1139 krb5_db_mkey_list_alias(krb5_context kcontext) 1140 { 1141 return kcontext->dal_handle->master_keylist; 1142 } 1143 1144 krb5_error_code 1145 krb5_db_fetch_mkey_list(krb5_context context, krb5_principal mname, 1146 const krb5_keyblock *mkey) 1147 { 1148 kdb_vftabl *v; 1149 krb5_error_code status = 0; 1150 krb5_keylist_node *local_keylist; 1151 1152 status = get_vftabl(context, &v); 1153 if (status) 1154 return status; 1155 1156 if (!context->dal_handle->master_princ) { 1157 status = krb5_copy_principal(context, mname, 1158 &context->dal_handle->master_princ); 1159 if (status) 1160 return status; 1161 } 1162 1163 status = v->fetch_master_key_list(context, mname, mkey, &local_keylist); 1164 if (status == 0) { 1165 free_mkey_list(context, context->dal_handle->master_keylist); 1166 context->dal_handle->master_keylist = local_keylist; 1167 } 1168 return status; 1169 } 1170 1171 krb5_error_code 1172 krb5_db_store_master_key(krb5_context kcontext, char *keyfile, 1173 krb5_principal mname, krb5_kvno kvno, 1174 krb5_keyblock * key, char *master_pwd) 1175 { 1176 krb5_error_code status = 0; 1177 kdb_vftabl *v; 1178 krb5_keylist_node list; 1179 1180 status = get_vftabl(kcontext, &v); 1181 if (status) 1182 return status; 1183 1184 if (v->store_master_key_list == NULL) 1185 return KRB5_KDB_DBTYPE_NOSUP; 1186 1187 list.kvno = kvno; 1188 list.keyblock = *key; 1189 list.next = NULL; 1190 1191 return v->store_master_key_list(kcontext, keyfile, mname, 1192 &list, master_pwd); 1193 } 1194 1195 krb5_error_code 1196 krb5_db_store_master_key_list(krb5_context kcontext, char *keyfile, 1197 krb5_principal mname, char *master_pwd) 1198 { 1199 krb5_error_code status = 0; 1200 kdb_vftabl *v; 1201 1202 status = get_vftabl(kcontext, &v); 1203 if (status) 1204 return status; 1205 1206 if (v->store_master_key_list == NULL) 1207 return KRB5_KDB_DBTYPE_NOSUP; 1208 1209 if (kcontext->dal_handle->master_keylist == NULL) 1210 return KRB5_KDB_DBNOTINITED; 1211 1212 return v->store_master_key_list(kcontext, keyfile, mname, 1213 kcontext->dal_handle->master_keylist, 1214 master_pwd); 1215 } 1216 1217 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; 1218 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; 1219 1220 krb5_error_code 1221 krb5_db_fetch_mkey(krb5_context context, krb5_principal mname, 1222 krb5_enctype etype, krb5_boolean fromkeyboard, 1223 krb5_boolean twice, char *db_args, krb5_kvno *kvno, 1224 krb5_data *salt, krb5_keyblock *key) 1225 { 1226 krb5_error_code retval; 1227 char password[BUFSIZ]; 1228 krb5_data pwd; 1229 unsigned int size = sizeof(password); 1230 krb5_keyblock tmp_key; 1231 1232 memset(&tmp_key, 0, sizeof(tmp_key)); 1233 1234 if (fromkeyboard) { 1235 krb5_data scratch; 1236 1237 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, 1238 twice ? krb5_mkey_pwd_prompt2 : 0, 1239 password, &size))) { 1240 goto clean_n_exit; 1241 } 1242 1243 pwd.data = password; 1244 pwd.length = size; 1245 if (!salt) { 1246 retval = krb5_principal2salt(context, mname, &scratch); 1247 if (retval) 1248 goto clean_n_exit; 1249 } 1250 retval = 1251 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch, 1252 key); 1253 /* 1254 * If a kvno pointer was passed in and it dereferences the IGNORE_VNO 1255 * value then it should be assigned the value of the kvno associated 1256 * with the current mkey princ key if that princ entry is available 1257 * otherwise assign 1 which is the default kvno value for the mkey 1258 * princ. 1259 */ 1260 if (kvno != NULL && *kvno == IGNORE_VNO) { 1261 krb5_error_code rc; 1262 krb5_db_entry *master_entry; 1263 1264 rc = krb5_db_get_principal(context, mname, 0, &master_entry); 1265 if (rc == 0 && master_entry->n_key_data > 0) 1266 *kvno = (krb5_kvno) master_entry->key_data->key_data_kvno; 1267 else 1268 *kvno = 1; 1269 if (rc == 0) 1270 krb5_db_free_principal(context, master_entry); 1271 } 1272 1273 if (!salt) 1274 free(scratch.data); 1275 zap(password, sizeof(password)); /* erase it */ 1276 1277 } else { 1278 kdb_vftabl *v; 1279 1280 if (context->dal_handle == NULL) { 1281 retval = krb5_db_setup_lib_handle(context); 1282 if (retval) 1283 goto clean_n_exit; 1284 } 1285 1286 /* get the enctype from the stash */ 1287 tmp_key.enctype = ENCTYPE_UNKNOWN; 1288 1289 v = &context->dal_handle->lib_handle->vftabl; 1290 retval = v->fetch_master_key(context, mname, &tmp_key, kvno, db_args); 1291 1292 if (retval) 1293 goto clean_n_exit; 1294 1295 key->contents = k5memdup(tmp_key.contents, tmp_key.length, &retval); 1296 if (key->contents == NULL) 1297 goto clean_n_exit; 1298 1299 key->magic = tmp_key.magic; 1300 key->enctype = tmp_key.enctype; 1301 key->length = tmp_key.length; 1302 } 1303 1304 clean_n_exit: 1305 zapfree(tmp_key.contents, tmp_key.length); 1306 return retval; 1307 } 1308 1309 krb5_error_code 1310 krb5_dbe_fetch_act_key_list(krb5_context context, krb5_principal princ, 1311 krb5_actkvno_node **act_key_list) 1312 { 1313 krb5_error_code retval = 0; 1314 krb5_db_entry *entry; 1315 1316 if (act_key_list == NULL) 1317 return (EINVAL); 1318 1319 retval = krb5_db_get_principal(context, princ, 0, &entry); 1320 if (retval == KRB5_KDB_NOENTRY) 1321 return KRB5_KDB_NOMASTERKEY; 1322 else if (retval) 1323 return retval; 1324 1325 retval = krb5_dbe_lookup_actkvno(context, entry, act_key_list); 1326 krb5_db_free_principal(context, entry); 1327 return retval; 1328 } 1329 1330 /* Find the most recent entry in list (which must not be empty) for the given 1331 * timestamp, and return its kvno. */ 1332 static krb5_kvno 1333 find_actkvno(krb5_actkvno_node *list, krb5_timestamp now) 1334 { 1335 /* 1336 * The list is sorted in ascending order of time. Return the kvno of the 1337 * predecessor of the first entry whose time is in the future. If 1338 * (contrary to the safety checks in kdb5_util use_mkey) all of the entries 1339 * are in the future, we will return the first node; if all are in the 1340 * past, we will return the last node. 1341 */ 1342 while (list->next != NULL && !ts_after(list->next->act_time, now)) 1343 list = list->next; 1344 return list->act_kvno; 1345 } 1346 1347 /* Search the master keylist for the master key with the specified kvno. 1348 * Return the keyblock of the matching entry or NULL if it does not exist. */ 1349 static krb5_keyblock * 1350 find_master_key(krb5_context context, krb5_kvno kvno) 1351 { 1352 krb5_keylist_node *n; 1353 1354 for (n = context->dal_handle->master_keylist; n != NULL; n = n->next) { 1355 if (n->kvno == kvno) 1356 return &n->keyblock; 1357 } 1358 return NULL; 1359 } 1360 1361 /* 1362 * Locates the "active" mkey used when encrypting a princ's keys. Note, the 1363 * caller must NOT free the output act_mkey. 1364 */ 1365 1366 krb5_error_code 1367 krb5_dbe_find_act_mkey(krb5_context context, krb5_actkvno_node *act_mkey_list, 1368 krb5_kvno *act_kvno, krb5_keyblock **act_mkey) 1369 { 1370 krb5_kvno kvno; 1371 krb5_error_code retval; 1372 krb5_keyblock *mkey, *cur_mkey; 1373 krb5_timestamp now; 1374 1375 if (act_mkey_list == NULL) { 1376 *act_kvno = 0; 1377 *act_mkey = NULL; 1378 return 0; 1379 } 1380 1381 if (context->dal_handle->master_keylist == NULL) 1382 return KRB5_KDB_DBNOTINITED; 1383 1384 /* Find the currently active master key version. */ 1385 if ((retval = krb5_timeofday(context, &now))) 1386 return (retval); 1387 kvno = find_actkvno(act_mkey_list, now); 1388 1389 /* Find the corresponding master key. */ 1390 mkey = find_master_key(context, kvno); 1391 if (mkey == NULL) { 1392 /* Reload the master key list and try again. */ 1393 cur_mkey = &context->dal_handle->master_keylist->keyblock; 1394 if (krb5_db_fetch_mkey_list(context, context->dal_handle->master_princ, 1395 cur_mkey) == 0) 1396 mkey = find_master_key(context, kvno); 1397 } 1398 if (mkey == NULL) 1399 return KRB5_KDB_NO_MATCHING_KEY; 1400 1401 *act_mkey = mkey; 1402 if (act_kvno != NULL) 1403 *act_kvno = kvno; 1404 return 0; 1405 } 1406 1407 /* 1408 * Locates the mkey used to protect a princ's keys. Note, the caller must not 1409 * free the output key. 1410 */ 1411 krb5_error_code 1412 krb5_dbe_find_mkey(krb5_context context, krb5_db_entry *entry, 1413 krb5_keyblock **mkey) 1414 { 1415 krb5_kvno mkvno; 1416 krb5_error_code retval; 1417 krb5_keylist_node *cur_keyblock = context->dal_handle->master_keylist; 1418 1419 if (!cur_keyblock) 1420 return KRB5_KDB_DBNOTINITED; 1421 1422 retval = krb5_dbe_get_mkvno(context, entry, &mkvno); 1423 if (retval) 1424 return (retval); 1425 1426 while (cur_keyblock && cur_keyblock->kvno != mkvno) 1427 cur_keyblock = cur_keyblock->next; 1428 1429 if (cur_keyblock) { 1430 *mkey = &cur_keyblock->keyblock; 1431 return (0); 1432 } else { 1433 return KRB5_KDB_NO_MATCHING_KEY; 1434 } 1435 } 1436 1437 void * 1438 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size) 1439 { 1440 return realloc(ptr, size); 1441 } 1442 1443 void 1444 krb5_db_free(krb5_context kcontext, void *ptr) 1445 { 1446 free(ptr); 1447 } 1448 1449 /* has to be modified */ 1450 1451 krb5_error_code 1452 krb5_dbe_find_enctype(krb5_context kcontext, krb5_db_entry *dbentp, 1453 krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno, 1454 krb5_key_data **kdatap) 1455 { 1456 krb5_int32 start = 0; 1457 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype, 1458 kvno, kdatap); 1459 } 1460 1461 krb5_error_code 1462 krb5_dbe_search_enctype(krb5_context kcontext, krb5_db_entry *dbentp, 1463 krb5_int32 *start, krb5_int32 ktype, krb5_int32 stype, 1464 krb5_int32 kvno, krb5_key_data ** kdatap) 1465 { 1466 krb5_error_code status = 0; 1467 kdb_vftabl *v; 1468 1469 status = get_vftabl(kcontext, &v); 1470 if (status) 1471 return status; 1472 return v->dbe_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, 1473 kdatap); 1474 } 1475 1476 #define REALM_SEP_STRING "@" 1477 1478 krb5_error_code 1479 krb5_db_setup_mkey_name(krb5_context context, const char *keyname, 1480 const char *realm, char **fullname, 1481 krb5_principal *principal) 1482 { 1483 krb5_error_code retval; 1484 char *fname; 1485 1486 if (!keyname) 1487 keyname = KRB5_KDB_M_NAME; /* XXX external? */ 1488 1489 if (asprintf(&fname, "%s%s%s", keyname, REALM_SEP_STRING, realm) < 0) 1490 return ENOMEM; 1491 1492 retval = krb5_parse_name(context, fname, principal); 1493 if (retval) { 1494 free(fname); 1495 return retval; 1496 } 1497 if (fullname) 1498 *fullname = fname; 1499 else 1500 free(fname); 1501 return 0; 1502 } 1503 1504 krb5_error_code 1505 krb5_dbe_lookup_last_pwd_change(krb5_context context, krb5_db_entry *entry, 1506 krb5_timestamp *stamp) 1507 { 1508 krb5_tl_data tl_data; 1509 krb5_error_code code; 1510 krb5_int32 tmp; 1511 1512 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1513 1514 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1515 return (code); 1516 1517 if (tl_data.tl_data_length != 4) { 1518 *stamp = 0; 1519 return (0); 1520 } 1521 1522 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1523 1524 *stamp = (krb5_timestamp) tmp; 1525 1526 return (0); 1527 } 1528 1529 krb5_error_code 1530 krb5_dbe_lookup_last_admin_unlock(krb5_context context, krb5_db_entry *entry, 1531 krb5_timestamp *stamp) 1532 { 1533 krb5_tl_data tl_data; 1534 krb5_error_code code; 1535 krb5_int32 tmp; 1536 1537 tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK; 1538 1539 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1540 return (code); 1541 1542 if (tl_data.tl_data_length != 4) { 1543 *stamp = 0; 1544 return (0); 1545 } 1546 1547 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1548 1549 *stamp = (krb5_timestamp) tmp; 1550 1551 return (0); 1552 } 1553 1554 krb5_error_code 1555 krb5_dbe_lookup_tl_data(krb5_context context, krb5_db_entry *entry, 1556 krb5_tl_data *ret_tl_data) 1557 { 1558 krb5_tl_data *tl_data; 1559 1560 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 1561 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { 1562 *ret_tl_data = *tl_data; 1563 return (0); 1564 } 1565 } 1566 1567 /* 1568 * If the requested record isn't found, return zero bytes. If it 1569 * ever means something to have a zero-length tl_data, this code 1570 * and its callers will have to be changed. 1571 */ 1572 1573 ret_tl_data->tl_data_length = 0; 1574 ret_tl_data->tl_data_contents = NULL; 1575 return (0); 1576 } 1577 1578 krb5_error_code 1579 krb5_dbe_create_key_data(krb5_context context, krb5_db_entry *entry) 1580 { 1581 krb5_key_data *newptr; 1582 1583 newptr = realloc(entry->key_data, 1584 (entry->n_key_data + 1) * sizeof(*entry->key_data)); 1585 if (newptr == NULL) 1586 return ENOMEM; 1587 entry->key_data = newptr; 1588 1589 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data)); 1590 entry->n_key_data++; 1591 1592 return 0; 1593 } 1594 1595 krb5_error_code 1596 krb5_dbe_update_mod_princ_data(krb5_context context, krb5_db_entry *entry, 1597 krb5_timestamp mod_date, 1598 krb5_const_principal mod_princ) 1599 { 1600 krb5_tl_data tl_data; 1601 1602 krb5_error_code retval = 0; 1603 krb5_octet *nextloc = 0; 1604 char *unparse_mod_princ = 0; 1605 unsigned int unparse_mod_princ_size; 1606 1607 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ))) 1608 return (retval); 1609 1610 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; 1611 1612 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) 1613 == NULL) { 1614 free(unparse_mod_princ); 1615 return (ENOMEM); 1616 } 1617 1618 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1619 tl_data.tl_data_length = unparse_mod_princ_size + 4; 1620 tl_data.tl_data_contents = nextloc; 1621 1622 /* Mod Date */ 1623 krb5_kdb_encode_int32(mod_date, nextloc); 1624 1625 /* Mod Princ */ 1626 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size); 1627 1628 retval = krb5_dbe_update_tl_data(context, entry, &tl_data); 1629 1630 free(unparse_mod_princ); 1631 free(nextloc); 1632 1633 return (retval); 1634 } 1635 1636 krb5_error_code 1637 krb5_dbe_lookup_mod_princ_data(krb5_context context, krb5_db_entry *entry, 1638 krb5_timestamp *mod_time, 1639 krb5_principal *mod_princ) 1640 { 1641 krb5_tl_data tl_data; 1642 krb5_error_code code; 1643 1644 *mod_princ = NULL; 1645 *mod_time = 0; 1646 1647 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1648 1649 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1650 return (code); 1651 1652 if ((tl_data.tl_data_length < 5) || 1653 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0')) 1654 return (KRB5_KDB_TRUNCATED_RECORD); 1655 1656 /* Mod Date */ 1657 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); 1658 1659 /* Mod Princ */ 1660 if ((code = krb5_parse_name(context, 1661 (const char *) (tl_data.tl_data_contents + 4), 1662 mod_princ))) 1663 return (code); 1664 1665 return (0); 1666 } 1667 1668 krb5_error_code 1669 krb5_dbe_lookup_mkvno(krb5_context context, krb5_db_entry *entry, 1670 krb5_kvno *mkvno) 1671 { 1672 krb5_tl_data tl_data; 1673 krb5_error_code code; 1674 krb5_int16 tmp; 1675 1676 tl_data.tl_data_type = KRB5_TL_MKVNO; 1677 1678 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1679 return (code); 1680 1681 if (tl_data.tl_data_length == 0) { 1682 *mkvno = 0; /* Indicates KRB5_TL_MKVNO data not present */ 1683 return (0); 1684 } else if (tl_data.tl_data_length != 2) { 1685 return (KRB5_KDB_TRUNCATED_RECORD); 1686 } 1687 1688 krb5_kdb_decode_int16(tl_data.tl_data_contents, tmp); 1689 *mkvno = (krb5_kvno) tmp; 1690 return (0); 1691 } 1692 1693 krb5_error_code 1694 krb5_dbe_get_mkvno(krb5_context context, krb5_db_entry *entry, 1695 krb5_kvno *mkvno) 1696 { 1697 krb5_error_code code; 1698 krb5_kvno kvno; 1699 krb5_keylist_node *mkey_list = context->dal_handle->master_keylist; 1700 1701 if (mkey_list == NULL) 1702 return KRB5_KDB_DBNOTINITED; 1703 1704 /* Output the value from entry tl_data if present. */ 1705 code = krb5_dbe_lookup_mkvno(context, entry, &kvno); 1706 if (code != 0) 1707 return code; 1708 if (kvno != 0) { 1709 *mkvno = kvno; 1710 return 0; 1711 } 1712 1713 /* Determine the minimum kvno in mkey_list and output that. */ 1714 kvno = (krb5_kvno) -1; 1715 while (mkey_list != NULL) { 1716 if (mkey_list->kvno < kvno) 1717 kvno = mkey_list->kvno; 1718 mkey_list = mkey_list->next; 1719 } 1720 *mkvno = kvno; 1721 return 0; 1722 } 1723 1724 krb5_error_code 1725 krb5_dbe_update_mkvno(krb5_context context, krb5_db_entry *entry, 1726 krb5_kvno mkvno) 1727 { 1728 krb5_tl_data tl_data; 1729 krb5_octet buf[2]; /* this is the encoded size of an int16 */ 1730 krb5_int16 tmp_kvno = (krb5_int16) mkvno; 1731 1732 tl_data.tl_data_type = KRB5_TL_MKVNO; 1733 tl_data.tl_data_length = sizeof(buf); 1734 krb5_kdb_encode_int16(tmp_kvno, buf); 1735 tl_data.tl_data_contents = buf; 1736 1737 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 1738 } 1739 1740 krb5_error_code 1741 krb5_dbe_lookup_mkey_aux(krb5_context context, krb5_db_entry *entry, 1742 krb5_mkey_aux_node **mkey_aux_data_list) 1743 { 1744 krb5_tl_data tl_data; 1745 krb5_int16 version, mkey_kvno; 1746 krb5_mkey_aux_node *head_data = NULL, *new_data = NULL, 1747 *prev_data = NULL; 1748 krb5_octet *curloc; /* current location pointer */ 1749 krb5_error_code code; 1750 1751 tl_data.tl_data_type = KRB5_TL_MKEY_AUX; 1752 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1753 return (code); 1754 1755 if (tl_data.tl_data_contents == NULL) { 1756 *mkey_aux_data_list = NULL; 1757 return (0); 1758 } else { 1759 /* get version to determine how to parse the data */ 1760 krb5_kdb_decode_int16(tl_data.tl_data_contents, version); 1761 if (version == 1) { 1762 /* variable size, must be at least 10 bytes */ 1763 if (tl_data.tl_data_length < 10) 1764 return (KRB5_KDB_TRUNCATED_RECORD); 1765 1766 /* curloc points to first tuple entry in the tl_data_contents */ 1767 curloc = tl_data.tl_data_contents + sizeof(version); 1768 1769 while (curloc < (tl_data.tl_data_contents + tl_data.tl_data_length)) { 1770 1771 new_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); 1772 if (new_data == NULL) { 1773 krb5_dbe_free_mkey_aux_list(context, head_data); 1774 return (ENOMEM); 1775 } 1776 memset(new_data, 0, sizeof(krb5_mkey_aux_node)); 1777 1778 krb5_kdb_decode_int16(curloc, mkey_kvno); 1779 new_data->mkey_kvno = mkey_kvno; 1780 curloc += sizeof(krb5_ui_2); 1781 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_kvno); 1782 curloc += sizeof(krb5_ui_2); 1783 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_type[0]); 1784 curloc += sizeof(krb5_ui_2); 1785 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_length[0]); 1786 curloc += sizeof(krb5_ui_2); 1787 1788 new_data->latest_mkey.key_data_contents[0] = (krb5_octet *) 1789 malloc(new_data->latest_mkey.key_data_length[0]); 1790 1791 if (new_data->latest_mkey.key_data_contents[0] == NULL) { 1792 krb5_dbe_free_mkey_aux_list(context, head_data); 1793 free(new_data); 1794 return (ENOMEM); 1795 } 1796 memcpy(new_data->latest_mkey.key_data_contents[0], curloc, 1797 new_data->latest_mkey.key_data_length[0]); 1798 curloc += new_data->latest_mkey.key_data_length[0]; 1799 1800 /* always using key data ver 1 for mkeys */ 1801 new_data->latest_mkey.key_data_ver = 1; 1802 1803 new_data->next = NULL; 1804 if (prev_data != NULL) 1805 prev_data->next = new_data; 1806 else 1807 head_data = new_data; 1808 prev_data = new_data; 1809 } 1810 } else { 1811 k5_setmsg(context, KRB5_KDB_BAD_VERSION, 1812 _("Illegal version number for KRB5_TL_MKEY_AUX %d\n"), 1813 version); 1814 return (KRB5_KDB_BAD_VERSION); 1815 } 1816 } 1817 *mkey_aux_data_list = head_data; 1818 return (0); 1819 } 1820 1821 #if KRB5_TL_MKEY_AUX_VER == 1 1822 krb5_error_code 1823 krb5_dbe_update_mkey_aux(krb5_context context, krb5_db_entry *entry, 1824 krb5_mkey_aux_node *mkey_aux_data_list) 1825 { 1826 krb5_error_code status; 1827 krb5_tl_data tl_data; 1828 krb5_int16 version, tmp_kvno; 1829 unsigned char *nextloc; 1830 krb5_mkey_aux_node *aux_data_entry; 1831 1832 if (!mkey_aux_data_list) { 1833 /* delete the KRB5_TL_MKEY_AUX from the entry */ 1834 krb5_dbe_delete_tl_data(context, entry, KRB5_TL_MKEY_AUX); 1835 return (0); 1836 } 1837 1838 memset(&tl_data, 0, sizeof(tl_data)); 1839 tl_data.tl_data_type = KRB5_TL_MKEY_AUX; 1840 /* 1841 * determine out how much space to allocate. Note key_data_ver not stored 1842 * as this is hard coded to one and is accounted for in 1843 * krb5_dbe_lookup_mkey_aux. 1844 */ 1845 tl_data.tl_data_length = sizeof(version); /* version */ 1846 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL; 1847 aux_data_entry = aux_data_entry->next) { 1848 1849 tl_data.tl_data_length += (sizeof(krb5_ui_2) + /* mkey_kvno */ 1850 sizeof(krb5_ui_2) + /* latest_mkey kvno */ 1851 sizeof(krb5_ui_2) + /* latest_mkey enctype */ 1852 sizeof(krb5_ui_2) + /* latest_mkey length */ 1853 aux_data_entry->latest_mkey.key_data_length[0]); 1854 } 1855 1856 tl_data.tl_data_contents = (krb5_octet *) malloc(tl_data.tl_data_length); 1857 if (tl_data.tl_data_contents == NULL) 1858 return (ENOMEM); 1859 1860 nextloc = tl_data.tl_data_contents; 1861 version = KRB5_TL_MKEY_AUX_VER; 1862 krb5_kdb_encode_int16(version, nextloc); 1863 nextloc += sizeof(krb5_ui_2); 1864 1865 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL; 1866 aux_data_entry = aux_data_entry->next) { 1867 1868 tmp_kvno = (krb5_int16) aux_data_entry->mkey_kvno; 1869 krb5_kdb_encode_int16(tmp_kvno, nextloc); 1870 nextloc += sizeof(krb5_ui_2); 1871 1872 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_kvno, 1873 nextloc); 1874 nextloc += sizeof(krb5_ui_2); 1875 1876 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_type[0], 1877 nextloc); 1878 nextloc += sizeof(krb5_ui_2); 1879 1880 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_length[0], 1881 nextloc); 1882 nextloc += sizeof(krb5_ui_2); 1883 1884 if (aux_data_entry->latest_mkey.key_data_length[0] > 0) { 1885 memcpy(nextloc, aux_data_entry->latest_mkey.key_data_contents[0], 1886 aux_data_entry->latest_mkey.key_data_length[0]); 1887 nextloc += aux_data_entry->latest_mkey.key_data_length[0]; 1888 } 1889 } 1890 1891 status = krb5_dbe_update_tl_data(context, entry, &tl_data); 1892 free(tl_data.tl_data_contents); 1893 return status; 1894 } 1895 #endif /* KRB5_TL_MKEY_AUX_VER == 1 */ 1896 1897 #if KRB5_TL_ACTKVNO_VER == 1 1898 /* 1899 * If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER == 1 then size of 1900 * a actkvno tuple {act_kvno, act_time} entry is: 1901 */ 1902 #define ACTKVNO_TUPLE_SIZE (sizeof(krb5_int16) + sizeof(krb5_int32)) 1903 #define act_kvno(cp) (cp) /* return pointer to start of act_kvno data */ 1904 #define act_time(cp) ((cp) + sizeof(krb5_int16)) /* return pointer to start of act_time data */ 1905 #endif 1906 1907 krb5_error_code 1908 krb5_dbe_lookup_actkvno(krb5_context context, krb5_db_entry *entry, 1909 krb5_actkvno_node **actkvno_list) 1910 { 1911 krb5_tl_data tl_data; 1912 krb5_error_code code; 1913 krb5_int16 version, tmp_kvno; 1914 krb5_actkvno_node *head_data = NULL, *new_data = NULL, *prev_data = NULL; 1915 unsigned int num_actkvno, i; 1916 krb5_octet *next_tuple; 1917 krb5_kvno earliest_kvno; 1918 1919 memset(&tl_data, 0, sizeof(tl_data)); 1920 tl_data.tl_data_type = KRB5_TL_ACTKVNO; 1921 1922 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1923 return (code); 1924 1925 if (tl_data.tl_data_contents == NULL) { 1926 /* 1927 * If there is no KRB5_TL_ACTKVNO data (likely because the KDB was 1928 * created prior to 1.7), synthesize the list which should have been 1929 * created at KDB initialization, making the earliest master key 1930 * active. 1931 */ 1932 1933 /* Get the earliest master key version. */ 1934 if (entry->n_key_data == 0) 1935 return KRB5_KDB_NOMASTERKEY; 1936 earliest_kvno = entry->key_data[entry->n_key_data - 1].key_data_kvno; 1937 1938 head_data = malloc(sizeof(*head_data)); 1939 if (head_data == NULL) 1940 return ENOMEM; 1941 memset(head_data, 0, sizeof(*head_data)); 1942 head_data->act_time = 0; /* earliest time possible */ 1943 head_data->act_kvno = earliest_kvno; 1944 } else { 1945 /* get version to determine how to parse the data */ 1946 krb5_kdb_decode_int16(tl_data.tl_data_contents, version); 1947 if (version == 1) { 1948 1949 /* variable size, must be at least 8 bytes */ 1950 if (tl_data.tl_data_length < 8) 1951 return (KRB5_KDB_TRUNCATED_RECORD); 1952 1953 /* 1954 * Find number of tuple entries, remembering to account for version 1955 * field. 1956 */ 1957 num_actkvno = (tl_data.tl_data_length - sizeof(version)) / 1958 ACTKVNO_TUPLE_SIZE; 1959 prev_data = NULL; 1960 /* next_tuple points to first tuple entry in the tl_data_contents */ 1961 next_tuple = tl_data.tl_data_contents + sizeof(version); 1962 for (i = 0; i < num_actkvno; i++) { 1963 new_data = (krb5_actkvno_node *) malloc(sizeof(krb5_actkvno_node)); 1964 if (new_data == NULL) { 1965 krb5_dbe_free_actkvno_list(context, head_data); 1966 return (ENOMEM); 1967 } 1968 memset(new_data, 0, sizeof(krb5_actkvno_node)); 1969 1970 /* using tmp_kvno to avoid type mismatch */ 1971 krb5_kdb_decode_int16(act_kvno(next_tuple), tmp_kvno); 1972 new_data->act_kvno = (krb5_kvno) tmp_kvno; 1973 krb5_kdb_decode_int32(act_time(next_tuple), new_data->act_time); 1974 1975 if (prev_data != NULL) 1976 prev_data->next = new_data; 1977 else 1978 head_data = new_data; 1979 prev_data = new_data; 1980 next_tuple += ACTKVNO_TUPLE_SIZE; 1981 } 1982 } else { 1983 k5_setmsg(context, KRB5_KDB_BAD_VERSION, 1984 _("Illegal version number for KRB5_TL_ACTKVNO %d\n"), 1985 version); 1986 return (KRB5_KDB_BAD_VERSION); 1987 } 1988 } 1989 *actkvno_list = head_data; 1990 return (0); 1991 } 1992 1993 /* 1994 * Add KRB5_TL_ACTKVNO TL data entries to krb5_db_entry *entry 1995 */ 1996 #if KRB5_TL_ACTKVNO_VER == 1 1997 krb5_error_code 1998 krb5_dbe_update_actkvno(krb5_context context, krb5_db_entry *entry, 1999 const krb5_actkvno_node *actkvno_list) 2000 { 2001 krb5_error_code retval = 0; 2002 krb5_int16 version, tmp_kvno; 2003 krb5_tl_data new_tl_data; 2004 unsigned char *nextloc; 2005 const krb5_actkvno_node *cur_actkvno; 2006 krb5_octet *tmpptr; 2007 2008 if (actkvno_list == NULL) 2009 return EINVAL; 2010 2011 memset(&new_tl_data, 0, sizeof(new_tl_data)); 2012 /* allocate initial KRB5_TL_ACTKVNO tl_data entry */ 2013 new_tl_data.tl_data_length = sizeof(version); 2014 new_tl_data.tl_data_contents = (krb5_octet *) malloc(new_tl_data.tl_data_length); 2015 if (new_tl_data.tl_data_contents == NULL) 2016 return ENOMEM; 2017 2018 /* add the current version # for the data format used for KRB5_TL_ACTKVNO */ 2019 version = KRB5_TL_ACTKVNO_VER; 2020 krb5_kdb_encode_int16(version, (unsigned char *) new_tl_data.tl_data_contents); 2021 2022 for (cur_actkvno = actkvno_list; cur_actkvno != NULL; 2023 cur_actkvno = cur_actkvno->next) { 2024 2025 new_tl_data.tl_data_length += ACTKVNO_TUPLE_SIZE; 2026 tmpptr = realloc(new_tl_data.tl_data_contents, new_tl_data.tl_data_length); 2027 if (tmpptr == NULL) { 2028 free(new_tl_data.tl_data_contents); 2029 return ENOMEM; 2030 } else { 2031 new_tl_data.tl_data_contents = tmpptr; 2032 } 2033 2034 /* 2035 * Using realloc so tl_data_contents is required to correctly calculate 2036 * next location to store new tuple. 2037 */ 2038 nextloc = new_tl_data.tl_data_contents + new_tl_data.tl_data_length - ACTKVNO_TUPLE_SIZE; 2039 /* using tmp_kvno to avoid type mismatch issues */ 2040 tmp_kvno = (krb5_int16) cur_actkvno->act_kvno; 2041 krb5_kdb_encode_int16(tmp_kvno, nextloc); 2042 nextloc += sizeof(krb5_ui_2); 2043 krb5_kdb_encode_int32((krb5_ui_4)cur_actkvno->act_time, nextloc); 2044 } 2045 2046 new_tl_data.tl_data_type = KRB5_TL_ACTKVNO; 2047 retval = krb5_dbe_update_tl_data(context, entry, &new_tl_data); 2048 free(new_tl_data.tl_data_contents); 2049 2050 return (retval); 2051 } 2052 #endif /* KRB5_TL_ACTKVNO_VER == 1 */ 2053 2054 krb5_error_code 2055 krb5_dbe_update_last_pwd_change(krb5_context context, krb5_db_entry *entry, 2056 krb5_timestamp stamp) 2057 { 2058 krb5_tl_data tl_data; 2059 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 2060 2061 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 2062 tl_data.tl_data_length = sizeof(buf); 2063 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 2064 tl_data.tl_data_contents = buf; 2065 2066 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 2067 } 2068 2069 krb5_error_code 2070 krb5_dbe_update_last_admin_unlock(krb5_context context, krb5_db_entry *entry, 2071 krb5_timestamp stamp) 2072 { 2073 krb5_tl_data tl_data; 2074 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 2075 2076 tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK; 2077 tl_data.tl_data_length = sizeof(buf); 2078 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 2079 tl_data.tl_data_contents = buf; 2080 2081 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 2082 } 2083 2084 /* 2085 * Prepare to iterate over the string attributes of entry. The returned 2086 * pointers are aliases into entry's tl_data (or into an empty string literal) 2087 * and remain valid until the entry's tl_data is changed. 2088 */ 2089 static krb5_error_code 2090 begin_attrs(krb5_context context, krb5_db_entry *entry, const char **pos_out, 2091 const char **end_out) 2092 { 2093 krb5_error_code code; 2094 krb5_tl_data tl_data; 2095 2096 *pos_out = *end_out = NULL; 2097 tl_data.tl_data_type = KRB5_TL_STRING_ATTRS; 2098 code = krb5_dbe_lookup_tl_data(context, entry, &tl_data); 2099 if (code) 2100 return code; 2101 2102 /* Copy the current mapping to buf, updating key with value if found. */ 2103 *pos_out = (const char *)tl_data.tl_data_contents; 2104 *end_out = *pos_out + tl_data.tl_data_length; 2105 return 0; 2106 } 2107 2108 /* Find the next key and value pair in *pos and update *pos. */ 2109 static krb5_boolean 2110 next_attr(const char **pos, const char *end, const char **key_out, 2111 const char **val_out) 2112 { 2113 const char *key, *key_end, *val, *val_end; 2114 2115 *key_out = *val_out = NULL; 2116 if (*pos == end) 2117 return FALSE; 2118 key = *pos; 2119 key_end = memchr(key, '\0', end - key); 2120 if (key_end == NULL) /* Malformed representation; give up. */ 2121 return FALSE; 2122 val = key_end + 1; 2123 val_end = memchr(val, '\0', end - val); 2124 if (val_end == NULL) /* Malformed representation; give up. */ 2125 return FALSE; 2126 2127 *key_out = key; 2128 *val_out = val; 2129 *pos = val_end + 1; 2130 return TRUE; 2131 } 2132 2133 krb5_error_code 2134 krb5_dbe_get_strings(krb5_context context, krb5_db_entry *entry, 2135 krb5_string_attr **strings_out, int *count_out) 2136 { 2137 krb5_error_code code; 2138 const char *pos, *end, *mapkey, *mapval; 2139 char *key = NULL, *val = NULL; 2140 krb5_string_attr *strings = NULL, *newstrings; 2141 int count = 0; 2142 2143 *strings_out = NULL; 2144 *count_out = 0; 2145 code = begin_attrs(context, entry, &pos, &end); 2146 if (code) 2147 return code; 2148 2149 while (next_attr(&pos, end, &mapkey, &mapval)) { 2150 /* Add a copy of mapkey and mapvalue to strings. */ 2151 newstrings = realloc(strings, (count + 1) * sizeof(*strings)); 2152 if (newstrings == NULL) 2153 goto oom; 2154 strings = newstrings; 2155 key = strdup(mapkey); 2156 val = strdup(mapval); 2157 if (key == NULL || val == NULL) 2158 goto oom; 2159 strings[count].key = key; 2160 strings[count].value = val; 2161 count++; 2162 } 2163 2164 *strings_out = strings; 2165 *count_out = count; 2166 return 0; 2167 2168 oom: 2169 free(key); 2170 free(val); 2171 krb5_dbe_free_strings(context, strings, count); 2172 return ENOMEM; 2173 } 2174 2175 krb5_error_code 2176 krb5_dbe_get_string(krb5_context context, krb5_db_entry *entry, 2177 const char *key, char **value_out) 2178 { 2179 krb5_error_code code; 2180 const char *pos, *end, *mapkey, *mapval; 2181 2182 *value_out = NULL; 2183 code = begin_attrs(context, entry, &pos, &end); 2184 if (code) 2185 return code; 2186 while (next_attr(&pos, end, &mapkey, &mapval)) { 2187 if (strcmp(mapkey, key) == 0) { 2188 *value_out = strdup(mapval); 2189 return (*value_out == NULL) ? ENOMEM : 0; 2190 } 2191 } 2192 2193 return 0; 2194 } 2195 2196 krb5_error_code 2197 krb5_dbe_set_string(krb5_context context, krb5_db_entry *entry, 2198 const char *key, const char *value) 2199 { 2200 krb5_error_code code; 2201 const char *pos, *end, *mapkey, *mapval; 2202 struct k5buf buf = EMPTY_K5BUF; 2203 krb5_boolean found = FALSE; 2204 krb5_tl_data tl_data; 2205 2206 /* Copy the current mapping to buf, updating key with value if found. */ 2207 code = begin_attrs(context, entry, &pos, &end); 2208 if (code) 2209 return code; 2210 k5_buf_init_dynamic(&buf); 2211 while (next_attr(&pos, end, &mapkey, &mapval)) { 2212 if (strcmp(mapkey, key) == 0) { 2213 if (value != NULL) { 2214 k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1); 2215 k5_buf_add_len(&buf, value, strlen(value) + 1); 2216 } 2217 found = TRUE; 2218 } else { 2219 k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1); 2220 k5_buf_add_len(&buf, mapval, strlen(mapval) + 1); 2221 } 2222 } 2223 2224 /* If key wasn't found in the map, add a new entry for it. */ 2225 if (!found && value != NULL) { 2226 k5_buf_add_len(&buf, key, strlen(key) + 1); 2227 k5_buf_add_len(&buf, value, strlen(value) + 1); 2228 } 2229 2230 if (k5_buf_status(&buf) != 0) 2231 return ENOMEM; 2232 if (buf.len > 65535) { 2233 code = KRB5_KDB_STRINGS_TOOLONG; 2234 goto cleanup; 2235 } 2236 tl_data.tl_data_type = KRB5_TL_STRING_ATTRS; 2237 tl_data.tl_data_contents = buf.data; 2238 tl_data.tl_data_length = buf.len; 2239 2240 code = krb5_dbe_update_tl_data(context, entry, &tl_data); 2241 2242 cleanup: 2243 k5_buf_free(&buf); 2244 return code; 2245 } 2246 2247 krb5_error_code 2248 krb5_dbe_delete_tl_data(krb5_context context, krb5_db_entry *entry, 2249 krb5_int16 tl_data_type) 2250 { 2251 krb5_tl_data *tl_data, *prev_tl_data, *free_tl_data; 2252 2253 /* 2254 * Find existing entries of the specified type and remove them from the 2255 * entry's tl_data list. 2256 */ 2257 2258 for (prev_tl_data = tl_data = entry->tl_data; tl_data != NULL;) { 2259 if (tl_data->tl_data_type == tl_data_type) { 2260 if (tl_data == entry->tl_data) { 2261 /* remove from head */ 2262 entry->tl_data = tl_data->tl_data_next; 2263 prev_tl_data = entry->tl_data; 2264 } else if (tl_data->tl_data_next == NULL) { 2265 /* remove from tail */ 2266 prev_tl_data->tl_data_next = NULL; 2267 } else { 2268 /* remove in between */ 2269 prev_tl_data->tl_data_next = tl_data->tl_data_next; 2270 } 2271 free_tl_data = tl_data; 2272 tl_data = tl_data->tl_data_next; 2273 krb5_dbe_free_tl_data(context, free_tl_data); 2274 entry->n_tl_data--; 2275 } else { 2276 prev_tl_data = tl_data; 2277 tl_data = tl_data->tl_data_next; 2278 } 2279 } 2280 2281 return (0); 2282 } 2283 2284 krb5_error_code 2285 krb5_db_update_tl_data(krb5_context context, krb5_int16 *n_tl_datap, 2286 krb5_tl_data **tl_datap, krb5_tl_data *new_tl_data) 2287 { 2288 krb5_tl_data *tl_data = NULL; 2289 krb5_octet *tmp; 2290 2291 /* 2292 * Copy the new data first, so we can fail cleanly if malloc() 2293 * fails. 2294 */ 2295 tmp = malloc(new_tl_data->tl_data_length); 2296 if (tmp == NULL) 2297 return (ENOMEM); 2298 2299 /* 2300 * Find an existing entry of the specified type and point at 2301 * it, or NULL if not found. 2302 */ 2303 2304 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */ 2305 for (tl_data = *tl_datap; tl_data; 2306 tl_data = tl_data->tl_data_next) 2307 if (tl_data->tl_data_type == new_tl_data->tl_data_type) 2308 break; 2309 } 2310 2311 /* If necessary, chain a new record in the beginning and point at it. */ 2312 2313 if (!tl_data) { 2314 tl_data = calloc(1, sizeof(*tl_data)); 2315 if (tl_data == NULL) { 2316 free(tmp); 2317 return (ENOMEM); 2318 } 2319 tl_data->tl_data_next = *tl_datap; 2320 *tl_datap = tl_data; 2321 (*n_tl_datap)++; 2322 } 2323 2324 /* fill in the record */ 2325 2326 free(tl_data->tl_data_contents); 2327 2328 tl_data->tl_data_type = new_tl_data->tl_data_type; 2329 tl_data->tl_data_length = new_tl_data->tl_data_length; 2330 tl_data->tl_data_contents = tmp; 2331 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); 2332 2333 return (0); 2334 } 2335 2336 krb5_error_code 2337 krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry, 2338 krb5_tl_data *new_tl_data) 2339 { 2340 return krb5_db_update_tl_data(context, &entry->n_tl_data, &entry->tl_data, 2341 new_tl_data); 2342 } 2343 2344 krb5_error_code 2345 krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key, 2346 krb5_const_principal princ, krb5_int16 *salttype_out, 2347 krb5_data **salt_out) 2348 { 2349 krb5_error_code retval; 2350 krb5_int16 stype; 2351 krb5_data *salt, sdata; 2352 2353 stype = (key->key_data_ver < 2) ? KRB5_KDB_SALTTYPE_NORMAL : 2354 key->key_data_type[1]; 2355 *salttype_out = stype; 2356 *salt_out = NULL; 2357 2358 /* Place computed salt into sdata, or directly into salt_out and return. */ 2359 switch (stype) { 2360 case KRB5_KDB_SALTTYPE_NORMAL: 2361 retval = krb5_principal2salt(context, princ, &sdata); 2362 if (retval) 2363 return retval; 2364 break; 2365 case KRB5_KDB_SALTTYPE_NOREALM: 2366 retval = krb5_principal2salt_norealm(context, princ, &sdata); 2367 if (retval) 2368 return retval; 2369 break; 2370 case KRB5_KDB_SALTTYPE_ONLYREALM: 2371 return krb5_copy_data(context, &princ->realm, salt_out); 2372 case KRB5_KDB_SALTTYPE_SPECIAL: 2373 sdata = make_data(key->key_data_contents[1], key->key_data_length[1]); 2374 return krb5_copy_data(context, &sdata, salt_out); 2375 default: 2376 return KRB5_KDB_BAD_SALTTYPE; 2377 } 2378 2379 /* Make a container for sdata. */ 2380 salt = malloc(sizeof(*salt)); 2381 if (salt == NULL) { 2382 free(sdata.data); 2383 return ENOMEM; 2384 } 2385 *salt = sdata; 2386 *salt_out = salt; 2387 return 0; 2388 } 2389 2390 krb5_error_code 2391 krb5_dbe_specialize_salt(krb5_context context, krb5_db_entry *entry) 2392 { 2393 krb5_int16 stype, i; 2394 krb5_data *salt; 2395 krb5_error_code ret; 2396 2397 if (context == NULL || entry == NULL) 2398 return EINVAL; 2399 2400 /* 2401 * Store salt values explicitly so that they don't depend on the principal 2402 * name. 2403 */ 2404 for (i = 0; i < entry->n_key_data; i++) { 2405 ret = krb5_dbe_compute_salt(context, &entry->key_data[i], entry->princ, 2406 &stype, &salt); 2407 if (ret) 2408 return ret; 2409 2410 /* Steal the data pointer from salt and free the container. */ 2411 if (entry->key_data[i].key_data_ver >= 2) 2412 free(entry->key_data[i].key_data_contents[1]); 2413 entry->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL; 2414 entry->key_data[i].key_data_contents[1] = (uint8_t *)salt->data; 2415 entry->key_data[i].key_data_length[1] = salt->length; 2416 entry->key_data[i].key_data_ver = 2; 2417 free(salt); 2418 } 2419 2420 return 0; 2421 } 2422 2423 /* change password functions */ 2424 krb5_error_code 2425 krb5_dbe_cpw(krb5_context kcontext, krb5_keyblock *master_key, 2426 krb5_key_salt_tuple *ks_tuple, int ks_tuple_count, char *passwd, 2427 int new_kvno, krb5_boolean keepold, krb5_db_entry *db_entry) 2428 { 2429 krb5_error_code status = 0; 2430 kdb_vftabl *v; 2431 2432 status = get_vftabl(kcontext, &v); 2433 if (status) 2434 return status; 2435 return v->change_pwd(kcontext, master_key, ks_tuple, ks_tuple_count, 2436 passwd, new_kvno, keepold, db_entry); 2437 } 2438 2439 /* policy management functions */ 2440 krb5_error_code 2441 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy) 2442 { 2443 krb5_error_code status = 0; 2444 kdb_vftabl *v; 2445 2446 status = get_vftabl(kcontext, &v); 2447 if (status) 2448 return status; 2449 if (v->create_policy == NULL) 2450 return KRB5_PLUGIN_OP_NOTSUPP; 2451 2452 status = v->create_policy(kcontext, policy); 2453 /* iprop does not support policy mods; force full resync. */ 2454 if (!status && logging(kcontext)) 2455 status = ulog_init_header(kcontext); 2456 return status; 2457 } 2458 2459 krb5_error_code 2460 krb5_db_get_policy(krb5_context kcontext, char *name, osa_policy_ent_t *policy) 2461 { 2462 krb5_error_code status = 0; 2463 kdb_vftabl *v; 2464 2465 status = get_vftabl(kcontext, &v); 2466 if (status) 2467 return status; 2468 if (v->get_policy == NULL) 2469 return KRB5_PLUGIN_OP_NOTSUPP; 2470 return v->get_policy(kcontext, name, policy); 2471 } 2472 2473 krb5_error_code 2474 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy) 2475 { 2476 krb5_error_code status = 0; 2477 kdb_vftabl *v; 2478 2479 status = get_vftabl(kcontext, &v); 2480 if (status) 2481 return status; 2482 if (v->put_policy == NULL) 2483 return KRB5_PLUGIN_OP_NOTSUPP; 2484 2485 status = v->put_policy(kcontext, policy); 2486 /* iprop does not support policy mods; force full resync. */ 2487 if (!status && logging(kcontext)) 2488 status = ulog_init_header(kcontext); 2489 return status; 2490 } 2491 2492 krb5_error_code 2493 krb5_db_iter_policy(krb5_context kcontext, char *match_entry, 2494 osa_adb_iter_policy_func func, void *data) 2495 { 2496 krb5_error_code status = 0; 2497 kdb_vftabl *v; 2498 2499 status = get_vftabl(kcontext, &v); 2500 if (status) 2501 return status; 2502 if (v->iter_policy == NULL) 2503 return 0; 2504 return v->iter_policy(kcontext, match_entry, func, data); 2505 } 2506 2507 krb5_error_code 2508 krb5_db_delete_policy(krb5_context kcontext, char *policy) 2509 { 2510 krb5_error_code status = 0; 2511 kdb_vftabl *v; 2512 2513 status = get_vftabl(kcontext, &v); 2514 if (status) 2515 return status; 2516 if (v->delete_policy == NULL) 2517 return KRB5_PLUGIN_OP_NOTSUPP; 2518 2519 status = v->delete_policy(kcontext, policy); 2520 /* iprop does not support policy mods; force full resync. */ 2521 if (!status && logging(kcontext)) 2522 status = ulog_init_header(kcontext); 2523 return status; 2524 } 2525 2526 void 2527 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy) 2528 { 2529 if (policy == NULL) 2530 return; 2531 free(policy->name); 2532 free(policy->allowed_keysalts); 2533 free_tl_data(policy->tl_data); 2534 free(policy); 2535 } 2536 2537 krb5_error_code 2538 krb5_db_promote(krb5_context kcontext, char **db_args) 2539 { 2540 krb5_error_code status; 2541 char *section; 2542 kdb_vftabl *v; 2543 2544 status = get_vftabl(kcontext, &v); 2545 if (status) 2546 return status; 2547 if (v->promote_db == NULL) 2548 return KRB5_PLUGIN_OP_NOTSUPP; 2549 status = get_conf_section(kcontext, §ion); 2550 if (status) 2551 return status; 2552 status = v->promote_db(kcontext, section, db_args); 2553 free(section); 2554 return status; 2555 } 2556 2557 static krb5_error_code 2558 decrypt_iterator(krb5_context kcontext, const krb5_key_data * key_data, 2559 krb5_keyblock *dbkey, krb5_keysalt *keysalt) 2560 { 2561 krb5_error_code status = 0; 2562 kdb_vftabl *v; 2563 krb5_keylist_node *n = kcontext->dal_handle->master_keylist; 2564 2565 status = get_vftabl(kcontext, &v); 2566 if (status) 2567 return status; 2568 for (; n; n = n->next) { 2569 krb5_clear_error_message(kcontext); 2570 status = v->decrypt_key_data(kcontext, &n->keyblock, key_data, dbkey, 2571 keysalt); 2572 if (status == 0) 2573 return 0; 2574 } 2575 return status; 2576 } 2577 2578 krb5_error_code 2579 krb5_dbe_decrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey, 2580 const krb5_key_data *key_data, krb5_keyblock *dbkey, 2581 krb5_keysalt *keysalt) 2582 { 2583 krb5_error_code status = 0; 2584 kdb_vftabl *v; 2585 krb5_keyblock *cur_mkey; 2586 2587 status = get_vftabl(kcontext, &v); 2588 if (status) 2589 return status; 2590 if (mkey || kcontext->dal_handle->master_keylist == NULL) 2591 return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt); 2592 status = decrypt_iterator(kcontext, key_data, dbkey, keysalt); 2593 if (status == 0) 2594 return 0; 2595 if (kcontext->dal_handle->master_keylist) { 2596 /* Try reloading master keys. */ 2597 cur_mkey = &kcontext->dal_handle->master_keylist->keyblock; 2598 if (krb5_db_fetch_mkey_list(kcontext, 2599 kcontext->dal_handle->master_princ, 2600 cur_mkey) == 0) 2601 return decrypt_iterator(kcontext, key_data, dbkey, keysalt); 2602 } 2603 return status; 2604 } 2605 2606 krb5_error_code 2607 krb5_dbe_encrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey, 2608 const krb5_keyblock *dbkey, 2609 const krb5_keysalt *keysalt, int keyver, 2610 krb5_key_data *key_data) 2611 { 2612 krb5_error_code status = 0; 2613 kdb_vftabl *v; 2614 2615 status = get_vftabl(kcontext, &v); 2616 if (status) 2617 return status; 2618 return v->encrypt_key_data(kcontext, mkey, dbkey, keysalt, keyver, 2619 key_data); 2620 } 2621 2622 krb5_error_code 2623 krb5_db_get_context(krb5_context context, void **db_context) 2624 { 2625 *db_context = KRB5_DB_GET_DB_CONTEXT(context); 2626 if (*db_context == NULL) 2627 return KRB5_KDB_DBNOTINITED; 2628 return 0; 2629 } 2630 2631 krb5_error_code 2632 krb5_db_set_context(krb5_context context, void *db_context) 2633 { 2634 KRB5_DB_GET_DB_CONTEXT(context) = db_context; 2635 2636 return 0; 2637 } 2638 2639 krb5_error_code 2640 krb5_db_check_transited_realms(krb5_context kcontext, 2641 const krb5_data *tr_contents, 2642 const krb5_data *client_realm, 2643 const krb5_data *server_realm) 2644 { 2645 krb5_error_code status; 2646 kdb_vftabl *v; 2647 2648 status = get_vftabl(kcontext, &v); 2649 if (status) 2650 return status; 2651 if (v->check_transited_realms == NULL) 2652 return KRB5_PLUGIN_OP_NOTSUPP; 2653 return v->check_transited_realms(kcontext, tr_contents, client_realm, 2654 server_realm); 2655 } 2656 2657 krb5_error_code 2658 krb5_db_check_policy_as(krb5_context kcontext, krb5_kdc_req *request, 2659 krb5_db_entry *client, krb5_db_entry *server, 2660 krb5_timestamp kdc_time, const char **status, 2661 krb5_pa_data ***e_data) 2662 { 2663 krb5_error_code ret; 2664 kdb_vftabl *v; 2665 2666 *status = NULL; 2667 *e_data = NULL; 2668 ret = get_vftabl(kcontext, &v); 2669 if (ret) 2670 return ret; 2671 if (v->check_policy_as == NULL) 2672 return KRB5_PLUGIN_OP_NOTSUPP; 2673 return v->check_policy_as(kcontext, request, client, server, kdc_time, 2674 status, e_data); 2675 } 2676 2677 krb5_error_code 2678 krb5_db_check_policy_tgs(krb5_context kcontext, krb5_kdc_req *request, 2679 krb5_db_entry *server, krb5_ticket *ticket, 2680 const char **status, krb5_pa_data ***e_data) 2681 { 2682 krb5_error_code ret; 2683 kdb_vftabl *v; 2684 2685 *status = NULL; 2686 *e_data = NULL; 2687 ret = get_vftabl(kcontext, &v); 2688 if (ret) 2689 return ret; 2690 if (v->check_policy_tgs == NULL) 2691 return KRB5_PLUGIN_OP_NOTSUPP; 2692 return v->check_policy_tgs(kcontext, request, server, ticket, status, 2693 e_data); 2694 } 2695 2696 void 2697 krb5_db_audit_as_req(krb5_context kcontext, krb5_kdc_req *request, 2698 const krb5_address *local_addr, 2699 const krb5_address *remote_addr, krb5_db_entry *client, 2700 krb5_db_entry *server, krb5_timestamp authtime, 2701 krb5_error_code error_code) 2702 { 2703 krb5_error_code status; 2704 kdb_vftabl *v; 2705 2706 status = get_vftabl(kcontext, &v); 2707 if (status || v->audit_as_req == NULL) 2708 return; 2709 v->audit_as_req(kcontext, request, local_addr, remote_addr, 2710 client, server, authtime, error_code); 2711 } 2712 2713 void 2714 krb5_db_refresh_config(krb5_context kcontext) 2715 { 2716 krb5_error_code status; 2717 kdb_vftabl *v; 2718 2719 status = get_vftabl(kcontext, &v); 2720 if (status || v->refresh_config == NULL) 2721 return; 2722 v->refresh_config(kcontext); 2723 } 2724 2725 krb5_error_code 2726 krb5_db_check_allowed_to_delegate(krb5_context kcontext, 2727 krb5_const_principal client, 2728 const krb5_db_entry *server, 2729 krb5_const_principal proxy) 2730 { 2731 krb5_error_code ret; 2732 kdb_vftabl *v; 2733 2734 ret = get_vftabl(kcontext, &v); 2735 if (ret) 2736 return ret; 2737 if (v->check_allowed_to_delegate == NULL) 2738 return KRB5_PLUGIN_OP_NOTSUPP; 2739 return v->check_allowed_to_delegate(kcontext, client, server, proxy); 2740 } 2741 2742 krb5_error_code 2743 krb5_db_get_s4u_x509_principal(krb5_context kcontext, 2744 const krb5_data *client_cert, 2745 krb5_const_principal in_princ, 2746 unsigned int flags, krb5_db_entry **entry) 2747 { 2748 krb5_error_code ret; 2749 kdb_vftabl *v; 2750 2751 ret = get_vftabl(kcontext, &v); 2752 if (ret) 2753 return ret; 2754 if (v->get_s4u_x509_principal == NULL) 2755 return KRB5_PLUGIN_OP_NOTSUPP; 2756 ret = v->get_s4u_x509_principal(kcontext, client_cert, in_princ, flags, 2757 entry); 2758 if (ret) 2759 return ret; 2760 2761 /* Sort the keys in the db entry, same as get_principal(). */ 2762 if ((*entry)->key_data != NULL) 2763 krb5_dbe_sort_key_data((*entry)->key_data, (*entry)->n_key_data); 2764 2765 return 0; 2766 } 2767 2768 krb5_error_code 2769 krb5_db_allowed_to_delegate_from(krb5_context kcontext, 2770 krb5_const_principal client, 2771 krb5_const_principal server, 2772 krb5_pac server_pac, 2773 const krb5_db_entry *proxy) 2774 { 2775 krb5_error_code ret; 2776 kdb_vftabl *v; 2777 2778 ret = get_vftabl(kcontext, &v); 2779 if (ret) 2780 return ret; 2781 if (v->allowed_to_delegate_from == NULL) 2782 return KRB5_PLUGIN_OP_NOTSUPP; 2783 return v->allowed_to_delegate_from(kcontext, client, server, server_pac, 2784 proxy); 2785 } 2786 2787 void 2788 krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length) 2789 { 2790 size_t i, j; 2791 krb5_key_data tmp; 2792 2793 /* Use insertion sort as a stable sort. */ 2794 for (i = 1; i < key_data_length; i++) { 2795 j = i; 2796 while (j > 0 && 2797 key_data[j - 1].key_data_kvno < key_data[j].key_data_kvno) { 2798 tmp = key_data[j]; 2799 key_data[j] = key_data[j - 1]; 2800 key_data[j - 1] = tmp; 2801 j--; 2802 } 2803 } 2804 } 2805 2806 krb5_error_code 2807 krb5_db_issue_pac(krb5_context context, unsigned int flags, 2808 krb5_db_entry *client, krb5_keyblock *replaced_reply_key, 2809 krb5_db_entry *server, krb5_db_entry *krbtgt, 2810 krb5_timestamp authtime, krb5_pac old_pac, krb5_pac new_pac, 2811 krb5_data ***auth_indicators) 2812 { 2813 krb5_error_code ret; 2814 kdb_vftabl *v; 2815 2816 ret = get_vftabl(context, &v); 2817 if (ret) 2818 return ret; 2819 if (v->issue_pac == NULL) 2820 return KRB5_PLUGIN_OP_NOTSUPP; 2821 return v->issue_pac(context, flags, client, replaced_reply_key, server, 2822 krbtgt, authtime, old_pac, new_pac, auth_indicators); 2823 } 2824 2825 krb5_error_code 2826 krb5_dbe_make_alias_entry(krb5_context context, krb5_const_principal alias, 2827 krb5_const_principal target, krb5_db_entry **out) 2828 { 2829 krb5_error_code ret; 2830 krb5_principal princ = NULL; 2831 char *target_str = NULL; 2832 krb5_tl_data *tl = NULL; 2833 krb5_db_entry *ent; 2834 2835 *out = NULL; 2836 2837 ret = krb5_copy_principal(context, alias, &princ); 2838 if (ret) 2839 goto cleanup; 2840 2841 ret = krb5_unparse_name(context, target, &target_str); 2842 if (ret) 2843 goto cleanup; 2844 tl = k5alloc(sizeof(*tl), &ret); 2845 if (tl == NULL) 2846 goto cleanup; 2847 tl->tl_data_next = NULL; 2848 tl->tl_data_type = KRB5_TL_ALIAS_TARGET; 2849 tl->tl_data_length = strlen(target_str) + 1; 2850 tl->tl_data_contents = (uint8_t *)target_str; 2851 2852 ent = k5alloc(sizeof(*ent), &ret); 2853 if (ent == NULL) 2854 goto cleanup; 2855 ent->len = KRB5_KDB_V1_BASE_LENGTH; 2856 ent->attributes = KRB5_KDB_DISALLOW_ALL_TIX; 2857 ent->princ = princ; 2858 ent->tl_data = tl; 2859 ent->n_tl_data = 1; 2860 princ = NULL; 2861 target_str = NULL; 2862 tl = NULL; 2863 *out = ent; 2864 2865 cleanup: 2866 krb5_free_principal(context, princ); 2867 krb5_free_unparsed_name(context, target_str); 2868 free(tl); 2869 return ret; 2870 } 2871 2872 krb5_error_code 2873 krb5_dbe_read_alias(krb5_context context, krb5_db_entry *entry, 2874 krb5_principal *target_out) 2875 { 2876 krb5_error_code ret; 2877 krb5_tl_data tl; 2878 2879 *target_out = NULL; 2880 2881 tl.tl_data_type = KRB5_TL_ALIAS_TARGET; 2882 ret = krb5_dbe_lookup_tl_data(context, entry, &tl); 2883 if (ret) 2884 return ret; 2885 2886 if (tl.tl_data_length == 0) 2887 return 0; 2888 2889 if (tl.tl_data_contents[tl.tl_data_length - 1] != '\0') 2890 return KRB5_KDB_TRUNCATED_RECORD; 2891 2892 return krb5_parse_name(context, (char *)tl.tl_data_contents, target_out); 2893 } 2894