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 /* Solaris Kerberos */ 635 kdb_free_lib_handle(kcontext); 636 goto clean_n_exit; 637 } 638 639 status = 640 dal_handle->lib_handle->vftabl.init_module(kcontext, section, db_args, 641 mode); 642 get_errmsg(kcontext, status); 643 644 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 645 646 /* Solaris Kerberos */ 647 if (status) 648 kdb_free_lib_handle(kcontext); 649 650 clean_n_exit: 651 if (section) 652 free(section); 653 return status; 654 } 655 656 krb5_error_code 657 krb5_db_inited(krb5_context kcontext) 658 { 659 return !(kcontext && kcontext->db_context && 660 ((kdb5_dal_handle *) kcontext->db_context)->db_context); 661 } 662 663 krb5_error_code 664 krb5_db_create(krb5_context kcontext, char **db_args) 665 { 666 krb5_error_code status = 0; 667 char *section = NULL; 668 kdb5_dal_handle *dal_handle; 669 670 section = kdb_get_conf_section(kcontext); 671 if (section == NULL) { 672 status = KRB5_KDB_SERVER_INTERNAL_ERR; 673 krb5_set_error_message (kcontext, status, 674 gettext("unable to determine configuration section for realm %s\n"), 675 kcontext->default_realm); 676 goto clean_n_exit; 677 } 678 679 if (kcontext->db_context == NULL) { 680 status = kdb_setup_lib_handle(kcontext); 681 if (status) { 682 goto clean_n_exit; 683 } 684 } 685 686 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 687 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 688 if (status) { 689 goto clean_n_exit; 690 } 691 692 status = 693 dal_handle->lib_handle->vftabl.db_create(kcontext, section, db_args); 694 get_errmsg(kcontext, status); 695 696 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 697 698 clean_n_exit: 699 if (section) 700 free(section); 701 return status; 702 } 703 704 krb5_error_code 705 krb5_db_fini(krb5_context kcontext) 706 { 707 krb5_error_code status = 0; 708 kdb5_dal_handle *dal_handle; 709 710 if (kcontext->db_context == NULL) { 711 /* module not loaded. So nothing to be done */ 712 goto clean_n_exit; 713 } 714 715 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 716 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 717 if (status) { 718 goto clean_n_exit; 719 } 720 721 status = dal_handle->lib_handle->vftabl.fini_module(kcontext); 722 get_errmsg(kcontext, status); 723 724 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 725 726 if (status) { 727 goto clean_n_exit; 728 } 729 730 status = kdb_free_lib_handle(kcontext); 731 732 clean_n_exit: 733 return status; 734 } 735 736 krb5_error_code 737 krb5_db_destroy(krb5_context kcontext, char **db_args) 738 { 739 krb5_error_code status = 0; 740 char *section = NULL; 741 kdb5_dal_handle *dal_handle; 742 743 section = kdb_get_conf_section(kcontext); 744 if (section == NULL) { 745 status = KRB5_KDB_SERVER_INTERNAL_ERR; 746 krb5_set_error_message (kcontext, status, 747 gettext("unable to determine configuration section for realm %s\n"), 748 kcontext->default_realm); 749 goto clean_n_exit; 750 } 751 752 if (kcontext->db_context == NULL) { 753 status = kdb_setup_lib_handle(kcontext); 754 if (status) { 755 goto clean_n_exit; 756 } 757 } 758 759 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 760 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 761 if (status) { 762 goto clean_n_exit; 763 } 764 765 status = 766 dal_handle->lib_handle->vftabl.db_destroy(kcontext, section, db_args); 767 get_errmsg(kcontext, status); 768 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 769 770 clean_n_exit: 771 if (section) 772 free(section); 773 return status; 774 } 775 776 krb5_error_code 777 krb5_db_get_age(krb5_context kcontext, char *db_name, time_t * t) 778 { 779 krb5_error_code status = 0; 780 kdb5_dal_handle *dal_handle; 781 782 if (kcontext->db_context == NULL) { 783 status = kdb_setup_lib_handle(kcontext); 784 if (status) { 785 goto clean_n_exit; 786 } 787 } 788 789 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 790 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 791 if (status) { 792 goto clean_n_exit; 793 } 794 795 status = dal_handle->lib_handle->vftabl.db_get_age(kcontext, db_name, t); 796 get_errmsg(kcontext, status); 797 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 798 799 clean_n_exit: 800 return status; 801 } 802 803 krb5_error_code 804 krb5_db_set_option(krb5_context kcontext, int option, void *value) 805 { 806 krb5_error_code status = 0; 807 kdb5_dal_handle *dal_handle; 808 809 if (kcontext->db_context == NULL) { 810 status = kdb_setup_lib_handle(kcontext); 811 if (status) { 812 goto clean_n_exit; 813 } 814 } 815 816 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 817 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 818 if (status) { 819 goto clean_n_exit; 820 } 821 822 status = 823 dal_handle->lib_handle->vftabl.db_set_option(kcontext, option, value); 824 get_errmsg(kcontext, status); 825 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 826 827 clean_n_exit: 828 return status; 829 } 830 831 krb5_error_code 832 krb5_db_lock(krb5_context kcontext, int lock_mode) 833 { 834 krb5_error_code status = 0; 835 kdb5_dal_handle *dal_handle; 836 837 if (kcontext->db_context == NULL) { 838 status = kdb_setup_lib_handle(kcontext); 839 if (status) { 840 goto clean_n_exit; 841 } 842 } 843 844 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 845 /* acquire an exclusive lock, ensures no other thread uses this context */ 846 status = kdb_lock_lib_lock(dal_handle->lib_handle, TRUE); 847 if (status) { 848 goto clean_n_exit; 849 } 850 851 status = dal_handle->lib_handle->vftabl.db_lock(kcontext, lock_mode); 852 get_errmsg(kcontext, status); 853 854 /* exclusive lock is still held, so no other thread could use this context */ 855 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 856 857 clean_n_exit: 858 return status; 859 } 860 861 krb5_error_code 862 krb5_db_unlock(krb5_context kcontext) 863 { 864 krb5_error_code status = 0; 865 kdb5_dal_handle *dal_handle; 866 867 if (kcontext->db_context == NULL) { 868 status = kdb_setup_lib_handle(kcontext); 869 if (status) { 870 goto clean_n_exit; 871 } 872 } 873 874 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 875 /* normal lock acquired and exclusive lock released */ 876 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 877 if (status) { 878 goto clean_n_exit; 879 } 880 881 status = dal_handle->lib_handle->vftabl.db_unlock(kcontext); 882 get_errmsg(kcontext, status); 883 884 kdb_unlock_lib_lock(dal_handle->lib_handle, TRUE); 885 886 clean_n_exit: 887 return status; 888 } 889 890 krb5_error_code 891 krb5_db_get_principal(krb5_context kcontext, 892 krb5_const_principal search_for, 893 krb5_db_entry * entries, 894 int *nentries, krb5_boolean * more) 895 { 896 krb5_error_code status = 0; 897 kdb5_dal_handle *dal_handle; 898 899 if (kcontext->db_context == NULL) { 900 status = kdb_setup_lib_handle(kcontext); 901 if (status) { 902 goto clean_n_exit; 903 } 904 } 905 906 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 907 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 908 if (status) { 909 goto clean_n_exit; 910 } 911 912 status = 913 dal_handle->lib_handle->vftabl.db_get_principal(kcontext, search_for, 914 entries, nentries, 915 more); 916 get_errmsg(kcontext, status); 917 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 918 919 clean_n_exit: 920 return status; 921 } 922 923 krb5_error_code 924 krb5_db_get_principal_nolock(krb5_context kcontext, 925 krb5_const_principal search_for, 926 krb5_db_entry * entries, 927 int *nentries, krb5_boolean * more) 928 { 929 krb5_error_code status = 0; 930 kdb5_dal_handle *dal_handle; 931 932 if (kcontext->db_context == NULL) { 933 status = kdb_setup_lib_handle(kcontext); 934 if (status) { 935 goto clean_n_exit; 936 } 937 } 938 939 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 940 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 941 if (status) { 942 goto clean_n_exit; 943 } 944 945 status = 946 dal_handle->lib_handle->vftabl.db_get_principal_nolock(kcontext, 947 search_for, 948 entries, nentries, 949 more); 950 get_errmsg(kcontext, status); 951 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 952 953 clean_n_exit: 954 return status; 955 } 956 957 krb5_error_code 958 krb5_db_free_principal(krb5_context kcontext, krb5_db_entry * entry, int count) 959 { 960 krb5_error_code status = 0; 961 kdb5_dal_handle *dal_handle; 962 963 if (kcontext->db_context == NULL) { 964 status = kdb_setup_lib_handle(kcontext); 965 if (status) { 966 goto clean_n_exit; 967 } 968 } 969 970 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 971 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 972 if (status) { 973 goto clean_n_exit; 974 } 975 976 status = 977 dal_handle->lib_handle->vftabl.db_free_principal(kcontext, entry, 978 count); 979 get_errmsg(kcontext, status); 980 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 981 982 clean_n_exit: 983 return status; 984 } 985 986 krb5_error_code 987 krb5_db_put_principal(krb5_context kcontext, 988 krb5_db_entry * entries, int *nentries) 989 { 990 krb5_error_code status = 0; 991 kdb5_dal_handle *dal_handle; 992 char **db_args = NULL; 993 krb5_tl_data *prev, *curr, *next; 994 int db_args_size = 0; 995 996 if (kcontext->db_context == NULL) { 997 status = kdb_setup_lib_handle(kcontext); 998 if (status) { 999 goto clean_n_exit; 1000 } 1001 } 1002 1003 /* Giving db_args as part of tl data causes, db2 to store the 1004 tl_data as such. To prevent this, tl_data is collated and 1005 passed as a sepearte argument. Currently supports only one 1006 principal. but passing it as a seperate argument makes it 1007 difficult for kadmin remote to pass arguments to server. */ 1008 prev = NULL, curr = entries->tl_data; 1009 while (curr) { 1010 if (curr->tl_data_type == KRB5_TL_DB_ARGS) { 1011 char **t; 1012 /* Since this is expected to be NULL terminated string and 1013 this could come from any client, do a check before 1014 passing it to db. */ 1015 if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] != 1016 '\0') { 1017 /* not null terminated. Dangerous input */ 1018 status = EINVAL; 1019 goto clean_n_exit; 1020 } 1021 1022 db_args_size++; 1023 t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */ 1024 if (t == NULL) { 1025 status = ENOMEM; 1026 goto clean_n_exit; 1027 } 1028 1029 db_args = t; 1030 db_args[db_args_size - 1] = (char *) curr->tl_data_contents; 1031 db_args[db_args_size] = NULL; 1032 1033 next = curr->tl_data_next; 1034 if (prev == NULL) { 1035 /* current node is the first in the linked list. remove it */ 1036 entries->tl_data = curr->tl_data_next; 1037 } else { 1038 prev->tl_data_next = curr->tl_data_next; 1039 } 1040 entries->n_tl_data--; 1041 krb5_db_free(kcontext, curr); 1042 1043 /* previous does not change */ 1044 curr = next; 1045 } else { 1046 prev = curr; 1047 curr = curr->tl_data_next; 1048 } 1049 } 1050 1051 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1052 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1053 if (status) { 1054 goto clean_n_exit; 1055 } 1056 1057 status = dal_handle->lib_handle->vftabl.db_put_principal(kcontext, entries, 1058 nentries, 1059 db_args); 1060 get_errmsg(kcontext, status); 1061 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1062 1063 clean_n_exit: 1064 while (db_args_size) { 1065 if (db_args[db_args_size - 1]) 1066 krb5_db_free(kcontext, db_args[db_args_size - 1]); 1067 1068 db_args_size--; 1069 } 1070 1071 if (db_args) 1072 free(db_args); 1073 1074 return status; 1075 } 1076 1077 krb5_error_code 1078 krb5_db_delete_principal(krb5_context kcontext, 1079 krb5_principal search_for, int *nentries) 1080 { 1081 krb5_error_code status = 0; 1082 kdb5_dal_handle *dal_handle; 1083 1084 if (kcontext->db_context == NULL) { 1085 status = kdb_setup_lib_handle(kcontext); 1086 if (status) { 1087 goto clean_n_exit; 1088 } 1089 } 1090 1091 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1092 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1093 if (status) { 1094 goto clean_n_exit; 1095 } 1096 1097 status = 1098 dal_handle->lib_handle->vftabl.db_delete_principal(kcontext, 1099 search_for, 1100 nentries); 1101 get_errmsg(kcontext, status); 1102 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1103 1104 clean_n_exit: 1105 return status; 1106 } 1107 1108 krb5_error_code 1109 krb5_db_iterate(krb5_context kcontext, 1110 char *match_entry, 1111 int (*func) (krb5_pointer, krb5_db_entry *), 1112 krb5_pointer func_arg, 1113 /* Solaris Kerberos: adding support for db_args */ 1114 char **db_args) 1115 { 1116 krb5_error_code status = 0; 1117 kdb5_dal_handle *dal_handle; 1118 1119 if (kcontext->db_context == NULL) { 1120 status = kdb_setup_lib_handle(kcontext); 1121 if (status) { 1122 goto clean_n_exit; 1123 } 1124 } 1125 1126 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1127 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1128 if (status) { 1129 goto clean_n_exit; 1130 } 1131 1132 /* Solaris Kerberos: adding support for db_args */ 1133 status = dal_handle->lib_handle->vftabl.db_iterate(kcontext, 1134 match_entry, 1135 func, func_arg, 1136 db_args); 1137 get_errmsg(kcontext, status); 1138 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1139 1140 clean_n_exit: 1141 return status; 1142 } 1143 1144 krb5_error_code 1145 krb5_supported_realms(krb5_context kcontext, char **realms) 1146 { 1147 krb5_error_code status = 0; 1148 kdb5_dal_handle *dal_handle; 1149 1150 if (kcontext->db_context == NULL) { 1151 status = kdb_setup_lib_handle(kcontext); 1152 if (status) { 1153 goto clean_n_exit; 1154 } 1155 } 1156 1157 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1158 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1159 if (status) { 1160 goto clean_n_exit; 1161 } 1162 1163 status = 1164 dal_handle->lib_handle->vftabl.db_supported_realms(kcontext, realms); 1165 get_errmsg(kcontext, status); 1166 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1167 1168 clean_n_exit: 1169 return status; 1170 } 1171 1172 krb5_error_code 1173 krb5_free_supported_realms(krb5_context kcontext, char **realms) 1174 { 1175 krb5_error_code status = 0; 1176 kdb5_dal_handle *dal_handle; 1177 1178 if (kcontext->db_context == NULL) { 1179 status = kdb_setup_lib_handle(kcontext); 1180 if (status) { 1181 goto clean_n_exit; 1182 } 1183 } 1184 1185 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1186 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1187 if (status) { 1188 goto clean_n_exit; 1189 } 1190 1191 status = 1192 dal_handle->lib_handle->vftabl.db_free_supported_realms(kcontext, 1193 realms); 1194 get_errmsg(kcontext, status); 1195 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1196 1197 clean_n_exit: 1198 return status; 1199 } 1200 1201 krb5_error_code 1202 krb5_db_set_master_key_ext(krb5_context kcontext, 1203 char *pwd, krb5_keyblock * key) 1204 { 1205 krb5_error_code status = 0; 1206 kdb5_dal_handle *dal_handle; 1207 1208 if (kcontext->db_context == NULL) { 1209 status = kdb_setup_lib_handle(kcontext); 1210 if (status) { 1211 goto clean_n_exit; 1212 } 1213 } 1214 1215 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1216 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1217 if (status) { 1218 goto clean_n_exit; 1219 } 1220 1221 status = dal_handle->lib_handle->vftabl.set_master_key(kcontext, pwd, key); 1222 get_errmsg(kcontext, status); 1223 1224 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1225 1226 clean_n_exit: 1227 return status; 1228 } 1229 1230 krb5_error_code 1231 krb5_db_set_mkey(krb5_context context, krb5_keyblock * key) 1232 { 1233 return krb5_db_set_master_key_ext(context, NULL, key); 1234 } 1235 1236 krb5_error_code 1237 krb5_db_get_mkey(krb5_context kcontext, krb5_keyblock ** key) 1238 { 1239 krb5_error_code status = 0; 1240 kdb5_dal_handle *dal_handle; 1241 1242 if (kcontext->db_context == NULL) { 1243 status = kdb_setup_lib_handle(kcontext); 1244 if (status) { 1245 goto clean_n_exit; 1246 } 1247 } 1248 1249 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1250 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1251 if (status) { 1252 goto clean_n_exit; 1253 } 1254 1255 /* Lets use temp key and copy it later to avoid memory problems 1256 when freed by the caller. */ 1257 status = dal_handle->lib_handle->vftabl.get_master_key(kcontext, key); 1258 get_errmsg(kcontext, status); 1259 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1260 1261 clean_n_exit: 1262 return status; 1263 } 1264 1265 krb5_error_code 1266 krb5_db_store_master_key(krb5_context kcontext, 1267 char *db_arg, 1268 krb5_principal mname, 1269 krb5_keyblock * key, char *master_pwd) 1270 { 1271 krb5_error_code status = 0; 1272 kdb5_dal_handle *dal_handle; 1273 1274 if (kcontext->db_context == NULL) { 1275 status = kdb_setup_lib_handle(kcontext); 1276 if (status) { 1277 goto clean_n_exit; 1278 } 1279 } 1280 1281 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1282 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1283 if (status) { 1284 goto clean_n_exit; 1285 } 1286 1287 status = dal_handle->lib_handle->vftabl.store_master_key(kcontext, 1288 db_arg, 1289 mname, 1290 key, master_pwd); 1291 get_errmsg(kcontext, status); 1292 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1293 1294 clean_n_exit: 1295 return status; 1296 } 1297 1298 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; 1299 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; 1300 1301 krb5_error_code 1302 krb5_db_fetch_mkey(krb5_context context, 1303 krb5_principal mname, 1304 krb5_enctype etype, 1305 krb5_boolean fromkeyboard, 1306 krb5_boolean twice, 1307 char *db_args, krb5_data * salt, krb5_keyblock * key) 1308 { 1309 krb5_error_code retval; 1310 char password[BUFSIZ]; 1311 krb5_data pwd; 1312 unsigned int size = sizeof(password); 1313 int kvno; 1314 krb5_keyblock tmp_key; 1315 1316 memset(&tmp_key, 0, sizeof(tmp_key)); 1317 1318 if (fromkeyboard) { 1319 krb5_data scratch; 1320 1321 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, 1322 twice ? krb5_mkey_pwd_prompt2 : 0, 1323 password, &size))) { 1324 goto clean_n_exit; 1325 } 1326 1327 pwd.data = password; 1328 pwd.length = size; 1329 if (!salt) { 1330 retval = krb5_principal2salt(context, mname, &scratch); 1331 if (retval) 1332 goto clean_n_exit; 1333 } 1334 retval = 1335 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch, 1336 key); 1337 1338 if (!salt) 1339 krb5_xfree(scratch.data); 1340 memset(password, 0, sizeof(password)); /* erase it */ 1341 1342 } else { 1343 kdb5_dal_handle *dal_handle; 1344 1345 if (context->db_context == NULL) { 1346 retval = kdb_setup_lib_handle(context); 1347 if (retval) { 1348 goto clean_n_exit; 1349 } 1350 } 1351 1352 dal_handle = (kdb5_dal_handle *) context->db_context; 1353 retval = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1354 if (retval) { 1355 goto clean_n_exit; 1356 } 1357 #if 0 /************** Begin IFDEF'ed OUT *******************************/ 1358 /* Orig MIT */ 1359 tmp_key.enctype = key->enctype; 1360 #else 1361 /* Solaris Kerberos: need to use etype */ 1362 tmp_key.enctype = etype; 1363 #endif /**************** END IFDEF'ed OUT *******************************/ 1364 retval = dal_handle->lib_handle->vftabl.fetch_master_key(context, 1365 mname, 1366 &tmp_key, 1367 &kvno, 1368 db_args); 1369 get_errmsg(context, retval); 1370 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1371 1372 if (retval) { 1373 goto clean_n_exit; 1374 } 1375 1376 key->contents = malloc(tmp_key.length); 1377 if (key->contents == NULL) { 1378 retval = ENOMEM; 1379 goto clean_n_exit; 1380 } 1381 1382 key->magic = tmp_key.magic; 1383 key->enctype = tmp_key.enctype; 1384 key->length = tmp_key.length; 1385 memcpy(key->contents, tmp_key.contents, tmp_key.length); 1386 } 1387 1388 clean_n_exit: 1389 if (tmp_key.contents) { 1390 memset(tmp_key.contents, 0, tmp_key.length); 1391 krb5_db_free(context, tmp_key.contents); 1392 } 1393 return retval; 1394 } 1395 1396 krb5_error_code 1397 krb5_db_verify_master_key(krb5_context kcontext, 1398 krb5_principal mprinc, krb5_keyblock * mkey) 1399 { 1400 krb5_error_code status = 0; 1401 kdb5_dal_handle *dal_handle; 1402 1403 if (kcontext->db_context == NULL) { 1404 status = kdb_setup_lib_handle(kcontext); 1405 if (status) { 1406 goto clean_n_exit; 1407 } 1408 } 1409 1410 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1411 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1412 if (status) { 1413 goto clean_n_exit; 1414 } 1415 1416 status = dal_handle->lib_handle->vftabl.verify_master_key(kcontext, 1417 mprinc, mkey); 1418 get_errmsg(kcontext, status); 1419 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1420 1421 clean_n_exit: 1422 return status; 1423 } 1424 1425 void * 1426 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size) 1427 { 1428 krb5_error_code status; 1429 kdb5_dal_handle *dal_handle; 1430 void *new_ptr = NULL; 1431 1432 if (kcontext->db_context == NULL) { 1433 status = kdb_setup_lib_handle(kcontext); 1434 if (status) { 1435 goto clean_n_exit; 1436 } 1437 } 1438 1439 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1440 1441 new_ptr = dal_handle->lib_handle->vftabl.db_alloc(kcontext, ptr, size); 1442 1443 clean_n_exit: 1444 return new_ptr; 1445 } 1446 1447 void 1448 krb5_db_free(krb5_context kcontext, void *ptr) 1449 { 1450 krb5_error_code status; 1451 kdb5_dal_handle *dal_handle; 1452 1453 if (kcontext->db_context == NULL) { 1454 status = kdb_setup_lib_handle(kcontext); 1455 if (status) { 1456 goto clean_n_exit; 1457 } 1458 } 1459 1460 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1461 1462 dal_handle->lib_handle->vftabl.db_free(kcontext, ptr); 1463 1464 clean_n_exit: 1465 return; 1466 } 1467 1468 /* has to be modified */ 1469 1470 krb5_error_code 1471 krb5_dbe_find_enctype(krb5_context kcontext, 1472 krb5_db_entry * dbentp, 1473 krb5_int32 ktype, 1474 krb5_int32 stype, 1475 krb5_int32 kvno, krb5_key_data ** kdatap) 1476 { 1477 krb5_int32 start = 0; 1478 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype, 1479 kvno, kdatap); 1480 } 1481 1482 krb5_error_code 1483 krb5_dbe_search_enctype(krb5_context kcontext, 1484 krb5_db_entry * dbentp, 1485 krb5_int32 * start, 1486 krb5_int32 ktype, 1487 krb5_int32 stype, 1488 krb5_int32 kvno, krb5_key_data ** kdatap) 1489 { 1490 krb5_error_code status = 0; 1491 kdb5_dal_handle *dal_handle; 1492 1493 if (kcontext->db_context == NULL) { 1494 status = kdb_setup_lib_handle(kcontext); 1495 if (status) { 1496 goto clean_n_exit; 1497 } 1498 } 1499 1500 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1501 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1502 if (status) { 1503 goto clean_n_exit; 1504 } 1505 1506 status = dal_handle->lib_handle->vftabl.dbe_search_enctype(kcontext, 1507 dbentp, 1508 start, 1509 ktype, 1510 stype, 1511 kvno, kdatap); 1512 get_errmsg(kcontext, status); 1513 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1514 1515 clean_n_exit: 1516 return status; 1517 } 1518 1519 #define REALM_SEP_STRING "@" 1520 1521 krb5_error_code 1522 krb5_db_setup_mkey_name(krb5_context context, 1523 const char *keyname, 1524 const char *realm, 1525 char **fullname, krb5_principal * principal) 1526 { 1527 krb5_error_code retval; 1528 size_t keylen; 1529 size_t rlen = strlen(realm); 1530 char *fname; 1531 1532 if (!keyname) 1533 keyname = KRB5_KDB_M_NAME; /* XXX external? */ 1534 1535 keylen = strlen(keyname); 1536 1537 fname = malloc(keylen + rlen + strlen(REALM_SEP_STRING) + 1); 1538 if (!fname) 1539 return ENOMEM; 1540 1541 strcpy(fname, keyname); 1542 (void)strcat(fname, REALM_SEP_STRING); 1543 (void)strcat(fname, realm); 1544 1545 if ((retval = krb5_parse_name(context, fname, principal))) 1546 return retval; 1547 if (fullname) 1548 *fullname = fname; 1549 else 1550 free(fname); 1551 return 0; 1552 } 1553 1554 krb5_error_code 1555 krb5_dbe_lookup_last_pwd_change(context, entry, stamp) 1556 krb5_context context; 1557 krb5_db_entry *entry; 1558 krb5_timestamp *stamp; 1559 { 1560 krb5_tl_data tl_data; 1561 krb5_error_code code; 1562 krb5_int32 tmp; 1563 1564 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1565 1566 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1567 return (code); 1568 1569 if (tl_data.tl_data_length != 4) { 1570 *stamp = 0; 1571 return (0); 1572 } 1573 1574 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1575 1576 *stamp = (krb5_timestamp) tmp; 1577 1578 return (0); 1579 } 1580 1581 /*ARGSUSED*/ 1582 krb5_error_code 1583 krb5_dbe_lookup_tl_data(context, entry, ret_tl_data) 1584 krb5_context context; 1585 krb5_db_entry *entry; 1586 krb5_tl_data *ret_tl_data; 1587 { 1588 krb5_tl_data *tl_data; 1589 1590 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 1591 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { 1592 *ret_tl_data = *tl_data; 1593 return (0); 1594 } 1595 } 1596 1597 /* if the requested record isn't found, return zero bytes. 1598 * if it ever means something to have a zero-length tl_data, 1599 * this code and its callers will have to be changed */ 1600 1601 ret_tl_data->tl_data_length = 0; 1602 ret_tl_data->tl_data_contents = NULL; 1603 return (0); 1604 } 1605 1606 krb5_error_code 1607 krb5_dbe_create_key_data(context, entry) 1608 krb5_context context; 1609 krb5_db_entry *entry; 1610 { 1611 if ((entry->key_data = 1612 (krb5_key_data *) krb5_db_alloc(context, entry->key_data, 1613 (sizeof(krb5_key_data) * 1614 (entry->n_key_data + 1)))) == NULL) 1615 return (ENOMEM); 1616 1617 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data)); 1618 entry->n_key_data++; 1619 1620 return 0; 1621 } 1622 1623 krb5_error_code 1624 krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ) 1625 krb5_context context; 1626 krb5_db_entry *entry; 1627 krb5_timestamp mod_date; 1628 krb5_const_principal mod_princ; 1629 { 1630 krb5_tl_data tl_data; 1631 1632 krb5_error_code retval = 0; 1633 krb5_octet *nextloc = 0; 1634 char *unparse_mod_princ = 0; 1635 unsigned int unparse_mod_princ_size; 1636 1637 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ))) 1638 return (retval); 1639 1640 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; 1641 1642 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) 1643 == NULL) { 1644 free(unparse_mod_princ); 1645 return (ENOMEM); 1646 } 1647 1648 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1649 tl_data.tl_data_length = unparse_mod_princ_size + 4; 1650 tl_data.tl_data_contents = nextloc; 1651 1652 /* Mod Date */ 1653 krb5_kdb_encode_int32(mod_date, nextloc); 1654 1655 /* Mod Princ */ 1656 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size); 1657 1658 retval = krb5_dbe_update_tl_data(context, entry, &tl_data); 1659 1660 free(unparse_mod_princ); 1661 free(nextloc); 1662 1663 return (retval); 1664 } 1665 1666 krb5_error_code 1667 krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ) 1668 krb5_context context; 1669 krb5_db_entry *entry; 1670 krb5_timestamp *mod_time; 1671 krb5_principal *mod_princ; 1672 { 1673 krb5_tl_data tl_data; 1674 krb5_error_code code; 1675 1676 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1677 1678 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1679 return (code); 1680 1681 if ((tl_data.tl_data_length < 5) || 1682 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0')) 1683 return (KRB5_KDB_TRUNCATED_RECORD); 1684 1685 /* Mod Date */ 1686 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); 1687 1688 /* Mod Princ */ 1689 if ((code = krb5_parse_name(context, 1690 (const char *) (tl_data.tl_data_contents + 4), 1691 mod_princ))) 1692 return (code); 1693 1694 return (0); 1695 } 1696 1697 krb5_error_code 1698 krb5_dbe_update_last_pwd_change(context, entry, stamp) 1699 krb5_context context; 1700 krb5_db_entry *entry; 1701 krb5_timestamp stamp; 1702 { 1703 krb5_tl_data tl_data; 1704 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 1705 1706 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1707 tl_data.tl_data_length = sizeof(buf); 1708 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 1709 tl_data.tl_data_contents = buf; 1710 1711 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 1712 } 1713 1714 krb5_error_code 1715 krb5_dbe_update_tl_data(context, entry, new_tl_data) 1716 krb5_context context; 1717 krb5_db_entry *entry; 1718 krb5_tl_data *new_tl_data; 1719 { 1720 krb5_tl_data *tl_data = NULL; 1721 krb5_octet *tmp; 1722 1723 /* copy the new data first, so we can fail cleanly if malloc() 1724 * fails */ 1725 if ((tmp = 1726 (krb5_octet *) krb5_db_alloc(context, NULL, 1727 new_tl_data->tl_data_length)) == NULL) 1728 return (ENOMEM); 1729 1730 /* Find an existing entry of the specified type and point at 1731 * it, or NULL if not found */ 1732 1733 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */ 1734 for (tl_data = entry->tl_data; tl_data; 1735 tl_data = tl_data->tl_data_next) 1736 if (tl_data->tl_data_type == new_tl_data->tl_data_type) 1737 break; 1738 } 1739 1740 /* if necessary, chain a new record in the beginning and point at it */ 1741 1742 if (!tl_data) { 1743 if ((tl_data = 1744 (krb5_tl_data *) krb5_db_alloc(context, NULL, 1745 sizeof(krb5_tl_data))) 1746 == NULL) { 1747 free(tmp); 1748 return (ENOMEM); 1749 } 1750 memset(tl_data, 0, sizeof(krb5_tl_data)); 1751 tl_data->tl_data_next = entry->tl_data; 1752 entry->tl_data = tl_data; 1753 entry->n_tl_data++; 1754 } 1755 1756 /* fill in the record */ 1757 1758 if (tl_data->tl_data_contents) 1759 krb5_db_free(context, tl_data->tl_data_contents); 1760 1761 tl_data->tl_data_type = new_tl_data->tl_data_type; 1762 tl_data->tl_data_length = new_tl_data->tl_data_length; 1763 tl_data->tl_data_contents = tmp; 1764 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); 1765 1766 return (0); 1767 } 1768 1769 /* change password functions */ 1770 krb5_error_code 1771 krb5_dbe_cpw(krb5_context kcontext, 1772 krb5_keyblock * master_key, 1773 krb5_key_salt_tuple * ks_tuple, 1774 int ks_tuple_count, 1775 char *passwd, 1776 int new_kvno, krb5_boolean keepold, krb5_db_entry * db_entry) 1777 { 1778 krb5_error_code status = 0; 1779 kdb5_dal_handle *dal_handle; 1780 1781 if (kcontext->db_context == NULL) { 1782 status = kdb_setup_lib_handle(kcontext); 1783 if (status) { 1784 goto clean_n_exit; 1785 } 1786 } 1787 1788 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1789 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1790 if (status) { 1791 goto clean_n_exit; 1792 } 1793 1794 status = dal_handle->lib_handle->vftabl.db_change_pwd(kcontext, 1795 master_key, 1796 ks_tuple, 1797 ks_tuple_count, 1798 passwd, 1799 new_kvno, 1800 keepold, db_entry); 1801 get_errmsg(kcontext, status); 1802 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1803 1804 clean_n_exit: 1805 return status; 1806 } 1807 1808 /* policy management functions */ 1809 krb5_error_code 1810 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy) 1811 { 1812 krb5_error_code status = 0; 1813 kdb5_dal_handle *dal_handle; 1814 1815 if (kcontext->db_context == NULL) { 1816 status = kdb_setup_lib_handle(kcontext); 1817 if (status) { 1818 goto clean_n_exit; 1819 } 1820 } 1821 1822 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1823 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1824 if (status) { 1825 goto clean_n_exit; 1826 } 1827 1828 status = dal_handle->lib_handle->vftabl.db_create_policy(kcontext, policy); 1829 get_errmsg(kcontext, status); 1830 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1831 1832 clean_n_exit: 1833 return status; 1834 } 1835 1836 krb5_error_code 1837 krb5_db_get_policy(krb5_context kcontext, char *name, 1838 osa_policy_ent_t * policy, int *cnt) 1839 { 1840 krb5_error_code status = 0; 1841 kdb5_dal_handle *dal_handle; 1842 1843 if (kcontext->db_context == NULL) { 1844 status = kdb_setup_lib_handle(kcontext); 1845 if (status) { 1846 goto clean_n_exit; 1847 } 1848 } 1849 1850 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1851 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1852 if (status) { 1853 goto clean_n_exit; 1854 } 1855 1856 status = 1857 dal_handle->lib_handle->vftabl.db_get_policy(kcontext, name, policy, 1858 cnt); 1859 get_errmsg(kcontext, status); 1860 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1861 1862 clean_n_exit: 1863 return status; 1864 } 1865 1866 krb5_error_code 1867 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy) 1868 { 1869 krb5_error_code status = 0; 1870 kdb5_dal_handle *dal_handle; 1871 1872 if (kcontext->db_context == NULL) { 1873 status = kdb_setup_lib_handle(kcontext); 1874 if (status) { 1875 goto clean_n_exit; 1876 } 1877 } 1878 1879 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1880 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1881 if (status) { 1882 goto clean_n_exit; 1883 } 1884 1885 status = dal_handle->lib_handle->vftabl.db_put_policy(kcontext, policy); 1886 get_errmsg(kcontext, status); 1887 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1888 1889 clean_n_exit: 1890 return status; 1891 } 1892 1893 krb5_error_code 1894 krb5_db_iter_policy(krb5_context kcontext, char *match_entry, 1895 osa_adb_iter_policy_func func, void *data) 1896 { 1897 krb5_error_code status = 0; 1898 kdb5_dal_handle *dal_handle; 1899 1900 if (kcontext->db_context == NULL) { 1901 status = kdb_setup_lib_handle(kcontext); 1902 if (status) { 1903 goto clean_n_exit; 1904 } 1905 } 1906 1907 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1908 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1909 if (status) { 1910 goto clean_n_exit; 1911 } 1912 1913 status = 1914 dal_handle->lib_handle->vftabl.db_iter_policy(kcontext, match_entry, 1915 func, data); 1916 get_errmsg(kcontext, status); 1917 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1918 1919 clean_n_exit: 1920 return status; 1921 } 1922 1923 krb5_error_code 1924 krb5_db_delete_policy(krb5_context kcontext, char *policy) 1925 { 1926 krb5_error_code status = 0; 1927 kdb5_dal_handle *dal_handle; 1928 1929 if (kcontext->db_context == NULL) { 1930 status = kdb_setup_lib_handle(kcontext); 1931 if (status) { 1932 goto clean_n_exit; 1933 } 1934 } 1935 1936 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1937 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1938 if (status) { 1939 goto clean_n_exit; 1940 } 1941 1942 status = dal_handle->lib_handle->vftabl.db_delete_policy(kcontext, policy); 1943 get_errmsg(kcontext, status); 1944 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1945 1946 clean_n_exit: 1947 return status; 1948 } 1949 1950 void 1951 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy) 1952 { 1953 krb5_error_code status = 0; 1954 kdb5_dal_handle *dal_handle; 1955 1956 if (kcontext->db_context == NULL) { 1957 status = kdb_setup_lib_handle(kcontext); 1958 if (status) { 1959 goto clean_n_exit; 1960 } 1961 } 1962 1963 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1964 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1965 if (status) { 1966 goto clean_n_exit; 1967 } 1968 1969 dal_handle->lib_handle->vftabl.db_free_policy(kcontext, policy); 1970 get_errmsg(kcontext, status); 1971 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1972 1973 clean_n_exit: 1974 return; 1975 } 1976 1977 krb5_error_code 1978 krb5_db_promote(krb5_context kcontext, char **db_args) 1979 { 1980 krb5_error_code status = 0; 1981 char *section = NULL; 1982 kdb5_dal_handle *dal_handle; 1983 1984 section = kdb_get_conf_section(kcontext); 1985 if (section == NULL) { 1986 status = KRB5_KDB_SERVER_INTERNAL_ERR; 1987 krb5_set_error_message (kcontext, status, 1988 gettext("unable to determine configuration section for realm %s\n"), 1989 kcontext->default_realm); 1990 goto clean_n_exit; 1991 } 1992 1993 if (kcontext->db_context == NULL) { 1994 status = kdb_setup_lib_handle(kcontext); 1995 if (status) { 1996 goto clean_n_exit; 1997 } 1998 } 1999 2000 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 2001 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 2002 if (status) { 2003 goto clean_n_exit; 2004 } 2005 2006 status = 2007 dal_handle->lib_handle->vftabl.promote_db(kcontext, section, db_args); 2008 get_errmsg(kcontext, status); 2009 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 2010 2011 clean_n_exit: 2012 if (section) 2013 free(section); 2014 return status; 2015 } 2016 2017 /* 2018 * Solaris Kerberos: support for iprop 2019 * 2020 * Not all KDB plugins support iprop. 2021 * 2022 * sets iprop_supported to 1 if iprop supportd, 0 otherwise. 2023 */ 2024 krb5_error_code 2025 krb5_db_supports_iprop(krb5_context kcontext, int *iprop_supported) 2026 { 2027 krb5_error_code status = 0; 2028 kdb5_dal_handle *dal_handle; 2029 2030 if (kcontext->db_context == NULL) { 2031 status = kdb_setup_lib_handle(kcontext); 2032 if (status) { 2033 goto clean_n_exit; 2034 } 2035 } 2036 2037 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 2038 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 2039 if (status) { 2040 goto clean_n_exit; 2041 } 2042 2043 *iprop_supported = dal_handle->lib_handle->vftabl.iprop_supported; 2044 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 2045 2046 clean_n_exit: 2047 return status; 2048 } 2049