Home | History | Annotate | Download | only in libgss
      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 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * This file contains functions to initialize the gssapi library and
     30  * load mechanism libraries.
     31  *
     32  * It also contain functions requiring direct access to the mechanism's
     33  * list (gss_inidicate_mechs and gss_release_oid) as well as support
     34  * functions which translate the mechanism strings to oids and vise versa.
     35  *
     36  * The mechanism libraries are loaded on demand.  This is triggered
     37  * through the get_mechanism function call.
     38  *
     39  * Updates to the mechList are performed with the following restrictions:
     40  *	- once a library is loaded, none of the fields are updated
     41  *	- existing entiries for non-loaded mechs, will have the
     42  *		library and kernel module names updated only
     43  *		(i.e. the mech oid and mech name will not be updated)
     44  */
     45 
     46 #include <mechglueP.h>
     47 #include <stdio.h>
     48 #include <syslog.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <sys/stat.h>
     52 #include <ctype.h>
     53 #include <errno.h>
     54 #include <synch.h>
     55 #include <dlfcn.h>
     56 #include <libintl.h>
     57 
     58 
     59 #ifndef TEXT_DOMAIN
     60 #error TEXT_DOMAIN not defined
     61 #endif
     62 
     63 #define	MECH_CONF "/etc/gss/mech"
     64 
     65 #define	MECH_LIB_PREFIX1	"/usr/lib/"
     66 
     67 /*
     68  * This #ifdef mess figures out if we are to be compiled into
     69  * a sparcv9/lp64 binary for the purposes of figuring the absolute location
     70  * of gss-api mechanism modules.
     71  */
     72 #ifdef	_LP64
     73 
     74 #ifdef	__sparc
     75 
     76 #define	MECH_LIB_PREFIX2	"sparcv9/"
     77 
     78 #elif defined(__amd64)
     79 
     80 #define	MECH_LIB_PREFIX2	"amd64/"
     81 
     82 #else	/* __sparc */
     83 
     84 you need to define where under /usr the LP64 libraries live for this platform
     85 
     86 #endif	/* __sparc */
     87 
     88 #else	/* _LP64 */
     89 
     90 #define	MECH_LIB_PREFIX2	""
     91 
     92 #endif	/* _LP64 */
     93 
     94 #define	MECH_LIB_DIR		"gss/"
     95 
     96 #define	MECH_LIB_PREFIX	MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR
     97 
     98 
     99 #ifndef	MECH_SYM
    100 #define	MECH_SYM "gss_mech_initialize"
    101 #endif
    102 
    103 #define	M_DEFAULT	"default"
    104 
    105 /* Local functions */
    106 static gss_mech_info searchMechList(const gss_OID);
    107 static void loadConfigFile(const char *);
    108 static void updateMechList(void);
    109 
    110 
    111 /*
    112  * list of mechanism libraries and their entry points.
    113  * the list also maintains state of the mech libraries (loaded or not).
    114  */
    115 static gss_mech_info g_mechList = NULL;
    116 static gss_mech_info g_mechListTail = NULL;
    117 static mutex_t g_mechListLock;
    118 static time_t g_confFileModTime = (time_t)0;
    119 
    120 /*
    121  * function used to reclaim the memory used by a gss_OID structure.
    122  * This routine requires direct access to the mechList.
    123  */
    124 OM_uint32
    125 gss_release_oid(minor_status, oid)
    126 OM_uint32 *minor_status;
    127 gss_OID *oid;
    128 {
    129 	OM_uint32 major;
    130 	gss_mech_info aMech = g_mechList;
    131 
    132 	if (minor_status == NULL)
    133 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    134 
    135 	*minor_status = 0;
    136 
    137 	while (aMech != NULL) {
    138 
    139 		/*
    140 		 * look through the loaded mechanism libraries for
    141 		 * gss_internal_release_oid until one returns success.
    142 		 * gss_internal_release_oid will only return success when
    143 		 * the OID was recognized as an internal mechanism OID. if no
    144 		 * mechanisms recognize the OID, then call the generic version.
    145 		 */
    146 
    147 		/*
    148 		 * we can walk the mechanism list without a mutex, because we
    149 		 * are only looking at fields which once read will never change.
    150 		 * Mechanism entries are always added to the end, and as
    151 		 * complete entries.
    152 		 */
    153 		if (aMech->mech && aMech->mech->gss_internal_release_oid) {
    154 			major = aMech->mech->gss_internal_release_oid(
    155 					aMech->mech->context,
    156 					minor_status, oid);
    157 			if (major == GSS_S_COMPLETE)
    158 				return (GSS_S_COMPLETE);
    159 		}
    160 		aMech = aMech->next;
    161 	} /* while */
    162 
    163 	return (generic_gss_release_oid(minor_status, oid));
    164 } /* gss_release_oid */
    165 
    166 
    167 /*
    168  * this function will return an oid set indicating available mechanisms.
    169  * The set returned is based on configuration file entries and
    170  * NOT on the loaded mechanisms.  This function does not check if any
    171  * of these can actually be loaded.
    172  * This routine needs direct access to the mechanism list.
    173  * To avoid reading the configuration file each call, we will save a
    174  * a mech oid set, and only update it once the file has changed.
    175  */
    176 static time_t g_mechSetTime = (time_t)0;
    177 static gss_OID_set_desc g_mechSet = { 0, NULL };
    178 static mutex_t g_mechSetLock;
    179 
    180 
    181 OM_uint32
    182 gss_indicate_mechs(minorStatus, mechSet)
    183 OM_uint32 *minorStatus;
    184 gss_OID_set *mechSet;
    185 {
    186 	gss_mech_info mList;
    187 	char *fileName;
    188 	struct stat fileInfo;
    189 	int count, i, j;
    190 	gss_OID curItem;
    191 
    192 	if (!minorStatus)
    193 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    194 
    195 	*minorStatus = 0;
    196 
    197 
    198 	/* check output parameter */
    199 	if (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