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