aboutsummaryrefslogtreecommitdiff
path: root/src/lib/gssapi/mechglue/g_initialize.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/mechglue/g_initialize.c')
-rw-r--r--src/lib/gssapi/mechglue/g_initialize.c695
1 files changed, 632 insertions, 63 deletions
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index f2f1226..e762341 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -27,10 +27,15 @@
*/
#include "mglueP.h"
-#include "gss_libinit.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
#include <stdio.h>
#include <string.h>
@@ -40,16 +45,27 @@
#define M_DEFAULT "default"
#include "k5-thread.h"
+#include "k5-plugin.h"
+#include "osconf.h"
+#ifdef _GSS_STATIC_LINK
+#include "gssapiP_krb5.h"
+#include "gssapiP_spnego.h"
+#endif
+
+#define MECH_SYM "gss_mech_initialize"
+
+#ifndef MECH_CONF
+#define MECH_CONF "/etc/gss/mech"
+#endif
/* Local functions */
static gss_mech_info searchMechList(const gss_OID);
+static void loadConfigFile(const char *);
static void updateMechList(void);
static void freeMechList(void);
-static void register_mech(gss_mechanism, const char *, void *);
static OM_uint32 build_mechSet(void);
static void free_mechSet(void);
-static void init_hardcoded(void);
/*
* list of mechanism libraries and their entry points.
@@ -58,28 +74,67 @@ static void init_hardcoded(void);
static gss_mech_info g_mechList = NULL;
static gss_mech_info g_mechListTail = NULL;
static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
+static time_t g_confFileModTime = (time_t)0;
+static time_t g_mechSetTime = (time_t)0;
static gss_OID_set_desc g_mechSet = { 0, NULL };
static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;
+MAKE_INIT_FUNCTION(gssint_mechglue_init);
+MAKE_FINI_FUNCTION(gssint_mechglue_fini);
+
int
gssint_mechglue_init(void)
{
int err;
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gssint_mechglue_init\n");
+#endif
+
+ add_error_table(&et_ggss_error_table);
+
err = k5_mutex_finish_init(&g_mechSetLock);
- return k5_mutex_finish_init(&g_mechListLock);
+ err = k5_mutex_finish_init(&g_mechListLock);
+
+#ifdef _GSS_STATIC_LINK
+ err = gss_krb5int_lib_init();
+ err = gss_spnegoint_lib_init();
+#endif
+
+ return err;
}
void
gssint_mechglue_fini(void)
{
+ if (!INITIALIZER_RAN(gssint_mechglue_init) || PROGRAM_EXITING()) {
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gssint_mechglue_fini: skipping\n");
+#endif
+ return;
+ }
+
+#ifdef SHOW_INITFINI_FUNCS
+ printf("gssint_mechglue_fini\n");
+#endif
+#ifdef _GSS_STATIC_LINK
+ gss_spnegoint_lib_fini();
+ gss_krb5int_lib_fini();
+#endif
k5_mutex_destroy(&g_mechSetLock);
k5_mutex_destroy(&g_mechListLock);
free_mechSet();
freeMechList();
+ remove_error_table(&et_ggss_error_table);
+ gssint_mecherrmap_destroy();
}
+int
+gssint_mechglue_initialize_library(void)
+{
+ return CALL_INIT_FUNCTION(gssint_mechglue_init);
+}
/*
* function used to reclaim the memory used by a gss_OID structure.
@@ -93,13 +148,12 @@ gss_OID *oid;
OM_uint32 major;
gss_mech_info aMech;
- if (gssint_initialize_library())
- return GSS_S_FAILURE;
-
if (minor_status == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
- *minor_status = 0;
+ *minor_status = gssint_mechglue_initialize_library();
+ if (*minor_status != 0)
+ return (GSS_S_FAILURE);
*minor_status = k5_mutex_lock(&g_mechListLock);
if (*minor_status)
@@ -116,7 +170,6 @@ gss_OID *oid;
*/
if (aMech->mech && aMech->mech->gss_internal_release_oid) {
major = aMech->mech->gss_internal_release_oid(
- aMech->mech->context,
minor_status, oid);
if (major == GSS_S_COMPLETE) {
k5_mutex_unlock(&g_mechListLock);
@@ -146,6 +199,8 @@ gss_indicate_mechs(minorStatus, mechSet)
OM_uint32 *minorStatus;
gss_OID_set *mechSet;
{
+ char *fileName;
+ struct stat fileInfo;
unsigned int i, j;
gss_OID curItem;
@@ -161,9 +216,20 @@ gss_OID_set *mechSet;
if (minorStatus == NULL || mechSet == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
- if (gssint_initialize_library())
- return GSS_S_FAILURE;
+ *minorStatus = gssint_mechglue_initialize_library();
+ if (*minorStatus != 0)
+ return (GSS_S_FAILURE);
+
+ fileName = MECH_CONF;
+ /*
+ * 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.
+ */
+ if ((stat(fileName, &fileInfo) == 0 &&
+ fileInfo.st_mtime > g_mechSetTime)) {
+ } /* if g_mechSet is out of date or not initialized */
if (build_mechSet())
return GSS_S_FAILURE;
@@ -247,7 +313,8 @@ static OM_uint32
build_mechSet(void)
{
gss_mech_info mList;
- int i, count;
+ size_t i;
+ size_t count;
gss_OID curItem;
/*
@@ -260,6 +327,20 @@ build_mechSet(void)
if (k5_mutex_lock(&g_mechListLock) != 0)
return GSS_S_FAILURE;
+#if 0
+ /*
+ * 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
+ * gssint_get_mechanism)
+ */
+ if (fileInfo.st_mtime > g_confFileModTime)
+ {
+ g_confFileModTime = fileInfo.st_mtime;
+ loadConfigFile(fileName);
+ }
+#endif
+
updateMechList();
/*
@@ -323,6 +404,9 @@ build_mechSet(void)
}
}
+#if 0
+ g_mechSetTime = fileInfo.st_mtime;
+#endif
(void) k5_mutex_unlock(&g_mechSetLock);
(void) k5_mutex_unlock(&g_mechListLock);
@@ -344,6 +428,9 @@ const gss_OID oid;
gss_mech_info aMech;
char *modOptions = NULL;
+ if (gssint_mechglue_initialize_library() != 0)
+ return (NULL);
+
/* make sure we have fresh data */
if (k5_mutex_lock(&g_mechListLock) != 0)
return NULL;
@@ -375,6 +462,9 @@ gssint_mech_to_oid(const char *mechStr, gss_OID* oid)
*oid = GSS_C_NULL_OID;
+ if (gssint_mechglue_initialize_library() != 0)
+ return (GSS_S_FAILURE);
+
if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
(strcasecmp(mechStr, M_DEFAULT) == 0))
return (GSS_S_COMPLETE);
@@ -413,6 +503,9 @@ gssint_oid_to_mech(const gss_OID oid)
if (oid == GSS_C_NULL_OID)
return (M_DEFAULT);
+ if (gssint_mechglue_initialize_library() != 0)
+ return (NULL);
+
/* ensure we have fresh data */
if (k5_mutex_lock(&g_mechListLock) != 0)
return NULL;
@@ -437,11 +530,12 @@ gssint_get_mechanisms(char *mechArray[], int arrayLen)
gss_mech_info aMech;
int i;
- if (gssint_initialize_library())
- return GSS_S_FAILURE;
if (mechArray == NULL || arrayLen < 1)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ if (gssint_mechglue_initialize_library() != 0)
+ return (GSS_S_FAILURE);
+
/* ensure we have fresh data */
if (k5_mutex_lock(&g_mechListLock) != 0)
return GSS_S_FAILURE;
@@ -463,7 +557,6 @@ gssint_get_mechanisms(char *mechArray[], int arrayLen)
return (GSS_S_COMPLETE);
} /* gss_get_mechanisms */
-
/*
* determines if the mechList needs to be updated from file
* and performs the update.
@@ -472,56 +565,128 @@ gssint_get_mechanisms(char *mechArray[], int arrayLen)
static void
updateMechList(void)
{
-
+ char *fileName;
+ struct stat fileInfo;
+
+ fileName = MECH_CONF;
+
+ /* check if mechList needs updating */
+ if (stat(fileName, &fileInfo) == 0 &&
+ (fileInfo.st_mtime > g_confFileModTime)) {
+ loadConfigFile(fileName);
+ g_confFileModTime = fileInfo.st_mtime;
+ }
+#if 0
init_hardcoded();
-
+#endif
} /* updateMechList */
+#ifdef _GSS_STATIC_LINK
static void
-freeMechList(void)
+releaseMechInfo(gss_mech_info *pCf)
{
- gss_mech_info cf, next_cf;
+ gss_mech_info cf;
+ OM_uint32 minor_status;
- for (cf = g_mechList; cf != NULL; cf = next_cf) {
- next_cf = cf->next;
+ if (*pCf == NULL) {
+ return;
+ }
+
+ cf = *pCf;
+
+ if (cf->kmodName != NULL)
+ free(cf->kmodName);
+ if (cf->uLibName != NULL)
free(cf->uLibName);
+ if (cf->mechNameStr != NULL)
free(cf->mechNameStr);
- free(cf);
+ if (cf->optionStr != NULL)
+ free(cf->optionStr);
+ if (cf->mech_type != GSS_C_NO_OID &&
+ cf->mech_type != &cf->mech->mech_type)
+ generic_gss_release_oid(&minor_status, &cf->mech_type);
+ if (cf->mech != NULL) {
+ memset(cf->mech, 0, sizeof(*cf->mech));
+ free(cf->mech);
}
+ if (cf->dl_handle != NULL)
+ krb5int_close_plugin(cf->dl_handle);
+
+ memset(cf, 0, sizeof(*cf));
+ free(cf);
+
+ *pCf = NULL;
}
/*
* Register a mechanism. Called with g_mechListLock held.
*/
-static void
-register_mech(gss_mechanism mech, const char *namestr, void *dl_handle)
+int
+gssint_register_mechinfo(gss_mech_info template)
{
gss_mech_info cf, new_cf;
- new_cf = malloc(sizeof(*new_cf));
- if (new_cf == NULL)
- return;
+ new_cf = calloc(1, sizeof(*new_cf));
+ if (new_cf == NULL) {
+ return ENOMEM;
+ }
- memset(new_cf, 0, sizeof(*new_cf));
- new_cf->kmodName = NULL;
- new_cf->uLibName = strdup(namestr);
- new_cf->mechNameStr = strdup(mech->mechNameStr);
- new_cf->mech_type = &mech->mech_type;
- new_cf->mech = mech;
+ new_cf->dl_handle = template->dl_handle;
+ /* copy mech so we can rewrite canonical mechanism OID */
+ new_cf->mech = (gss_mechanism)calloc(1, sizeof(struct gss_config));
+ if (new_cf->mech == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ memcpy(new_cf->mech, template->mech, sizeof(struct gss_config));
+ if (template->mech_type != NULL)
+ new_cf->mech->mech_type = *(template->mech_type);
+ new_cf->mech_type = &new_cf->mech->mech_type;
+ new_cf->priority = template->priority;
+ new_cf->freeMech = 1;
new_cf->next = NULL;
+ if (template->kmodName != NULL) {
+ new_cf->kmodName = strdup(template->kmodName);
+ if (new_cf->kmodName == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (template->uLibName != NULL) {
+ new_cf->uLibName = strdup(template->uLibName);
+ if (new_cf->uLibName == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (template->mechNameStr != NULL) {
+ new_cf->mechNameStr = strdup(template->mechNameStr);
+ if (new_cf->mechNameStr == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
+ if (template->optionStr != NULL) {
+ new_cf->optionStr = strdup(template->optionStr);
+ if (new_cf->optionStr == NULL) {
+ releaseMechInfo(&new_cf);
+ return ENOMEM;
+ }
+ }
if (g_mechList == NULL) {
g_mechList = new_cf;
g_mechListTail = new_cf;
- return;
- } else if (mech->priority < g_mechList->mech->priority) {
+ return 0;
+ } else if (new_cf->priority < g_mechList->priority) {
new_cf->next = g_mechList;
g_mechList = new_cf;
- return;
+ return 0;
}
+
for (cf = g_mechList; cf != NULL; cf = cf->next) {
if (cf->next == NULL ||
- mech->priority < cf->next->mech->priority) {
+ new_cf->priority < cf->next->priority) {
new_cf->next = cf->next;
cf->next = new_cf;
if (g_mechListTail == cf) {
@@ -530,36 +695,113 @@ register_mech(gss_mechanism mech, const char *namestr, void *dl_handle)
break;
}
}
+
+ return 0;
+}
+#endif /* _GSS_STATIC_LINK */
+
+#define GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol) \
+ do { \
+ struct errinfo errinfo; \
+ \
+ memset(&errinfo, 0, sizeof(errinfo)); \
+ if (krb5int_get_plugin_func(_dl, \
+ #_symbol, \
+ (void (**)())&(_mech)->_symbol, \
+ &errinfo) || errinfo.code) \
+ (_mech)->_symbol = NULL; \
+ } while (0)
+
+static gss_mechanism
+build_dynamicMech(void *dl, const gss_OID mech_type)
+{
+ gss_mechanism mech;
+
+ mech = (gss_mechanism)calloc(1, sizeof(*mech));
+ if (mech == NULL) {
+ return NULL;
+ }
+
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_acquire_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_release_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_init_sec_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_accept_sec_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_process_context_token);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_delete_sec_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_context_time);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_get_mic);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_verify_mic);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_display_status);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_indicate_mechs);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_compare_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_display_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_import_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_release_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_add_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_export_sec_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_import_sec_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_cred_by_mech);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_names_for_mech);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_context);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_internal_release_oid);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_size_limit);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_export_name);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_store_cred);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_import_name_object);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_export_name_object);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_sec_context_by_oid);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_inquire_cred_by_oid);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_set_sec_context_option);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_set_cred_option);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_mech_invoke);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_aead);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap_aead);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_iov);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_unwrap_iov);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_wrap_iov_length);
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_complete_auth_token);
+
+ assert(mech_type != GSS_C_NO_OID);
+
+ mech->mech_type = *(mech_type);
+
+ return mech;
}
-/*
- * Initialize the hardcoded mechanisms. This function is called with
- * g_mechListLock held.
- */
static void
-init_hardcoded(void)
+freeMechList(void)
{
- gss_mechanism *cflist;
- static int inited;
-
- if (inited)
- return;
+ gss_mech_info cf, next_cf;
+ OM_uint32 minor;
- cflist = krb5_gss_get_mech_configs();
- if (cflist == NULL)
- return;
- for ( ; *cflist != NULL; cflist++) {
- register_mech(*cflist, "<builtin krb5>", NULL);
- }
- cflist = spnego_gss_get_mech_configs();
- if (cflist == NULL)
- return;
- for ( ; *cflist != NULL; cflist++) {
- register_mech(*cflist, "<builtin spnego>", NULL);
+ for (cf = g_mechList; cf != NULL; cf = next_cf) {
+ next_cf = cf->next;
+ if (cf->kmodName != NULL)
+ free(cf->kmodName);
+ if (cf->uLibName != NULL)
+ free(cf->uLibName);
+ if (cf->mechNameStr != NULL)
+ free(cf->mechNameStr);
+ if (cf->optionStr != NULL)
+ free(cf->optionStr);
+ if (cf->mech_type != &cf->mech->mech_type)
+ generic_gss_release_oid(&minor, &cf->mech_type);
+ if (cf->mech != NULL && cf->freeMech)
+ free(cf->mech);
+ if (cf->mech_ext != NULL && cf->freeMech)
+ free(cf->mech_ext);
+ if (cf->dl_handle != NULL)
+ (void) krb5int_close_plugin(cf->dl_handle);
+ free(cf);
}
- inited = 1;
}
+/*
+ * Register a mechanism. Called with g_mechListLock held.
+ */
/*
* given the mechanism type, return the mechanism structure
@@ -569,12 +811,16 @@ init_hardcoded(void)
* module if it has not been already loaded.
*/
gss_mechanism
-gssint_get_mechanism(gss_OID oid)
+gssint_get_mechanism(oid)
+const gss_OID oid;
{
gss_mech_info aMech;
+ gss_mechanism (*sym)(const gss_OID);
+ struct plugin_file_handle *dl;
+ struct errinfo errinfo;
- if (gssint_initialize_library())
- return NULL;
+ if (gssint_mechglue_initialize_library() != 0)
+ return (NULL);
if (k5_mutex_lock(&g_mechListLock) != 0)
return NULL;
@@ -602,11 +848,102 @@ gssint_get_mechanism(gss_OID oid)
if (aMech->mech) {
(void) k5_mutex_unlock(&g_mechListLock);
return (aMech->mech);
+ }
+
+ memset(&errinfo, 0, sizeof(errinfo));
+
+ if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||
+ errinfo.code != 0) {
+#if 0
+ (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+ aMech->uLibName, dlerror());
+#endif
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
+ }
+
+ if (krb5int_get_plugin_func(dl, MECH_SYM, (void (**)())&sym,
+ &errinfo) == 0) {
+ /* Call the symbol to get the mechanism table */
+ aMech->mech = (*sym)(aMech->mech_type);
} else {
- return NULL;
+ /* Try dynamic dispatch table */
+ aMech->mech = build_dynamicMech(dl, aMech->mech_type);
+ aMech->freeMech = 1;
}
+ if (aMech->mech == NULL) {
+ (void) krb5int_close_plugin(dl);
+#if 0
+ (void) syslog(LOG_INFO, "unable to initialize mechanism"
+ " library [%s]\n", aMech->uLibName);
+#endif
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return ((gss_mechanism)NULL);
+ }
+
+ aMech->dl_handle = dl;
+
+ (void) k5_mutex_unlock(&g_mechListLock);
+ return (aMech->mech);
} /* gssint_get_mechanism */
+gss_mechanism_ext
+gssint_get_mechanism_ext(oid)
+const gss_OID oid;
+{
+ gss_mech_info aMech;
+ gss_mechanism_ext mech_ext;
+
+ if (gssint_mechglue_initialize_library() != 0)
+ return (NULL);
+
+ /* check if the mechanism is already loaded */
+ if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL)
+ return (aMech->mech_ext);
+
+ if (gssint_get_mechanism(oid) == NULL)
+ return (NULL);
+
+ if (aMech->dl_handle == NULL)
+ return (NULL);
+
+ /* Load the gss_config_ext struct for this mech */
+
+ mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext));
+
+ if (mech_ext == NULL)
+ return (NULL);
+
+#if 0
+ /*
+ * 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_*.
+ */
+ mech_ext->gss_acquire_cred_with_password =
+ (gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle,
+ "gssspi_acquire_cred_with_password");
+#endif
+
+ /* Set aMech->mech_ext */
+ (void) k5_mutex_lock(&g_mechListLock);
+
+ if (aMech->mech_ext == NULL)
+ aMech->mech_ext = mech_ext;
+ else
+ free(mech_ext); /* we raced and lost; don't leak */
+
+ (void) k5_mutex_unlock(&g_mechListLock);
+
+ return (aMech->mech_ext);
+
+} /* gssint_get_mechanism_ext */
+
/*
* this routine is used for searching the list of mechanism data.
@@ -631,3 +968,235 @@ const gss_OID oid;
/* 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 buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp;
+ char *modOptions;
+ char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
+ char *tmpStr;
+ FILE *confFile;
+ gss_OID mechOid;
+ gss_mech_info aMech, tmp;
+ OM_uint32 minor;
+ gss_buffer_desc oidBuf;
+
+ if ((confFile = fopen(fileName, "r")) == NULL) {
+ return;
+ }
+
+ (void) memset(buffer, 0, sizeof (buffer));
+ while (fgets(buffer, BUFSIZ, confFile) != NULL) {
+
+ /* ignore lines beginning with # */
+ if (*buffer == '#')
+ continue;
+
+ /*
+ * find the first white-space character after
+ * the mechanism name
+ */
+ oidStr = buffer;
+ for (oid = buffer; *oid && !isspace(*oid); oid++);
+
+ /* Now find the first non-white-space character */
+ if (*oid) {
+ *oid = '\0';
+ oid++;
+ while (*oid && isspace(*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 */
+ for (endp = oid; *endp && !isspace(*endp); endp++)
+ ;
+
+ 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
+ */
+ oidBuf.value = (void *)oid;
+ oidBuf.length = strlen(oid);
+ if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
+ != GSS_S_COMPLETE) {
+#if 0
+ (void) syslog(LOG_INFO, "invalid mechanism oid"
+ " [%s] in configuration file", oid);
+#endif
+ continue;
+ }
+
+ aMech = searchMechList(mechOid);
+ if (aMech && aMech->mech) {
+ generic_gss_release_oid(&minor, &mechOid);
+ continue;
+ }
+
+ /* Find the start of the shared lib name */
+ for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib);
+ sharedLib++)
+ ;
+
+ /*
+ * If that's all, then this is a corrupt entry. Skip it.
+ */
+ if (! *sharedLib) {
+ generic_gss_release_oid(&minor, &mechOid);
+ continue;
+ }
+
+ /*
+ * Find the end of the shared lib name and make sure it is
+ * NULL-terminated.
+ */
+ for (endp = sharedLib; *endp && !isspace(*endp); endp++)
+ ;
+
+ if (*endp) {
+ *endp = '\0';
+ }
+
+ /* Find the start of the optional kernel module lib name */
+ for (kernMod = endp+1; *kernMod && isspace(*kernMod);
+ 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.
+ */
+ if (*kernMod && *kernMod != '[') {
+ /*
+ * Find the end of the shared lib name and make sure
+ * it is NULL-terminated.
+ */
+ for (endp = kernMod; *endp && !isspace(*endp); endp++)
+ ;
+
+ if (*endp) {
+ *endp = '\0';
+ }
+ } else
+ kernMod = NULL;
+
+ /* Find the start of the optional module options list */
+ for (modOptions = endp+1; *modOptions && isspace(*modOptions);
+ modOptions++);
+
+ if (*modOptions == '[') {
+ /* move past the opening bracket */
+ for (modOptions = modOptions+1;
+ *modOptions && isspace(*modOptions);
+ modOptions++);
+
+ /* Find the closing bracket */
+ for (endp = modOptions;
+ *endp && *endp != ']'; endp++);
+
+ if (endp)
+ *endp = '\0';
+
+ } else {
+ modOptions = NULL;
+ }
+
+ snprintf(sharedPath, sizeof(sharedPath), "%s%s", MECH_LIB_PREFIX, sharedLib);
+
+ /*
+ * 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 (aMech->kmodName) {
+ free(aMech->kmodName);
+ aMech->kmodName = NULL;
+ }
+
+ if (aMech->optionStr) {
+ free(aMech->optionStr);
+ aMech->optionStr = NULL;
+ }
+
+ if ((tmpStr = strdup(sharedPath)) != NULL) {
+ if (aMech->uLibName)
+ free(aMech->uLibName);
+ aMech->uLibName = tmpStr;
+ }
+
+ if (kernMod) /* this is an optional parameter */
+ aMech->kmodName = strdup(kernMod);
+
+ if (modOptions) /* optional module options */
+ aMech->optionStr = strdup(modOptions);
+
+ /* the oid is already set */
+ generic_gss_release_oid(&minor, &mechOid);
+ continue;
+ }
+
+ /* adding a new entry */
+ aMech = calloc(1, sizeof (struct gss_mech_config));
+ if (aMech == NULL) {
+ generic_gss_release_oid(&minor, &mechOid);
+ continue;
+ }
+ aMech->mech_type = mechOid;
+ aMech->uLibName = strdup(sharedPath);
+ aMech->mechNameStr = strdup(oidStr);
+ aMech->freeMech = 0;
+
+ /* check if any memory allocations failed - bad news */
+ if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
+ if (aMech->uLibName)
+ free(aMech->uLibName);
+ if (aMech->mechNameStr)
+ free(aMech->mechNameStr);
+ generic_gss_release_oid(&minor, &mechOid);
+ free(aMech);
+ continue;
+ }
+ if (kernMod) /* this is an optional parameter */
+ aMech->kmodName = strdup(kernMod);
+
+ if (modOptions)
+ aMech->optionStr = strdup(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.
+ */
+ tmp = g_mechListTail;
+ g_mechListTail = aMech;
+
+ if (tmp != NULL)
+ tmp->next = aMech;
+
+ if (g_mechList == NULL)
+ g_mechList = aMech;
+ } /* while */
+ (void) fclose(confFile);
+} /* loadConfigFile */