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