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() 79 { 80 return k5_mutex_finish_init(&db_lock); 81 } 82 83 static int 84 kdb_lock_list() 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() 96 { 97 if (INITIALIZER_RAN(kdb_init_lock_list)) 98 k5_mutex_destroy(&db_lock); 99 } 100 101 static void 102 kdb_unlock_list() 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 kdb_load_library(krb5_context kcontext, 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 kdb_load_library(krb5_context kcontext, 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 kdb_find_library(krb5_context kcontext, 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 = kdb_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_setup_lib_handle(krb5_context kcontext) 589 { 590 char *library = NULL; 591 krb5_error_code status = 0; 592 db_library lib = NULL; 593 kdb5_dal_handle *dal_handle = NULL; 594 595 dal_handle = calloc((size_t) 1, sizeof(kdb5_dal_handle)); 596 if (dal_handle == NULL) { 597 status = ENOMEM; 598 goto clean_n_exit; 599 } 600 601 status = kdb_get_library_name(kcontext, &library); 602 if (library == NULL) { 603 k5_prependmsg(kcontext, status, 604 _("Cannot initialize database library")); 605 goto clean_n_exit; 606 } 607 608 status = kdb_find_library(kcontext, library, &lib); 609 if (status) 610 goto clean_n_exit; 611 612 dal_handle->lib_handle = lib; 613 kcontext->dal_handle = dal_handle; 614 615 clean_n_exit: 616 free(library); 617 618 if (status) { 619 free(dal_handle); 620 if (lib) 621 kdb_free_library(lib); 622 } 623 624 return status; 625 } 626 627 static krb5_error_code 628 kdb_free_lib_handle(krb5_context kcontext) 629 { 630 krb5_error_code status = 0; 631 632 status = kdb_free_library(kcontext->dal_handle->lib_handle); 633 if (status) 634 return status; 635 636 free_mkey_list(kcontext, kcontext->dal_handle->master_keylist); 637 krb5_free_principal(kcontext, kcontext->dal_handle->master_princ); 638 free(kcontext->dal_handle); 639 kcontext->dal_handle = NULL; 640 return 0; 641 } 642 643 static krb5_error_code 644 get_vftabl(krb5_context kcontext, kdb_vftabl **vftabl_ptr) 645 { 646 krb5_error_code status; 647 648 *vftabl_ptr = NULL; 649 if (kcontext->dal_handle == NULL) { 650 status = krb5_db_setup_lib_handle(kcontext); 651 if (status) 652 return status; 653 } 654 *vftabl_ptr = &kcontext->dal_handle->lib_handle->vftabl; 655 return 0; 656 } 657 658 /* 659 * External functions... DAL API 660 */ 661 krb5_error_code 662 krb5_db_open(krb5_context kcontext, char **db_args, int mode) 663 { 664 krb5_error_code status; 665 char *section; 666 kdb_vftabl *v; 667 668 status = get_vftabl(kcontext, &v); 669 if (status) 670 return status; 671 status = get_conf_section(kcontext, §ion); 672 if (status) 673 return status; 674 status = v->init_module(kcontext, section, db_args, mode); 675 free(section); 676 if (status) 677 (void)krb5_db_fini(kcontext); 678 return status; 679 } 680 681 krb5_error_code 682 krb5_db_inited(krb5_context kcontext) 683 { 684 return !(kcontext && kcontext->dal_handle && 685 kcontext->dal_handle->db_context); 686 } 687 688 krb5_error_code 689 krb5_db_create(krb5_context kcontext, char **db_args) 690 { 691 krb5_error_code status; 692 char *section; 693 kdb_vftabl *v; 694 695 status = get_vftabl(kcontext, &v); 696 if (status) 697 return status; 698 if (v->create == NULL) 699 return KRB5_PLUGIN_OP_NOTSUPP; 700 status = get_conf_section(kcontext, §ion); 701 if (status) 702 return status; 703 status = v->create(kcontext, section, db_args); 704 free(section); 705 if (status) 706 (void)krb5_db_fini(kcontext); 707 return status; 708 } 709 710 krb5_error_code 711 krb5_db_fini(krb5_context kcontext) 712 { 713 krb5_error_code status = 0; 714 kdb_vftabl *v; 715 716 /* Do nothing if module was never loaded. */ 717 if (kcontext->dal_handle == NULL) 718 return 0; 719 720 v = &kcontext->dal_handle->lib_handle->vftabl; 721 status = v->fini_module(kcontext); 722 723 if (status) 724 return status; 725 726 return kdb_free_lib_handle(kcontext); 727 } 728 729 krb5_error_code 730 krb5_db_destroy(krb5_context kcontext, char **db_args) 731 { 732 krb5_error_code status; 733 char *section; 734 kdb_vftabl *v; 735 736 status = get_vftabl(kcontext, &v); 737 if (status) 738 return status; 739 if (v->destroy == NULL) 740 return KRB5_PLUGIN_OP_NOTSUPP; 741 status = get_conf_section(kcontext, §ion); 742 if (status) 743 return status; 744 status = v->destroy(kcontext, section, db_args); 745 free(section); 746 return status; 747 } 748 749 krb5_error_code 750 krb5_db_get_age(krb5_context kcontext, char *db_name, time_t *t) 751 { 752 krb5_error_code status = 0; 753 kdb_vftabl *v; 754 755 status = get_vftabl(kcontext, &v); 756 if (status) 757 return status; 758 if (v->get_age == NULL) 759 return KRB5_PLUGIN_OP_NOTSUPP; 760 return v->get_age(kcontext, db_name, t); 761 } 762 763 krb5_error_code 764 krb5_db_lock(krb5_context kcontext, int lock_mode) 765 { 766 krb5_error_code status = 0; 767 kdb_vftabl *v; 768 769 status = get_vftabl(kcontext, &v); 770 if (status) 771 return status; 772 if (v->lock == NULL) 773 return KRB5_PLUGIN_OP_NOTSUPP; 774 return v->lock(kcontext, lock_mode); 775 } 776 777 krb5_error_code 778 krb5_db_unlock(krb5_context kcontext) 779 { 780 krb5_error_code status = 0; 781 kdb_vftabl *v; 782 783 status = get_vftabl(kcontext, &v); 784 if (status) 785 return status; 786 if (v->unlock == NULL) 787 return KRB5_PLUGIN_OP_NOTSUPP; 788 return v->unlock(kcontext); 789 } 790 791 krb5_error_code 792 krb5_db_get_principal(krb5_context kcontext, krb5_const_principal search_for, 793 unsigned int flags, krb5_db_entry **entry) 794 { 795 krb5_error_code status = 0; 796 kdb_vftabl *v; 797 798 *entry = NULL; 799 status = get_vftabl(kcontext, &v); 800 if (status) 801 return status; 802 if (v->get_principal == NULL) 803 return KRB5_PLUGIN_OP_NOTSUPP; 804 status = v->get_principal(kcontext, search_for, flags, entry); 805 if (status) 806 return status; 807 808 /* Sort the keys in the db entry as some parts of krb5 expect it to be. */ 809 if ((*entry)->key_data != NULL) 810 krb5_dbe_sort_key_data((*entry)->key_data, (*entry)->n_key_data); 811 812 return 0; 813 } 814 815 static void 816 free_tl_data(krb5_tl_data *list) 817 { 818 krb5_tl_data *next; 819 820 for (; list != NULL; list = next) { 821 next = list->tl_data_next; 822 free(list->tl_data_contents); 823 free(list); 824 } 825 } 826 827 void 828 krb5_db_free_principal(krb5_context kcontext, krb5_db_entry *entry) 829 { 830 kdb_vftabl *v; 831 int i; 832 833 if (entry == NULL) 834 return; 835 if (entry->e_data != NULL) { 836 if (get_vftabl(kcontext, &v) == 0 && v->free_principal_e_data != NULL) 837 v->free_principal_e_data(kcontext, entry->e_data); 838 else 839 free(entry->e_data); 840 } 841 krb5_free_principal(kcontext, entry->princ); 842 free_tl_data(entry->tl_data); 843 for (i = 0; i < entry->n_key_data; i++) 844 krb5_dbe_free_key_data_contents(kcontext, &entry->key_data[i]); 845 free(entry->key_data); 846 free(entry); 847 } 848 849 static void 850 free_db_args(char **db_args) 851 { 852 int i; 853 if (db_args) { 854 for (i = 0; db_args[i]; i++) 855 free(db_args[i]); 856 free(db_args); 857 } 858 } 859 860 static krb5_error_code 861 extract_db_args_from_tl_data(krb5_context kcontext, krb5_tl_data **start, 862 krb5_int16 *count, char ***db_argsp) 863 { 864 char **db_args = NULL; 865 int db_args_size = 0; 866 krb5_tl_data *prev, *curr, *next; 867 krb5_error_code status; 868 869 /* Giving db_args as part of tl data causes db2 to store the 870 tl_data as such. To prevent this, tl_data is collated and 871 passed as a separate argument. Currently supports only one 872 principal, but passing it as a separate argument makes it 873 difficult for kadmin remote to pass arguments to server. */ 874 prev = NULL, curr = *start; 875 while (curr) { 876 if (curr->tl_data_type == KRB5_TL_DB_ARGS) { 877 char **t; 878 /* Since this is expected to be NULL terminated string and 879 this could come from any client, do a check before 880 passing it to db. */ 881 if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] != 882 '\0') { 883 /* Not null terminated. Dangerous input. */ 884 status = EINVAL; 885 goto clean_n_exit; 886 } 887 888 db_args_size++; 889 t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */ 890 if (t == NULL) { 891 status = ENOMEM; 892 goto clean_n_exit; 893 } 894 895 db_args = t; 896 db_args[db_args_size - 1] = (char *) curr->tl_data_contents; 897 db_args[db_args_size] = NULL; 898 899 next = curr->tl_data_next; 900 if (prev == NULL) { 901 /* current node is the first in the linked list. remove it */ 902 *start = curr->tl_data_next; 903 } else { 904 prev->tl_data_next = curr->tl_data_next; 905 } 906 (*count)--; 907 free(curr); 908 909 /* previous does not change */ 910 curr = next; 911 } else { 912 prev = curr; 913 curr = curr->tl_data_next; 914 } 915 } 916 status = 0; 917 clean_n_exit: 918 if (status != 0) { 919 free_db_args(db_args); 920 db_args = NULL; 921 } 922 *db_argsp = db_args; 923 return status; 924 } 925 926 krb5_error_code 927 krb5int_put_principal_no_log(krb5_context kcontext, krb5_db_entry *entry) 928 { 929 kdb_vftabl *v; 930 krb5_error_code status; 931 char **db_args; 932 933 status = get_vftabl(kcontext, &v); 934 if (status) 935 return status; 936 if (v->put_principal == NULL) 937 return KRB5_PLUGIN_OP_NOTSUPP; 938 status = extract_db_args_from_tl_data(kcontext, &entry->tl_data, 939 &entry->n_tl_data, 940 &db_args); 941 if (status) 942 return status; 943 status = v->put_principal(kcontext, entry, db_args); 944 free_db_args(db_args); 945 return status; 946 } 947 948 krb5_error_code 949 krb5_db_put_principal(krb5_context kcontext, krb5_db_entry *entry) 950 { 951 krb5_error_code status = 0; 952 kdb_incr_update_t *upd = NULL; 953 char *princ_name = NULL; 954 955 if (logging(kcontext)) { 956 upd = k5alloc(sizeof(*upd), &status); 957 if (upd == NULL) 958 goto cleanup; 959 if ((status = ulog_conv_2logentry(kcontext, entry, upd))) 960 goto cleanup; 961 962 status = krb5_unparse_name(kcontext, entry->princ, &princ_name); 963 if (status != 0) 964 goto cleanup; 965 966 upd->kdb_princ_name.utf8str_t_val = princ_name; 967 upd->kdb_princ_name.utf8str_t_len = strlen(princ_name); 968 } 969 970 status = krb5int_put_principal_no_log(kcontext, entry); 971 if (status) 972 goto cleanup; 973 974 if (logging(kcontext)) 975 status = ulog_add_update(kcontext, upd); 976 977 cleanup: 978 ulog_free_entries(upd, 1); 979 return status; 980 } 981 982 krb5_error_code 983 krb5int_delete_principal_no_log(krb5_context kcontext, 984 krb5_principal search_for) 985 { 986 kdb_vftabl *v; 987 krb5_error_code status; 988 989 status = get_vftabl(kcontext, &v); 990 if (status) 991 return status; 992 if (v->delete_principal == NULL) 993 return KRB5_PLUGIN_OP_NOTSUPP; 994 return v->delete_principal(kcontext, search_for); 995 } 996 997 krb5_error_code 998 krb5_db_delete_principal(krb5_context kcontext, krb5_principal search_for) 999 { 1000 krb5_error_code status = 0; 1001 kdb_incr_update_t upd; 1002 char *princ_name = NULL; 1003 1004 status = krb5int_delete_principal_no_log(kcontext, search_for); 1005 if (status || !logging(kcontext)) 1006 return status; 1007 1008 status = krb5_unparse_name(kcontext, search_for, &princ_name); 1009 if (status) 1010 return status; 1011 1012 memset(&upd, 0, sizeof(kdb_incr_update_t)); 1013 upd.kdb_princ_name.utf8str_t_val = princ_name; 1014 upd.kdb_princ_name.utf8str_t_len = strlen(princ_name); 1015 upd.kdb_deleted = TRUE; 1016 1017 status = ulog_add_update(kcontext, &upd); 1018 free(princ_name); 1019 return status; 1020 } 1021 1022 krb5_error_code 1023 krb5_db_rename_principal(krb5_context kcontext, krb5_principal source, 1024 krb5_principal target) 1025 { 1026 kdb_vftabl *v; 1027 krb5_error_code status; 1028 krb5_db_entry *entry; 1029 1030 status = get_vftabl(kcontext, &v); 1031 if (status) 1032 return status; 1033 1034 /* 1035 * If the default rename function isn't used and logging is enabled, iprop 1036 * would fail since it doesn't formally support renaming. In that case 1037 * return KRB5_PLUGIN_OP_NOTSUPP. 1038 */ 1039 if (v->rename_principal != krb5_db_def_rename_principal && 1040 logging(kcontext)) 1041 return KRB5_PLUGIN_OP_NOTSUPP; 1042 1043 status = krb5_db_get_principal(kcontext, target, 0, &entry); 1044 if (status == 0) { 1045 krb5_db_free_principal(kcontext, entry); 1046 return KRB5_KDB_INUSE; 1047 } 1048 1049 return v->rename_principal(kcontext, source, target); 1050 } 1051 1052 /* 1053 * Use a proxy function for iterate so that we can sort the keys before sending 1054 * them to the callback. 1055 */ 1056 struct callback_proxy_args { 1057 int (*func)(krb5_pointer, krb5_db_entry *); 1058 krb5_pointer func_arg; 1059 }; 1060 1061 static int 1062 sort_entry_callback_proxy(krb5_pointer func_arg, krb5_db_entry *entry) 1063 { 1064 struct callback_proxy_args *args = (struct callback_proxy_args *)func_arg; 1065 1066 /* Sort the keys in the db entry as some parts of krb5 expect it to be. */ 1067 if (entry && entry->key_data) 1068 krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data); 1069 return args->func(args->func_arg, entry); 1070 } 1071 1072 krb5_error_code 1073 krb5_db_iterate(krb5_context kcontext, char *match_entry, 1074 int (*func)(krb5_pointer, krb5_db_entry *), 1075 krb5_pointer func_arg, krb5_flags iterflags) 1076 { 1077 krb5_error_code status = 0; 1078 kdb_vftabl *v; 1079 struct callback_proxy_args proxy_args; 1080 1081 status = get_vftabl(kcontext, &v); 1082 if (status) 1083 return status; 1084 if (v->iterate == NULL) 1085 return KRB5_PLUGIN_OP_NOTSUPP; 1086 1087 /* Use the proxy function to sort key data before passing entries to 1088 * callback. */ 1089 proxy_args.func = func; 1090 proxy_args.func_arg = func_arg; 1091 return v->iterate(kcontext, match_entry, sort_entry_callback_proxy, 1092 &proxy_args, iterflags); 1093 } 1094 1095 /* Return a read only pointer alias to mkey list. Do not free this! */ 1096 krb5_keylist_node * 1097 krb5_db_mkey_list_alias(krb5_context kcontext) 1098 { 1099 return kcontext->dal_handle->master_keylist; 1100 } 1101 1102 krb5_error_code 1103 krb5_db_fetch_mkey_list(krb5_context context, krb5_principal mname, 1104 const krb5_keyblock *mkey) 1105 { 1106 kdb_vftabl *v; 1107 krb5_error_code status = 0; 1108 krb5_keylist_node *local_keylist; 1109 1110 status = get_vftabl(context, &v); 1111 if (status) 1112 return status; 1113 1114 if (!context->dal_handle->master_princ) { 1115 status = krb5_copy_principal(context, mname, 1116 &context->dal_handle->master_princ); 1117 if (status) 1118 return status; 1119 } 1120 1121 status = v->fetch_master_key_list(context, mname, mkey, &local_keylist); 1122 if (status == 0) { 1123 free_mkey_list(context, context->dal_handle->master_keylist); 1124 context->dal_handle->master_keylist = local_keylist; 1125 } 1126 return status; 1127 } 1128 1129 krb5_error_code 1130 krb5_db_store_master_key(krb5_context kcontext, char *keyfile, 1131 krb5_principal mname, krb5_kvno kvno, 1132 krb5_keyblock * key, char *master_pwd) 1133 { 1134 krb5_error_code status = 0; 1135 kdb_vftabl *v; 1136 krb5_keylist_node list; 1137 1138 status = get_vftabl(kcontext, &v); 1139 if (status) 1140 return status; 1141 1142 if (v->store_master_key_list == NULL) 1143 return KRB5_KDB_DBTYPE_NOSUP; 1144 1145 list.kvno = kvno; 1146 list.keyblock = *key; 1147 list.next = NULL; 1148 1149 return v->store_master_key_list(kcontext, keyfile, mname, 1150 &list, master_pwd); 1151 } 1152 1153 krb5_error_code 1154 krb5_db_store_master_key_list(krb5_context kcontext, char *keyfile, 1155 krb5_principal mname, char *master_pwd) 1156 { 1157 krb5_error_code status = 0; 1158 kdb_vftabl *v; 1159 1160 status = get_vftabl(kcontext, &v); 1161 if (status) 1162 return status; 1163 1164 if (v->store_master_key_list == NULL) 1165 return KRB5_KDB_DBTYPE_NOSUP; 1166 1167 if (kcontext->dal_handle->master_keylist == NULL) 1168 return KRB5_KDB_DBNOTINITED; 1169 1170 return v->store_master_key_list(kcontext, keyfile, mname, 1171 kcontext->dal_handle->master_keylist, 1172 master_pwd); 1173 } 1174 1175 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; 1176 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; 1177 1178 krb5_error_code 1179 krb5_db_fetch_mkey(krb5_context context, krb5_principal mname, 1180 krb5_enctype etype, krb5_boolean fromkeyboard, 1181 krb5_boolean twice, char *db_args, krb5_kvno *kvno, 1182 krb5_data *salt, krb5_keyblock *key) 1183 { 1184 krb5_error_code retval; 1185 char password[BUFSIZ]; 1186 krb5_data pwd; 1187 unsigned int size = sizeof(password); 1188 krb5_keyblock tmp_key; 1189 1190 memset(&tmp_key, 0, sizeof(tmp_key)); 1191 1192 if (fromkeyboard) { 1193 krb5_data scratch; 1194 1195 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, 1196 twice ? krb5_mkey_pwd_prompt2 : 0, 1197 password, &size))) { 1198 goto clean_n_exit; 1199 } 1200 1201 pwd.data = password; 1202 pwd.length = size; 1203 if (!salt) { 1204 retval = krb5_principal2salt(context, mname, &scratch); 1205 if (retval) 1206 goto clean_n_exit; 1207 } 1208 retval = 1209 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch, 1210 key); 1211 /* 1212 * If a kvno pointer was passed in and it dereferences the IGNORE_VNO 1213 * value then it should be assigned the value of the kvno associated 1214 * with the current mkey princ key if that princ entry is available 1215 * otherwise assign 1 which is the default kvno value for the mkey 1216 * princ. 1217 */ 1218 if (kvno != NULL && *kvno == IGNORE_VNO) { 1219 krb5_error_code rc; 1220 krb5_db_entry *master_entry; 1221 1222 rc = krb5_db_get_principal(context, mname, 0, &master_entry); 1223 if (rc == 0 && master_entry->n_key_data > 0) 1224 *kvno = (krb5_kvno) master_entry->key_data->key_data_kvno; 1225 else 1226 *kvno = 1; 1227 if (rc == 0) 1228 krb5_db_free_principal(context, master_entry); 1229 } 1230 1231 if (!salt) 1232 free(scratch.data); 1233 zap(password, sizeof(password)); /* erase it */ 1234 1235 } else { 1236 kdb_vftabl *v; 1237 1238 if (context->dal_handle == NULL) { 1239 retval = krb5_db_setup_lib_handle(context); 1240 if (retval) 1241 goto clean_n_exit; 1242 } 1243 1244 /* get the enctype from the stash */ 1245 tmp_key.enctype = ENCTYPE_UNKNOWN; 1246 1247 v = &context->dal_handle->lib_handle->vftabl; 1248 retval = v->fetch_master_key(context, mname, &tmp_key, kvno, db_args); 1249 1250 if (retval) 1251 goto clean_n_exit; 1252 1253 key->contents = k5memdup(tmp_key.contents, tmp_key.length, &retval); 1254 if (key->contents == NULL) 1255 goto clean_n_exit; 1256 1257 key->magic = tmp_key.magic; 1258 key->enctype = tmp_key.enctype; 1259 key->length = tmp_key.length; 1260 } 1261 1262 clean_n_exit: 1263 zapfree(tmp_key.contents, tmp_key.length); 1264 return retval; 1265 } 1266 1267 krb5_error_code 1268 krb5_dbe_fetch_act_key_list(krb5_context context, krb5_principal princ, 1269 krb5_actkvno_node **act_key_list) 1270 { 1271 krb5_error_code retval = 0; 1272 krb5_db_entry *entry; 1273 1274 if (act_key_list == NULL) 1275 return (EINVAL); 1276 1277 retval = krb5_db_get_principal(context, princ, 0, &entry); 1278 if (retval == KRB5_KDB_NOENTRY) 1279 return KRB5_KDB_NOMASTERKEY; 1280 else if (retval) 1281 return retval; 1282 1283 retval = krb5_dbe_lookup_actkvno(context, entry, act_key_list); 1284 krb5_db_free_principal(context, entry); 1285 return retval; 1286 } 1287 1288 /* Find the most recent entry in list (which must not be empty) for the given 1289 * timestamp, and return its kvno. */ 1290 static krb5_kvno 1291 find_actkvno(krb5_actkvno_node *list, krb5_timestamp now) 1292 { 1293 /* 1294 * The list is sorted in ascending order of time. Return the kvno of the 1295 * predecessor of the first entry whose time is in the future. If 1296 * (contrary to the safety checks in kdb5_util use_mkey) all of the entries 1297 * are in the future, we will return the first node; if all are in the 1298 * past, we will return the last node. 1299 */ 1300 while (list->next != NULL && !ts_after(list->next->act_time, now)) 1301 list = list->next; 1302 return list->act_kvno; 1303 } 1304 1305 /* Search the master keylist for the master key with the specified kvno. 1306 * Return the keyblock of the matching entry or NULL if it does not exist. */ 1307 static krb5_keyblock * 1308 find_master_key(krb5_context context, krb5_kvno kvno) 1309 { 1310 krb5_keylist_node *n; 1311 1312 for (n = context->dal_handle->master_keylist; n != NULL; n = n->next) { 1313 if (n->kvno == kvno) 1314 return &n->keyblock; 1315 } 1316 return NULL; 1317 } 1318 1319 /* 1320 * Locates the "active" mkey used when encrypting a princ's keys. Note, the 1321 * caller must NOT free the output act_mkey. 1322 */ 1323 1324 krb5_error_code 1325 krb5_dbe_find_act_mkey(krb5_context context, krb5_actkvno_node *act_mkey_list, 1326 krb5_kvno *act_kvno, krb5_keyblock **act_mkey) 1327 { 1328 krb5_kvno kvno; 1329 krb5_error_code retval; 1330 krb5_keyblock *mkey, *cur_mkey; 1331 krb5_timestamp now; 1332 1333 if (act_mkey_list == NULL) { 1334 *act_kvno = 0; 1335 *act_mkey = NULL; 1336 return 0; 1337 } 1338 1339 if (context->dal_handle->master_keylist == NULL) 1340 return KRB5_KDB_DBNOTINITED; 1341 1342 /* Find the currently active master key version. */ 1343 if ((retval = krb5_timeofday(context, &now))) 1344 return (retval); 1345 kvno = find_actkvno(act_mkey_list, now); 1346 1347 /* Find the corresponding master key. */ 1348 mkey = find_master_key(context, kvno); 1349 if (mkey == NULL) { 1350 /* Reload the master key list and try again. */ 1351 cur_mkey = &context->dal_handle->master_keylist->keyblock; 1352 if (krb5_db_fetch_mkey_list(context, context->dal_handle->master_princ, 1353 cur_mkey) == 0) 1354 mkey = find_master_key(context, kvno); 1355 } 1356 if (mkey == NULL) 1357 return KRB5_KDB_NO_MATCHING_KEY; 1358 1359 *act_mkey = mkey; 1360 if (act_kvno != NULL) 1361 *act_kvno = kvno; 1362 return 0; 1363 } 1364 1365 /* 1366 * Locates the mkey used to protect a princ's keys. Note, the caller must not 1367 * free the output key. 1368 */ 1369 krb5_error_code 1370 krb5_dbe_find_mkey(krb5_context context, krb5_db_entry *entry, 1371 krb5_keyblock **mkey) 1372 { 1373 krb5_kvno mkvno; 1374 krb5_error_code retval; 1375 krb5_keylist_node *cur_keyblock = context->dal_handle->master_keylist; 1376 1377 if (!cur_keyblock) 1378 return KRB5_KDB_DBNOTINITED; 1379 1380 retval = krb5_dbe_get_mkvno(context, entry, &mkvno); 1381 if (retval) 1382 return (retval); 1383 1384 while (cur_keyblock && cur_keyblock->kvno != mkvno) 1385 cur_keyblock = cur_keyblock->next; 1386 1387 if (cur_keyblock) { 1388 *mkey = &cur_keyblock->keyblock; 1389 return (0); 1390 } else { 1391 return KRB5_KDB_NO_MATCHING_KEY; 1392 } 1393 } 1394 1395 void * 1396 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size) 1397 { 1398 return realloc(ptr, size); 1399 } 1400 1401 void 1402 krb5_db_free(krb5_context kcontext, void *ptr) 1403 { 1404 free(ptr); 1405 } 1406 1407 /* has to be modified */ 1408 1409 krb5_error_code 1410 krb5_dbe_find_enctype(krb5_context kcontext, krb5_db_entry *dbentp, 1411 krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno, 1412 krb5_key_data **kdatap) 1413 { 1414 krb5_int32 start = 0; 1415 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype, 1416 kvno, kdatap); 1417 } 1418 1419 krb5_error_code 1420 krb5_dbe_search_enctype(krb5_context kcontext, krb5_db_entry *dbentp, 1421 krb5_int32 *start, krb5_int32 ktype, krb5_int32 stype, 1422 krb5_int32 kvno, krb5_key_data ** kdatap) 1423 { 1424 krb5_error_code status = 0; 1425 kdb_vftabl *v; 1426 1427 status = get_vftabl(kcontext, &v); 1428 if (status) 1429 return status; 1430 return v->dbe_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, 1431 kdatap); 1432 } 1433 1434 #define REALM_SEP_STRING "@" 1435 1436 krb5_error_code 1437 krb5_db_setup_mkey_name(krb5_context context, const char *keyname, 1438 const char *realm, char **fullname, 1439 krb5_principal *principal) 1440 { 1441 krb5_error_code retval; 1442 char *fname; 1443 1444 if (!keyname) 1445 keyname = KRB5_KDB_M_NAME; /* XXX external? */ 1446 1447 if (asprintf(&fname, "%s%s%s", keyname, REALM_SEP_STRING, realm) < 0) 1448 return ENOMEM; 1449 1450 retval = krb5_parse_name(context, fname, principal); 1451 if (retval) { 1452 free(fname); 1453 return retval; 1454 } 1455 if (fullname) 1456 *fullname = fname; 1457 else 1458 free(fname); 1459 return 0; 1460 } 1461 1462 krb5_error_code 1463 krb5_dbe_lookup_last_pwd_change(krb5_context context, krb5_db_entry *entry, 1464 krb5_timestamp *stamp) 1465 { 1466 krb5_tl_data tl_data; 1467 krb5_error_code code; 1468 krb5_int32 tmp; 1469 1470 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1471 1472 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1473 return (code); 1474 1475 if (tl_data.tl_data_length != 4) { 1476 *stamp = 0; 1477 return (0); 1478 } 1479 1480 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1481 1482 *stamp = (krb5_timestamp) tmp; 1483 1484 return (0); 1485 } 1486 1487 krb5_error_code 1488 krb5_dbe_lookup_last_admin_unlock(krb5_context context, krb5_db_entry *entry, 1489 krb5_timestamp *stamp) 1490 { 1491 krb5_tl_data tl_data; 1492 krb5_error_code code; 1493 krb5_int32 tmp; 1494 1495 tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK; 1496 1497 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1498 return (code); 1499 1500 if (tl_data.tl_data_length != 4) { 1501 *stamp = 0; 1502 return (0); 1503 } 1504 1505 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1506 1507 *stamp = (krb5_timestamp) tmp; 1508 1509 return (0); 1510 } 1511 1512 krb5_error_code 1513 krb5_dbe_lookup_tl_data(krb5_context context, krb5_db_entry *entry, 1514 krb5_tl_data *ret_tl_data) 1515 { 1516 krb5_tl_data *tl_data; 1517 1518 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 1519 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { 1520 *ret_tl_data = *tl_data; 1521 return (0); 1522 } 1523 } 1524 1525 /* 1526 * If the requested record isn't found, return zero bytes. If it 1527 * ever means something to have a zero-length tl_data, this code 1528 * and its callers will have to be changed. 1529 */ 1530 1531 ret_tl_data->tl_data_length = 0; 1532 ret_tl_data->tl_data_contents = NULL; 1533 return (0); 1534 } 1535 1536 krb5_error_code 1537 krb5_dbe_create_key_data(krb5_context context, krb5_db_entry *entry) 1538 { 1539 krb5_key_data *newptr; 1540 1541 newptr = realloc(entry->key_data, 1542 (entry->n_key_data + 1) * sizeof(*entry->key_data)); 1543 if (newptr == NULL) 1544 return ENOMEM; 1545 entry->key_data = newptr; 1546 1547 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data)); 1548 entry->n_key_data++; 1549 1550 return 0; 1551 } 1552 1553 krb5_error_code 1554 krb5_dbe_update_mod_princ_data(krb5_context context, krb5_db_entry *entry, 1555 krb5_timestamp mod_date, 1556 krb5_const_principal mod_princ) 1557 { 1558 krb5_tl_data tl_data; 1559 1560 krb5_error_code retval = 0; 1561 krb5_octet *nextloc = 0; 1562 char *unparse_mod_princ = 0; 1563 unsigned int unparse_mod_princ_size; 1564 1565 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ))) 1566 return (retval); 1567 1568 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; 1569 1570 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) 1571 == NULL) { 1572 free(unparse_mod_princ); 1573 return (ENOMEM); 1574 } 1575 1576 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1577 tl_data.tl_data_length = unparse_mod_princ_size + 4; 1578 tl_data.tl_data_contents = nextloc; 1579 1580 /* Mod Date */ 1581 krb5_kdb_encode_int32(mod_date, nextloc); 1582 1583 /* Mod Princ */ 1584 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size); 1585 1586 retval = krb5_dbe_update_tl_data(context, entry, &tl_data); 1587 1588 free(unparse_mod_princ); 1589 free(nextloc); 1590 1591 return (retval); 1592 } 1593 1594 krb5_error_code 1595 krb5_dbe_lookup_mod_princ_data(krb5_context context, krb5_db_entry *entry, 1596 krb5_timestamp *mod_time, 1597 krb5_principal *mod_princ) 1598 { 1599 krb5_tl_data tl_data; 1600 krb5_error_code code; 1601 1602 *mod_princ = NULL; 1603 *mod_time = 0; 1604 1605 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1606 1607 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1608 return (code); 1609 1610 if ((tl_data.tl_data_length < 5) || 1611 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0')) 1612 return (KRB5_KDB_TRUNCATED_RECORD); 1613 1614 /* Mod Date */ 1615 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); 1616 1617 /* Mod Princ */ 1618 if ((code = krb5_parse_name(context, 1619 (const char *) (tl_data.tl_data_contents + 4), 1620 mod_princ))) 1621 return (code); 1622 1623 return (0); 1624 } 1625 1626 krb5_error_code 1627 krb5_dbe_lookup_mkvno(krb5_context context, krb5_db_entry *entry, 1628 krb5_kvno *mkvno) 1629 { 1630 krb5_tl_data tl_data; 1631 krb5_error_code code; 1632 krb5_int16 tmp; 1633 1634 tl_data.tl_data_type = KRB5_TL_MKVNO; 1635 1636 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1637 return (code); 1638 1639 if (tl_data.tl_data_length == 0) { 1640 *mkvno = 0; /* Indicates KRB5_TL_MKVNO data not present */ 1641 return (0); 1642 } else if (tl_data.tl_data_length != 2) { 1643 return (KRB5_KDB_TRUNCATED_RECORD); 1644 } 1645 1646 krb5_kdb_decode_int16(tl_data.tl_data_contents, tmp); 1647 *mkvno = (krb5_kvno) tmp; 1648 return (0); 1649 } 1650 1651 krb5_error_code 1652 krb5_dbe_get_mkvno(krb5_context context, krb5_db_entry *entry, 1653 krb5_kvno *mkvno) 1654 { 1655 krb5_error_code code; 1656 krb5_kvno kvno; 1657 krb5_keylist_node *mkey_list = context->dal_handle->master_keylist; 1658 1659 if (mkey_list == NULL) 1660 return KRB5_KDB_DBNOTINITED; 1661 1662 /* Output the value from entry tl_data if present. */ 1663 code = krb5_dbe_lookup_mkvno(context, entry, &kvno); 1664 if (code != 0) 1665 return code; 1666 if (kvno != 0) { 1667 *mkvno = kvno; 1668 return 0; 1669 } 1670 1671 /* Determine the minimum kvno in mkey_list and output that. */ 1672 kvno = (krb5_kvno) -1; 1673 while (mkey_list != NULL) { 1674 if (mkey_list->kvno < kvno) 1675 kvno = mkey_list->kvno; 1676 mkey_list = mkey_list->next; 1677 } 1678 *mkvno = kvno; 1679 return 0; 1680 } 1681 1682 krb5_error_code 1683 krb5_dbe_update_mkvno(krb5_context context, krb5_db_entry *entry, 1684 krb5_kvno mkvno) 1685 { 1686 krb5_tl_data tl_data; 1687 krb5_octet buf[2]; /* this is the encoded size of an int16 */ 1688 krb5_int16 tmp_kvno = (krb5_int16) mkvno; 1689 1690 tl_data.tl_data_type = KRB5_TL_MKVNO; 1691 tl_data.tl_data_length = sizeof(buf); 1692 krb5_kdb_encode_int16(tmp_kvno, buf); 1693 tl_data.tl_data_contents = buf; 1694 1695 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 1696 } 1697 1698 krb5_error_code 1699 krb5_dbe_lookup_mkey_aux(krb5_context context, krb5_db_entry *entry, 1700 krb5_mkey_aux_node **mkey_aux_data_list) 1701 { 1702 krb5_tl_data tl_data; 1703 krb5_int16 version, mkey_kvno; 1704 krb5_mkey_aux_node *head_data = NULL, *new_data = NULL, 1705 *prev_data = NULL; 1706 krb5_octet *curloc; /* current location pointer */ 1707 krb5_error_code code; 1708 1709 tl_data.tl_data_type = KRB5_TL_MKEY_AUX; 1710 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1711 return (code); 1712 1713 if (tl_data.tl_data_contents == NULL) { 1714 *mkey_aux_data_list = NULL; 1715 return (0); 1716 } else { 1717 /* get version to determine how to parse the data */ 1718 krb5_kdb_decode_int16(tl_data.tl_data_contents, version); 1719 if (version == 1) { 1720 /* variable size, must be at least 10 bytes */ 1721 if (tl_data.tl_data_length < 10) 1722 return (KRB5_KDB_TRUNCATED_RECORD); 1723 1724 /* curloc points to first tuple entry in the tl_data_contents */ 1725 curloc = tl_data.tl_data_contents + sizeof(version); 1726 1727 while (curloc < (tl_data.tl_data_contents + tl_data.tl_data_length)) { 1728 1729 new_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); 1730 if (new_data == NULL) { 1731 krb5_dbe_free_mkey_aux_list(context, head_data); 1732 return (ENOMEM); 1733 } 1734 memset(new_data, 0, sizeof(krb5_mkey_aux_node)); 1735 1736 krb5_kdb_decode_int16(curloc, mkey_kvno); 1737 new_data->mkey_kvno = mkey_kvno; 1738 curloc += sizeof(krb5_ui_2); 1739 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_kvno); 1740 curloc += sizeof(krb5_ui_2); 1741 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_type[0]); 1742 curloc += sizeof(krb5_ui_2); 1743 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_length[0]); 1744 curloc += sizeof(krb5_ui_2); 1745 1746 new_data->latest_mkey.key_data_contents[0] = (krb5_octet *) 1747 malloc(new_data->latest_mkey.key_data_length[0]); 1748 1749 if (new_data->latest_mkey.key_data_contents[0] == NULL) { 1750 krb5_dbe_free_mkey_aux_list(context, head_data); 1751 free(new_data); 1752 return (ENOMEM); 1753 } 1754 memcpy(new_data->latest_mkey.key_data_contents[0], curloc, 1755 new_data->latest_mkey.key_data_length[0]); 1756 curloc += new_data->latest_mkey.key_data_length[0]; 1757 1758 /* always using key data ver 1 for mkeys */ 1759 new_data->latest_mkey.key_data_ver = 1; 1760 1761 new_data->next = NULL; 1762 if (prev_data != NULL) 1763 prev_data->next = new_data; 1764 else 1765 head_data = new_data; 1766 prev_data = new_data; 1767 } 1768 } else { 1769 k5_setmsg(context, KRB5_KDB_BAD_VERSION, 1770 _("Illegal version number for KRB5_TL_MKEY_AUX %d\n"), 1771 version); 1772 return (KRB5_KDB_BAD_VERSION); 1773 } 1774 } 1775 *mkey_aux_data_list = head_data; 1776 return (0); 1777 } 1778 1779 #if KRB5_TL_MKEY_AUX_VER == 1 1780 krb5_error_code 1781 krb5_dbe_update_mkey_aux(krb5_context context, krb5_db_entry *entry, 1782 krb5_mkey_aux_node *mkey_aux_data_list) 1783 { 1784 krb5_error_code status; 1785 krb5_tl_data tl_data; 1786 krb5_int16 version, tmp_kvno; 1787 unsigned char *nextloc; 1788 krb5_mkey_aux_node *aux_data_entry; 1789 1790 if (!mkey_aux_data_list) { 1791 /* delete the KRB5_TL_MKEY_AUX from the entry */ 1792 krb5_dbe_delete_tl_data(context, entry, KRB5_TL_MKEY_AUX); 1793 return (0); 1794 } 1795 1796 memset(&tl_data, 0, sizeof(tl_data)); 1797 tl_data.tl_data_type = KRB5_TL_MKEY_AUX; 1798 /* 1799 * determine out how much space to allocate. Note key_data_ver not stored 1800 * as this is hard coded to one and is accounted for in 1801 * krb5_dbe_lookup_mkey_aux. 1802 */ 1803 tl_data.tl_data_length = sizeof(version); /* version */ 1804 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL; 1805 aux_data_entry = aux_data_entry->next) { 1806 1807 tl_data.tl_data_length += (sizeof(krb5_ui_2) + /* mkey_kvno */ 1808 sizeof(krb5_ui_2) + /* latest_mkey kvno */ 1809 sizeof(krb5_ui_2) + /* latest_mkey enctype */ 1810 sizeof(krb5_ui_2) + /* latest_mkey length */ 1811 aux_data_entry->latest_mkey.key_data_length[0]); 1812 } 1813 1814 tl_data.tl_data_contents = (krb5_octet *) malloc(tl_data.tl_data_length); 1815 if (tl_data.tl_data_contents == NULL) 1816 return (ENOMEM); 1817 1818 nextloc = tl_data.tl_data_contents; 1819 version = KRB5_TL_MKEY_AUX_VER; 1820 krb5_kdb_encode_int16(version, nextloc); 1821 nextloc += sizeof(krb5_ui_2); 1822 1823 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL; 1824 aux_data_entry = aux_data_entry->next) { 1825 1826 tmp_kvno = (krb5_int16) aux_data_entry->mkey_kvno; 1827 krb5_kdb_encode_int16(tmp_kvno, nextloc); 1828 nextloc += sizeof(krb5_ui_2); 1829 1830 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_kvno, 1831 nextloc); 1832 nextloc += sizeof(krb5_ui_2); 1833 1834 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_type[0], 1835 nextloc); 1836 nextloc += sizeof(krb5_ui_2); 1837 1838 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_length[0], 1839 nextloc); 1840 nextloc += sizeof(krb5_ui_2); 1841 1842 if (aux_data_entry->latest_mkey.key_data_length[0] > 0) { 1843 memcpy(nextloc, aux_data_entry->latest_mkey.key_data_contents[0], 1844 aux_data_entry->latest_mkey.key_data_length[0]); 1845 nextloc += aux_data_entry->latest_mkey.key_data_length[0]; 1846 } 1847 } 1848 1849 status = krb5_dbe_update_tl_data(context, entry, &tl_data); 1850 free(tl_data.tl_data_contents); 1851 return status; 1852 } 1853 #endif /* KRB5_TL_MKEY_AUX_VER == 1 */ 1854 1855 #if KRB5_TL_ACTKVNO_VER == 1 1856 /* 1857 * If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER == 1 then size of 1858 * a actkvno tuple {act_kvno, act_time} entry is: 1859 */ 1860 #define ACTKVNO_TUPLE_SIZE (sizeof(krb5_int16) + sizeof(krb5_int32)) 1861 #define act_kvno(cp) (cp) /* return pointer to start of act_kvno data */ 1862 #define act_time(cp) ((cp) + sizeof(krb5_int16)) /* return pointer to start of act_time data */ 1863 #endif 1864 1865 krb5_error_code 1866 krb5_dbe_lookup_actkvno(krb5_context context, krb5_db_entry *entry, 1867 krb5_actkvno_node **actkvno_list) 1868 { 1869 krb5_tl_data tl_data; 1870 krb5_error_code code; 1871 krb5_int16 version, tmp_kvno; 1872 krb5_actkvno_node *head_data = NULL, *new_data = NULL, *prev_data = NULL; 1873 unsigned int num_actkvno, i; 1874 krb5_octet *next_tuple; 1875 krb5_kvno earliest_kvno; 1876 1877 memset(&tl_data, 0, sizeof(tl_data)); 1878 tl_data.tl_data_type = KRB5_TL_ACTKVNO; 1879 1880 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1881 return (code); 1882 1883 if (tl_data.tl_data_contents == NULL) { 1884 /* 1885 * If there is no KRB5_TL_ACTKVNO data (likely because the KDB was 1886 * created prior to 1.7), synthesize the list which should have been 1887 * created at KDB initialization, making the earliest master key 1888 * active. 1889 */ 1890 1891 /* Get the earliest master key version. */ 1892 if (entry->n_key_data == 0) 1893 return KRB5_KDB_NOMASTERKEY; 1894 earliest_kvno = entry->key_data[entry->n_key_data - 1].key_data_kvno; 1895 1896 head_data = malloc(sizeof(*head_data)); 1897 if (head_data == NULL) 1898 return ENOMEM; 1899 memset(head_data, 0, sizeof(*head_data)); 1900 head_data->act_time = 0; /* earliest time possible */ 1901 head_data->act_kvno = earliest_kvno; 1902 } else { 1903 /* get version to determine how to parse the data */ 1904 krb5_kdb_decode_int16(tl_data.tl_data_contents, version); 1905 if (version == 1) { 1906 1907 /* variable size, must be at least 8 bytes */ 1908 if (tl_data.tl_data_length < 8) 1909 return (KRB5_KDB_TRUNCATED_RECORD); 1910 1911 /* 1912 * Find number of tuple entries, remembering to account for version 1913 * field. 1914 */ 1915 num_actkvno = (tl_data.tl_data_length - sizeof(version)) / 1916 ACTKVNO_TUPLE_SIZE; 1917 prev_data = NULL; 1918 /* next_tuple points to first tuple entry in the tl_data_contents */ 1919 next_tuple = tl_data.tl_data_contents + sizeof(version); 1920 for (i = 0; i < num_actkvno; i++) { 1921 new_data = (krb5_actkvno_node *) malloc(sizeof(krb5_actkvno_node)); 1922 if (new_data == NULL) { 1923 krb5_dbe_free_actkvno_list(context, head_data); 1924 return (ENOMEM); 1925 } 1926 memset(new_data, 0, sizeof(krb5_actkvno_node)); 1927 1928 /* using tmp_kvno to avoid type mismatch */ 1929 krb5_kdb_decode_int16(act_kvno(next_tuple), tmp_kvno); 1930 new_data->act_kvno = (krb5_kvno) tmp_kvno; 1931 krb5_kdb_decode_int32(act_time(next_tuple), new_data->act_time); 1932 1933 if (prev_data != NULL) 1934 prev_data->next = new_data; 1935 else 1936 head_data = new_data; 1937 prev_data = new_data; 1938 next_tuple += ACTKVNO_TUPLE_SIZE; 1939 } 1940 } else { 1941 k5_setmsg(context, KRB5_KDB_BAD_VERSION, 1942 _("Illegal version number for KRB5_TL_ACTKVNO %d\n"), 1943 version); 1944 return (KRB5_KDB_BAD_VERSION); 1945 } 1946 } 1947 *actkvno_list = head_data; 1948 return (0); 1949 } 1950 1951 /* 1952 * Add KRB5_TL_ACTKVNO TL data entries to krb5_db_entry *entry 1953 */ 1954 #if KRB5_TL_ACTKVNO_VER == 1 1955 krb5_error_code 1956 krb5_dbe_update_actkvno(krb5_context context, krb5_db_entry *entry, 1957 const krb5_actkvno_node *actkvno_list) 1958 { 1959 krb5_error_code retval = 0; 1960 krb5_int16 version, tmp_kvno; 1961 krb5_tl_data new_tl_data; 1962 unsigned char *nextloc; 1963 const krb5_actkvno_node *cur_actkvno; 1964 krb5_octet *tmpptr; 1965 1966 if (actkvno_list == NULL) 1967 return EINVAL; 1968 1969 memset(&new_tl_data, 0, sizeof(new_tl_data)); 1970 /* allocate initial KRB5_TL_ACTKVNO tl_data entry */ 1971 new_tl_data.tl_data_length = sizeof(version); 1972 new_tl_data.tl_data_contents = (krb5_octet *) malloc(new_tl_data.tl_data_length); 1973 if (new_tl_data.tl_data_contents == NULL) 1974 return ENOMEM; 1975 1976 /* add the current version # for the data format used for KRB5_TL_ACTKVNO */ 1977 version = KRB5_TL_ACTKVNO_VER; 1978 krb5_kdb_encode_int16(version, (unsigned char *) new_tl_data.tl_data_contents); 1979 1980 for (cur_actkvno = actkvno_list; cur_actkvno != NULL; 1981 cur_actkvno = cur_actkvno->next) { 1982 1983 new_tl_data.tl_data_length += ACTKVNO_TUPLE_SIZE; 1984 tmpptr = realloc(new_tl_data.tl_data_contents, new_tl_data.tl_data_length); 1985 if (tmpptr == NULL) { 1986 free(new_tl_data.tl_data_contents); 1987 return ENOMEM; 1988 } else { 1989 new_tl_data.tl_data_contents = tmpptr; 1990 } 1991 1992 /* 1993 * Using realloc so tl_data_contents is required to correctly calculate 1994 * next location to store new tuple. 1995 */ 1996 nextloc = new_tl_data.tl_data_contents + new_tl_data.tl_data_length - ACTKVNO_TUPLE_SIZE; 1997 /* using tmp_kvno to avoid type mismatch issues */ 1998 tmp_kvno = (krb5_int16) cur_actkvno->act_kvno; 1999 krb5_kdb_encode_int16(tmp_kvno, nextloc); 2000 nextloc += sizeof(krb5_ui_2); 2001 krb5_kdb_encode_int32((krb5_ui_4)cur_actkvno->act_time, nextloc); 2002 } 2003 2004 new_tl_data.tl_data_type = KRB5_TL_ACTKVNO; 2005 retval = krb5_dbe_update_tl_data(context, entry, &new_tl_data); 2006 free(new_tl_data.tl_data_contents); 2007 2008 return (retval); 2009 } 2010 #endif /* KRB5_TL_ACTKVNO_VER == 1 */ 2011 2012 krb5_error_code 2013 krb5_dbe_update_last_pwd_change(krb5_context context, krb5_db_entry *entry, 2014 krb5_timestamp stamp) 2015 { 2016 krb5_tl_data tl_data; 2017 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 2018 2019 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 2020 tl_data.tl_data_length = sizeof(buf); 2021 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 2022 tl_data.tl_data_contents = buf; 2023 2024 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 2025 } 2026 2027 krb5_error_code 2028 krb5_dbe_update_last_admin_unlock(krb5_context context, krb5_db_entry *entry, 2029 krb5_timestamp stamp) 2030 { 2031 krb5_tl_data tl_data; 2032 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 2033 2034 tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK; 2035 tl_data.tl_data_length = sizeof(buf); 2036 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 2037 tl_data.tl_data_contents = buf; 2038 2039 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 2040 } 2041 2042 /* 2043 * Prepare to iterate over the string attributes of entry. The returned 2044 * pointers are aliases into entry's tl_data (or into an empty string literal) 2045 * and remain valid until the entry's tl_data is changed. 2046 */ 2047 static krb5_error_code 2048 begin_attrs(krb5_context context, krb5_db_entry *entry, const char **pos_out, 2049 const char **end_out) 2050 { 2051 krb5_error_code code; 2052 krb5_tl_data tl_data; 2053 2054 *pos_out = *end_out = NULL; 2055 tl_data.tl_data_type = KRB5_TL_STRING_ATTRS; 2056 code = krb5_dbe_lookup_tl_data(context, entry, &tl_data); 2057 if (code) 2058 return code; 2059 2060 /* Copy the current mapping to buf, updating key with value if found. */ 2061 *pos_out = (const char *)tl_data.tl_data_contents; 2062 *end_out = *pos_out + tl_data.tl_data_length; 2063 return 0; 2064 } 2065 2066 /* Find the next key and value pair in *pos and update *pos. */ 2067 static krb5_boolean 2068 next_attr(const char **pos, const char *end, const char **key_out, 2069 const char **val_out) 2070 { 2071 const char *key, *key_end, *val, *val_end; 2072 2073 *key_out = *val_out = NULL; 2074 if (*pos == end) 2075 return FALSE; 2076 key = *pos; 2077 key_end = memchr(key, '\0', end - key); 2078 if (key_end == NULL) /* Malformed representation; give up. */ 2079 return FALSE; 2080 val = key_end + 1; 2081 val_end = memchr(val, '\0', end - val); 2082 if (val_end == NULL) /* Malformed representation; give up. */ 2083 return FALSE; 2084 2085 *key_out = key; 2086 *val_out = val; 2087 *pos = val_end + 1; 2088 return TRUE; 2089 } 2090 2091 krb5_error_code 2092 krb5_dbe_get_strings(krb5_context context, krb5_db_entry *entry, 2093 krb5_string_attr **strings_out, int *count_out) 2094 { 2095 krb5_error_code code; 2096 const char *pos, *end, *mapkey, *mapval; 2097 char *key = NULL, *val = NULL; 2098 krb5_string_attr *strings = NULL, *newstrings; 2099 int count = 0; 2100 2101 *strings_out = NULL; 2102 *count_out = 0; 2103 code = begin_attrs(context, entry, &pos, &end); 2104 if (code) 2105 return code; 2106 2107 while (next_attr(&pos, end, &mapkey, &mapval)) { 2108 /* Add a copy of mapkey and mapvalue to strings. */ 2109 newstrings = realloc(strings, (count + 1) * sizeof(*strings)); 2110 if (newstrings == NULL) 2111 goto oom; 2112 strings = newstrings; 2113 key = strdup(mapkey); 2114 val = strdup(mapval); 2115 if (key == NULL || val == NULL) 2116 goto oom; 2117 strings[count].key = key; 2118 strings[count].value = val; 2119 count++; 2120 } 2121 2122 *strings_out = strings; 2123 *count_out = count; 2124 return 0; 2125 2126 oom: 2127 free(key); 2128 free(val); 2129 krb5_dbe_free_strings(context, strings, count); 2130 return ENOMEM; 2131 } 2132 2133 krb5_error_code 2134 krb5_dbe_get_string(krb5_context context, krb5_db_entry *entry, 2135 const char *key, char **value_out) 2136 { 2137 krb5_error_code code; 2138 const char *pos, *end, *mapkey, *mapval; 2139 2140 *value_out = NULL; 2141 code = begin_attrs(context, entry, &pos, &end); 2142 if (code) 2143 return code; 2144 while (next_attr(&pos, end, &mapkey, &mapval)) { 2145 if (strcmp(mapkey, key) == 0) { 2146 *value_out = strdup(mapval); 2147 return (*value_out == NULL) ? ENOMEM : 0; 2148 } 2149 } 2150 2151 return 0; 2152 } 2153 2154 krb5_error_code 2155 krb5_dbe_set_string(krb5_context context, krb5_db_entry *entry, 2156 const char *key, const char *value) 2157 { 2158 krb5_error_code code; 2159 const char *pos, *end, *mapkey, *mapval; 2160 struct k5buf buf = EMPTY_K5BUF; 2161 krb5_boolean found = FALSE; 2162 krb5_tl_data tl_data; 2163 2164 /* Copy the current mapping to buf, updating key with value if found. */ 2165 code = begin_attrs(context, entry, &pos, &end); 2166 if (code) 2167 return code; 2168 k5_buf_init_dynamic(&buf); 2169 while (next_attr(&pos, end, &mapkey, &mapval)) { 2170 if (strcmp(mapkey, key) == 0) { 2171 if (value != NULL) { 2172 k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1); 2173 k5_buf_add_len(&buf, value, strlen(value) + 1); 2174 } 2175 found = TRUE; 2176 } else { 2177 k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1); 2178 k5_buf_add_len(&buf, mapval, strlen(mapval) + 1); 2179 } 2180 } 2181 2182 /* If key wasn't found in the map, add a new entry for it. */ 2183 if (!found && value != NULL) { 2184 k5_buf_add_len(&buf, key, strlen(key) + 1); 2185 k5_buf_add_len(&buf, value, strlen(value) + 1); 2186 } 2187 2188 if (k5_buf_status(&buf) != 0) 2189 return ENOMEM; 2190 if (buf.len > 65535) { 2191 code = KRB5_KDB_STRINGS_TOOLONG; 2192 goto cleanup; 2193 } 2194 tl_data.tl_data_type = KRB5_TL_STRING_ATTRS; 2195 tl_data.tl_data_contents = buf.data; 2196 tl_data.tl_data_length = buf.len; 2197 2198 code = krb5_dbe_update_tl_data(context, entry, &tl_data); 2199 2200 cleanup: 2201 k5_buf_free(&buf); 2202 return code; 2203 } 2204 2205 krb5_error_code 2206 krb5_dbe_delete_tl_data(krb5_context context, krb5_db_entry *entry, 2207 krb5_int16 tl_data_type) 2208 { 2209 krb5_tl_data *tl_data, *prev_tl_data, *free_tl_data; 2210 2211 /* 2212 * Find existing entries of the specified type and remove them from the 2213 * entry's tl_data list. 2214 */ 2215 2216 for (prev_tl_data = tl_data = entry->tl_data; tl_data != NULL;) { 2217 if (tl_data->tl_data_type == tl_data_type) { 2218 if (tl_data == entry->tl_data) { 2219 /* remove from head */ 2220 entry->tl_data = tl_data->tl_data_next; 2221 prev_tl_data = entry->tl_data; 2222 } else if (tl_data->tl_data_next == NULL) { 2223 /* remove from tail */ 2224 prev_tl_data->tl_data_next = NULL; 2225 } else { 2226 /* remove in between */ 2227 prev_tl_data->tl_data_next = tl_data->tl_data_next; 2228 } 2229 free_tl_data = tl_data; 2230 tl_data = tl_data->tl_data_next; 2231 krb5_dbe_free_tl_data(context, free_tl_data); 2232 entry->n_tl_data--; 2233 } else { 2234 prev_tl_data = tl_data; 2235 tl_data = tl_data->tl_data_next; 2236 } 2237 } 2238 2239 return (0); 2240 } 2241 2242 krb5_error_code 2243 krb5_db_update_tl_data(krb5_context context, krb5_int16 *n_tl_datap, 2244 krb5_tl_data **tl_datap, krb5_tl_data *new_tl_data) 2245 { 2246 krb5_tl_data *tl_data = NULL; 2247 krb5_octet *tmp; 2248 2249 /* 2250 * Copy the new data first, so we can fail cleanly if malloc() 2251 * fails. 2252 */ 2253 tmp = malloc(new_tl_data->tl_data_length); 2254 if (tmp == NULL) 2255 return (ENOMEM); 2256 2257 /* 2258 * Find an existing entry of the specified type and point at 2259 * it, or NULL if not found. 2260 */ 2261 2262 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */ 2263 for (tl_data = *tl_datap; tl_data; 2264 tl_data = tl_data->tl_data_next) 2265 if (tl_data->tl_data_type == new_tl_data->tl_data_type) 2266 break; 2267 } 2268 2269 /* If necessary, chain a new record in the beginning and point at it. */ 2270 2271 if (!tl_data) { 2272 tl_data = calloc(1, sizeof(*tl_data)); 2273 if (tl_data == NULL) { 2274 free(tmp); 2275 return (ENOMEM); 2276 } 2277 tl_data->tl_data_next = *tl_datap; 2278 *tl_datap = tl_data; 2279 (*n_tl_datap)++; 2280 } 2281 2282 /* fill in the record */ 2283 2284 free(tl_data->tl_data_contents); 2285 2286 tl_data->tl_data_type = new_tl_data->tl_data_type; 2287 tl_data->tl_data_length = new_tl_data->tl_data_length; 2288 tl_data->tl_data_contents = tmp; 2289 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); 2290 2291 return (0); 2292 } 2293 2294 krb5_error_code 2295 krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry, 2296 krb5_tl_data *new_tl_data) 2297 { 2298 return krb5_db_update_tl_data(context, &entry->n_tl_data, &entry->tl_data, 2299 new_tl_data); 2300 } 2301 2302 krb5_error_code 2303 krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key, 2304 krb5_const_principal princ, krb5_int16 *salttype_out, 2305 krb5_data **salt_out) 2306 { 2307 krb5_error_code retval; 2308 krb5_int16 stype; 2309 krb5_data *salt, sdata; 2310 2311 stype = (key->key_data_ver < 2) ? KRB5_KDB_SALTTYPE_NORMAL : 2312 key->key_data_type[1]; 2313 *salttype_out = stype; 2314 *salt_out = NULL; 2315 2316 /* Place computed salt into sdata, or directly into salt_out and return. */ 2317 switch (stype) { 2318 case KRB5_KDB_SALTTYPE_NORMAL: 2319 retval = krb5_principal2salt(context, princ, &sdata); 2320 if (retval) 2321 return retval; 2322 break; 2323 case KRB5_KDB_SALTTYPE_NOREALM: 2324 retval = krb5_principal2salt_norealm(context, princ, &sdata); 2325 if (retval) 2326 return retval; 2327 break; 2328 case KRB5_KDB_SALTTYPE_ONLYREALM: 2329 return krb5_copy_data(context, &princ->realm, salt_out); 2330 case KRB5_KDB_SALTTYPE_SPECIAL: 2331 sdata = make_data(key->key_data_contents[1], key->key_data_length[1]); 2332 return krb5_copy_data(context, &sdata, salt_out); 2333 default: 2334 return KRB5_KDB_BAD_SALTTYPE; 2335 } 2336 2337 /* Make a container for sdata. */ 2338 salt = malloc(sizeof(*salt)); 2339 if (salt == NULL) { 2340 free(sdata.data); 2341 return ENOMEM; 2342 } 2343 *salt = sdata; 2344 *salt_out = salt; 2345 return 0; 2346 } 2347 2348 krb5_error_code 2349 krb5_dbe_specialize_salt(krb5_context context, krb5_db_entry *entry) 2350 { 2351 krb5_int16 stype, i; 2352 krb5_data *salt; 2353 krb5_error_code ret; 2354 2355 if (context == NULL || entry == NULL) 2356 return EINVAL; 2357 2358 /* 2359 * Store salt values explicitly so that they don't depend on the principal 2360 * name. 2361 */ 2362 for (i = 0; i < entry->n_key_data; i++) { 2363 ret = krb5_dbe_compute_salt(context, &entry->key_data[i], entry->princ, 2364 &stype, &salt); 2365 if (ret) 2366 return ret; 2367 2368 /* Steal the data pointer from salt and free the container. */ 2369 if (entry->key_data[i].key_data_ver >= 2) 2370 free(entry->key_data[i].key_data_contents[1]); 2371 entry->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL; 2372 entry->key_data[i].key_data_contents[1] = (uint8_t *)salt->data; 2373 entry->key_data[i].key_data_length[1] = salt->length; 2374 entry->key_data[i].key_data_ver = 2; 2375 free(salt); 2376 } 2377 2378 return 0; 2379 } 2380 2381 /* change password functions */ 2382 krb5_error_code 2383 krb5_dbe_cpw(krb5_context kcontext, krb5_keyblock *master_key, 2384 krb5_key_salt_tuple *ks_tuple, int ks_tuple_count, char *passwd, 2385 int new_kvno, krb5_boolean keepold, krb5_db_entry *db_entry) 2386 { 2387 krb5_error_code status = 0; 2388 kdb_vftabl *v; 2389 2390 status = get_vftabl(kcontext, &v); 2391 if (status) 2392 return status; 2393 return v->change_pwd(kcontext, master_key, ks_tuple, ks_tuple_count, 2394 passwd, new_kvno, keepold, db_entry); 2395 } 2396 2397 /* policy management functions */ 2398 krb5_error_code 2399 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy) 2400 { 2401 krb5_error_code status = 0; 2402 kdb_vftabl *v; 2403 2404 status = get_vftabl(kcontext, &v); 2405 if (status) 2406 return status; 2407 if (v->create_policy == NULL) 2408 return KRB5_PLUGIN_OP_NOTSUPP; 2409 2410 status = v->create_policy(kcontext, policy); 2411 /* iprop does not support policy mods; force full resync. */ 2412 if (!status && logging(kcontext)) 2413 status = ulog_init_header(kcontext); 2414 return status; 2415 } 2416 2417 krb5_error_code 2418 krb5_db_get_policy(krb5_context kcontext, char *name, osa_policy_ent_t *policy) 2419 { 2420 krb5_error_code status = 0; 2421 kdb_vftabl *v; 2422 2423 status = get_vftabl(kcontext, &v); 2424 if (status) 2425 return status; 2426 if (v->get_policy == NULL) 2427 return KRB5_PLUGIN_OP_NOTSUPP; 2428 return v->get_policy(kcontext, name, policy); 2429 } 2430 2431 krb5_error_code 2432 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy) 2433 { 2434 krb5_error_code status = 0; 2435 kdb_vftabl *v; 2436 2437 status = get_vftabl(kcontext, &v); 2438 if (status) 2439 return status; 2440 if (v->put_policy == NULL) 2441 return KRB5_PLUGIN_OP_NOTSUPP; 2442 2443 status = v->put_policy(kcontext, policy); 2444 /* iprop does not support policy mods; force full resync. */ 2445 if (!status && logging(kcontext)) 2446 status = ulog_init_header(kcontext); 2447 return status; 2448 } 2449 2450 krb5_error_code 2451 krb5_db_iter_policy(krb5_context kcontext, char *match_entry, 2452 osa_adb_iter_policy_func func, void *data) 2453 { 2454 krb5_error_code status = 0; 2455 kdb_vftabl *v; 2456 2457 status = get_vftabl(kcontext, &v); 2458 if (status) 2459 return status; 2460 if (v->iter_policy == NULL) 2461 return 0; 2462 return v->iter_policy(kcontext, match_entry, func, data); 2463 } 2464 2465 krb5_error_code 2466 krb5_db_delete_policy(krb5_context kcontext, char *policy) 2467 { 2468 krb5_error_code status = 0; 2469 kdb_vftabl *v; 2470 2471 status = get_vftabl(kcontext, &v); 2472 if (status) 2473 return status; 2474 if (v->delete_policy == NULL) 2475 return KRB5_PLUGIN_OP_NOTSUPP; 2476 2477 status = v->delete_policy(kcontext, policy); 2478 /* iprop does not support policy mods; force full resync. */ 2479 if (!status && logging(kcontext)) 2480 status = ulog_init_header(kcontext); 2481 return status; 2482 } 2483 2484 void 2485 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy) 2486 { 2487 if (policy == NULL) 2488 return; 2489 free(policy->name); 2490 free(policy->allowed_keysalts); 2491 free_tl_data(policy->tl_data); 2492 free(policy); 2493 } 2494 2495 krb5_error_code 2496 krb5_db_promote(krb5_context kcontext, char **db_args) 2497 { 2498 krb5_error_code status; 2499 char *section; 2500 kdb_vftabl *v; 2501 2502 status = get_vftabl(kcontext, &v); 2503 if (status) 2504 return status; 2505 if (v->promote_db == NULL) 2506 return KRB5_PLUGIN_OP_NOTSUPP; 2507 status = get_conf_section(kcontext, §ion); 2508 if (status) 2509 return status; 2510 status = v->promote_db(kcontext, section, db_args); 2511 free(section); 2512 return status; 2513 } 2514 2515 static krb5_error_code 2516 decrypt_iterator(krb5_context kcontext, const krb5_key_data * key_data, 2517 krb5_keyblock *dbkey, krb5_keysalt *keysalt) 2518 { 2519 krb5_error_code status = 0; 2520 kdb_vftabl *v; 2521 krb5_keylist_node *n = kcontext->dal_handle->master_keylist; 2522 2523 status = get_vftabl(kcontext, &v); 2524 if (status) 2525 return status; 2526 for (; n; n = n->next) { 2527 krb5_clear_error_message(kcontext); 2528 status = v->decrypt_key_data(kcontext, &n->keyblock, key_data, dbkey, 2529 keysalt); 2530 if (status == 0) 2531 return 0; 2532 } 2533 return status; 2534 } 2535 2536 krb5_error_code 2537 krb5_dbe_decrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey, 2538 const krb5_key_data *key_data, krb5_keyblock *dbkey, 2539 krb5_keysalt *keysalt) 2540 { 2541 krb5_error_code status = 0; 2542 kdb_vftabl *v; 2543 krb5_keyblock *cur_mkey; 2544 2545 status = get_vftabl(kcontext, &v); 2546 if (status) 2547 return status; 2548 if (mkey || kcontext->dal_handle->master_keylist == NULL) 2549 return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt); 2550 status = decrypt_iterator(kcontext, key_data, dbkey, keysalt); 2551 if (status == 0) 2552 return 0; 2553 if (kcontext->dal_handle->master_keylist) { 2554 /* Try reloading master keys. */ 2555 cur_mkey = &kcontext->dal_handle->master_keylist->keyblock; 2556 if (krb5_db_fetch_mkey_list(kcontext, 2557 kcontext->dal_handle->master_princ, 2558 cur_mkey) == 0) 2559 return decrypt_iterator(kcontext, key_data, dbkey, keysalt); 2560 } 2561 return status; 2562 } 2563 2564 krb5_error_code 2565 krb5_dbe_encrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey, 2566 const krb5_keyblock *dbkey, 2567 const krb5_keysalt *keysalt, int keyver, 2568 krb5_key_data *key_data) 2569 { 2570 krb5_error_code status = 0; 2571 kdb_vftabl *v; 2572 2573 status = get_vftabl(kcontext, &v); 2574 if (status) 2575 return status; 2576 return v->encrypt_key_data(kcontext, mkey, dbkey, keysalt, keyver, 2577 key_data); 2578 } 2579 2580 krb5_error_code 2581 krb5_db_get_context(krb5_context context, void **db_context) 2582 { 2583 *db_context = KRB5_DB_GET_DB_CONTEXT(context); 2584 if (*db_context == NULL) 2585 return KRB5_KDB_DBNOTINITED; 2586 return 0; 2587 } 2588 2589 krb5_error_code 2590 krb5_db_set_context(krb5_context context, void *db_context) 2591 { 2592 KRB5_DB_GET_DB_CONTEXT(context) = db_context; 2593 2594 return 0; 2595 } 2596 2597 krb5_error_code 2598 krb5_db_check_transited_realms(krb5_context kcontext, 2599 const krb5_data *tr_contents, 2600 const krb5_data *client_realm, 2601 const krb5_data *server_realm) 2602 { 2603 krb5_error_code status; 2604 kdb_vftabl *v; 2605 2606 status = get_vftabl(kcontext, &v); 2607 if (status) 2608 return status; 2609 if (v->check_transited_realms == NULL) 2610 return KRB5_PLUGIN_OP_NOTSUPP; 2611 return v->check_transited_realms(kcontext, tr_contents, client_realm, 2612 server_realm); 2613 } 2614 2615 krb5_error_code 2616 krb5_db_check_policy_as(krb5_context kcontext, krb5_kdc_req *request, 2617 krb5_db_entry *client, krb5_db_entry *server, 2618 krb5_timestamp kdc_time, const char **status, 2619 krb5_pa_data ***e_data) 2620 { 2621 krb5_error_code ret; 2622 kdb_vftabl *v; 2623 2624 *status = NULL; 2625 *e_data = NULL; 2626 ret = get_vftabl(kcontext, &v); 2627 if (ret) 2628 return ret; 2629 if (v->check_policy_as == NULL) 2630 return KRB5_PLUGIN_OP_NOTSUPP; 2631 return v->check_policy_as(kcontext, request, client, server, kdc_time, 2632 status, e_data); 2633 } 2634 2635 krb5_error_code 2636 krb5_db_check_policy_tgs(krb5_context kcontext, krb5_kdc_req *request, 2637 krb5_db_entry *server, krb5_ticket *ticket, 2638 const char **status, krb5_pa_data ***e_data) 2639 { 2640 krb5_error_code ret; 2641 kdb_vftabl *v; 2642 2643 *status = NULL; 2644 *e_data = NULL; 2645 ret = get_vftabl(kcontext, &v); 2646 if (ret) 2647 return ret; 2648 if (v->check_policy_tgs == NULL) 2649 return KRB5_PLUGIN_OP_NOTSUPP; 2650 return v->check_policy_tgs(kcontext, request, server, ticket, status, 2651 e_data); 2652 } 2653 2654 void 2655 krb5_db_audit_as_req(krb5_context kcontext, krb5_kdc_req *request, 2656 const krb5_address *local_addr, 2657 const krb5_address *remote_addr, krb5_db_entry *client, 2658 krb5_db_entry *server, krb5_timestamp authtime, 2659 krb5_error_code error_code) 2660 { 2661 krb5_error_code status; 2662 kdb_vftabl *v; 2663 2664 status = get_vftabl(kcontext, &v); 2665 if (status || v->audit_as_req == NULL) 2666 return; 2667 v->audit_as_req(kcontext, request, local_addr, remote_addr, 2668 client, server, authtime, error_code); 2669 } 2670 2671 void 2672 krb5_db_refresh_config(krb5_context kcontext) 2673 { 2674 krb5_error_code status; 2675 kdb_vftabl *v; 2676 2677 status = get_vftabl(kcontext, &v); 2678 if (status || v->refresh_config == NULL) 2679 return; 2680 v->refresh_config(kcontext); 2681 } 2682 2683 krb5_error_code 2684 krb5_db_check_allowed_to_delegate(krb5_context kcontext, 2685 krb5_const_principal client, 2686 const krb5_db_entry *server, 2687 krb5_const_principal proxy) 2688 { 2689 krb5_error_code ret; 2690 kdb_vftabl *v; 2691 2692 ret = get_vftabl(kcontext, &v); 2693 if (ret) 2694 return ret; 2695 if (v->check_allowed_to_delegate == NULL) 2696 return KRB5_PLUGIN_OP_NOTSUPP; 2697 return v->check_allowed_to_delegate(kcontext, client, server, proxy); 2698 } 2699 2700 krb5_error_code 2701 krb5_db_get_s4u_x509_principal(krb5_context kcontext, 2702 const krb5_data *client_cert, 2703 krb5_const_principal in_princ, 2704 unsigned int flags, krb5_db_entry **entry) 2705 { 2706 krb5_error_code ret; 2707 kdb_vftabl *v; 2708 2709 ret = get_vftabl(kcontext, &v); 2710 if (ret) 2711 return ret; 2712 if (v->get_s4u_x509_principal == NULL) 2713 return KRB5_PLUGIN_OP_NOTSUPP; 2714 ret = v->get_s4u_x509_principal(kcontext, client_cert, in_princ, flags, 2715 entry); 2716 if (ret) 2717 return ret; 2718 2719 /* Sort the keys in the db entry, same as get_principal(). */ 2720 if ((*entry)->key_data != NULL) 2721 krb5_dbe_sort_key_data((*entry)->key_data, (*entry)->n_key_data); 2722 2723 return 0; 2724 } 2725 2726 krb5_error_code 2727 krb5_db_allowed_to_delegate_from(krb5_context kcontext, 2728 krb5_const_principal client, 2729 krb5_const_principal server, 2730 krb5_pac server_pac, 2731 const krb5_db_entry *proxy) 2732 { 2733 krb5_error_code ret; 2734 kdb_vftabl *v; 2735 2736 ret = get_vftabl(kcontext, &v); 2737 if (ret) 2738 return ret; 2739 if (v->allowed_to_delegate_from == NULL) 2740 return KRB5_PLUGIN_OP_NOTSUPP; 2741 return v->allowed_to_delegate_from(kcontext, client, server, server_pac, 2742 proxy); 2743 } 2744 2745 void 2746 krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length) 2747 { 2748 size_t i, j; 2749 krb5_key_data tmp; 2750 2751 /* Use insertion sort as a stable sort. */ 2752 for (i = 1; i < key_data_length; i++) { 2753 j = i; 2754 while (j > 0 && 2755 key_data[j - 1].key_data_kvno < key_data[j].key_data_kvno) { 2756 tmp = key_data[j]; 2757 key_data[j] = key_data[j - 1]; 2758 key_data[j - 1] = tmp; 2759 j--; 2760 } 2761 } 2762 } 2763 2764 krb5_error_code 2765 krb5_db_issue_pac(krb5_context context, unsigned int flags, 2766 krb5_db_entry *client, krb5_keyblock *replaced_reply_key, 2767 krb5_db_entry *server, krb5_db_entry *krbtgt, 2768 krb5_timestamp authtime, krb5_pac old_pac, krb5_pac new_pac, 2769 krb5_data ***auth_indicators) 2770 { 2771 krb5_error_code ret; 2772 kdb_vftabl *v; 2773 2774 ret = get_vftabl(context, &v); 2775 if (ret) 2776 return ret; 2777 if (v->issue_pac == NULL) 2778 return KRB5_PLUGIN_OP_NOTSUPP; 2779 return v->issue_pac(context, flags, client, replaced_reply_key, server, 2780 krbtgt, authtime, old_pac, new_pac, auth_indicators); 2781 } 2782