1 /* 2 * Copyright 2007 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 { 1108 krb5_error_code status = 0; 1109 kdb5_dal_handle *dal_handle; 1110 1111 if (kcontext->db_context == NULL) { 1112 status = kdb_setup_lib_handle(kcontext); 1113 if (status) { 1114 goto clean_n_exit; 1115 } 1116 } 1117 1118 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1119 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1120 if (status) { 1121 goto clean_n_exit; 1122 } 1123 1124 status = dal_handle->lib_handle->vftabl.db_iterate(kcontext, 1125 match_entry, 1126 func, func_arg); 1127 get_errmsg(kcontext, status); 1128 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1129 1130 clean_n_exit: 1131 return status; 1132 } 1133 1134 krb5_error_code 1135 krb5_supported_realms(krb5_context kcontext, char **realms) 1136 { 1137 krb5_error_code status = 0; 1138 kdb5_dal_handle *dal_handle; 1139 1140 if (kcontext->db_context == NULL) { 1141 status = kdb_setup_lib_handle(kcontext); 1142 if (status) { 1143 goto clean_n_exit; 1144 } 1145 } 1146 1147 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1148 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1149 if (status) { 1150 goto clean_n_exit; 1151 } 1152 1153 status = 1154 dal_handle->lib_handle->vftabl.db_supported_realms(kcontext, realms); 1155 get_errmsg(kcontext, status); 1156 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1157 1158 clean_n_exit: 1159 return status; 1160 } 1161 1162 krb5_error_code 1163 krb5_free_supported_realms(krb5_context kcontext, char **realms) 1164 { 1165 krb5_error_code status = 0; 1166 kdb5_dal_handle *dal_handle; 1167 1168 if (kcontext->db_context == NULL) { 1169 status = kdb_setup_lib_handle(kcontext); 1170 if (status) { 1171 goto clean_n_exit; 1172 } 1173 } 1174 1175 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1176 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1177 if (status) { 1178 goto clean_n_exit; 1179 } 1180 1181 status = 1182 dal_handle->lib_handle->vftabl.db_free_supported_realms(kcontext, 1183 realms); 1184 get_errmsg(kcontext, status); 1185 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1186 1187 clean_n_exit: 1188 return status; 1189 } 1190 1191 krb5_error_code 1192 krb5_db_set_master_key_ext(krb5_context kcontext, 1193 char *pwd, krb5_keyblock * key) 1194 { 1195 krb5_error_code status = 0; 1196 kdb5_dal_handle *dal_handle; 1197 1198 if (kcontext->db_context == NULL) { 1199 status = kdb_setup_lib_handle(kcontext); 1200 if (status) { 1201 goto clean_n_exit; 1202 } 1203 } 1204 1205 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1206 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1207 if (status) { 1208 goto clean_n_exit; 1209 } 1210 1211 status = dal_handle->lib_handle->vftabl.set_master_key(kcontext, pwd, key); 1212 get_errmsg(kcontext, status); 1213 1214 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1215 1216 clean_n_exit: 1217 return status; 1218 } 1219 1220 krb5_error_code 1221 krb5_db_set_mkey(krb5_context context, krb5_keyblock * key) 1222 { 1223 return krb5_db_set_master_key_ext(context, NULL, key); 1224 } 1225 1226 krb5_error_code 1227 krb5_db_get_mkey(krb5_context kcontext, krb5_keyblock ** key) 1228 { 1229 krb5_error_code status = 0; 1230 kdb5_dal_handle *dal_handle; 1231 1232 if (kcontext->db_context == NULL) { 1233 status = kdb_setup_lib_handle(kcontext); 1234 if (status) { 1235 goto clean_n_exit; 1236 } 1237 } 1238 1239 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1240 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1241 if (status) { 1242 goto clean_n_exit; 1243 } 1244 1245 /* Lets use temp key and copy it later to avoid memory problems 1246 when freed by the caller. */ 1247 status = dal_handle->lib_handle->vftabl.get_master_key(kcontext, key); 1248 get_errmsg(kcontext, status); 1249 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1250 1251 clean_n_exit: 1252 return status; 1253 } 1254 1255 krb5_error_code 1256 krb5_db_store_master_key(krb5_context kcontext, 1257 char *db_arg, 1258 krb5_principal mname, 1259 krb5_keyblock * key, char *master_pwd) 1260 { 1261 krb5_error_code status = 0; 1262 kdb5_dal_handle *dal_handle; 1263 1264 if (kcontext->db_context == NULL) { 1265 status = kdb_setup_lib_handle(kcontext); 1266 if (status) { 1267 goto clean_n_exit; 1268 } 1269 } 1270 1271 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1272 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1273 if (status) { 1274 goto clean_n_exit; 1275 } 1276 1277 status = dal_handle->lib_handle->vftabl.store_master_key(kcontext, 1278 db_arg, 1279 mname, 1280 key, master_pwd); 1281 get_errmsg(kcontext, status); 1282 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1283 1284 clean_n_exit: 1285 return status; 1286 } 1287 1288 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1; 1289 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2; 1290 1291 krb5_error_code 1292 krb5_db_fetch_mkey(krb5_context context, 1293 krb5_principal mname, 1294 krb5_enctype etype, 1295 krb5_boolean fromkeyboard, 1296 krb5_boolean twice, 1297 char *db_args, krb5_data * salt, krb5_keyblock * key) 1298 { 1299 krb5_error_code retval; 1300 char password[BUFSIZ]; 1301 krb5_data pwd; 1302 unsigned int size = sizeof(password); 1303 int kvno; 1304 krb5_keyblock tmp_key; 1305 1306 memset(&tmp_key, 0, sizeof(tmp_key)); 1307 1308 if (fromkeyboard) { 1309 krb5_data scratch; 1310 1311 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1, 1312 twice ? krb5_mkey_pwd_prompt2 : 0, 1313 password, &size))) { 1314 goto clean_n_exit; 1315 } 1316 1317 pwd.data = password; 1318 pwd.length = size; 1319 if (!salt) { 1320 retval = krb5_principal2salt(context, mname, &scratch); 1321 if (retval) 1322 goto clean_n_exit; 1323 } 1324 retval = 1325 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch, 1326 key); 1327 1328 if (!salt) 1329 krb5_xfree(scratch.data); 1330 memset(password, 0, sizeof(password)); /* erase it */ 1331 1332 } else { 1333 kdb5_dal_handle *dal_handle; 1334 1335 if (context->db_context == NULL) { 1336 retval = kdb_setup_lib_handle(context); 1337 if (retval) { 1338 goto clean_n_exit; 1339 } 1340 } 1341 1342 dal_handle = (kdb5_dal_handle *) context->db_context; 1343 retval = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1344 if (retval) { 1345 goto clean_n_exit; 1346 } 1347 #if 0 /************** Begin IFDEF'ed OUT *******************************/ 1348 /* Orig MIT */ 1349 tmp_key.enctype = key->enctype; 1350 #else 1351 /* Solaris Kerberos: need to use etype */ 1352 tmp_key.enctype = etype; 1353 #endif /**************** END IFDEF'ed OUT *******************************/ 1354 retval = dal_handle->lib_handle->vftabl.fetch_master_key(context, 1355 mname, 1356 &tmp_key, 1357 &kvno, 1358 db_args); 1359 get_errmsg(context, retval); 1360 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1361 1362 if (retval) { 1363 goto clean_n_exit; 1364 } 1365 1366 key->contents = malloc(tmp_key.length); 1367 if (key->contents == NULL) { 1368 retval = ENOMEM; 1369 goto clean_n_exit; 1370 } 1371 1372 key->magic = tmp_key.magic; 1373 key->enctype = tmp_key.enctype; 1374 key->length = tmp_key.length; 1375 memcpy(key->contents, tmp_key.contents, tmp_key.length); 1376 } 1377 1378 clean_n_exit: 1379 if (tmp_key.contents) { 1380 memset(tmp_key.contents, 0, tmp_key.length); 1381 krb5_db_free(context, tmp_key.contents); 1382 } 1383 return retval; 1384 } 1385 1386 krb5_error_code 1387 krb5_db_verify_master_key(krb5_context kcontext, 1388 krb5_principal mprinc, krb5_keyblock * mkey) 1389 { 1390 krb5_error_code status = 0; 1391 kdb5_dal_handle *dal_handle; 1392 1393 if (kcontext->db_context == NULL) { 1394 status = kdb_setup_lib_handle(kcontext); 1395 if (status) { 1396 goto clean_n_exit; 1397 } 1398 } 1399 1400 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1401 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1402 if (status) { 1403 goto clean_n_exit; 1404 } 1405 1406 status = dal_handle->lib_handle->vftabl.verify_master_key(kcontext, 1407 mprinc, mkey); 1408 get_errmsg(kcontext, status); 1409 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1410 1411 clean_n_exit: 1412 return status; 1413 } 1414 1415 void * 1416 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size) 1417 { 1418 krb5_error_code status; 1419 kdb5_dal_handle *dal_handle; 1420 void *new_ptr = NULL; 1421 1422 if (kcontext->db_context == NULL) { 1423 status = kdb_setup_lib_handle(kcontext); 1424 if (status) { 1425 goto clean_n_exit; 1426 } 1427 } 1428 1429 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1430 1431 new_ptr = dal_handle->lib_handle->vftabl.db_alloc(kcontext, ptr, size); 1432 1433 clean_n_exit: 1434 return new_ptr; 1435 } 1436 1437 void 1438 krb5_db_free(krb5_context kcontext, void *ptr) 1439 { 1440 krb5_error_code status; 1441 kdb5_dal_handle *dal_handle; 1442 1443 if (kcontext->db_context == NULL) { 1444 status = kdb_setup_lib_handle(kcontext); 1445 if (status) { 1446 goto clean_n_exit; 1447 } 1448 } 1449 1450 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1451 1452 dal_handle->lib_handle->vftabl.db_free(kcontext, ptr); 1453 1454 clean_n_exit: 1455 return; 1456 } 1457 1458 /* has to be modified */ 1459 1460 krb5_error_code 1461 krb5_dbe_find_enctype(krb5_context kcontext, 1462 krb5_db_entry * dbentp, 1463 krb5_int32 ktype, 1464 krb5_int32 stype, 1465 krb5_int32 kvno, krb5_key_data ** kdatap) 1466 { 1467 krb5_int32 start = 0; 1468 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype, 1469 kvno, kdatap); 1470 } 1471 1472 krb5_error_code 1473 krb5_dbe_search_enctype(krb5_context kcontext, 1474 krb5_db_entry * dbentp, 1475 krb5_int32 * start, 1476 krb5_int32 ktype, 1477 krb5_int32 stype, 1478 krb5_int32 kvno, krb5_key_data ** kdatap) 1479 { 1480 krb5_error_code status = 0; 1481 kdb5_dal_handle *dal_handle; 1482 1483 if (kcontext->db_context == NULL) { 1484 status = kdb_setup_lib_handle(kcontext); 1485 if (status) { 1486 goto clean_n_exit; 1487 } 1488 } 1489 1490 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1491 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1492 if (status) { 1493 goto clean_n_exit; 1494 } 1495 1496 status = dal_handle->lib_handle->vftabl.dbe_search_enctype(kcontext, 1497 dbentp, 1498 start, 1499 ktype, 1500 stype, 1501 kvno, kdatap); 1502 get_errmsg(kcontext, status); 1503 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1504 1505 clean_n_exit: 1506 return status; 1507 } 1508 1509 #define REALM_SEP_STRING "@" 1510 1511 krb5_error_code 1512 krb5_db_setup_mkey_name(krb5_context context, 1513 const char *keyname, 1514 const char *realm, 1515 char **fullname, krb5_principal * principal) 1516 { 1517 krb5_error_code retval; 1518 size_t keylen; 1519 size_t rlen = strlen(realm); 1520 char *fname; 1521 1522 if (!keyname) 1523 keyname = KRB5_KDB_M_NAME; /* XXX external? */ 1524 1525 keylen = strlen(keyname); 1526 1527 fname = malloc(keylen + rlen + strlen(REALM_SEP_STRING) + 1); 1528 if (!fname) 1529 return ENOMEM; 1530 1531 strcpy(fname, keyname); 1532 (void)strcat(fname, REALM_SEP_STRING); 1533 (void)strcat(fname, realm); 1534 1535 if ((retval = krb5_parse_name(context, fname, principal))) 1536 return retval; 1537 if (fullname) 1538 *fullname = fname; 1539 else 1540 free(fname); 1541 return 0; 1542 } 1543 1544 krb5_error_code 1545 krb5_dbe_lookup_last_pwd_change(context, entry, stamp) 1546 krb5_context context; 1547 krb5_db_entry *entry; 1548 krb5_timestamp *stamp; 1549 { 1550 krb5_tl_data tl_data; 1551 krb5_error_code code; 1552 krb5_int32 tmp; 1553 1554 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1555 1556 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1557 return (code); 1558 1559 if (tl_data.tl_data_length != 4) { 1560 *stamp = 0; 1561 return (0); 1562 } 1563 1564 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); 1565 1566 *stamp = (krb5_timestamp) tmp; 1567 1568 return (0); 1569 } 1570 1571 /*ARGSUSED*/ 1572 krb5_error_code 1573 krb5_dbe_lookup_tl_data(context, entry, ret_tl_data) 1574 krb5_context context; 1575 krb5_db_entry *entry; 1576 krb5_tl_data *ret_tl_data; 1577 { 1578 krb5_tl_data *tl_data; 1579 1580 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { 1581 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { 1582 *ret_tl_data = *tl_data; 1583 return (0); 1584 } 1585 } 1586 1587 /* if the requested record isn't found, return zero bytes. 1588 * if it ever means something to have a zero-length tl_data, 1589 * this code and its callers will have to be changed */ 1590 1591 ret_tl_data->tl_data_length = 0; 1592 ret_tl_data->tl_data_contents = NULL; 1593 return (0); 1594 } 1595 1596 krb5_error_code 1597 krb5_dbe_create_key_data(context, entry) 1598 krb5_context context; 1599 krb5_db_entry *entry; 1600 { 1601 if ((entry->key_data = 1602 (krb5_key_data *) krb5_db_alloc(context, entry->key_data, 1603 (sizeof(krb5_key_data) * 1604 (entry->n_key_data + 1)))) == NULL) 1605 return (ENOMEM); 1606 1607 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data)); 1608 entry->n_key_data++; 1609 1610 return 0; 1611 } 1612 1613 krb5_error_code 1614 krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ) 1615 krb5_context context; 1616 krb5_db_entry *entry; 1617 krb5_timestamp mod_date; 1618 krb5_const_principal mod_princ; 1619 { 1620 krb5_tl_data tl_data; 1621 1622 krb5_error_code retval = 0; 1623 krb5_octet *nextloc = 0; 1624 char *unparse_mod_princ = 0; 1625 unsigned int unparse_mod_princ_size; 1626 1627 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ))) 1628 return (retval); 1629 1630 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1; 1631 1632 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) 1633 == NULL) { 1634 free(unparse_mod_princ); 1635 return (ENOMEM); 1636 } 1637 1638 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1639 tl_data.tl_data_length = unparse_mod_princ_size + 4; 1640 tl_data.tl_data_contents = nextloc; 1641 1642 /* Mod Date */ 1643 krb5_kdb_encode_int32(mod_date, nextloc); 1644 1645 /* Mod Princ */ 1646 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size); 1647 1648 retval = krb5_dbe_update_tl_data(context, entry, &tl_data); 1649 1650 free(unparse_mod_princ); 1651 free(nextloc); 1652 1653 return (retval); 1654 } 1655 1656 krb5_error_code 1657 krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ) 1658 krb5_context context; 1659 krb5_db_entry *entry; 1660 krb5_timestamp *mod_time; 1661 krb5_principal *mod_princ; 1662 { 1663 krb5_tl_data tl_data; 1664 krb5_error_code code; 1665 1666 tl_data.tl_data_type = KRB5_TL_MOD_PRINC; 1667 1668 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data))) 1669 return (code); 1670 1671 if ((tl_data.tl_data_length < 5) || 1672 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0')) 1673 return (KRB5_KDB_TRUNCATED_RECORD); 1674 1675 /* Mod Date */ 1676 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); 1677 1678 /* Mod Princ */ 1679 if ((code = krb5_parse_name(context, 1680 (const char *) (tl_data.tl_data_contents + 4), 1681 mod_princ))) 1682 return (code); 1683 1684 return (0); 1685 } 1686 1687 krb5_error_code 1688 krb5_dbe_update_last_pwd_change(context, entry, stamp) 1689 krb5_context context; 1690 krb5_db_entry *entry; 1691 krb5_timestamp stamp; 1692 { 1693 krb5_tl_data tl_data; 1694 krb5_octet buf[4]; /* this is the encoded size of an int32 */ 1695 1696 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; 1697 tl_data.tl_data_length = sizeof(buf); 1698 krb5_kdb_encode_int32((krb5_int32) stamp, buf); 1699 tl_data.tl_data_contents = buf; 1700 1701 return (krb5_dbe_update_tl_data(context, entry, &tl_data)); 1702 } 1703 1704 krb5_error_code 1705 krb5_dbe_update_tl_data(context, entry, new_tl_data) 1706 krb5_context context; 1707 krb5_db_entry *entry; 1708 krb5_tl_data *new_tl_data; 1709 { 1710 krb5_tl_data *tl_data = NULL; 1711 krb5_octet *tmp; 1712 1713 /* copy the new data first, so we can fail cleanly if malloc() 1714 * fails */ 1715 if ((tmp = 1716 (krb5_octet *) krb5_db_alloc(context, NULL, 1717 new_tl_data->tl_data_length)) == NULL) 1718 return (ENOMEM); 1719 1720 /* Find an existing entry of the specified type and point at 1721 * it, or NULL if not found */ 1722 1723 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */ 1724 for (tl_data = entry->tl_data; tl_data; 1725 tl_data = tl_data->tl_data_next) 1726 if (tl_data->tl_data_type == new_tl_data->tl_data_type) 1727 break; 1728 } 1729 1730 /* if necessary, chain a new record in the beginning and point at it */ 1731 1732 if (!tl_data) { 1733 if ((tl_data = 1734 (krb5_tl_data *) krb5_db_alloc(context, NULL, 1735 sizeof(krb5_tl_data))) 1736 == NULL) { 1737 free(tmp); 1738 return (ENOMEM); 1739 } 1740 memset(tl_data, 0, sizeof(krb5_tl_data)); 1741 tl_data->tl_data_next = entry->tl_data; 1742 entry->tl_data = tl_data; 1743 entry->n_tl_data++; 1744 } 1745 1746 /* fill in the record */ 1747 1748 if (tl_data->tl_data_contents) 1749 krb5_db_free(context, tl_data->tl_data_contents); 1750 1751 tl_data->tl_data_type = new_tl_data->tl_data_type; 1752 tl_data->tl_data_length = new_tl_data->tl_data_length; 1753 tl_data->tl_data_contents = tmp; 1754 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); 1755 1756 return (0); 1757 } 1758 1759 /* change password functions */ 1760 krb5_error_code 1761 krb5_dbe_cpw(krb5_context kcontext, 1762 krb5_keyblock * master_key, 1763 krb5_key_salt_tuple * ks_tuple, 1764 int ks_tuple_count, 1765 char *passwd, 1766 int new_kvno, krb5_boolean keepold, krb5_db_entry * db_entry) 1767 { 1768 krb5_error_code status = 0; 1769 kdb5_dal_handle *dal_handle; 1770 1771 if (kcontext->db_context == NULL) { 1772 status = kdb_setup_lib_handle(kcontext); 1773 if (status) { 1774 goto clean_n_exit; 1775 } 1776 } 1777 1778 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1779 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1780 if (status) { 1781 goto clean_n_exit; 1782 } 1783 1784 status = dal_handle->lib_handle->vftabl.db_change_pwd(kcontext, 1785 master_key, 1786 ks_tuple, 1787 ks_tuple_count, 1788 passwd, 1789 new_kvno, 1790 keepold, db_entry); 1791 get_errmsg(kcontext, status); 1792 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1793 1794 clean_n_exit: 1795 return status; 1796 } 1797 1798 /* policy management functions */ 1799 krb5_error_code 1800 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy) 1801 { 1802 krb5_error_code status = 0; 1803 kdb5_dal_handle *dal_handle; 1804 1805 if (kcontext->db_context == NULL) { 1806 status = kdb_setup_lib_handle(kcontext); 1807 if (status) { 1808 goto clean_n_exit; 1809 } 1810 } 1811 1812 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1813 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1814 if (status) { 1815 goto clean_n_exit; 1816 } 1817 1818 status = dal_handle->lib_handle->vftabl.db_create_policy(kcontext, policy); 1819 get_errmsg(kcontext, status); 1820 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1821 1822 clean_n_exit: 1823 return status; 1824 } 1825 1826 krb5_error_code 1827 krb5_db_get_policy(krb5_context kcontext, char *name, 1828 osa_policy_ent_t * policy, int *cnt) 1829 { 1830 krb5_error_code status = 0; 1831 kdb5_dal_handle *dal_handle; 1832 1833 if (kcontext->db_context == NULL) { 1834 status = kdb_setup_lib_handle(kcontext); 1835 if (status) { 1836 goto clean_n_exit; 1837 } 1838 } 1839 1840 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1841 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1842 if (status) { 1843 goto clean_n_exit; 1844 } 1845 1846 status = 1847 dal_handle->lib_handle->vftabl.db_get_policy(kcontext, name, policy, 1848 cnt); 1849 get_errmsg(kcontext, status); 1850 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1851 1852 clean_n_exit: 1853 return status; 1854 } 1855 1856 krb5_error_code 1857 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy) 1858 { 1859 krb5_error_code status = 0; 1860 kdb5_dal_handle *dal_handle; 1861 1862 if (kcontext->db_context == NULL) { 1863 status = kdb_setup_lib_handle(kcontext); 1864 if (status) { 1865 goto clean_n_exit; 1866 } 1867 } 1868 1869 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1870 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1871 if (status) { 1872 goto clean_n_exit; 1873 } 1874 1875 status = dal_handle->lib_handle->vftabl.db_put_policy(kcontext, policy); 1876 get_errmsg(kcontext, status); 1877 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1878 1879 clean_n_exit: 1880 return status; 1881 } 1882 1883 krb5_error_code 1884 krb5_db_iter_policy(krb5_context kcontext, char *match_entry, 1885 osa_adb_iter_policy_func func, void *data) 1886 { 1887 krb5_error_code status = 0; 1888 kdb5_dal_handle *dal_handle; 1889 1890 if (kcontext->db_context == NULL) { 1891 status = kdb_setup_lib_handle(kcontext); 1892 if (status) { 1893 goto clean_n_exit; 1894 } 1895 } 1896 1897 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1898 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1899 if (status) { 1900 goto clean_n_exit; 1901 } 1902 1903 status = 1904 dal_handle->lib_handle->vftabl.db_iter_policy(kcontext, match_entry, 1905 func, data); 1906 get_errmsg(kcontext, status); 1907 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1908 1909 clean_n_exit: 1910 return status; 1911 } 1912 1913 krb5_error_code 1914 krb5_db_delete_policy(krb5_context kcontext, char *policy) 1915 { 1916 krb5_error_code status = 0; 1917 kdb5_dal_handle *dal_handle; 1918 1919 if (kcontext->db_context == NULL) { 1920 status = kdb_setup_lib_handle(kcontext); 1921 if (status) { 1922 goto clean_n_exit; 1923 } 1924 } 1925 1926 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1927 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1928 if (status) { 1929 goto clean_n_exit; 1930 } 1931 1932 status = dal_handle->lib_handle->vftabl.db_delete_policy(kcontext, policy); 1933 get_errmsg(kcontext, status); 1934 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1935 1936 clean_n_exit: 1937 return status; 1938 } 1939 1940 void 1941 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy) 1942 { 1943 krb5_error_code status = 0; 1944 kdb5_dal_handle *dal_handle; 1945 1946 if (kcontext->db_context == NULL) { 1947 status = kdb_setup_lib_handle(kcontext); 1948 if (status) { 1949 goto clean_n_exit; 1950 } 1951 } 1952 1953 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1954 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1955 if (status) { 1956 goto clean_n_exit; 1957 } 1958 1959 dal_handle->lib_handle->vftabl.db_free_policy(kcontext, policy); 1960 get_errmsg(kcontext, status); 1961 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 1962 1963 clean_n_exit: 1964 return; 1965 } 1966 1967 krb5_error_code 1968 krb5_db_promote(krb5_context kcontext, char **db_args) 1969 { 1970 krb5_error_code status = 0; 1971 char *section = NULL; 1972 kdb5_dal_handle *dal_handle; 1973 1974 section = kdb_get_conf_section(kcontext); 1975 if (section == NULL) { 1976 status = KRB5_KDB_SERVER_INTERNAL_ERR; 1977 krb5_set_error_message (kcontext, status, 1978 gettext("unable to determine configuration section for realm %s\n"), 1979 kcontext->default_realm); 1980 goto clean_n_exit; 1981 } 1982 1983 if (kcontext->db_context == NULL) { 1984 status = kdb_setup_lib_handle(kcontext); 1985 if (status) { 1986 goto clean_n_exit; 1987 } 1988 } 1989 1990 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 1991 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 1992 if (status) { 1993 goto clean_n_exit; 1994 } 1995 1996 status = 1997 dal_handle->lib_handle->vftabl.promote_db(kcontext, section, db_args); 1998 get_errmsg(kcontext, status); 1999 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 2000 2001 clean_n_exit: 2002 if (section) 2003 free(section); 2004 return status; 2005 } 2006 2007 /* 2008 * Solaris Kerberos: support for iprop 2009 * 2010 * Not all KDB plugins support iprop. 2011 * 2012 * sets iprop_supported to 1 if iprop supportd, 0 otherwise. 2013 */ 2014 krb5_error_code 2015 krb5_db_supports_iprop(krb5_context kcontext, int *iprop_supported) 2016 { 2017 krb5_error_code status = 0; 2018 kdb5_dal_handle *dal_handle; 2019 2020 if (kcontext->db_context == NULL) { 2021 status = kdb_setup_lib_handle(kcontext); 2022 if (status) { 2023 goto clean_n_exit; 2024 } 2025 } 2026 2027 dal_handle = (kdb5_dal_handle *) kcontext->db_context; 2028 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE); 2029 if (status) { 2030 goto clean_n_exit; 2031 } 2032 2033 *iprop_supported = dal_handle->lib_handle->vftabl.iprop_supported; 2034 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE); 2035 2036 clean_n_exit: 2037 return status; 2038 } 2039