1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * prof_solaris.c: 28 * Abstracted contract private interfaces for configuring krb5.conf(4). 29 */ 30 31 #include <ctype.h> 32 #include "prof_int.h" 33 #include "k5-int.h" 34 35 errcode_t 36 __profile_iter_name_value(profile_t profile, char *section, char *key, 37 char ***retvals) 38 { 39 const char *hierarchy[4]; 40 errcode_t code, code2; 41 char *name = NULL, *value = NULL, **ret_values = NULL; 42 void *state = NULL; 43 struct profile_string_list values; 44 boolean_t found = FALSE; 45 46 hierarchy[0] = section; 47 hierarchy[1] = NULL; 48 49 if (code = init_list(&values)) 50 return (code); 51 52 code = profile_iterator_create(profile, hierarchy, 53 PROFILE_ITER_LIST_SECTION, &state); 54 while (code == 0) { 55 code = profile_iterator(&state, &name, &value); 56 if (code == 0 && name != NULL) { 57 if ((key == NULL) || (strcmp(value, key) == 0)) { 58 code2 = add_to_list(&values, name); 59 if (code2 != 0) { 60 end_list(&values, &ret_values); 61 profile_free_list(ret_values); 62 code2 = code; 63 goto cleanup; 64 } 65 found = TRUE; 66 } 67 } 68 if (name != NULL) { 69 profile_release_string(name); 70 name = NULL; 71 } 72 if (value != NULL) { 73 profile_release_string(value); 74 value = NULL; 75 } 76 } 77 code = 0; 78 if (found == TRUE) 79 end_list(&values, &ret_values); 80 81 cleanup: 82 83 if (state != NULL) 84 profile_iterator_free(&state); 85 if (name != NULL) 86 profile_release_string(name); 87 if (value != NULL) 88 profile_release_string(value); 89 90 *retvals = ret_values; 91 92 return (code); 93 } 94 95 errcode_t 96 __profile_get_domain_realm(profile_t profile, char *realm, char ***domains) 97 { 98 if (profile == NULL || realm == NULL || domains == NULL) 99 return (EINVAL); 100 101 return (__profile_iter_name_value(profile, "domain_realm", realm, 102 domains)); 103 } 104 105 errcode_t 106 __profile_set_appdefaults(profile_t profile) 107 { 108 const char *hierarchy[4]; 109 errcode_t code; 110 111 if (profile == NULL) 112 return (EINVAL); 113 114 hierarchy[0] = "appdefaults"; 115 hierarchy[1] = "kinit"; 116 hierarchy[3] = NULL; 117 118 hierarchy[2] = "renewable"; 119 120 /* 121 * Not fatal if this fails, continue on. 122 */ 123 (void) profile_clear_relation(profile, hierarchy); 124 125 code = profile_add_relation(profile, hierarchy, "true"); 126 if (code != 0) 127 return (code); 128 129 hierarchy[2] = "forwardable"; 130 131 (void) profile_clear_relation(profile, hierarchy); 132 133 code = profile_add_relation(profile, hierarchy, "true"); 134 135 return (code); 136 } 137 138 errcode_t 139 __profile_set_logging(profile_t profile) 140 { 141 const char *hierarchy[4]; 142 errcode_t code; 143 144 if (profile == NULL) 145 return (EINVAL); 146 147 hierarchy[0] = "logging"; 148 hierarchy[2] = NULL; 149 hierarchy[3] = NULL; 150 151 hierarchy[1] = "default"; 152 153 /* 154 * Not fatal if this fails, continue on. 155 */ 156 (void) profile_clear_relation(profile, hierarchy); 157 158 code = profile_add_relation(profile, hierarchy, 159 "FILE:/var/krb5/kdc.log"); 160 if (code != 0) 161 return (code); 162 163 hierarchy[1] = "kdc"; 164 165 (void) profile_clear_relation(profile, hierarchy); 166 167 code = profile_add_relation(profile, hierarchy, 168 "FILE:/var/krb5/kdc.log"); 169 if (code != 0) 170 return (code); 171 172 hierarchy[1] = "kdc_rotate"; 173 174 hierarchy[2] = "period"; 175 176 (void) profile_clear_relation(profile, hierarchy); 177 178 code = profile_add_relation(profile, hierarchy, "1d"); 179 if (code != 0) 180 return (code); 181 182 hierarchy[2] = "versions"; 183 184 (void) profile_clear_relation(profile, hierarchy); 185 186 code = profile_add_relation(profile, hierarchy, "10"); 187 188 return (code); 189 } 190 191 errcode_t 192 __profile_set_libdefaults(profile_t profile, char *realm) 193 { 194 const char *hierarchy[4]; 195 errcode_t code; 196 197 if (profile == NULL || realm == NULL) 198 return (EINVAL); 199 200 hierarchy[0] = "libdefaults"; 201 hierarchy[1] = "default_realm"; 202 hierarchy[2] = NULL; 203 204 /* 205 * Not fatal if this fails, continue on. 206 */ 207 (void) profile_clear_relation(profile, hierarchy); 208 209 code = profile_add_relation(profile, hierarchy, realm); 210 211 return (code); 212 } 213 214 errcode_t 215 __profile_set_kdc(profile_t profile, char *realm, char *kdc, 216 boolean_t overwrite) 217 { 218 const char *hierarchy[4]; 219 errcode_t code; 220 221 if (profile == NULL || realm == NULL || kdc == NULL) 222 return (EINVAL); 223 224 hierarchy[0] = "realms"; 225 hierarchy[1] = realm; 226 hierarchy[3] = NULL; 227 228 hierarchy[2] = "kdc"; 229 230 if (overwrite == TRUE) { 231 /* 232 * Not fatal if this fails, continue on. 233 */ 234 (void) profile_clear_relation(profile, hierarchy); 235 } 236 237 code = profile_add_relation(profile, hierarchy, kdc); 238 239 return (code); 240 } 241 242 /* 243 * errcode_t __profile_release(profile_t profile) 244 * 245 * where profile was the pointer passed back by __profile_init 246 * Note: used to commit the associated profile to the backing store 247 * (e.g. file) and free profile memory 248 * Note: that this function returns an error code which profile_release 249 * does not. With the error code, the application can determine if they 250 * need to free the resulting profile information in memory 251 */ 252 errcode_t 253 __profile_release(profile_t profile) 254 { 255 prf_file_t p, next; 256 errcode_t code; 257 258 if (profile == NULL || profile->magic != PROF_MAGIC_PROFILE) 259 return (EINVAL); 260 261 for (p = profile->first_file; p; p = next) { 262 next = p->next; 263 if ((code = profile_close_file(p)) != 0) 264 return (code); 265 } 266 profile->magic = 0; 267 free(profile); 268 269 return (0); 270 } 271 272 /* 273 * void __profile_abandon(profile_t profile) 274 * 275 * where profile was the pointer passed back by __profile_init 276 * Note: used to free any profile information in memory. Typically can 277 * be used in conjunction with __profile_release upon error 278 */ 279 void 280 __profile_abandon(profile_t profile) 281 { 282 profile_abandon(profile); 283 } 284 285 /* 286 * errcode_t __profile_add_domain_mapping(profile_t profile, char *domain, 287 * char *realm) 288 * 289 * where profile was the pointer passed back by __profile_init 290 * where domain is the domain name of the associated realm name 291 * where realm is the corresponding realm name for the domain 292 */ 293 errcode_t 294 __profile_add_domain_mapping(profile_t profile, char *domain, char *realm) 295 { 296 const char *hierarchy[4]; 297 errcode_t code = 0; 298 299 if (profile == NULL || domain == NULL || realm == NULL) 300 return (EINVAL); 301 302 hierarchy[0] = "domain_realm"; 303 hierarchy[1] = domain; 304 hierarchy[2] = NULL; 305 306 /* 307 * Not fatal if relation can't be cleared, continue on. 308 */ 309 (void) profile_clear_relation(profile, hierarchy); 310 311 code = profile_add_relation(profile, hierarchy, realm); 312 313 return (code); 314 } 315 316 /* 317 * errcode_t __profile_remove_domain_mapping(profile_t profile, char *realm) 318 * 319 * where profile was the pointer passed back by __profile_init 320 * where domain is the domain name of the associated realm name 321 * where realm is the corresponding realm name for the domain 322 * Note: for the remove function, all matching domain - realm mappings 323 * will be removed for realm 324 */ 325 errcode_t 326 __profile_remove_domain_mapping(profile_t profile, char *realm) 327 { 328 const char *hierarchy[4]; 329 errcode_t code; 330 char **domains = NULL, **domain = NULL; 331 332 if (profile == NULL || realm == NULL) 333 return (EINVAL); 334 335 hierarchy[0] = "domain_realm"; 336 hierarchy[1] = NULL; 337 hierarchy[2] = NULL; 338 339 code = __profile_get_domain_realm(profile, realm, &domains); 340 if (code == 0 && domains != NULL) { 341 for (domain = domains; *domain; domain++) { 342 hierarchy[1] = *domain; 343 code = profile_clear_relation(profile, hierarchy); 344 if (code != 0) 345 goto error; 346 } 347 } 348 349 error: 350 if (domains != NULL) 351 profile_free_list(domains); 352 353 return (code); 354 } 355 356 /* 357 * errcode_t __profile_get_realm_entry(profile_t profile, char *realm, 358 * char *name, char ***ret_value) 359 * 360 * where profile was the pointer passed back by __profile_init 361 * where realm is the target realm for lookup 362 * where name is the name in the realm section requested 363 * where value is a string array of any matching values assigned to name. 364 * The array is terminated with a NULL pointer. 365 * Note: if no name has been configured and a profile does exist 366 * then value is set to NULL 367 */ 368 errcode_t 369 __profile_get_realm_entry(profile_t profile, char *realm, char *name, 370 char ***ret_value) 371 { 372 const char *hierarchy[4]; 373 errcode_t code; 374 char **values = NULL; 375 376 if (profile == NULL || realm == NULL || name == NULL || 377 ret_value == NULL) 378 return (EINVAL); 379 380 hierarchy[0] = "realms"; 381 hierarchy[1] = realm; 382 hierarchy[2] = name; 383 hierarchy[3] = NULL; 384 385 code = profile_get_values(profile, hierarchy, &values); 386 if (code == 0 && values != NULL) 387 *ret_value = values; 388 389 if (code == PROF_NO_RELATION) 390 code = 0; 391 392 return (code); 393 } 394 395 /* 396 * errcode_t __profile_add_realm_entry(profile_t profile, char *realm, 397 * char *name, char **value) 398 * 399 * where profile was the pointer passed back by __profile_init 400 * where realm is the target realm for the name-value pair 401 * where name is the name in the realm subsection to add 402 * where value is a string array values to assigned to name. The array is 403 * terminated with a NULL pointer. 404 * Note: if the realm subsection does no exist then an error is returned 405 * Note: if the name already exists the set is overwritten with the values 406 * passed 407 */ 408 errcode_t 409 __profile_add_realm_entry(profile_t profile, char *realm, char *name, 410 char **values) 411 { 412 const char *hierarchy[4]; 413 errcode_t code; 414 char **tvalue = NULL; 415 416 if (profile == NULL || realm == NULL || name == NULL || values == NULL) 417 return (EINVAL); 418 419 hierarchy[0] = "realms"; 420 hierarchy[1] = realm; 421 hierarchy[2] = name; 422 hierarchy[3] = NULL; 423 424 /* 425 * Not fatal if this fails, continue on. 426 */ 427 (void) profile_clear_relation(profile, hierarchy); 428 429 for (tvalue = values; *tvalue; tvalue++) { 430 431 code = profile_add_relation(profile, hierarchy, *tvalue); 432 if (code != 0) 433 return (code); 434 } 435 436 return (0); 437 } 438 439 /* 440 * errcode_t __profile_get_default_realm(profile_t profile, char **realm) 441 * 442 * where profile was the pointer passed back by __profile_init 443 * where realm is the default_realm configured for the system 444 * Note: if no default_realm has been configured and a profile does exist 445 * then realm is set to NULL 446 */ 447 errcode_t 448 __profile_get_default_realm(profile_t profile, char **realm) 449 { 450 errcode_t code; 451 char *value = NULL; 452 453 if (profile == NULL || realm == NULL) 454 return (EINVAL); 455 456 code = profile_get_string(profile, "libdefaults", "default_realm", 0, 0, 457 &value); 458 if (code == 0 && value != NULL) 459 *realm = value; 460 461 if (code == PROF_NO_RELATION) 462 code = 0; 463 464 return (code); 465 } 466 467 /* 468 * errcode_t __profile_get_realms(profile_t profile, char ***realms) 469 * 470 * where profile was the pointer passed back by __profile_init 471 * where realms is a string array of realm names currently configured. 472 * The array is terminated with a NULL pointer. 473 * Note: if no realms have been configured and a profile does exist then 474 * realms is set to NULL 475 */ 476 errcode_t 477 __profile_get_realms(profile_t profile, char ***realms) 478 { 479 480 if (profile == NULL || realms == NULL) 481 return (EINVAL); 482 483 return (__profile_iter_name_value(profile, "realms", NULL, realms)); 484 } 485 486 /* 487 * errcode_t __profile_add_realm(profile_t profile, char *realm, 488 * char *master, char **kdcs, boolean_t set_change, boolean_t 489 * default_realm) 490 * 491 * where profile was the pointer passed back by __profile_init 492 * where realm is the realm name associated with the configuration 493 * where master is the server that is assigned to admin_server 494 * where kdcs is a string array of KDCs used to populate the kdc set. 495 * The array is terminated with a NULL pointer. 496 * where set_change, if set, will use the SET_CHANGE protocol for password 497 * modifications. RPCSEC_GSS is set by default 498 * where default_realm, if set, will assign the realm to default_realm 499 * Note: the ordering of kdcs is determined by the server's position in the 500 * array 501 * Note: kdcs must be assigned a value, even if it is the same value as the 502 * master. 503 */ 504 errcode_t 505 __profile_add_realm(profile_t profile, char *realm, char *master, char **kdcs, 506 boolean_t set_change, boolean_t default_realm) 507 { 508 const char *hierarchy[4]; 509 errcode_t code; 510 boolean_t ow = TRUE; 511 char **tkdcs; 512 513 if (profile == NULL || realm == NULL || master == NULL || kdcs == NULL) 514 return (EINVAL); 515 516 /* 517 * Sets the default realm to realm if default_realm flag is set. 518 */ 519 if (default_realm == TRUE) { 520 if (code = __profile_set_libdefaults(profile, realm)) 521 return (code); 522 } 523 524 hierarchy[0] = "realms"; 525 hierarchy[1] = realm; 526 hierarchy[3] = NULL; 527 528 hierarchy[2] = "admin_server"; 529 530 /* 531 * Not fatal if this fails, therefore return code is not checked. 532 */ 533 (void) profile_clear_relation(profile, hierarchy); 534 535 if (code = profile_add_relation(profile, hierarchy, master)) 536 return (code); 537 538 /* 539 * If not set then defaults to undefined, which defaults to RPCSEC_GSS. 540 */ 541 if (set_change == TRUE) { 542 hierarchy[2] = "kpasswd_protocol"; 543 544 (void) profile_clear_relation(profile, hierarchy); 545 546 code = profile_add_relation(profile, hierarchy, "SET_CHANGE"); 547 if (code != 0) 548 return (code); 549 } 550 551 for (tkdcs = kdcs; *tkdcs; tkdcs++) { 552 if (code = __profile_set_kdc(profile, realm, *tkdcs, ow)) 553 return (code); 554 ow = FALSE; 555 } 556 557 code = __profile_set_logging(profile); 558 if (code != 0) 559 return (code); 560 561 code = __profile_set_appdefaults(profile); 562 563 return (code); 564 } 565 566 /* 567 * errcode_t __profile_remove_xrealm_mapping(profile_t profile, char *realm) 568 * 569 * where profile was the pointer passed back by __profile_init 570 * where source is the source realm for the capath 571 * where target is the target realm for the capath 572 * where inter is the intermediate realm between the source and target 573 * realms. If the source and target share x-realm keys then this set to "." 574 * Note: for the remove function, all associated source, target, and 575 * intermediate entries will be removed matching the realm name 576 */ 577 errcode_t 578 __profile_remove_xrealm_mapping(profile_t profile, char *realm) 579 { 580 const char *hierarchy[4]; 581 errcode_t code, code2, code3; 582 void *state = NULL, *state2 = NULL; 583 char *source = NULL, *dummy_val = NULL, *target = NULL; 584 char *inter = NULL; 585 586 if (profile == NULL || realm == NULL) 587 return (EINVAL); 588 589 hierarchy[0] = "capaths"; 590 hierarchy[1] = realm; 591 hierarchy[2] = NULL; 592 hierarchy[3] = NULL; 593 594 /* 595 * Not fatal if this fails, continue on. 596 */ 597 code = profile_rename_section(profile, hierarchy, NULL); 598 599 hierarchy[1] = NULL; 600 code = profile_iterator_create(profile, hierarchy, 601 PROFILE_ITER_LIST_SECTION, &state); 602 while (code == 0) { 603 code = profile_iterator(&state, &source, &dummy_val); 604 if (code == 0 && source != NULL) { 605 hierarchy[1] = source; 606 code2 = profile_iterator_create(profile, hierarchy, 607 PROFILE_ITER_LIST_SECTION, &state2); 608 while (code2 == 0) { 609 code2 = profile_iterator(&state2, &target, 610 &inter); 611 if (code2 == 0 && target != NULL && 612 inter != NULL) { 613 if (strcmp(realm, target) == 0 || 614 strcmp(realm, inter) == 0) { 615 hierarchy[2] = target; 616 code3 = 617 profile_clear_relation( 618 profile, hierarchy); 619 if (code3 != 0) { 620 code = code3; 621 goto error; 622 } 623 } 624 } 625 if (target != NULL) { 626 profile_release_string(target); 627 target = NULL; 628 } 629 if (inter != NULL) { 630 profile_release_string(inter); 631 inter = NULL; 632 } 633 } 634 } 635 if (source != NULL) { 636 profile_release_string(source); 637 source = NULL; 638 } 639 if (dummy_val != NULL) { 640 profile_release_string(dummy_val); 641 dummy_val = NULL; 642 } 643 } 644 code = 0; 645 646 error: 647 if (state != NULL) 648 profile_iterator_free(&state); 649 if (state2 != NULL) 650 profile_iterator_free(&state2); 651 if (target != NULL) 652 profile_release_string(target); 653 if (inter != NULL) 654 profile_release_string(inter); 655 if (source != NULL) 656 profile_release_string(source); 657 if (dummy_val != NULL) 658 profile_release_string(dummy_val); 659 660 return (code); 661 } 662 663 /* 664 * errcode_t __profile_remove_realm(profile_t profile, char *realm) 665 * 666 * where profile was the pointer passed back by __profile_init 667 * where realm is the target realm for removal 668 * Note: the function removes the matching realm in the realms section, 669 * the default_realm, relevant domain_realm mappings with the realm name, 670 * and matching capaths source realm subsection. 671 */ 672 errcode_t 673 __profile_remove_realm(profile_t profile, char *realm) 674 { 675 const char *hierarchy[4]; 676 errcode_t code; 677 char *drealm = NULL; 678 679 if (profile == NULL || realm == NULL) 680 return (EINVAL); 681 682 /* 683 * Remove the default realm. 684 */ 685 hierarchy[0] = "libdefaults"; 686 hierarchy[1] = "default_realm"; 687 hierarchy[2] = NULL; 688 689 code = __profile_get_default_realm(profile, &drealm); 690 if (code != 0) 691 return (code); 692 else if (drealm != NULL) { 693 if (strcmp(drealm, realm) == 0) { 694 code = profile_clear_relation(profile, hierarchy); 695 if (code != 0) { 696 free(drealm); 697 return (code); 698 } 699 } 700 free(drealm); 701 } 702 703 hierarchy[0] = "realms"; 704 hierarchy[1] = realm; 705 hierarchy[2] = NULL; 706 707 code = profile_rename_section(profile, hierarchy, NULL); 708 if (code != 0) 709 return (code); 710 711 code = __profile_remove_domain_mapping(profile, realm); 712 if (code != 0) 713 return (code); 714 715 code = __profile_remove_xrealm_mapping(profile, realm); 716 if (code != 0) 717 return (code); 718 719 /* 720 * Not fatal even if realm wasn't available to remove. 721 */ 722 return (0); 723 } 724 725 /* 726 * errcode_t __profile_add_xrealm_mapping(profile_t profile, char *source, 727 * char *target, char *inter) 728 * 729 * where profile was the pointer passed back by __profile_init 730 * where source is the source realm for the capath 731 * where target is the target realm for the capath 732 * where inter is the intermediate realm between the source and target 733 * realms. If the source and target share x-realm keys then this set to "." 734 * Note: if the section does not exist one will be created 735 */ 736 errcode_t 737 __profile_add_xrealm_mapping(profile_t profile, char *source, char *target, 738 char *inter) 739 { 740 const char *hierarchy[4]; 741 errcode_t code; 742 743 if (profile == NULL || source == NULL || target == NULL || 744 inter == NULL) 745 return (EINVAL); 746 747 hierarchy[0] = "capaths"; 748 hierarchy[1] = source; 749 hierarchy[2] = target; 750 hierarchy[3] = NULL; 751 752 /* 753 * Not fatal if this fails, continue on. 754 */ 755 (void) profile_clear_relation(profile, hierarchy); 756 757 code = profile_add_relation(profile, hierarchy, inter); 758 759 return (code); 760 } 761 762 /* 763 * errcode_t __profile_validate(profile_t profile, int *val_err, char **val) 764 * 765 * where profile was the pointer passed back by __profile_init 766 * where val_err is a function specific error code of the following values: 767 * 0 No errors detected in profile 768 * 1 default realm is in lower-case (val returns realm) 769 * 2 realm in realms section is in lower-case (val returns realm) 770 * 3 default realm is not found in realms section 771 * (val returns realm not found) 772 * 4 default realm does not exist 773 * 5 no realm found in realms section 774 * 6 no domain realm mapping entry found corresponding to a realm 775 * in the realms section (val returns realm name) 776 * 7 kdc relation-value does not exist in realm 777 * (val returns realm name) 778 * 8 admin_server relation-value does not exist in realm 779 * (val returns realm name) 780 * where val is the associated errant value, associated with val_err. This 781 * value is returned as is from the profile 782 * Note: function infers the following: 783 * 1. REALM should be in upper-case 784 * 2. all required entries are present 785 * 3. all relations are defined between default realm, realm, and 786 * domain - realm mappings 787 * 788 * Note: The return value of this function is based on the error code returned 789 * by the framework/mechanism. The function could return zero with the 790 * validation error code set to non-zero if the profile is invalid in any way. 791 * 792 * Caution: This function could return false positives on valid 793 * configurations and should only be used by the CIFS team for 794 * specific purposes. 795 */ 796 errcode_t 797 __profile_validate(profile_t profile, int *val_err, char **val) 798 { 799 errcode_t code; 800 register int c; 801 boolean_t found = FALSE; 802 char *default_realm = NULL, **realms = NULL, *tr = NULL; 803 char **trealms = NULL, **domains = NULL, **ret_vals = NULL; 804 805 if (profile == NULL || val_err == NULL || val == NULL) 806 return (EINVAL); 807 808 *val_err = 0; 809 *val = NULL; 810 811 code = __profile_get_default_realm(profile, &default_realm); 812 if (code == 0 && default_realm != NULL) { 813 tr = default_realm; 814 815 while ((c = *tr++) != NULL) { 816 if (islower(c)) { 817 *val_err = 1; 818 *val = strdup(default_realm); 819 if (*val == NULL) 820 code = ENOMEM; 821 goto cleanup; 822 } 823 } 824 } else if (code == 0 && default_realm == NULL) { 825 *val_err = 4; 826 goto cleanup; 827 } else 828 goto cleanup; 829 830 code = __profile_get_realms(profile, &realms); 831 if (code == 0 && realms != NULL) { 832 for (trealms = realms; *trealms; trealms++) { 833 834 tr = *trealms; 835 while ((c = *tr++) != NULL) { 836 if (islower(c)) { 837 *val_err = 2; 838 *val = strdup(*trealms); 839 if (*val == NULL) 840 code = ENOMEM; 841 goto cleanup; 842 } 843 } 844 845 if (strcmp(default_realm, *trealms) == 0) 846 found = TRUE; 847 848 code = __profile_get_domain_realm(profile, *trealms, 849 &domains); 850 if (code == 0 && domains != NULL) { 851 profile_free_list(domains); 852 domains = NULL; 853 } else if (code == 0 && domains == NULL) { 854 *val_err = 6; 855 *val = strdup(*trealms); 856 if (*val == NULL) 857 code = ENOMEM; 858 goto cleanup; 859 } else 860 goto cleanup; 861 862 code = __profile_get_realm_entry(profile, *trealms, 863 "kdc", &ret_vals); 864 if (code == 0 && ret_vals != NULL) { 865 profile_free_list(ret_vals); 866 ret_vals = NULL; 867 } else if (code == 0 && ret_vals == NULL) { 868 *val_err = 7; 869 *val = strdup(*trealms); 870 if (*val == NULL) 871 code = ENOMEM; 872 goto cleanup; 873 } else 874 goto cleanup; 875 876 code = __profile_get_realm_entry(profile, *trealms, 877 "admin_server", &ret_vals); 878 if (code == 0 && ret_vals != NULL) { 879 profile_free_list(ret_vals); 880 ret_vals = NULL; 881 } else if (code == 0 && ret_vals == NULL) { 882 *val_err = 8; 883 *val = strdup(*trealms); 884 if (*val == NULL) 885 code = ENOMEM; 886 goto cleanup; 887 } else 888 goto cleanup; 889 } 890 891 if (found == FALSE) { 892 *val_err = 3; 893 *val = strdup(default_realm); 894 if (*val == NULL) 895 code = ENOMEM; 896 goto cleanup; 897 } 898 } else if (code == 0 && realms == NULL) 899 *val_err = 5; 900 901 cleanup: 902 903 if (realms != NULL) 904 profile_free_list(realms); 905 if (ret_vals != NULL) 906 profile_free_list(ret_vals); 907 if (default_realm != NULL) 908 profile_release_string(default_realm); 909 if (domains != NULL) 910 profile_free_list(domains); 911 912 return (code); 913 } 914 915 /* 916 * errcode_t __profile_init(char *filename, profile_t *profile) 917 * 918 * where filename is the specified profile location. If filename is NULL 919 * then function uses the system default name, /etc/krb5/krb5.conf 920 * where profile is pointer passed to caller upon success 921 * Note: if the file does not exist then one will be created 922 * Note: if the file does exist then any existing profile information will 923 * be in profile 924 * Note: profile_release() should be used by the caller to free profile 925 */ 926 errcode_t 927 __profile_init(char *filename, profile_t *profile) 928 { 929 profile_filespec_t *filenames = NULL; 930 krb5_error_code ret = 0; 931 errcode_t code = 0; 932 int err = 0, fd; 933 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 934 935 if (profile == NULL) 936 return (EINVAL); 937 938 if (filename != NULL) { 939 filenames = malloc(2 * sizeof (char *)); 940 if (filenames == NULL) 941 return (ENOMEM); 942 filenames[0] = strdup(filename); 943 if (filenames[0] == NULL) { 944 free(filenames); 945 return (ENOMEM); 946 } 947 filenames[1] = NULL; 948 } else { 949 ret = krb5_get_default_config_files(&filenames); 950 if (ret != 0) 951 return (ret); 952 } 953 954 /* 955 * If file does not exist then create said file. 956 */ 957 fd = open(*filenames, O_RDWR|O_CREAT|O_NOFOLLOW|O_NOLINKS, mode); 958 if (fd < 0) { 959 err = errno; 960 krb5_free_config_files(filenames); 961 return (err); 962 } else 963 close(fd); 964 965 /* 966 * Specify non-null for specific file (to load any existing profile) 967 */ 968 code = profile_init((const_profile_filespec_t *)filenames, profile); 969 970 krb5_free_config_files(filenames); 971 972 return (code); 973 } 974