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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains functions to initialize the gssapi library and 28 * load mechanism libraries. 29 * 30 * It also contain functions requiring direct access to the mechanism's 31 * list (gss_inidicate_mechs and gss_release_oid) as well as support 32 * functions which translate the mechanism strings to oids and vise versa. 33 * 34 * The mechanism libraries are loaded on demand. This is triggered 35 * through the get_mechanism function call. 36 * 37 * Updates to the mechList are performed with the following restrictions: 38 * - once a library is loaded, none of the fields are updated 39 * - existing entiries for non-loaded mechs, will have the 40 * library and kernel module names updated only 41 * (i.e. the mech oid and mech name will not be updated) 42 */ 43 44 #include <mechglueP.h> 45 #include <stdio.h> 46 #include <syslog.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <sys/stat.h> 50 #include <ctype.h> 51 #include <errno.h> 52 #include <synch.h> 53 #include <dlfcn.h> 54 #include <libintl.h> 55 56 57 #ifndef TEXT_DOMAIN 58 #error TEXT_DOMAIN not defined 59 #endif 60 61 #define MECH_CONF "/etc/gss/mech" 62 63 #define MECH_LIB_PREFIX1 "/usr/lib/" 64 65 /* 66 * This #ifdef mess figures out if we are to be compiled into 67 * a sparcv9/lp64 binary for the purposes of figuring the absolute location 68 * of gss-api mechanism modules. 69 */ 70 #ifdef _LP64 71 72 #ifdef __sparc 73 74 #define MECH_LIB_PREFIX2 "sparcv9/" 75 76 #elif defined(__amd64) 77 78 #define MECH_LIB_PREFIX2 "amd64/" 79 80 #else /* __sparc */ 81 82 you need to define where under /usr the LP64 libraries live for this platform 83 84 #endif /* __sparc */ 85 86 #else /* _LP64 */ 87 88 #define MECH_LIB_PREFIX2 "" 89 90 #endif /* _LP64 */ 91 92 #define MECH_LIB_DIR "gss/" 93 94 #define MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR 95 96 97 #ifndef MECH_SYM 98 #define MECH_SYM "gss_mech_initialize" 99 #endif 100 101 #define M_DEFAULT "default" 102 103 /* Local functions */ 104 static gss_mech_info searchMechList(const gss_OID); 105 static void loadConfigFile(const char *); 106 static void updateMechList(void); 107 108 109 /* 110 * list of mechanism libraries and their entry points. 111 * the list also maintains state of the mech libraries (loaded or not). 112 */ 113 static gss_mech_info g_mechList = NULL; 114 static gss_mech_info g_mechListTail = NULL; 115 static mutex_t g_mechListLock; 116 static time_t g_confFileModTime = (time_t)0; 117 118 /* 119 * function used to reclaim the memory used by a gss_OID structure. 120 * This routine requires direct access to the mechList. 121 */ 122 OM_uint32 123 gss_release_oid(minor_status, oid) 124 OM_uint32 *minor_status; 125 gss_OID *oid; 126 { 127 OM_uint32 major; 128 gss_mech_info aMech = g_mechList; 129 130 if (minor_status == NULL) 131 return (GSS_S_CALL_INACCESSIBLE_WRITE); 132 133 *minor_status = 0; 134 135 while (aMech != NULL) { 136 137 /* 138 * look through the loaded mechanism libraries for 139 * gss_internal_release_oid until one returns success. 140 * gss_internal_release_oid will only return success when 141 * the OID was recognized as an internal mechanism OID. if no 142 * mechanisms recognize the OID, then call the generic version. 143 */ 144 145 /* 146 * we can walk the mechanism list without a mutex, because we 147 * are only looking at fields which once read will never change. 148 * Mechanism entries are always added to the end, and as 149 * complete entries. 150 */ 151 if (aMech->mech && aMech->mech->gss_internal_release_oid) { 152 major = aMech->mech->gss_internal_release_oid( 153 aMech->mech->context, 154 minor_status, oid); 155 if (major == GSS_S_COMPLETE) 156 return (GSS_S_COMPLETE); 157 } 158 aMech = aMech->next; 159 } /* while */ 160 161 return (generic_gss_release_oid(minor_status, oid)); 162 } /* gss_release_oid */ 163 164 165 /* 166 * this function will return an oid set indicating available mechanisms. 167 * The set returned is based on configuration file entries and 168 * NOT on the loaded mechanisms. This function does not check if any 169 * of these can actually be loaded. 170 * This routine needs direct access to the mechanism list. 171 * To avoid reading the configuration file each call, we will save a 172 * a mech oid set, and only update it once the file has changed. 173 */ 174 static time_t g_mechSetTime = (time_t)0; 175 static gss_OID_set_desc g_mechSet = { 0, NULL }; 176 static mutex_t g_mechSetLock; 177 178 179 OM_uint32 180 gss_indicate_mechs(minorStatus, mechSet) 181 OM_uint32 *minorStatus; 182 gss_OID_set *mechSet; 183 { 184 gss_mech_info mList; 185 char *fileName; 186 struct stat fileInfo; 187 int count, i, j; 188 gss_OID curItem; 189 190 /* Initialize outputs. */ 191 192 if (minorStatus != NULL) 193 *minorStatus = 0; 194 195 if (mechSet != NULL) 196 *mechSet = GSS_C_NO_OID_SET; 197 198 /* Validate arguments. */ 199 if (minorStatus == NULL || mechSet == NULL) 200 return (GSS_S_CALL_INACCESSIBLE_WRITE); 201 202 fileName = MECH_CONF; 203 204 /* 205 * If we have already computed the mechanisms supported and if it 206 * is still valid; make a copy and return to caller, 207 * otherwise build it first. 208 */ 209 if ((stat(fileName, &fileInfo) == 0 && 210 fileInfo.st_mtime > g_mechSetTime)) { 211 /* 212 * lock the mutex since we will be updating 213 * the mechList structure 214 * we need to keep the lock while we build the mechanism list 215 * since we are accessing parts of the mechList which could be 216 * modified. 217 */ 218 (void) mutex_lock(&g_mechListLock); 219 220 /* 221 * this checks for the case when we need to re-construct the 222 * g_mechSet structure, but the mechanism list is upto date 223 * (because it has been read by someone calling 224 * __gss_get_mechanism) 225 */ 226 if (fileInfo.st_mtime > g_confFileModTime) 227 { 228 g_confFileModTime = fileInfo.st_mtime; 229 loadConfigFile(fileName); 230 } 231 232 /* 233 * we need to lock the mech set so that no one else will 234 * try to read it as we are re-creating it 235 */ 236 (void) mutex_lock(&g_mechSetLock); 237 238 /* if the oid list already exists we must free it first */ 239 if (g_mechSet.count != 0) { 240 for (i = 0; i < g_mechSet.count; i++) 241 free(g_mechSet.elements[i].elements); 242 free(g_mechSet.elements); 243 g_mechSet.elements = NULL; 244 g_mechSet.count = 0; 245 } 246 247 /* determine how many elements to have in the list */ 248 mList = g_mechList; 249 count = 0; 250 while (mList != NULL) { 251 count++; 252 mList = mList->next; 253 } 254 255 /* this should always be true, but.... */ 256 if (count > 0) { 257 g_mechSet.elements = 258 (gss_OID) calloc(count, sizeof (gss_OID_desc)); 259 if (g_mechSet.elements == NULL) { 260 (void) mutex_unlock(&g_mechSetLock); 261 (void) mutex_unlock(&g_mechListLock); 262 return (GSS_S_FAILURE); 263 } 264 265 (void) memset(g_mechSet.elements, 0, 266 count * sizeof (gss_OID_desc)); 267 268 /* now copy each oid element */ 269 g_mechSet.count = count; 270 count = 0; 271 mList = g_mechList; 272 while (mList != NULL) { 273 curItem = &(g_mechSet.elements[count]); 274 curItem->elements = (void*) 275 malloc(mList->mech_type->length); 276 if (curItem->elements == NULL) { 277 /* 278 * this is nasty - we must delete the 279 * part of the array already copied 280 */ 281 for (i = 0; i < count; i++) { 282 free(g_mechSet.elements[i]. 283 elements); 284 } 285 free(g_mechSet.elements); 286 g_mechSet.count = 0; 287 g_mechSet.elements = NULL; 288 (void) mutex_unlock(&g_mechSetLock); 289 (void) mutex_unlock(&g_mechListLock); 290 return (GSS_S_FAILURE); 291 } 292 g_OID_copy(curItem, mList->mech_type); 293 count++; 294 mList = mList->next; 295 } 296 } 297 298 g_mechSetTime = fileInfo.st_mtime; 299 (void) mutex_unlock(&g_mechSetLock); 300 (void) mutex_unlock(&g_mechListLock); 301 } /* if g_mechSet is out of date or not initialized */ 302 303 /* 304 * the mech set is created and it is up to date 305 * so just copy it to caller 306 */ 307 if ((*mechSet = 308 (gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL) 309 { 310 return (GSS_S_FAILURE); 311 } 312 313 /* 314 * need to lock the g_mechSet in case someone tries to update it while 315 * I'm copying it. 316 */ 317 (void) mutex_lock(&g_mechSetLock); 318 319 /* allocate space for the oid structures */ 320 if (((*mechSet)->elements = 321 (void*) calloc(g_mechSet.count, sizeof (gss_OID_desc))) 322 == NULL) 323 { 324 (void) mutex_unlock(&g_mechSetLock); 325 free(*mechSet); 326 *mechSet = NULL; 327 return (GSS_S_FAILURE); 328 } 329 330 /* now copy the oid structures */ 331 (void) memcpy((*mechSet)->elements, g_mechSet.elements, 332 g_mechSet.count * sizeof (gss_OID_desc)); 333 334 (*mechSet)->count = g_mechSet.count; 335 336 /* still need to copy each of the oid elements arrays */ 337 for (i = 0; i < (*mechSet)->count; i++) { 338 curItem = &((*mechSet)->elements[i]); 339 curItem->elements = 340 (void *) malloc(g_mechSet.elements[i].length); 341 if (curItem->elements == NULL) { 342 (void) mutex_unlock(&g_mechSetLock); 343 /* 344 * must still free the allocated elements for 345 * each allocated gss_OID_desc 346 */ 347 for (j = 0; j < i; j++) { 348 free((*mechSet)->elements[j].elements); 349 } 350 free((*mechSet)->elements); 351 free(mechSet); 352 *mechSet = NULL; 353 return (GSS_S_FAILURE); 354 } 355 g_OID_copy(curItem, &g_mechSet.elements[i]); 356 } 357 (void) mutex_unlock(&g_mechSetLock); 358 return (GSS_S_COMPLETE); 359 } /* gss_indicate_mechs */ 360 361 /* 362 * this function has been added for use by modules that need to 363 * know what (if any) optional parameters are supplied in the 364 * config file (MECH_CONF). 365 * It will return the option string for a specified mechanism. 366 * caller is responsible for freeing the memory 367 */ 368 char * 369 __gss_get_modOptions(oid) 370 const gss_OID oid; 371 { 372 gss_mech_info aMech; 373 char *modOptions = NULL; 374 375 /* make sure we have fresh data */ 376 (void) mutex_lock(&g_mechListLock); 377 updateMechList(); 378 (void) mutex_unlock(&g_mechListLock); 379 380 /* searching the list does not require a lock */ 381 if ((aMech = searchMechList(oid)) == NULL || 382 aMech->optionStr == NULL) { 383 return (NULL); 384 } 385 386 /* 387 * need to obtain a lock on this structure in case someone else 388 * will try to update it during the copy 389 */ 390 (void) mutex_lock(&g_mechListLock); 391 if (aMech->optionStr) 392 modOptions = strdup(aMech->optionStr); 393 (void) mutex_unlock(&g_mechListLock); 394 395 return (modOptions); 396 } /* __gss_get_modOptions */ 397 398 /* 399 * this function has been added for use by gssd. 400 * It will return the kernel module name for a specified mechanism. 401 * caller is responsible for freeing the memory 402 */ 403 char * 404 __gss_get_kmodName(oid) 405 const gss_OID oid; 406 { 407 gss_mech_info aMech; 408 char *kmodName = NULL; 409 410 /* make sure we have fresh data */ 411 (void) mutex_lock(&g_mechListLock); 412 updateMechList(); 413 (void) mutex_unlock(&g_mechListLock); 414 415 /* searching the list does not require a lock */ 416 if ((aMech = searchMechList(oid)) == NULL || aMech->kmodName == NULL) { 417 return (NULL); 418 } 419 420 /* 421 * need to obtain a lock on this structure in case someone else 422 * will try to update it during the copy 423 */ 424 (void) mutex_lock(&g_mechListLock); 425 if (aMech->kmodName) 426 kmodName = strdup(aMech->kmodName); 427 (void) mutex_unlock(&g_mechListLock); 428 429 return (kmodName); 430 } /* __gss_get_kmodName */ 431 432 433 /* 434 * given a mechanism string return the mechanism oid 435 */ 436 OM_uint32 437 __gss_mech_to_oid(const char *mechStr, gss_OID* oid) 438 { 439 gss_mech_info aMech; 440 441 if (oid == NULL) 442 return (GSS_S_CALL_INACCESSIBLE_WRITE); 443 444 *oid = GSS_C_NULL_OID; 445 446 if ((mechStr == NULL) || (strlen(mechStr) == 0) || 447 (strcasecmp(mechStr, M_DEFAULT) == 0)) 448 return (GSS_S_COMPLETE); 449 450 /* ensure we have fresh data */ 451 (void) mutex_lock(&g_mechListLock); 452 updateMechList(); 453 (void) mutex_unlock(&g_mechListLock); 454 455 aMech = g_mechList; 456 457 /* no lock required - only looking at fields that are not updated */ 458 while (aMech != NULL) { 459 if ((aMech->mechNameStr) && 460 strcmp(aMech->mechNameStr, mechStr) == 0) { 461 *oid = aMech->mech_type; 462 return (GSS_S_COMPLETE); 463 } 464 aMech = aMech->next; 465 } 466 return (GSS_S_FAILURE); 467 } /* __gss_mech_to_oid */ 468 469 470 /* 471 * Given the mechanism oid, return the readable mechanism name 472 * associated with that oid from the mech config file 473 * (/etc/gss/mech). 474 */ 475 const char * 476 __gss_oid_to_mech(const gss_OID oid) 477 { 478 gss_mech_info aMech; 479 480 if (oid == GSS_C_NULL_OID) 481 return (M_DEFAULT); 482 483 /* ensure we have fresh data */ 484 (void) mutex_lock(&g_mechListLock); 485 updateMechList(); 486 (void) mutex_unlock(&g_mechListLock); 487 488 if ((aMech = searchMechList(oid)) == NULL) 489 return (NULL); 490 491 return (aMech->mechNameStr); 492 } /* __gss_oid_to_mech */ 493 494 495 /* 496 * return a list of mechanism strings supported 497 * upon return the array is terminated with a NULL entry 498 */ 499 OM_uint32 500 __gss_get_mechanisms(char *mechArray[], int arrayLen) 501 { 502 gss_mech_info aMech; 503 int i; 504 505 if (mechArray == NULL || arrayLen < 1) 506 return (GSS_S_CALL_INACCESSIBLE_WRITE); 507 508 /* ensure we have fresh data */ 509 (void) mutex_lock(&g_mechListLock); 510 updateMechList(); 511 (void) mutex_unlock(&g_mechListLock); 512 513 aMech = g_mechList; 514 515 /* no lock required - only looking at fields that are not updated */ 516 for (i = 1; i < arrayLen; i++) { 517 if (aMech != NULL) { 518 *mechArray = aMech->mechNameStr; 519 mechArray++; 520 aMech = aMech->next; 521 } else 522 break; 523 } 524 *mechArray = NULL; 525 return (GSS_S_COMPLETE); 526 } /* gss_get_mechanisms */ 527 528 529 /* 530 * determines if the mechList needs to be updated from file 531 * and performs the update. 532 * this functions must be called with a lock of g_mechListLock 533 */ 534 static void 535 updateMechList(void) 536 { 537 char *fileName; 538 struct stat fileInfo; 539 540 fileName = MECH_CONF; 541 542 /* check if mechList needs updating */ 543 if (stat(fileName, &fileInfo) == 0 && 544 (fileInfo.st_mtime > g_confFileModTime)) { 545 loadConfigFile(fileName); 546 g_confFileModTime = fileInfo.st_mtime; 547 } 548 } /* updateMechList */ 549 550 551 /* 552 * given the mechanism type, return the mechanism structure 553 * containing the mechanism library entry points. 554 * will return NULL if mech type is not found 555 * This function will also trigger the loading of the mechanism 556 * module if it has not been already loaded. 557 */ 558 gss_mechanism 559 __gss_get_mechanism(oid) 560 const gss_OID oid; 561 { 562 gss_mech_info aMech; 563 gss_mechanism (*sym)(const gss_OID); 564 void *dl; 565 566 /* check if the mechanism is already loaded */ 567 if ((aMech = searchMechList(oid)) != NULL && aMech->mech) { 568 return (aMech->mech); 569 } 570 571 /* 572 * might need to re-read the configuration file before loading 573 * the mechanism to ensure we have the latest info. 574 */ 575 (void) mutex_lock(&g_mechListLock); 576 updateMechList(); 577 578 aMech = searchMechList(oid); 579 580 /* is the mechanism present in the list ? */ 581 if (aMech == NULL) { 582 (void) mutex_unlock(&g_mechListLock); 583 return ((gss_mechanism)NULL); 584 } 585 586 /* has another thread loaded the mech */ 587 if (aMech->mech) { 588 (void) mutex_unlock(&g_mechListLock); 589 return (aMech->mech); 590 } 591 592 /* we found the mechanism, but it is not loaded */ 593 if ((dl = dlopen(aMech->uLibName, RTLD_NOW)) == NULL) { 594 (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n", 595 aMech->uLibName, dlerror()); 596 (void) mutex_unlock(&g_mechListLock); 597 return ((gss_mechanism)NULL); 598 } 599 600 if ((sym = (gss_mechanism (*)(const gss_OID))dlsym(dl, MECH_SYM)) 601 == NULL) { 602 (void) dlclose(dl); 603 (void) syslog(LOG_INFO, "unable to initialize mechanism" 604 " library [%s]\n", aMech->uLibName); 605 (void) mutex_unlock(&g_mechListLock); 606 return ((gss_mechanism)NULL); 607 } 608 609 /* Call the symbol to get the mechanism table */ 610 aMech->mech = (*sym)(aMech->mech_type); 611 612 if (aMech->mech == NULL) { 613 (void) dlclose(dl); 614 (void) syslog(LOG_INFO, "unable to initialize mechanism" 615 " library [%s]\n", aMech->uLibName); 616 (void) mutex_unlock(&g_mechListLock); 617 return ((gss_mechanism)NULL); 618 } 619 620 aMech->dl_handle = dl; 621 622 (void) mutex_unlock(&g_mechListLock); 623 return (aMech->mech); 624 } /* __gss_get_mechanism */ 625 626 gss_mechanism_ext 627 __gss_get_mechanism_ext(oid) 628 const gss_OID oid; 629 { 630 gss_mech_info aMech; 631 gss_mechanism_ext mech_ext; 632 633 /* check if the mechanism is already loaded */ 634 if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL) 635 return (aMech->mech_ext); 636 637 if (__gss_get_mechanism(oid) == NULL) 638 return (NULL); 639 640 if (aMech->dl_handle == NULL) 641 return (NULL); 642 643 /* Load the gss_config_ext struct for this mech */ 644 645 mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext)); 646 647 if (mech_ext == NULL) 648 return (NULL); 649 650 /* 651 * dlsym() the mech's 'method' functions for the extended APIs 652 * 653 * NOTE: Until the void *context argument is removed from the 654 * SPI method functions' signatures it will be necessary to have 655 * different function pointer typedefs and function names for 656 * the SPI methods than for the API. When this argument is 657 * removed it will be possible to rename gss_*_sfct to gss_*_fct 658 * and and gssspi_* to gss_*. 659 */ 660 mech_ext->gss_acquire_cred_with_password = 661 (gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle, 662 "gssspi_acquire_cred_with_password"); 663 664 /* Set aMech->mech_ext */ 665 (void) mutex_lock(&g_mechListLock); 666 667 if (aMech->mech_ext == NULL) 668 aMech->mech_ext = mech_ext; 669 else 670 free(mech_ext); /* we raced and lost; don't leak */ 671 672 (void) mutex_unlock(&g_mechListLock); 673 674 return (aMech->mech_ext); 675 676 } /* __gss_get_mechanism_ext */ 677 678 679 /* 680 * this routine is used for searching the list of mechanism data. 681 * it needs not be mutex protected because we only add new structures 682 * from the end and they are fully initialized before being added. 683 */ 684 static gss_mech_info searchMechList(oid) 685 const gss_OID oid; 686 { 687 gss_mech_info aMech = g_mechList; 688 689 /* if oid is null -> then get default which is the first in the list */ 690 if (oid == GSS_C_NULL_OID) 691 return (aMech); 692 693 while (aMech != NULL) { 694 if (g_OID_equal(aMech->mech_type, oid)) 695 return (aMech); 696 aMech = aMech->next; 697 } 698 699 /* none found */ 700 return ((gss_mech_info) NULL); 701 } /* searchMechList */ 702 703 704 /* 705 * loads the configuration file 706 * this is called while having a mutex lock on the mechanism list 707 * entries for libraries that have been loaded can't be modified 708 * mechNameStr and mech_type fields are not updated during updates 709 */ 710 static void loadConfigFile(fileName) 711 const char *fileName; 712 { 713 char buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp; 714 char *modOptions; 715 char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ]; 716 char *tmpStr; 717 FILE *confFile; 718 gss_OID mechOid; 719 gss_mech_info aMech, tmp; 720 OM_uint32 minor; 721 gss_buffer_desc oidBuf; 722 723 if ((confFile = fopen(fileName, "rF")) == NULL) { 724 return; 725 } 726 727 (void) memset(buffer, 0, sizeof (buffer)); 728 while (fgets(buffer, BUFSIZ, confFile) != NULL) { 729 730 /* ignore lines beginning with # */ 731 if (*buffer == '#') 732 continue; 733 734 /* 735 * find the first white-space character after 736 * the mechanism name 737 */ 738 oidStr = buffer; 739 for (oid = buffer; *oid && !isspace(*oid); oid++); 740 741 /* Now find the first non-white-space character */ 742 if (*oid) { 743 *oid = '\0'; 744 oid++; 745 while (*oid && isspace(*oid)) 746 oid++; 747 } 748 749 /* 750 * If that's all, then this is a corrupt entry. Skip it. 751 */ 752 if (! *oid) 753 continue; 754 755 /* Find the end of the oid and make sure it is NULL-ended */ 756 for (endp = oid; *endp && !isspace(*endp); endp++) 757 ; 758 759 if (*endp) { 760 *endp = '\0'; 761 } 762 763 /* 764 * check if an entry for this oid already exists 765 * if it does, and the library is already loaded then 766 * we can't modify it, so skip it 767 */ 768 oidBuf.value = (void *)oid; 769 oidBuf.length = strlen(oid); 770 if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid) 771 != GSS_S_COMPLETE) { 772 (void) syslog(LOG_INFO, "invalid mechanism oid" 773 " [%s] in configuration file", oid); 774 continue; 775 } 776 777 aMech = searchMechList(mechOid); 778 if (aMech && aMech->mech) { 779 free(mechOid->elements); 780 free(mechOid); 781 continue; 782 } 783 784 /* Find the start of the shared lib name */ 785 for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib); 786 sharedLib++) 787 ; 788 789 /* 790 * If that's all, then this is a corrupt entry. Skip it. 791 */ 792 if (! *sharedLib) { 793 free(mechOid->elements); 794 free(mechOid); 795 continue; 796 } 797 798 /* 799 * Find the end of the shared lib name and make sure it is 800 * NULL-terminated. 801 */ 802 for (endp = sharedLib; *endp && !isspace(*endp); endp++) 803 ; 804 805 if (*endp) { 806 *endp = '\0'; 807 } 808 809 /* Find the start of the optional kernel module lib name */ 810 for (kernMod = endp+1; *kernMod && isspace(*kernMod); 811 kernMod++) 812 ; 813 814 /* 815 * If this item starts with a bracket "[", then 816 * it is not a kernel module, but is a list of 817 * options for the user module to parse later. 818 */ 819 if (*kernMod && *kernMod != '[') { 820 /* 821 * Find the end of the shared lib name and make sure 822 * it is NULL-terminated. 823 */ 824 for (endp = kernMod; *endp && !isspace(*endp); endp++) 825 ; 826 827 if (*endp) { 828 *endp = '\0'; 829 } 830 } else 831 kernMod = NULL; 832 833 /* Find the start of the optional module options list */ 834 for (modOptions = endp+1; *modOptions && isspace(*modOptions); 835 modOptions++); 836 837 if (*modOptions == '[') { 838 /* move past the opening bracket */ 839 for (modOptions = modOptions+1; 840 *modOptions && isspace(*modOptions); 841 modOptions++); 842 843 /* Find the closing bracket */ 844 for (endp = modOptions; 845 *endp && *endp != ']'; endp++); 846 847 if (endp) 848 *endp = '\0'; 849 850 } else { 851 modOptions = NULL; 852 } 853 854 (void) strcpy(sharedPath, MECH_LIB_PREFIX); 855 (void) strcat(sharedPath, sharedLib); 856 857 /* 858 * are we creating a new mechanism entry or 859 * just modifying existing (non loaded) mechanism entry 860 */ 861 if (aMech) { 862 /* 863 * delete any old values and set new 864 * mechNameStr and mech_type are not modified 865 */ 866 if (aMech->kmodName) { 867 free(aMech->kmodName); 868 aMech->kmodName = NULL; 869 } 870 871 if (aMech->optionStr) { 872 free(aMech->optionStr); 873 aMech->optionStr = NULL; 874 } 875 876 if ((tmpStr = strdup(sharedPath)) != NULL) { 877 if (aMech->uLibName) 878 free(aMech->uLibName); 879 aMech->uLibName = tmpStr; 880 } 881 882 if (kernMod) /* this is an optional parameter */ 883 aMech->kmodName = strdup(kernMod); 884 885 if (modOptions) /* optional module options */ 886 aMech->optionStr = strdup(modOptions); 887 888 /* the oid is already set */ 889 free(mechOid->elements); 890 free(mechOid); 891 continue; 892 } 893 894 /* adding a new entry */ 895 aMech = malloc(sizeof (struct gss_mech_config)); 896 if (aMech == NULL) { 897 free(mechOid->elements); 898 free(mechOid); 899 continue; 900 } 901 (void) memset(aMech, 0, sizeof (struct gss_mech_config)); 902 aMech->mech_type = mechOid; 903 aMech->uLibName = strdup(sharedPath); 904 aMech->mechNameStr = strdup(oidStr); 905 906 /* check if any memory allocations failed - bad news */ 907 if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) { 908 if (aMech->uLibName) 909 free(aMech->uLibName); 910 if (aMech->mechNameStr) 911 free(aMech->mechNameStr); 912 free(mechOid->elements); 913 free(mechOid); 914 free(aMech); 915 continue; 916 } 917 if (kernMod) /* this is an optional parameter */ 918 aMech->kmodName = strdup(kernMod); 919 920 if (modOptions) 921 aMech->optionStr = strdup(modOptions); 922 /* 923 * add the new entry to the end of the list - make sure 924 * that only complete entries are added because other 925 * threads might currently be searching the list. 926 */ 927 tmp = g_mechListTail; 928 g_mechListTail = aMech; 929 930 if (tmp != NULL) 931 tmp->next = aMech; 932 933 if (g_mechList == NULL) 934 g_mechList = aMech; 935 } /* while */ 936 (void) fclose(confFile); 937 } /* loadConfigFile */ 938