g_initialize.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains functions to initialize the gssapi library and
* load mechanism libraries.
*
* It also contain functions requiring direct access to the mechanism's
* list (gss_inidicate_mechs and gss_release_oid) as well as support
* functions which translate the mechanism strings to oids and vise versa.
*
* The mechanism libraries are loaded on demand. This is triggered
* through the get_mechanism function call.
*
* Updates to the mechList are performed with the following restrictions:
* - once a library is loaded, none of the fields are updated
* - existing entiries for non-loaded mechs, will have the
* library and kernel module names updated only
* (i.e. the mech oid and mech name will not be updated)
*/
#include <mechglueP.h>
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <synch.h>
#include <dlfcn.h>
#include <libintl.h>
#ifndef TEXT_DOMAIN
#endif
#define MECH_LIB_PREFIX1 "/usr/lib/"
/*
* This #ifdef mess figures out if we are to be compiled into
* of gss-api mechanism modules.
*/
#ifdef _LP64
#ifdef __sparc
#define MECH_LIB_PREFIX2 "sparcv9/"
#define MECH_LIB_PREFIX2 "amd64/"
#else /* __sparc */
#endif /* __sparc */
#else /* _LP64 */
#define MECH_LIB_PREFIX2 ""
#endif /* _LP64 */
#define MECH_LIB_DIR "gss/"
#ifndef MECH_SYM
#define MECH_SYM "gss_mech_initialize"
#endif
#define M_DEFAULT "default"
/* Local functions */
static void loadConfigFile(const char *);
static void updateMechList(void);
/*
* list of mechanism libraries and their entry points.
* the list also maintains state of the mech libraries (loaded or not).
*/
static mutex_t g_mechListLock;
/*
* function used to reclaim the memory used by a gss_OID structure.
* This routine requires direct access to the mechList.
*/
{
if (minor_status == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor_status = 0;
/*
* look through the loaded mechanism libraries for
* gss_internal_release_oid until one returns success.
* gss_internal_release_oid will only return success when
* the OID was recognized as an internal mechanism OID. if no
* mechanisms recognize the OID, then call the generic version.
*/
/*
* we can walk the mechanism list without a mutex, because we
* are only looking at fields which once read will never change.
* Mechanism entries are always added to the end, and as
* complete entries.
*/
minor_status, oid);
if (major == GSS_S_COMPLETE)
return (GSS_S_COMPLETE);
}
} /* while */
} /* gss_release_oid */
/*
* this function will return an oid set indicating available mechanisms.
* The set returned is based on configuration file entries and
* NOT on the loaded mechanisms. This function does not check if any
* of these can actually be loaded.
* This routine needs direct access to the mechanism list.
* To avoid reading the configuration file each call, we will save a
* a mech oid set, and only update it once the file has changed.
*/
static mutex_t g_mechSetLock;
{
char *fileName;
int count, i, j;
if (!minorStatus)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minorStatus = 0;
/* check output parameter */
return (GSS_S_CALL_INACCESSIBLE_WRITE);
/*
* If we have already computed the mechanisms supported and if it
* is still valid; make a copy and return to caller,
* otherwise build it first.
*/
/*
* lock the mutex since we will be updating
* the mechList structure
* we need to keep the lock while we build the mechanism list
* since we are accessing parts of the mechList which could be
* modified.
*/
(void) mutex_lock(&g_mechListLock);
/*
* this checks for the case when we need to re-construct the
* g_mechSet structure, but the mechanism list is upto date
* (because it has been read by someone calling
* __gss_get_mechanism)
*/
{
}
/*
* we need to lock the mech set so that no one else will
* try to read it as we are re-creating it
*/
(void) mutex_lock(&g_mechSetLock);
/* if the oid list already exists we must free it first */
}
/* determine how many elements to have in the list */
mList = g_mechList;
count = 0;
count++;
}
/* this should always be true, but.... */
if (count > 0) {
(void) mutex_unlock(&g_mechSetLock);
(void) mutex_unlock(&g_mechListLock);
return (GSS_S_FAILURE);
}
count * sizeof (gss_OID_desc));
/* now copy each oid element */
count = 0;
mList = g_mechList;
/*
* this is nasty - we must delete the
* part of the array already copied
*/
for (i = 0; i < count; i++) {
elements);
}
(void) mutex_unlock(&g_mechSetLock);
(void) mutex_unlock(&g_mechListLock);
return (GSS_S_FAILURE);
}
count++;
}
}
(void) mutex_unlock(&g_mechSetLock);
(void) mutex_unlock(&g_mechListLock);
} /* if g_mechSet is out of date or not initialized */
/*
* the mech set is created and it is up to date
* so just copy it to caller
*/
if ((*mechSet =
{
return (GSS_S_FAILURE);
}
/*
* need to lock the g_mechSet in case someone tries to update it while
* I'm copying it.
*/
(void) mutex_lock(&g_mechSetLock);
/* allocate space for the oid structures */
== NULL)
{
(void) mutex_unlock(&g_mechSetLock);
return (GSS_S_FAILURE);
}
/* now copy the oid structures */
/* still need to copy each of the oid elements arrays */
(void) mutex_unlock(&g_mechSetLock);
/*
* must still free the allocated elements for
* each allocated gss_OID_desc
*/
for (j = 0; j < i; j++) {
}
return (GSS_S_FAILURE);
}
}
(void) mutex_unlock(&g_mechSetLock);
return (GSS_S_COMPLETE);
} /* gss_indicate_mechs */
/*
* this function has been added for use by modules that need to
* know what (if any) optional parameters are supplied in the
* config file (MECH_CONF).
* It will return the option string for a specified mechanism.
* caller is responsible for freeing the memory
*/
char *
{
char *modOptions = NULL;
/* make sure we have fresh data */
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
/* searching the list does not require a lock */
return (NULL);
}
/*
* need to obtain a lock on this structure in case someone else
* will try to update it during the copy
*/
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
return (modOptions);
} /* __gss_get_modOptions */
/*
* this function has been added for use by gssd.
* It will return the kernel module name for a specified mechanism.
* caller is responsible for freeing the memory
*/
char *
{
/* make sure we have fresh data */
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
/* searching the list does not require a lock */
return (NULL);
}
/*
* need to obtain a lock on this structure in case someone else
* will try to update it during the copy
*/
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
return (kmodName);
} /* __gss_get_kmodName */
/*
* given a mechanism string return the mechanism oid
*/
{
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*oid = GSS_C_NULL_OID;
return (GSS_S_COMPLETE);
/* ensure we have fresh data */
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
aMech = g_mechList;
/* no lock required - only looking at fields that are not updated */
if ((aMech->mechNameStr) &&
return (GSS_S_COMPLETE);
}
}
return (GSS_S_FAILURE);
} /* __gss_mech_to_oid */
/*
* Given the mechanism oid, return the readable mechanism name
* associated with that oid from the mech config file
*/
const char *
{
if (oid == GSS_C_NULL_OID)
return (M_DEFAULT);
/* ensure we have fresh data */
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
return (NULL);
return (aMech->mechNameStr);
} /* __gss_oid_to_mech */
/*
* return a list of mechanism strings supported
* upon return the array is terminated with a NULL entry
*/
{
int i;
return (GSS_S_CALL_INACCESSIBLE_WRITE);
/* ensure we have fresh data */
(void) mutex_lock(&g_mechListLock);
(void) mutex_unlock(&g_mechListLock);
aMech = g_mechList;
/* no lock required - only looking at fields that are not updated */
for (i = 1; i < arrayLen; i++) {
mechArray++;
} else
break;
}
return (GSS_S_COMPLETE);
} /* gss_get_mechanisms */
/*
* determines if the mechList needs to be updated from file
* and performs the update.
* this functions must be called with a lock of g_mechListLock
*/
static void
updateMechList(void)
{
char *fileName;
/* check if mechList needs updating */
}
} /* updateMechList */
/*
* given the mechanism type, return the mechanism structure
* containing the mechanism library entry points.
* will return NULL if mech type is not found
* This function will also trigger the loading of the mechanism
* module if it has not been already loaded.
*/
{
void *dl;
/* check if the mechanism is already loaded */
}
/*
* might need to re-read the configuration file before loading
* the mechanism to ensure we have the latest info.
*/
(void) mutex_lock(&g_mechListLock);
/* is the mechanism present in the list ? */
(void) mutex_unlock(&g_mechListLock);
return ((gss_mechanism)NULL);
}
/* has another thread loaded the mech */
(void) mutex_unlock(&g_mechListLock);
}
/* we found the mechanism, but it is not loaded */
(void) mutex_unlock(&g_mechListLock);
return ((gss_mechanism)NULL);
}
== NULL) {
(void) mutex_unlock(&g_mechListLock);
return ((gss_mechanism)NULL);
}
/* Call the symbol to get the mechanism table */
(void) mutex_unlock(&g_mechListLock);
return ((gss_mechanism)NULL);
}
(void) mutex_unlock(&g_mechListLock);
} /* __gss_get_mechanism */
{
/* check if the mechanism is already loaded */
return (NULL);
return (NULL);
/* Load the gss_config_ext struct for this mech */
return (NULL);
/*
* dlsym() the mech's 'method' functions for the extended APIs
*
* NOTE: Until the void *context argument is removed from the
* SPI method functions' signatures it will be necessary to have
* different function pointer typedefs and function names for
* the SPI methods than for the API. When this argument is
* removed it will be possible to rename gss_*_sfct to gss_*_fct
* and and gssspi_* to gss_*.
*/
"gssspi_acquire_cred_with_password");
/* Set aMech->mech_ext */
(void) mutex_lock(&g_mechListLock);
else
(void) mutex_unlock(&g_mechListLock);
} /* __gss_get_mechanism_ext */
/*
* this routine is used for searching the list of mechanism data.
* it needs not be mutex protected because we only add new structures
* from the end and they are fully initialized before being added.
*/
{
/* if oid is null -> then get default which is the first in the list */
if (oid == GSS_C_NULL_OID)
return (aMech);
return (aMech);
}
/* none found */
return ((gss_mech_info) NULL);
} /* searchMechList */
/*
* loads the configuration file
* this is called while having a mutex lock on the mechanism list
* entries for libraries that have been loaded can't be modified
* mechNameStr and mech_type fields are not updated during updates
*/
static void loadConfigFile(fileName)
const char *fileName;
{
char *modOptions;
char *tmpStr;
return;
}
/* ignore lines beginning with # */
if (*buffer == '#')
continue;
/*
* find the first white-space character after
* the mechanism name
*/
/* Now find the first non-white-space character */
if (*oid) {
*oid = '\0';
oid++;
oid++;
}
/*
* If that's all, then this is a corrupt entry. Skip it.
*/
if (! *oid)
continue;
/* Find the end of the oid and make sure it is NULL-ended */
;
if (*endp) {
*endp = '\0';
}
/*
* check if an entry for this oid already exists
* if it does, and the library is already loaded then
* we can't modify it, so skip it
*/
!= GSS_S_COMPLETE) {
" [%s] in configuration file", oid);
continue;
}
continue;
}
/* Find the start of the shared lib name */
sharedLib++)
;
/*
* If that's all, then this is a corrupt entry. Skip it.
*/
if (! *sharedLib) {
continue;
}
/*
* Find the end of the shared lib name and make sure it is
* NULL-terminated.
*/
;
if (*endp) {
*endp = '\0';
}
/* Find the start of the optional kernel module lib name */
kernMod++)
;
/*
* If this item starts with a bracket "[", then
* it is not a kernel module, but is a list of
* options for the user module to parse later.
*/
/*
* Find the end of the shared lib name and make sure
* it is NULL-terminated.
*/
;
if (*endp) {
*endp = '\0';
}
} else
/* Find the start of the optional module options list */
modOptions++);
if (*modOptions == '[') {
/* move past the opening bracket */
modOptions++);
/* Find the closing bracket */
for (endp = modOptions;
if (endp)
*endp = '\0';
} else {
modOptions = NULL;
}
/*
* are we creating a new mechanism entry or
* just modifying existing (non loaded) mechanism entry
*/
if (aMech) {
/*
* delete any old values and set new
* mechNameStr and mech_type are not modified
*/
}
}
}
if (kernMod) /* this is an optional parameter */
if (modOptions) /* optional module options */
/* the oid is already set */
continue;
}
/* adding a new entry */
continue;
}
/* check if any memory allocations failed - bad news */
if (aMech->mechNameStr)
continue;
}
if (kernMod) /* this is an optional parameter */
if (modOptions)
/*
* add the new entry to the end of the list - make sure
* that only complete entries are added because other
* threads might currently be searching the list.
*/
if (g_mechList == NULL)
g_mechList = aMech;
} /* while */
} /* loadConfigFile */