1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright 2006 by the Massachusetts Institute of Technology. 8 * All Rights Reserved. 9 * 10 * Export of this software from the United States of America may 11 * require a specific license from the United States Government. 12 * It is the responsibility of any person or organization contemplating 13 * export to obtain such a license before exporting. 14 * 15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 16 * distribute this software and its documentation for any purpose and 17 * without fee is hereby granted, provided that the above copyright 18 * notice appear in all copies and that both that copyright notice and 19 * this permission notice appear in supporting documentation, and that 20 * the name of M.I.T. not be used in advertising or publicity pertaining 21 * to distribution of the software without specific, written prior 22 * permission. Furthermore if you modify this software you must label 23 * your software as modified software and not distribute it in such a 24 * fashion that it might be confused with the original M.I.T. software. 25 * M.I.T. makes no representations about the suitability of 26 * this software for any purpose. It is provided "as is" without express 27 * or implied warranty. 28 */ 29 30 /* 31 * This code was based on code donated to MIT by Novell for 32 * distribution under the MIT license. 33 */ 34 35 /* 36 * Include files 37 */ 38 39 #include <stdio.h> 40 #include <string.h> 41 #include <k5-int.h> 42 #include <osconf.h> 43 #include "kdb5.h" 44 #include <assert.h> 45 #include "k5-platform.h" 46 #include <libintl.h> 47 48 /* Currently DB2 policy related errors are exported from DAL. But 49 other databases should set_err function to return string. */ 50 #include "adb_err.h" 51 52 /* 53 * Type definitions 54 */ 55 #define KRB5_TL_DB_ARGS 0x7fff 56 57 /* 58 * internal static variable 59 */ 60 61 static k5_mutex_t db_lock = K5_MUTEX_PARTIAL_INITIALIZER; 62 63 #ifdef _KDB5_STATIC_LINK 64 #undef _KDB5_DYNAMIC_LINK 65 #else 66 #undef _KDB5_DYNAMIC_LINK 67 /* to avoid redefinition problem */ 68 #define _KDB5_DYNAMIC_LINK 69 #endif 70 71 static db_library lib_list; 72 73 /* 74 * Helper Functions 75 */ 76 77 MAKE_INIT_FUNCTION(kdb_init_lock_list); 78 MAKE_FINI_FUNCTION(kdb_fini_lock_list); 79 80 int 81 kdb_init_lock_list(void) 82 { 83 return k5_mutex_finish_init(&db_lock); 84 } 85 86 static int 87 kdb_lock_list() 88 { 89 int err; 90 err = CALL_INIT_FUNCTION (kdb_init_lock_list); 91 if (err) 92 return err; 93 return k5_mutex_lock(&db_lock); 94 } 95 96 void 97 kdb_fini_lock_list(void) 98 { 99 if (INITIALIZER_RAN(kdb_init_lock_list)) 100 k5_mutex_destroy(&db_lock); 101 } 102 103 static int 104 kdb_unlock_list() 105 { 106 return k5_mutex_unlock(&db_lock); 107 } 108 109 #define kdb_init_lib_lock(a) 0 110 #define kdb_destroy_lib_lock(a) (void)0 111 #define kdb_lock_lib_lock(a, b) 0 112 #define kdb_unlock_lib_lock(a, b) (void)0 113 114 /* Caller must free result*/ 115 116 static char * 117 kdb_get_conf_section(krb5_context kcontext) 118 { 119 krb5_error_code status = 0; 120 char *result = NULL; 121 char *value = NULL; 122 123 if (kcontext->default_realm == NULL) 124 return NULL; 125 /* The profile has to have been initialized. If the profile was 126 not initialized, expect nothing less than a crash. */ 127 status = profile_get_string(kcontext->profile, 128 /* realms */ 129 KDB_REALM_SECTION, 130 kcontext->default_realm, 131 /* under the realm name, database_module */ 132 KDB_MODULE_POINTER, 133 /* default value is the realm name itself */ 134 kcontext->default_realm, 135 &value); 136 137 if (status) { 138 /* some problem */ 139 result = strdup(kcontext->default_realm); 140 /* let NULL be handled by the caller */ 141 } else { 142 result = strdup(value); 143 /* free profile string */ 144 profile_release_string(value); 145 } 146 147 return result; 148 } 149 150 static char * 151 kdb_get_library_name(krb5_context kcontext) 152 { 153 krb5_error_code status = 0; 154 char *result = NULL; 155 char *value = NULL; 156 char *lib = NULL; 157 158 status = profile_get_string(kcontext->profile, 159 /* realms */ 160 KDB_REALM_SECTION, 161 kcontext->default_realm, 162 /* under the realm name, database_module */ 163 KDB_MODULE_POINTER, 164 /* default value is the realm name itself */ 165 kcontext->default_realm, 166 &value); 167 if (status) { 168 goto clean_n_exit; 169 } 170 171 #define DB2_NAME "db2" 172 /* we got the module section. Get the library name from the module */ 173 status = profile_get_string(kcontext->profile, KDB_MODULE_SECTION, value, 174 KDB_LIB_POINTER, 175 /* default to db2 */ 176 DB2_NAME, 177 &lib); 178 179 if (status) { 180 goto clean_n_exit; 181 } 182 183 result = strdup(lib); 184 clean_n_exit: 185 if (value) { 186 /* free profile string */ 187 profile_release_string(value); 188 } 189 190 if (lib) { 191 /* free profile string */ 192 profile_release_string(lib); 193 } 194 return result; 195 } 196 197 static void 198 kdb_setup_opt_functions(db_library lib) 199 { 200 if (lib->vftabl.set_master_key == NULL) { 201 lib->vftabl.set_master_key = kdb_def_set_mkey; 202 } 203 204 if (lib->vftabl.get_master_key == NULL) { 205 lib->vftabl.get_master_key = kdb_def_get_mkey; 206 } 207 208 if (lib->vftabl.fetch_master_key == NULL) { 209 lib->vftabl.fetch_master_key = krb5_db_def_fetch_mkey; 210 } 211 212 if (lib->vftabl.verify_master_key == NULL) { 213 lib->vftabl.verify_master_key = krb5_def_verify_master_key; 214 } 215 216 if (lib->vftabl.dbe_search_enctype == NULL) { 217 lib->vftabl.dbe_search_enctype = krb5_dbe_def_search_enctype; 218 } 219 220 if (lib->vftabl.db_change_pwd == NULL) { 221 lib->vftabl.db_change_pwd = krb5_dbe_def_cpw; 222 } 223 224 if (lib->vftabl.store_master_key == NULL) { 225 lib->vftabl.store_master_key = krb5_def_store_mkey; 226 } 227 228 if (lib->vftabl.promote_db == NULL) { 229 lib->vftabl.promote_db = krb5_def_promote_db; 230 } 231 } 232 233 static int kdb_db2_pol_err_loaded = 0; 234 #ifdef _KDB5_STATIC_LINK 235 #define DEF_SYMBOL(a) extern kdb_vftabl krb5_db_vftabl_ ## a 236 #define GET_SYMBOL(a) (krb5_db_vftabl_ ## a) 237 static krb5_error_code 238 kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib) 239 { 240 krb5_error_code status; 241 void *vftabl_addr = NULL; 242 char buf[KRB5_MAX_ERR_STR]; 243 244 if (!strcmp("kdb_db2", lib_name) && (kdb_db2_pol_err_loaded == 0)) { 245 initialize_adb_error_table(); 246 kdb_db2_pol_err_loaded = 1; 247 } 248 249 *lib = calloc((size_t) 1, sizeof(**lib)); 250 if (*lib == NULL) { 251 status = ENOMEM; 252 goto clean_n_exit; 253 } 254 255 status = kdb_init_lib_lock(*lib); 256 if (status) { 257 goto clean_n_exit; 258 } 259 260 strcpy((*lib)->name, lib_name); 261 262 #if !defined(KDB5_USE_LIB_KDB_DB2) && !defined(KDB5_USE_LIB_TEST) 263 #error No database module defined 264 #endif 265 266 #ifdef KDB5_USE_LIB_KDB_DB2 267 if (strcmp(lib_name, "kdb_db2") == 0) { 268 DEF_SYMBOL(kdb_db2); 269 vftabl_addr = (void *) &GET_SYMBOL(kdb_db2); 270 } else 271 #endif 272 #ifdef KDB5_USE_LIB_TEST 273 if (strcmp(lib_name, "test") == 0) { 274 DEF_SYMBOL(test); 275 vftabl_addr = (void *) &GET_SYMBOL(test); 276 } else 277 #endif 278 { 279 snprintf(buf, sizeof(buf), gettext("Program not built to support %s database type\n"), 280 lib_name); 281 status = KRB5_KDB_DBTYPE_NOSUP; 282 krb5_db_set_err(kcontext, krb5_err_have_str, status, buf); 283 goto clean_n_exit; 284 } 285 286 memcpy(&(*lib)->vftabl, vftabl_addr, sizeof(kdb_vftabl)); 287 288 kdb_setup_opt_functions(*lib); 289 290 if ((status = (*lib)->vftabl.init_library())) { 291 /* ERROR. library not initialized cleanly */ 292 snprintf(buf, sizeof(buf), gettext("%s library initialization failed, error code %ld\n"), 293 lib_name, status); 294 status = KRB5_KDB_DBTYPE_INIT; 295 krb5_db_set_err(kcontext, krb5_err_have_str, status, buf); 296 goto clean_n_exit; 297 } 298 299 clean_n_exit: 300 if (status) { 301 free(*lib), *lib = NULL; 302 } 303 return status; 304 } 305 306 #else /* KDB5_STATIC_LINK*/ 307 308 static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH; 309 #define db_dl_n_locations (sizeof(db_dl_location) / sizeof(db_dl_location[0])) 310 311 static krb5_error_code 312 kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib) 313 { 314 krb5_error_code status = 0; 315 int ndx; 316 void **vftabl_addrs = NULL; 317 /* N.B.: If this is "const" but not "static", the Solaris 10 318 native compiler has trouble building the library because of 319 absolute relocations needed in read-only section ".rodata". 320 When it's static, it goes into ".picdata", which is 321 read-write. */ 322 static const char *const dbpath_names[] = { 323 KDB_MODULE_SECTION, "db_module_dir", NULL, 324 }; 325 const char *filebases[2]; 326 char **profpath = NULL; 327 char **path = NULL; 328 329 filebases[0] = lib_name; 330 filebases[1] = NULL; 331 332 if (!strcmp(DB2_NAME, lib_name) && (kdb_db2_pol_err_loaded == 0)) { 333 initialize_adb_error_table(); 334 kdb_db2_pol_err_loaded = 1; 335 } 336 337 *lib = calloc((size_t) 1, sizeof(**lib)); 338 if (*lib == NULL) { 339 status = ENOMEM; 340 goto clean_n_exit; 341 } 342 343 status = kdb_init_lib_lock(*lib); 344 if (status) { 345 goto clean_n_exit; 346 } 347 348 strcpy((*lib)->name, lib_name); 349 350 /* Fetch the list of directories specified in the config 351 file(s) first. */ 352 status = profile_get_values(kcontext->profile, dbpath_names, &profpath); 353 if (status != 0 && status != PROF_NO_RELATION) 354 goto clean_n_exit; 355 ndx = 0; 356 if (profpath) 357 while (profpath[ndx] != NULL) 358 ndx++; 359 360 path = calloc(ndx + db_dl_n_locations, sizeof (char *)); 361 if (path == NULL) { 362 status = errno; 363 goto clean_n_exit; 364 } 365 if (ndx) 366 memcpy(path, profpath, ndx * sizeof(profpath[0])); 367 memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *)); 368 status = 0; 369 370 if ((status = krb5int_open_plugin_dirs ((const char **) path, 371 filebases, 372 &(*lib)->dl_dir_handle, &kcontext->err))) { 373 const char *err_str = krb5_get_error_message(kcontext, status); 374 status = KRB5_KDB_DBTYPE_NOTFOUND; 375 krb5_set_error_message (kcontext, status, 376 gettext("Unable to find requested database type: %s"), err_str); 377 krb5_free_error_message (kcontext, err_str); 378 goto clean_n_exit; 379 } 380 381 if ((status = krb5int_get_plugin_dir_data (&(*lib)->dl_dir_handle, "kdb_function_table", 382 &vftabl_addrs, &kcontext->err))) { 383 const char *err_str = krb5_get_error_message(kcontext, status); 384 status = KRB5_KDB_DBTYPE_INIT; 385 krb5_set_error_message (kcontext, status, 386 gettext("plugin symbol 'kdb_function_table' lookup failed: %s"), err_str); 387 krb5_free_error_message (kcontext, err_str); 388 goto clean_n_exit; 389 } 390 391 if (vftabl_addrs[0] == NULL) { 392 /* No plugins! */ 393 status = KRB5_KDB_DBTYPE_NOTFOUND; 394 krb5_set_error_message (kcontext, status, 395 gettext("Unable to load requested database module '%s': plugin symbol 'kdb_function_table' not found"), 396 lib_name); 397 goto clean_n_exit; 398 } 399 400 memcpy(&(*lib)->vftabl, vftabl_addrs[0], sizeof(kdb_vftabl)); 401 kdb_setup_opt_functions(*lib); 402 403 if ((status = (*lib)->vftabl.init_library())) { 404 /* ERROR. library not initialized cleanly */ 405 goto clean_n_exit; 406 } 407 408 clean_n_exit: 409 if (vftabl_addrs != NULL) { krb5int_free_plugin_dir_data (vftabl_addrs); } 410 /* Both of these DTRT with NULL. */ 411 profile_free_list(profpath); 412 free(path); 413 if (status) { 414 if (*lib) { 415 kdb_destroy_lib_lock(*lib); 416 if (PLUGIN_DIR_OPEN((&(*lib)->dl_dir_handle))) { 417 krb5int_close_plugin_dirs (&(*lib)->dl_dir_handle); 418 } 419 free(*lib); 420 *lib = NULL; 421 } 422 } 423 return status; 424 } 425 426 #endif /* end of _KDB5_STATIC_LINK */ 427 428 static krb5_error_code 429 kdb_find_library(krb5_context kcontext, char *lib_name, db_library * lib) 430 { 431 /* lock here so that no two threads try to do the same at the same time */ 432 krb5_error_code status = 0; 433 int locked = 0; 434 db_library curr_elt, prev_elt = NULL; 435 436 if ((status = kdb_lock_list()) != 0) { 437 goto clean_n_exit; 438 } 439 locked = 1; 440 441 curr_elt = lib_list; 442 while (curr_elt != NULL) { 443 if (strcmp(lib_name, curr_elt->name) == 0) { 444 *lib = curr_elt; 445 goto clean_n_exit; 446 } 447 prev_elt = curr_elt; 448 curr_elt = curr_elt->next; 449 } 450 451 /* module not found. create and add to list */ 452 status = kdb_load_library(kcontext, lib_name, lib); 453 if (status) { 454 goto clean_n_exit; 455 } 456 457 if (prev_elt) { 458 /* prev_elt points to the last element in the list */ 459 prev_elt->next = *lib; 460 (*lib)->prev = prev_elt; 461 } else { 462 lib_list = *lib; 463 } 464 465 clean_n_exit: 466 if (*lib) { 467 (*lib)->reference_cnt++; 468 } 469 470 if (locked) { 471 (void)kdb_unlock_list(); 472 } 473 474 return status; 475 } 476 477 static krb5_error_code 478 kdb_free_library(db_library lib) 479 { 480 krb5_error_code status = 0; 481 int locked = 0; 482 483 if ((status = kdb_lock_list()) != 0) { 484 goto clean_n_exit; 485 } 486 locked = 1; 487 488 lib->reference_cnt--; 489 490 if (lib->reference_cnt == 0) { 491 status = lib->vftabl.fini_library(); 492 if (status) { 493 goto clean_n_exit; 494 } 495 496 /* close the library */ 497 if (PLUGIN_DIR_OPEN((&lib->dl_dir_handle))) { 498 krb5int_close_plugin_dirs (&lib->dl_dir_handle); 499 } 500 501 kdb_destroy_lib_lock(lib); 502 503 if (lib->prev == NULL) { 504 /* first element in the list */ 505 lib_list = lib->next; 506 } else { 507 lib->prev->next = lib->next; 508 } 509 510 if (lib->next) { 511 lib->next->prev = lib->prev; 512 } 513 free(lib); 514 } 515 516 clean_n_exit: 517 if (locked) { 518 (void)kdb_unlock_list(); 519 } 520 521 return status; 522 } 523 524 static krb5_error_code 525 kdb_setup_lib_handle(krb5_context kcontext) 526 { 527 char *library = NULL; 528 krb5_error_code status = 0; 529 db_library lib = NULL; 530 kdb5_dal_handle *dal_handle = NULL; 531 532 dal_handle = calloc((size_t) 1, sizeof(kdb5_dal_handle)); 533 if (dal_handle == NULL) { 534 status = ENOMEM; 535 goto clean_n_exit; 536 } 537 538 library = kdb_get_library_name(kcontext); 539 if (library == NULL) { 540 status = KRB5_KDB_DBTYPE_NOTFOUND; 541 goto clean_n_exit; 542 } 543 544 status = kdb_find_library(kcontext, library, &lib); 545 if (status) { 546 goto clean_n_exit; 547 } 548 549 dal_handle->lib_handle = lib; 550 kcontext->db_context = (void *) dal_handle; 551 552 clean_n_exit: 553 free(library); 554 555 if (status) { 556 free(dal_handle); 557 if (lib) { 558 (void)kdb_free_library(lib); 559 } 560 } 561 562 return status; 563 } 564 565 static krb5_error_code 566 kdb_free_lib_handle(krb5_context kcontext) 567 { 568 krb5_error_code status = 0; 569 570 status = 571 kdb_free_library(((kdb5_dal_handle *) kcontext->db_context)-> 572 lib_handle); 573 if (status) { 574 goto clean_n_exit; 575 } 576 577 free(kcontext->db_context); 578 kcontext->db_context = NULL; 579 580 clean_n_exit: 581 return status; 582 } 583 584 static void 585 get_errmsg (krb5_context kcontext, krb5_error_code err_code) 586 { 587 kdb5_dal_handle *dal_handle; 588 const char *e; 589 if (err_code == 0) 590 return; 591 assert(kcontext != NULL); 592 /* Must be called with dal_handle->lib_handle locked! */ 593 assert(kcontext->db_context != NULL); 594 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 595 if (dal_handle->lib_handle->vftabl.errcode_2_string == NULL) 596 return; 597 e = dal_handle->lib_handle->vftabl.errcode_2_string(kcontext, err_code); 598 assert (e != NULL); 599 krb5_set_error_message(kcontext, err_code, "%s", e); 600 if (dal_handle->lib_handle->vftabl.release_errcode_string) 601 dal_handle->lib_handle->vftabl.release_errcode_string(kcontext, e); 602 } 603 604 /* 605 * External functions... DAL API 606 */ 607 krb5_error_code 608 krb5_db_open(krb5_context kcontext, char **db_args, int mode) 609 { 610 krb5_error_code status = 0; 611 char *section = NULL; 612 kdb5_dal_handle *dal_handle; 613 614 section = kdb_get_conf_section(kcontext); 615 if (section == NULL) { 616 status = KRB5_KDB_SERVER_INTERNAL_ERR; 617 krb5_set_error_message (kcontext, status, 618 gettext("unable to determine configuration section for realm %s\n"), 619 kcontext->default_realm ? kcontext->default_realm : "[UNSET]"); 620 goto clean_n_exit; 621 } 622 623 if (kcontext->db_context == NULL) { 624 status = kdb_setup_lib_handle(kcontext); 625 if (status) { 626 goto clean_n_exit; 627 } 628 } 629 630 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 631 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 632 if (status) { 633 /* Solaris Kerberos */ 634 kdb_free_lib_handle(kcontext); 635 goto clean_n_exit; 636 } 637 638 status = 639 dal_handle->lib_handle->vftabl.init_module(kcontext, section, db_args, 640 mode); 641 get_errmsg(kcontext, status); 642 643 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 644 645 /* Solaris Kerberos */ 646 if (status) 647 kdb_free_lib_handle(kcontext); 648 649 clean_n_exit: 650 if (section) 651 free(section); 652 return status; 653 } 654 655 krb5_error_code 656 krb5_db_inited(krb5_context kcontext) 657 { 658 return !(kcontext && kcontext->db_context && 659 ((kdb5_dal_handle *) kcontext->db_context)->db_context); 660 } 661 662 krb5_error_code 663 krb5_db_create(krb5_context kcontext, char **db_args) 664 { 665 krb5_error_code status = 0; 666 char *section = NULL; 667 kdb5_dal_handle *dal_handle; 668 669 section = kdb_get_conf_section(kcontext); 670 if (section == NULL) { 671 status = KRB5_KDB_SERVER_INTERNAL_ERR; 672 krb5_set_error_message (kcontext, status, 673 gettext("unable to determine configuration section for realm %s\n"), 674 kcontext->default_realm); 675 goto clean_n_exit; 676 } 677 678 if (kcontext->db_context == NULL) { 679 status = kdb_setup_lib_handle(kcontext); 680 if (status) { 681 goto clean_n_exit; 682 } 683 } 684 685 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 686 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 687 if (status) { 688 goto clean_n_exit; 689 } 690 691 status = 692 dal_handle->lib_handle->vftabl.db_create(kcontext, section, db_args); 693 get_errmsg(kcontext, status); 694 695 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 696 697 clean_n_exit: 698 if (section) 699 free(section); 700 return status; 701 } 702 703 krb5_error_code 704 krb5_db_fini(krb5_context kcontext) 705 { 706 krb5_error_code status = 0; 707 kdb5_dal_handle *dal_handle; 708 709 if (kcontext->db_context == NULL) { 710 /* module not loaded. So nothing to be done */ 711 goto clean_n_exit; 712 } 713 714 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 715 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 716 if (status) { 717 goto clean_n_exit; 718 } 719 720 status = dal_handle->lib_handle->vftabl.fini_module(kcontext); 721 get_errmsg(kcontext, status); 722 723 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 724 725 if (status) { 726 goto clean_n_exit; 727 } 728 729 status = kdb_free_lib_handle(kcontext); 730 731 clean_n_exit: 732 return status; 733 } 734 735 krb5_error_code 736 krb5_db_destroy(krb5_context kcontext, char **db_args) 737 { 738 krb5_error_code status = 0; 739 char *section = NULL; 740 kdb5_dal_handle *dal_handle; 741 742 section = kdb_get_conf_section(kcontext); 743 if (section == NULL) { 744 status = KRB5_KDB_SERVER_INTERNAL_ERR; 745 krb5_set_error_message (kcontext, status, 746 gettext("unable to determine configuration section for realm %s\n"), 747 kcontext->default_realm); 748 goto clean_n_exit; 749 } 750 751 if (kcontext->db_context == NULL) { 752 status = kdb_setup_lib_handle(kcontext); 753 if (status) { 754 goto clean_n_exit; 755 } 756 } 757 758 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 759 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 760 if (status) { 761 goto clean_n_exit; 762 } 763 764 status = 765 dal_handle->lib_handle->vftabl.db_destroy(kcontext, section, db_args); 766 get_errmsg(kcontext, status); 767 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 768 769 clean_n_exit: 770 if (section) 771 free(section); 772 return status; 773 } 774 775 krb5_error_code 776 krb5_db_get_age(krb5_context kcontext, char *db_name, time_t * t) 777 { 778 krb5_error_code status = 0; 779 kdb5_dal_handle *dal_handle; 780 781 if (kcontext->db_context == NULL) { 782 status = kdb_setup_lib_handle(kcontext); 783 if (status) { 784 goto clean_n_exit; 785 } 786 } 787 788 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 789 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 790 if (status) { 791 goto clean_n_exit; 792 } 793 794 status = dal_handle->lib_handle->vftabl.db_get_age(kcontext, db_name, t); 795 get_errmsg(kcontext, status); 796 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 797 798 clean_n_exit: 799 return status; 800 } 801 802 krb5_error_code 803 krb5_db_set_option(krb5_context kcontext, int option, void *value) 804 { 805 krb5_error_code status = 0; 806 kdb5_dal_handle *dal_handle; 807 808 if (kcontext->db_context == NULL) { 809 status = kdb_setup_lib_handle(kcontext); 810 if (status) { 811 goto clean_n_exit; 812 } 813 } 814 815 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 816 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 817 if (status) { 818 goto clean_n_exit; 819 } 820 821 status = 822 dal_handle->lib_handle->vftabl.db_set_option(kcontext, option, value); 823 get_errmsg(kcontext, status); 824 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 825 826 clean_n_exit: 827 return status; 828 } 829 830 krb5_error_code 831 krb5_db_lock(krb5_context kcontext, int lock_mode) 832 { 833 krb5_error_code status = 0; 834 kdb5_dal_handle *dal_handle; 835 836 if (kcontext->db_context == NULL) { 837 status = kdb_setup_lib_handle(kcontext); 838 if (status) { 839 goto clean_n_exit; 840 } 841 } 842 843 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 844 /* acquire an exclusive lock, ensures no other thread uses this context */ 845 status = kdb_lock_lib_lock(dal_handle->lib_handle, TRUE); 846 if (status) { 847 goto clean_n_exit; 848 } 849 850 status = dal_handle->lib_handle->vftabl.db_lock(kcontext, lock_mode); 851 get_errmsg(kcontext, status); 852 853 /* exclusive lock is still held, so no other thread could use this context */ 854 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 855 856 clean_n_exit: 857 return status; 858 } 859 860 krb5_error_code 861 krb5_db_unlock(krb5_context kcontext) 862 { 863 krb5_error_code status = 0; 864 kdb5_dal_handle *dal_handle; 865 866 if (kcontext->db_context == NULL) { 867 status = kdb_setup_lib_handle(kcontext); 868 if (status) { 869 goto clean_n_exit; 870 } 871 } 872 873 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 874 /* normal lock acquired and exclusive lock released */ 875 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 876 if (status) { 877 goto clean_n_exit; 878 } 879 880 status = dal_handle->lib_handle->vftabl.db_unlock(kcontext); 881 get_errmsg(kcontext, status); 882 883 kdb_unlock_lib_lock(dal_handle->lib_handle, TRUE); 884 885 clean_n_exit: 886 return status; 887 } 888 889 krb5_error_code 890 krb5_db_get_principal(krb5_context kcontext, 891 krb5_const_principal search_for, 892 krb5_db_entry * entries, 893 int *nentries, krb5_boolean * more) 894 { 895 krb5_error_code status = 0; 896 kdb5_dal_handle *dal_handle; 897 898 if (kcontext->db_context == NULL) { 899 status = kdb_setup_lib_handle(kcontext); 900 if (status) { 901 goto clean_n_exit; 902 } 903 } 904 905 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 906 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 907 if (status) { 908 goto clean_n_exit; 909 } 910 911 status = 912 dal_handle->lib_handle->vftabl.db_get_principal(kcontext, search_for, 913 entries, nentries, 914 more); 915 get_errmsg(kcontext, status); 916 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 917 918 clean_n_exit: 919 return status; 920 } 921 922 krb5_error_code 923 krb5_db_get_principal_nolock(krb5_context kcontext, 924 krb5_const_principal search_for, 925 krb5_db_entry * entries, 926 int *nentries, krb5_boolean * more) 927 { 928 krb5_error_code status = 0; 929 kdb5_dal_handle *dal_handle; 930 931 if (kcontext->db_context == NULL) { 932 status = kdb_setup_lib_handle(kcontext); 933 if (status) { 934 goto clean_n_exit; 935 } 936 } 937 938 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 939 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 940 if (status) { 941 goto clean_n_exit; 942 } 943 944 status = 945 dal_handle->lib_handle->vftabl.db_get_principal_nolock(kcontext, 946 search_for, 947 entries, nentries, 948 more); 949 get_errmsg(kcontext, status); 950 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 951 952 clean_n_exit: 953 return status; 954 } 955 956 krb5_error_code 957 krb5_db_free_principal(krb5_context kcontext, krb5_db_entry * entry, int count) 958 { 959 krb5_error_code status = 0; 960 kdb5_dal_handle *dal_handle; 961 962 if (kcontext->db_context == NULL) { 963 status = kdb_setup_lib_handle(kcontext); 964 if (status) { 965 goto clean_n_exit; 966 } 967 } 968 969 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 970 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 971 if (status) { 972 goto clean_n_exit; 973 } 974 975 status = 976 dal_handle->lib_handle->vftabl.db_free_principal(kcontext, entry, 977 count); 978 get_errmsg(kcontext, status); 979 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 980 981 clean_n_exit: 982 return status; 983 } 984 985 krb5_error_code 986 krb5_db_put_principal(krb5_context kcontext, 987 krb5_db_entry * entries, int *nentries) 988 { 989 krb5_error_code status = 0; 990 kdb5_dal_handle *dal_handle; 991 char **db_args = NULL; 992 krb5_tl_data *prev, *curr, *next; 993 int db_args_size = 0; 994 995 if (kcontext->db_context == NULL) { 996 status = kdb_setup_lib_handle(kcontext); 997 if (status) { 998 goto clean_n_exit; 999 } 1000 } 1001 1002 /* Giving db_args as part of tl data causes, db2 to store the 1003 tl_data as such. To prevent this, tl_data is collated and 1004 passed as a sepearte argument. Currently supports only one 1005 principal. but passing it as a seperate argument makes it 1006 difficult for kadmin remote to pass arguments to server. */ 1007 prev = NULL, curr = entries->tl_data; 1008 while (curr) { 1009 if (curr->tl_data_type == KRB5_TL_DB_ARGS) { 1010 char **t; 1011 /* Since this is expected to be NULL terminated string and 1012 this could come from any client, do a check before 1013 passing it to db. */ 1014 if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] != 1015 '\0') { 1016 /* not null terminated. Dangerous input */ 1017 status = EINVAL; 1018 goto clean_n_exit; 1019 } 1020 1021 db_args_size++; 1022 t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */ 1023 if (t == NULL) { 1024 status = ENOMEM; 1025 goto clean_n_exit; 1026 } 1027 1028 db_args = t; 1029 db_args[db_args_size - 1] = (char *) curr->tl_data_contents; 1030 db_args[db_args_size] = NULL; 1031 1032 next = curr->tl_data_next; 1033 if (prev == NULL) { 1034 /* current node is the first in the linked list. remove it */ 1035 entries->tl_data = curr->tl_data_next; 1036 } else { 1037 prev->tl_data_next = curr->tl_data_next; 1038 } 1039 entries->n_tl_data--; 1040 krb5_db_free(kcontext, curr); 1041 1042 /* previous does not change */ 1043 curr = next; 1044 } else { 1045 prev = curr; 1046 curr = curr->tl_data_next; 1047 } 1048 } 1049 1050 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1051 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1052 if (status) { 1053 goto clean_n_exit; 1054 } 1055 1056 status = dal_handle->lib_handle->vftabl.db_put_principal(kcontext, entries, 1057 nentries, 1058 db_args); 1059 get_errmsg(kcontext, status); 1060 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1061 1062 clean_n_exit: 1063 while (db_args_size) { 1064 if (db_args[db_args_size - 1]) 1065 krb5_db_free(kcontext, db_args[db_args_size - 1]); 1066 1067 db_args_size--; 1068 } 1069 1070 if (db_args) 1071 free(db_args); 1072 1073 return status; 1074 } 1075 1076 krb5_error_code 1077 krb5_db_delete_principal(krb5_context kcontext, 1078 krb5_principal search_for, int *nentries) 1079 { 1080 krb5_error_code status = 0; 1081 kdb5_dal_handle *dal_handle; 1082 1083 if (kcontext->db_context == NULL) { 1084 status = kdb_setup_lib_handle(kcontext); 1085 if (status) { 1086 goto clean_n_exit; 1087 } 1088 } 1089 1090 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1091 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1092 if (status) { 1093 goto clean_n_exit; 1094 } 1095 1096 status = 1097 dal_handle->lib_handle->vftabl.db_delete_principal(kcontext, 1098 search_for, 1099 nentries); 1100 get_errmsg(kcontext, status); 1101 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1102 1103 clean_n_exit: 1104 return status; 1105 } 1106 1107 krb5_error_code 1108 krb5_db_iterate(krb5_context kcontext, 1109 char *match_entry, 1110 int (*func) (krb5_pointer, krb5_db_entry *), 1111 krb5_pointer func_arg, 1112 /* Solaris Kerberos: adding support for db_args */ 1113 char **db_args) 1114 { 1115 krb5_error_code status = 0; 1116 kdb5_dal_handle *dal_handle; 1117 1118 if (kcontext->db_context == NULL) { 1119 status = kdb_setup_lib_handle(kcontext); 1120 if (status) { 1121 goto clean_n_exit; 1122 } 1123 } 1124 1125 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1126 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1127 if (status) { 1128 goto clean_n_exit; 1129 } 1130 1131 /* Solaris Kerberos: adding support for db_args */ 1132 status = dal_handle->lib_handle->vftabl.db_iterate(kcontext, 1133 match_entry, 1134 func, func_arg, 1135 db_args); 1136 get_errmsg(kcontext, status); 1137 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1138 1139 clean_n_exit: 1140 return status; 1141 } 1142 1143 krb5_error_code 1144 krb5_supported_realms(krb5_context kcontext, char **realms) 1145 { 1146 krb5_error_code status = 0; 1147 kdb5_dal_handle *dal_handle; 1148 1149 if (kcontext->db_context == NULL) { 1150 status = kdb_setup_lib_handle(kcontext); 1151 if (status) { 1152 goto clean_n_exit; 1153 } 1154 } 1155 1156 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1157 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1158 if (status) { 1159 goto clean_n_exit; 1160 } 1161 1162 status = 1163 dal_handle->lib_handle->vftabl.db_supported_realms(kcontext, realms); 1164 get_errmsg(kcontext, status); 1165 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1166 1167 clean_n_exit: 1168 return status; 1169 } 1170 1171 krb5_error_code 1172 krb5_free_supported_realms(krb5_context kcontext, char **realms) 1173 { 1174 krb5_error_code status = 0; 1175 kdb5_dal_handle *dal_handle; 1176 1177 if (kcontext->db_context == NULL) { 1178 status = kdb_setup_lib_handle(kcontext); 1179 if (status) { 1180 goto clean_n_exit; 1181 } 1182 } 1183 1184 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1185 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1186 if (status) { 1187 goto clean_n_exit; 1188 } 1189 1190 status = 1191 dal_handle->lib_handle->vftabl.db_free_supported_realms(kcontext, 1192 realms); 1193 get_errmsg(kcontext, status); 1194 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1195 1196 clean_n_exit: 1197 return status; 1198 } 1199 1200 krb5_error_code 1201 krb5_db_set_master_key_ext(krb5_context kcontext, 1202 char *pwd, krb5_keyblock * key) 1203 { 1204 krb5_error_code status = 0; 1205 kdb5_dal_handle *dal_handle; 1206 1207 if (kcontext->db_context == NULL) { 1208 status = kdb_setup_lib_handle(kcontext); 1209 if (status) { 1210 goto clean_n_exit; 1211 } 1212 } 1213 1214 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1215 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1216 if (status) { 1217 goto clean_n_exit; 1218 } 1219 1220 status = dal_handle->lib_handle->vftabl.set_master_key(kcontext, pwd, key); 1221 get_errmsg(kcontext, status); 1222 1223 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1224 1225 clean_n_exit: 1226 return status; 1227 } 1228 1229 krb5_error_code 1230 krb5_db_set_mkey(krb5_context context, krb5_keyblock * key) 1231 { 1232 return krb5_db_set_master_key_ext(context, NULL, key); 1233 } 1234 1235 krb5_error_code 1236 krb5_db_get_mkey(krb5_context kcontext, krb5_keyblock ** key) 1237 { 1238 krb5_error_code status = 0; 1239 kdb5_dal_handle *dal_handle; 1240 1241 if (kcontext->db_context == NULL) { 1242 status = kdb_setup_lib_handle(kcontext); 1243 if (status) { 1244 goto clean_n_exit; 1245 } 1246 } 1247 1248 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1249 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1250 if (status) { 1251 goto clean_n_exit; 1252 } 1253 1254 /* Lets use temp key and copy it later to avoid memory problems 1255 when freed by the caller. */ 1256 status = dal_handle->lib_handle->vftabl.get_master_key(kcontext, key); 1257 get_errmsg(kcontext, status); 1258 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1259 1260 clean_n_exit: 1261 return status; 1262 } 1263 1264 krb5_error_code 1265 krb5_db_store_master_key(krb5_context kcontext, 1266 char *db_arg, 1267 krb5_principal mname, 1268 krb5_keyblock * key, char *master_pwd) 1269 { 1270 krb5_error_code status = 0; 1271 kdb5_dal_handle *dal_handle; 1272 1273 if (kcontext->db_context == NULL) { 1274 status = kdb_setup_lib_handle(kcontext); 1275 if (status) { 1276 goto clean_n_exit; 1277 } 1278 } 1279 1280 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1281 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1282 if (status) { 1283 goto clean_n_exit; 1284 } 1285 1286 status = dal_handle->lib_handle->vftabl.store_master_key(kcontext, 1287 db_arg, 1288 mname, 1289 key, master_pwd); 1290 get_errmsg(kcontext, status); 1291 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1292 1293 clean_n_exit: 1294 return status; 1295 } 1296 1297 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; 1298 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; 1299 1300 krb5_error_code 1301 krb5_db_fetch_mkey(krb5_context context, 1302 krb5_principal mname, 1303 krb5_enctype etype, 1304 krb5_boolean fromkeyboard, 1305 krb5_boolean twice, 1306 char *db_args, krb5_data * salt, krb5_keyblock * key) 1307 { 1308 krb5_error_code retval; 1309 char password[BUFSIZ]; 1310 krb5_data pwd; 1311 unsigned int size = sizeof(password); 1312 int kvno; 1313 krb5_keyblock tmp_key; 1314 1315 memset(&tmp_key, 0, sizeof(tmp_key)); 1316 1317 if (fromkeyboard) { 1318 krb5_data scratch; 1319 1320 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, 1321 twice ? krb5_mkey_pwd_prompt2 : 0, 1322 password, &size))) { 1323 goto clean_n_exit; 1324 } 1325 1326 pwd.data = password; 1327 pwd.length = size; 1328 if (!salt) { 1329 retval = krb5_principal2salt(context, mname, &scratch); 1330 if (retval) 1331 goto clean_n_exit; 1332 } 1333 retval = 1334 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch, 1335 key); 1336 1337 if (!salt) 1338 krb5_xfree(scratch.data); 1339 memset(password, 0, sizeof(password)); /* erase it */ 1340 1341 } else { 1342 kdb5_dal_handle *dal_handle; 1343 1344 if (context->db_context == NULL) { 1345 retval = kdb_setup_lib_handle(context); 1346 if (retval) { 1347 goto clean_n_exit; 1348 } 1349 } 1350 1351 dal_handle = (kdb5_dal_handle *) context->db_context; 1352 retval = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1353 if (retval) { 1354 goto clean_n_exit; 1355 } 1356 #if 0 /************** Begin IFDEF'ed OUT *******************************/ 1357 /* Orig MIT */ 1358 tmp_key.enctype = key->enctype; 1359 #else 1360 /* Solaris Kerberos: need to use etype */ 1361 tmp_key.enctype = etype; 1362 #endif /**************** END IFDEF'ed OUT *******************************/ 1363 retval = dal_handle->lib_handle->vftabl.fetch_master_key(context, 1364 mname, 1365 &tmp_key, 1366 &kvno, 1367 db_args); 1368 get_errmsg(context, retval); 1369 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1370 1371 if (retval) { 1372 goto clean_n_exit; 1373 } 1374 1375 key->contents = malloc(tmp_key.length); 1376 if (key->contents == NULL) { 1377 retval = ENOMEM; 1378 goto clean_n_exit; 1379 } 1380 1381 key->magic = tmp_key.magic; 1382 key->enctype = tmp_key.enctype; 1383 key->length = tmp_key.length; 1384 memcpy(key->contents, tmp_key.contents, tmp_key.length); 1385 } 1386 1387 clean_n_exit: 1388 if (tmp_key.contents) { 1389 memset(tmp_key.contents, 0, tmp_key.length); 1390 krb5_db_free(context, tmp_key.contents); 1391 } 1392 return retval; 1393 } 1394 1395 krb5_error_code 1396 krb5_db_verify_master_key(krb5_context kcontext, 1397 krb5_principal mprinc, krb5_keyblock * mkey) 1398 { 1399 krb5_error_code status = 0; 1400 kdb5_dal_handle *dal_handle; 1401 1402 if (kcontext->db_context == NULL) { 1403 status = kdb_setup_lib_handle(kcontext); 1404 if (status) { 1405 goto clean_n_exit; 1406 } 1407 } 1408 1409 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1410 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1411 if (status) { 1412 goto clean_n_exit; 1413 } 1414 1415 status = dal_handle->lib_handle->vftabl.verify_master_key(kcontext, 1416 mprinc, mkey); 1417 get_errmsg(kcontext, status); 1418 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1419 1420 clean_n_exit: 1421 return status; 1422 } 1423 1424 void * 1425 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size) 1426 { 1427 krb5_error_code status; 1428 kdb5_dal_handle *dal_handle; 1429 void *new_ptr = NULL; 1430 1431 if (kcontext->db_context == NULL) { 1432 status = kdb_setup_lib_handle(kcontext); 1433 if (status) { 1434 goto clean_n_exit; 1435 } 1436 } 1437 1438 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1439 1440 new_ptr = dal_handle->lib_handle->vftabl.db_alloc(kcontext, ptr, size); 1441 1442 clean_n_exit: 1443 return new_ptr; 1444 } 1445 1446 void 1447 krb5_db_free(krb5_context kcontext, void *ptr) 1448 { 1449 krb5_error_code status; 1450 kdb5_dal_handle *dal_handle; 1451 1452 if (kcontext->db_context == NULL) { 1453 status = kdb_setup_lib_handle(kcontext); 1454 if (status) { 1455 goto clean_n_exit; 1456 } 1457 } 1458 1459 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1460 1461 dal_handle->lib_handle->vftabl.db_free(kcontext, ptr); 1462 1463 clean_n_exit: 1464 return; 1465 } 1466 1467 /* has to be modified */ 1468 1469 krb5_error_code 1470 krb5_dbe_find_enctype(krb5_context kcontext, 1471 krb5_db_entry * dbentp, 1472 krb5_int32 ktype, 1473 krb5_int32 stype, 1474 krb5_int32 kvno, krb5_key_data ** kdatap) 1475 { 1476 krb5_int32 start = 0; 1477 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype, 1478 kvno, kdatap); 1479 } 1480 1481 krb5_error_code 1482 krb5_dbe_search_enctype(krb5_context kcontext, 1483 krb5_db_entry * dbentp, 1484 krb5_int32 * start, 1485 krb5_int32 ktype, 1486 krb5_int32 stype, 1487 krb5_int32 kvno, krb5_key_data ** kdatap) 1488 { 1489 krb5_error_code status = 0; 1490 kdb5_dal_handle *dal_handle; 1491 1492 if (kcontext->db_context == NULL) { 1493 status = kdb_setup_lib_handle(kcontext); 1494 if (status) { 1495 goto clean_n_exit; 1496 } 1497 } 1498 1499 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1500 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1501 if (status) { 1502 goto clean_n_exit; 1503 } 1504 1505 status = dal_handle->lib_handle->vftabl.dbe_search_enctype(kcontext, 1506 dbentp, 1507 start, 1508 ktype, 1509 stype, 1510 kvno, kdatap); 1511 get_errmsg(kcontext, status); 1512 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1513 1514 clean_n_exit: 1515 return status; 1516 } 1517 1518 #define REALM_SEP_STRING "@" 1519 1520 krb5_error_code 1521 krb5_db_setup_mkey_name(krb5_context context, 1522 const char *keyname, 1523 const char *realm, 1524 char **fullname, krb5_principal * principal) 1525 { 1526 krb5_error_code retval; 1527 size_t keylen; 1528 size_t rlen = strlen(realm); 1529 char *fname; 1530 1531 if (!keyname) 1532 keyname = KRB5_KDB_M_NAME; /* XXX external? */ 1533 1534 keylen = strlen(keyname); 1535 1536 fname = malloc(keylen + rlen + strlen(REALM_SEP_STRING) + 1); 1537 if (!fname) 1538 return ENOMEM; 1539 1540 strcpy(fname, keyname); 1541 (void)strcat(fname, REALM_SEP_STRING); 1542 (void)strcat(fname, realm); 1543 1544 if ((retval = krb5_parse_name(context, fname, principal))) 1545 return retval; 1546 if (fullname) 1547 *fullname = fname; 1548 else 1549 free(fname); 1550 return 0; 1551 } 1552 1553 krb5_error_code 1554 krb5_dbe_lookup_last_pwd_change(context, entry, stamp) 1555 krb5_context context; 1556 krb5_db_entry *entry; 1557 krb5_timestamp *stamp; 1558 { 1559 krb5_tl_data tl_data; 1560 krb5_error_code code; 1561 krb5_int32 tmp; 1562 1563 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1564 1565 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1566 return (code); 1567 1568 if (tl_data.tl_data_length != 4) { 1569 *stamp = 0; 1570 return (0); 1571 } 1572 1573 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1574 1575 *stamp = (krb5_timestamp) tmp; 1576 1577 return (0); 1578 } 1579 1580 /*ARGSUSED*/ 1581 krb5_error_code 1582 krb5_dbe_lookup_tl_data(context, entry, ret_tl_data) 1583 krb5_context context; 1584 krb5_db_entry *entry; 1585 krb5_tl_data *ret_tl_data; 1586 { 1587 krb5_tl_data *tl_data; 1588 1589 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 1590 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { 1591 *ret_tl_data = *tl_data; 1592 return (0); 1593 } 1594 } 1595 1596 /* if the requested record isn't found, return zero bytes. 1597 * if it ever means something to have a zero-length tl_data, 1598 * this code and its callers will have to be changed */ 1599 1600 ret_tl_data->tl_data_length = 0; 1601 ret_tl_data->tl_data_contents = NULL; 1602 return (0); 1603 } 1604 1605 krb5_error_code 1606 krb5_dbe_create_key_data(context, entry) 1607 krb5_context context; 1608 krb5_db_entry *entry; 1609 { 1610 if ((entry->key_data = 1611 (krb5_key_data *) krb5_db_alloc(context, entry->key_data, 1612 (sizeof(krb5_key_data) * 1613 (entry->n_key_data + 1)))) == NULL) 1614 return (ENOMEM); 1615 1616 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data)); 1617 entry->n_key_data++; 1618 1619 return 0; 1620 } 1621 1622 krb5_error_code 1623 krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ) 1624 krb5_context context; 1625 krb5_db_entry *entry; 1626 krb5_timestamp mod_date; 1627 krb5_const_principal mod_princ; 1628 { 1629 krb5_tl_data tl_data; 1630 1631 krb5_error_code retval = 0; 1632 krb5_octet *nextloc = 0; 1633 char *unparse_mod_princ = 0; 1634 unsigned int unparse_mod_princ_size; 1635 1636 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ))) 1637 return (retval); 1638 1639 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; 1640 1641 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) 1642 == NULL) { 1643 free(unparse_mod_princ); 1644 return (ENOMEM); 1645 } 1646 1647 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1648 tl_data.tl_data_length = unparse_mod_princ_size + 4; 1649 tl_data.tl_data_contents = nextloc; 1650 1651 /* Mod Date */ 1652 krb5_kdb_encode_int32(mod_date, nextloc); 1653 1654 /* Mod Princ */ 1655 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size); 1656 1657 retval = krb5_dbe_update_tl_data(context, entry, &tl_data); 1658 1659 free(unparse_mod_princ); 1660 free(nextloc); 1661 1662 return (retval); 1663 } 1664 1665 krb5_error_code 1666 krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ) 1667 krb5_context context; 1668 krb5_db_entry *entry; 1669 krb5_timestamp *mod_time; 1670 krb5_principal *mod_princ; 1671 { 1672 krb5_tl_data tl_data; 1673 krb5_error_code code; 1674 1675 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1676 1677 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1678 return (code); 1679 1680 if ((tl_data.tl_data_length < 5) || 1681 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0')) 1682 return (KRB5_KDB_TRUNCATED_RECORD); 1683 1684 /* Mod Date */ 1685 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); 1686 1687 /* Mod Princ */ 1688 if ((code = krb5_parse_name(context, 1689 (const char *) (tl_data.tl_data_contents + 4), 1690 mod_princ))) 1691 return (code); 1692 1693 return (0); 1694 } 1695 1696 krb5_error_code 1697 krb5_dbe_update_last_pwd_change(context, entry, stamp) 1698 krb5_context context; 1699 krb5_db_entry *entry; 1700 krb5_timestamp stamp; 1701 { 1702 krb5_tl_data tl_data; 1703 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 1704 1705 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1706 tl_data.tl_data_length = sizeof(buf); 1707 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 1708 tl_data.tl_data_contents = buf; 1709 1710 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 1711 } 1712 1713 krb5_error_code 1714 krb5_dbe_update_tl_data(context, entry, new_tl_data) 1715 krb5_context context; 1716 krb5_db_entry *entry; 1717 krb5_tl_data *new_tl_data; 1718 { 1719 krb5_tl_data *tl_data = NULL; 1720 krb5_octet *tmp; 1721 1722 /* copy the new data first, so we can fail cleanly if malloc() 1723 * fails */ 1724 if ((tmp = 1725 (krb5_octet *) krb5_db_alloc(context, NULL, 1726 new_tl_data->tl_data_length)) == NULL) 1727 return (ENOMEM); 1728 1729 /* Find an existing entry of the specified type and point at 1730 * it, or NULL if not found */ 1731 1732 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */ 1733 for (tl_data = entry->tl_data; tl_data; 1734 tl_data = tl_data->tl_data_next) 1735 if (tl_data->tl_data_type == new_tl_data->tl_data_type) 1736 break; 1737 } 1738 1739 /* if necessary, chain a new record in the beginning and point at it */ 1740 1741 if (!tl_data) { 1742 if ((tl_data = 1743 (krb5_tl_data *) krb5_db_alloc(context, NULL, 1744 sizeof(krb5_tl_data))) 1745 == NULL) { 1746 free(tmp); 1747 return (ENOMEM); 1748 } 1749 memset(tl_data, 0, sizeof(krb5_tl_data)); 1750 tl_data->tl_data_next = entry->tl_data; 1751 entry->tl_data = tl_data; 1752 entry->n_tl_data++; 1753 } 1754 1755 /* fill in the record */ 1756 1757 if (tl_data->tl_data_contents) 1758 krb5_db_free(context, tl_data->tl_data_contents); 1759 1760 tl_data->tl_data_type = new_tl_data->tl_data_type; 1761 tl_data->tl_data_length = new_tl_data->tl_data_length; 1762 tl_data->tl_data_contents = tmp; 1763 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); 1764 1765 return (0); 1766 } 1767 1768 /* change password functions */ 1769 krb5_error_code 1770 krb5_dbe_cpw(krb5_context kcontext, 1771 krb5_keyblock * master_key, 1772 krb5_key_salt_tuple * ks_tuple, 1773 int ks_tuple_count, 1774 char *passwd, 1775 int new_kvno, krb5_boolean keepold, krb5_db_entry * db_entry) 1776 { 1777 krb5_error_code status = 0; 1778 kdb5_dal_handle *dal_handle; 1779 1780 if (kcontext->db_context == NULL) { 1781 status = kdb_setup_lib_handle(kcontext); 1782 if (status) { 1783 goto clean_n_exit; 1784 } 1785 } 1786 1787 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1788 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1789 if (status) { 1790 goto clean_n_exit; 1791 } 1792 1793 status = dal_handle->lib_handle->vftabl.db_change_pwd(kcontext, 1794 master_key, 1795 ks_tuple, 1796 ks_tuple_count, 1797 passwd, 1798 new_kvno, 1799 keepold, db_entry); 1800 get_errmsg(kcontext, status); 1801 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1802 1803 clean_n_exit: 1804 return status; 1805 } 1806 1807 /* policy management functions */ 1808 krb5_error_code 1809 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy) 1810 { 1811 krb5_error_code status = 0; 1812 kdb5_dal_handle *dal_handle; 1813 1814 if (kcontext->db_context == NULL) { 1815 status = kdb_setup_lib_handle(kcontext); 1816 if (status) { 1817 goto clean_n_exit; 1818 } 1819 } 1820 1821 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1822 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1823 if (status) { 1824 goto clean_n_exit; 1825 } 1826 1827 status = dal_handle->lib_handle->vftabl.db_create_policy(kcontext, policy); 1828 get_errmsg(kcontext, status); 1829 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1830 1831 clean_n_exit: 1832 return status; 1833 } 1834 1835 krb5_error_code 1836 krb5_db_get_policy(krb5_context kcontext, char *name, 1837 osa_policy_ent_t * policy, int *cnt) 1838 { 1839 krb5_error_code status = 0; 1840 kdb5_dal_handle *dal_handle; 1841 1842 if (kcontext->db_context == NULL) { 1843 status = kdb_setup_lib_handle(kcontext); 1844 if (status) { 1845 goto clean_n_exit; 1846 } 1847 } 1848 1849 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1850 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1851 if (status) { 1852 goto clean_n_exit; 1853 } 1854 1855 status = 1856 dal_handle->lib_handle->vftabl.db_get_policy(kcontext, name, policy, 1857 cnt); 1858 get_errmsg(kcontext, status); 1859 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1860 1861 clean_n_exit: 1862 return status; 1863 } 1864 1865 krb5_error_code 1866 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy) 1867 { 1868 krb5_error_code status = 0; 1869 kdb5_dal_handle *dal_handle; 1870 1871 if (kcontext->db_context == NULL) { 1872 status = kdb_setup_lib_handle(kcontext); 1873 if (status) { 1874 goto clean_n_exit; 1875 } 1876 } 1877 1878 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1879 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1880 if (status) { 1881 goto clean_n_exit; 1882 } 1883 1884 status = dal_handle->lib_handle->vftabl.db_put_policy(kcontext, policy); 1885 get_errmsg(kcontext, status); 1886 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1887 1888 clean_n_exit: 1889 return status; 1890 } 1891 1892 krb5_error_code 1893 krb5_db_iter_policy(krb5_context kcontext, char *match_entry, 1894 osa_adb_iter_policy_func func, void *data) 1895 { 1896 krb5_error_code status = 0; 1897 kdb5_dal_handle *dal_handle; 1898 1899 if (kcontext->db_context == NULL) { 1900 status = kdb_setup_lib_handle(kcontext); 1901 if (status) { 1902 goto clean_n_exit; 1903 } 1904 } 1905 1906 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1907 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1908 if (status) { 1909 goto clean_n_exit; 1910 } 1911 1912 status = 1913 dal_handle->lib_handle->vftabl.db_iter_policy(kcontext, match_entry, 1914 func, data); 1915 get_errmsg(kcontext, status); 1916 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1917 1918 clean_n_exit: 1919 return status; 1920 } 1921 1922 krb5_error_code 1923 krb5_db_delete_policy(krb5_context kcontext, char *policy) 1924 { 1925 krb5_error_code status = 0; 1926 kdb5_dal_handle *dal_handle; 1927 1928 if (kcontext->db_context == NULL) { 1929 status = kdb_setup_lib_handle(kcontext); 1930 if (status) { 1931 goto clean_n_exit; 1932 } 1933 } 1934 1935 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1936 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1937 if (status) { 1938 goto clean_n_exit; 1939 } 1940 1941 status = dal_handle->lib_handle->vftabl.db_delete_policy(kcontext, policy); 1942 get_errmsg(kcontext, status); 1943 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1944 1945 clean_n_exit: 1946 return status; 1947 } 1948 1949 void 1950 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy) 1951 { 1952 krb5_error_code status = 0; 1953 kdb5_dal_handle *dal_handle; 1954 1955 if (kcontext->db_context == NULL) { 1956 status = kdb_setup_lib_handle(kcontext); 1957 if (status) { 1958 goto clean_n_exit; 1959 } 1960 } 1961 1962 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1963 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1964 if (status) { 1965 goto clean_n_exit; 1966 } 1967 1968 dal_handle->lib_handle->vftabl.db_free_policy(kcontext, policy); 1969 get_errmsg(kcontext, status); 1970 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1971 1972 clean_n_exit: 1973 return; 1974 } 1975 1976 krb5_error_code 1977 krb5_db_promote(krb5_context kcontext, char **db_args) 1978 { 1979 krb5_error_code status = 0; 1980 char *section = NULL; 1981 kdb5_dal_handle *dal_handle; 1982 1983 section = kdb_get_conf_section(kcontext); 1984 if (section == NULL) { 1985 status = KRB5_KDB_SERVER_INTERNAL_ERR; 1986 krb5_set_error_message (kcontext, status, 1987 gettext("unable to determine configuration section for realm %s\n"), 1988 kcontext->default_realm); 1989 goto clean_n_exit; 1990 } 1991 1992 if (kcontext->db_context == NULL) { 1993 status = kdb_setup_lib_handle(kcontext); 1994 if (status) { 1995 goto clean_n_exit; 1996 } 1997 } 1998 1999 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 2000 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 2001 if (status) { 2002 goto clean_n_exit; 2003 } 2004 2005 status = 2006 dal_handle->lib_handle->vftabl.promote_db(kcontext, section, db_args); 2007 get_errmsg(kcontext, status); 2008 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 2009 2010 clean_n_exit: 2011 if (section) 2012 free(section); 2013 return status; 2014 } 2015 2016 /* 2017 * Solaris Kerberos: support for iprop 2018 * 2019 * Not all KDB plugins support iprop. 2020 * 2021 * sets iprop_supported to 1 if iprop supportd, 0 otherwise. 2022 */ 2023 krb5_error_code 2024 krb5_db_supports_iprop(krb5_context kcontext, int *iprop_supported) 2025 { 2026 krb5_error_code status = 0; 2027 kdb5_dal_handle *dal_handle; 2028 2029 if (kcontext->db_context == NULL) { 2030 status = kdb_setup_lib_handle(kcontext); 2031 if (status) { 2032 goto clean_n_exit; 2033 } 2034 } 2035 2036 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 2037 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 2038 if (status) { 2039 goto clean_n_exit; 2040 } 2041 2042 *iprop_supported = dal_handle->lib_handle->vftabl.iprop_supported; 2043 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 2044 2045 clean_n_exit: 2046 return status; 2047 } 2048