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