Path: blob/main/crypto/krb5/src/lib/gssapi/mechglue/g_initialize.c
39586 views
/* #pragma ident "@(#)g_initialize.c 1.36 05/02/02 SMI" */12/*3* Copyright 1996 by Sun Microsystems, Inc.4*5* Permission to use, copy, modify, distribute, and sell this software6* and its documentation for any purpose is hereby granted without fee,7* provided that the above copyright notice appears in all copies and8* that both that copyright notice and this permission notice appear in9* supporting documentation, and that the name of Sun Microsystems not be used10* in advertising or publicity pertaining to distribution of the software11* without specific, written prior permission. Sun Microsystems makes no12* representations about the suitability of this software for any13* purpose. It is provided "as is" without express or implied warranty.14*15* SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,16* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO17* EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR18* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF19* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR20* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR21* PERFORMANCE OF THIS SOFTWARE.22*/2324/*25* This function will initialize the gssapi mechglue library26*/2728#include "mglueP.h"29#ifdef HAVE_STDLIB_H30#include <stdlib.h>31#endif32#ifdef HAVE_SYS_STAT_H33#include <sys/stat.h>34#endif35#ifdef HAVE_SYS_PARAM_H36#include <sys/param.h>37#endif3839#include <stdio.h>40#include <string.h>41#include <ctype.h>42#include <errno.h>43#ifndef _WIN3244#include <glob.h>45#endif4647#define M_DEFAULT "default"4849#include "k5-thread.h"50#include "k5-plugin.h"51#include "osconf.h"52#ifdef _GSS_STATIC_LINK53#include "gssapiP_krb5.h"54#include "gssapiP_spnego.h"55#endif5657#define MECH_SYM "gss_mech_initialize"58#define MECH_INTERPOSER_SYM "gss_mech_interposer"5960#ifndef MECH_CONF61#define MECH_CONF "/etc/gss/mech"62#endif63#define MECH_CONF_PATTERN MECH_CONF ".d/*.conf"6465/* Local functions */66static void addConfigEntry(const char *oidStr, const char *oid,67const char *sharedLib, const char *kernMod,68const char *modOptions, const char *modType);69static gss_mech_info searchMechList(gss_const_OID);70static void loadConfigFile(const char *);71#if defined(_WIN32)72#ifndef MECH_KEY73#define MECH_KEY "SOFTWARE\\gss\\mech"74#endif75static time_t getRegKeyModTime(HKEY hBaseKey, const char *keyPath);76static time_t getRegConfigModTime(const char *keyPath);77static void getRegKeyValue(HKEY key, const char *keyPath, const char *valueName, void **data, DWORD *dataLen);78static void loadConfigFromRegistry(HKEY keyBase, const char *keyPath);79#endif80static void updateMechList(void);81static void initMechList(void);82static void loadInterMech(gss_mech_info aMech);83static void freeMechList(void);8485static OM_uint32 build_mechSet(void);86static void free_mechSet(void);8788/*89* list of mechanism libraries and their entry points.90* the list also maintains state of the mech libraries (loaded or not).91*/92static gss_mech_info g_mechList = NULL;93static gss_mech_info g_mechListTail = NULL;94static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;95static time_t g_confFileModTime = (time_t)-1;96static time_t g_confLastCall = (time_t)0;9798static gss_OID_set_desc g_mechSet = { 0, NULL };99static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;100101MAKE_INIT_FUNCTION(gssint_mechglue_init);102MAKE_FINI_FUNCTION(gssint_mechglue_fini);103104int105gssint_mechglue_init(void)106{107int err;108109#ifdef SHOW_INITFINI_FUNCS110printf("gssint_mechglue_init\n");111#endif112113add_error_table(&et_ggss_error_table);114115err = k5_mutex_finish_init(&g_mechSetLock);116if (err)117return err;118err = k5_mutex_finish_init(&g_mechListLock);119if (err)120return err;121122#ifdef _GSS_STATIC_LINK123err = gss_krb5int_lib_init();124if (err)125return err;126err = gss_spnegoint_lib_init();127if (err)128return err;129#endif130131err = gssint_mecherrmap_init();132return err;133}134135void136gssint_mechglue_fini(void)137{138if (!INITIALIZER_RAN(gssint_mechglue_init) || PROGRAM_EXITING()) {139#ifdef SHOW_INITFINI_FUNCS140printf("gssint_mechglue_fini: skipping\n");141#endif142return;143}144145#ifdef SHOW_INITFINI_FUNCS146printf("gssint_mechglue_fini\n");147#endif148#ifdef _GSS_STATIC_LINK149gss_spnegoint_lib_fini();150gss_krb5int_lib_fini();151#endif152k5_mutex_destroy(&g_mechSetLock);153k5_mutex_destroy(&g_mechListLock);154free_mechSet();155freeMechList();156remove_error_table(&et_ggss_error_table);157gssint_mecherrmap_destroy();158}159160int161gssint_mechglue_initialize_library(void)162{163return CALL_INIT_FUNCTION(gssint_mechglue_init);164}165166/*167* function used to reclaim the memory used by a gss_OID structure.168* This routine requires direct access to the mechList.169*/170OM_uint32 KRB5_CALLCONV171gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)172{173OM_uint32 major;174gss_mech_info aMech;175176if (minor_status != NULL)177*minor_status = 0;178179if (minor_status == NULL || oid == NULL)180return (GSS_S_CALL_INACCESSIBLE_WRITE);181182*minor_status = gssint_mechglue_initialize_library();183if (*minor_status != 0)184return (GSS_S_FAILURE);185186k5_mutex_lock(&g_mechListLock);187aMech = g_mechList;188while (aMech != NULL) {189190/*191* look through the loaded mechanism libraries for192* gss_internal_release_oid until one returns success.193* gss_internal_release_oid will only return success when194* the OID was recognized as an internal mechanism OID. if no195* mechanisms recognize the OID, then call the generic version.196*/197if (aMech->mech && aMech->mech->gss_internal_release_oid) {198major = aMech->mech->gss_internal_release_oid(199minor_status, oid);200if (major == GSS_S_COMPLETE) {201k5_mutex_unlock(&g_mechListLock);202return (GSS_S_COMPLETE);203}204map_error(minor_status, aMech->mech);205}206aMech = aMech->next;207} /* while */208k5_mutex_unlock(&g_mechListLock);209210return (generic_gss_release_oid(minor_status, oid));211} /* gss_release_oid */212213/*214* Wrapper around inquire_attrs_for_mech to determine whether a mechanism has215* the deprecated attribute. Must be called without g_mechSetLock since it216* will call into the mechglue.217*/218static int219is_deprecated(gss_OID element)220{221OM_uint32 major, minor;222gss_OID_set mech_attrs = GSS_C_NO_OID_SET;223int deprecated = 0;224225major = gss_inquire_attrs_for_mech(&minor, element, &mech_attrs, NULL);226if (major == GSS_S_COMPLETE) {227gss_test_oid_set_member(&minor, (gss_OID)GSS_C_MA_DEPRECATED,228mech_attrs, &deprecated);229}230231if (mech_attrs != GSS_C_NO_OID_SET)232gss_release_oid_set(&minor, &mech_attrs);233234return deprecated;235}236237/*238* Removes mechs with the deprecated attribute from an OID set. Must be239* called without g_mechSetLock held since it calls into the mechglue.240*/241static void242prune_deprecated(gss_OID_set mech_set)243{244OM_uint32 i, j;245246j = 0;247for (i = 0; i < mech_set->count; i++) {248if (!is_deprecated(&mech_set->elements[i]))249mech_set->elements[j++] = mech_set->elements[i];250else251gssalloc_free(mech_set->elements[i].elements);252}253mech_set->count = j;254}255256/*257* this function will return an oid set indicating available mechanisms.258* The set returned is based on configuration file entries and259* NOT on the loaded mechanisms. This function does not check if any260* of these can actually be loaded.261* Deprecated mechanisms will not be returned.262* This routine needs direct access to the mechanism list.263* To avoid reading the configuration file each call, we will save a264* a mech oid set, and only update it once the file has changed.265*/266OM_uint32 KRB5_CALLCONV267gss_indicate_mechs(OM_uint32 *minorStatus, gss_OID_set *mechSet_out)268{269OM_uint32 status;270271/* Initialize outputs. */272273if (minorStatus != NULL)274*minorStatus = 0;275276if (mechSet_out != NULL)277*mechSet_out = GSS_C_NO_OID_SET;278279/* Validate arguments. */280if (minorStatus == NULL || mechSet_out == NULL)281return (GSS_S_CALL_INACCESSIBLE_WRITE);282283*minorStatus = gssint_mechglue_initialize_library();284if (*minorStatus != 0)285return (GSS_S_FAILURE);286287if (build_mechSet())288return GSS_S_FAILURE;289290/*291* need to lock the g_mechSet in case someone tries to update it while292* I'm copying it.293*/294k5_mutex_lock(&g_mechSetLock);295status = generic_gss_copy_oid_set(minorStatus, &g_mechSet, mechSet_out);296k5_mutex_unlock(&g_mechSetLock);297298if (*mechSet_out != GSS_C_NO_OID_SET)299prune_deprecated(*mechSet_out);300301return (status);302} /* gss_indicate_mechs */303304305/* Call with g_mechSetLock held, or during final cleanup. */306static void307free_mechSet(void)308{309unsigned int i;310311if (g_mechSet.count != 0) {312for (i = 0; i < g_mechSet.count; i++)313free(g_mechSet.elements[i].elements);314free(g_mechSet.elements);315g_mechSet.elements = NULL;316g_mechSet.count = 0;317}318}319320static OM_uint32321build_mechSet(void)322{323gss_mech_info mList;324size_t i;325size_t count;326gss_OID curItem;327328/*329* lock the mutex since we will be updating330* the mechList structure331* we need to keep the lock while we build the mechanism list332* since we are accessing parts of the mechList which could be333* modified.334*/335k5_mutex_lock(&g_mechListLock);336337updateMechList();338339/*340* we need to lock the mech set so that no one else will341* try to read it as we are re-creating it342*/343k5_mutex_lock(&g_mechSetLock);344345/* if the oid list already exists we must free it first */346free_mechSet();347348/* determine how many elements to have in the list */349mList = g_mechList;350count = 0;351while (mList != NULL) {352count++;353mList = mList->next;354}355356/* this should always be true, but.... */357if (count > 0) {358g_mechSet.elements =359(gss_OID) calloc(count, sizeof (gss_OID_desc));360if (g_mechSet.elements == NULL) {361k5_mutex_unlock(&g_mechSetLock);362k5_mutex_unlock(&g_mechListLock);363return (GSS_S_FAILURE);364}365366(void) memset(g_mechSet.elements, 0,367count * sizeof (gss_OID_desc));368369/* now copy each oid element */370count = 0;371for (mList = g_mechList; mList != NULL; mList = mList->next) {372/* Don't expose interposer mechanisms. */373if (mList->is_interposer)374continue;375curItem = &(g_mechSet.elements[count]);376curItem->elements = (void*)377malloc(mList->mech_type->length);378if (curItem->elements == NULL) {379/*380* this is nasty - we must delete the381* part of the array already copied382*/383for (i = 0; i < count; i++) {384free(g_mechSet.elements[i].385elements);386}387free(g_mechSet.elements);388g_mechSet.count = 0;389g_mechSet.elements = NULL;390k5_mutex_unlock(&g_mechSetLock);391k5_mutex_unlock(&g_mechListLock);392return (GSS_S_FAILURE);393}394g_OID_copy(curItem, mList->mech_type);395count++;396}397g_mechSet.count = count;398}399400k5_mutex_unlock(&g_mechSetLock);401k5_mutex_unlock(&g_mechListLock);402403return GSS_S_COMPLETE;404}405406407/*408* this function has been added for use by modules that need to409* know what (if any) optional parameters are supplied in the410* config file (MECH_CONF).411* It will return the option string for a specified mechanism.412* caller is responsible for freeing the memory413*/414char *415gssint_get_modOptions(const gss_OID oid)416{417gss_mech_info aMech;418char *modOptions = NULL;419420if (gssint_mechglue_initialize_library() != 0)421return (NULL);422423/* make sure we have fresh data */424k5_mutex_lock(&g_mechListLock);425updateMechList();426427if ((aMech = searchMechList(oid)) == NULL ||428aMech->optionStr == NULL) {429k5_mutex_unlock(&g_mechListLock);430return (NULL);431}432433if (aMech->optionStr)434modOptions = strdup(aMech->optionStr);435k5_mutex_unlock(&g_mechListLock);436437return (modOptions);438} /* gssint_get_modOptions */439440/* Return the mtime of filename or its eventual symlink target (if it is a441* symlink), whichever is larger. Return (time_t)-1 if lstat or stat fails. */442static time_t443check_link_mtime(const char *filename, time_t *mtime_out)444{445struct stat st1, st2;446447if (lstat(filename, &st1) != 0)448return (time_t)-1;449if (!S_ISLNK(st1.st_mode))450return st1.st_mtime;451if (stat(filename, &st2) != 0)452return (time_t)-1;453return (st1.st_mtime > st2.st_mtime) ? st1.st_mtime : st2.st_mtime;454}455456/* Load pathname if it is newer than last. Update *highest to the maximum of457* its current value and pathname's mod time. */458static void459load_if_changed(const char *pathname, time_t last, time_t *highest)460{461time_t mtime;462463mtime = check_link_mtime(pathname, &mtime);464if (mtime == (time_t)-1)465return;466if (mtime > *highest || *highest == (time_t)-1)467*highest = mtime;468if (mtime > last || last == (time_t)-1)469loadConfigFile(pathname);470}471472#ifndef _WIN32473/* Try to load any config files which have changed since the last call. Config474* files are MECH_CONF and any files matching MECH_CONF_PATTERN. */475static void476loadConfigFiles(void)477{478glob_t globbuf;479time_t highest = (time_t)-1, now;480char **path;481const char *val;482483/* Don't glob and stat more than once per second. */484if (time(&now) == (time_t)-1 || now == g_confLastCall)485return;486g_confLastCall = now;487488val = secure_getenv("GSS_MECH_CONFIG");489if (val != NULL) {490load_if_changed(val, g_confFileModTime, &g_confFileModTime);491return;492}493494load_if_changed(MECH_CONF, g_confFileModTime, &highest);495496memset(&globbuf, 0, sizeof(globbuf));497if (glob(MECH_CONF_PATTERN, 0, NULL, &globbuf) == 0) {498for (path = globbuf.gl_pathv; *path != NULL; path++)499load_if_changed(*path, g_confFileModTime, &highest);500}501globfree(&globbuf);502503g_confFileModTime = highest;504}505#endif506507/*508* determines if the mechList needs to be updated from file509* and performs the update.510* this functions must be called with a lock of g_mechListLock511*/512static void513updateMechList(void)514{515gss_mech_info minfo;516517#if defined(_WIN32)518time_t lastConfModTime = getRegConfigModTime(MECH_KEY);519if (g_confFileModTime >= lastConfModTime &&520g_confFileModTime != (time_t)-1)521return;522g_confFileModTime = lastConfModTime;523loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY);524loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY);525#else /* _WIN32 */526loadConfigFiles();527#endif /* !_WIN32 */528529/* Load any unloaded interposer mechanisms immediately, to make sure we530* interpose other mechanisms before they are used. */531for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {532if (minfo->is_interposer && minfo->mech == NULL)533loadInterMech(minfo);534}535} /* updateMechList */536537/* Update the mech list from system configuration if we have never done so.538* Must be invoked with the g_mechListLock mutex held. */539static void540initMechList(void)541{542static int lazy_init = 0;543544if (lazy_init == 0) {545updateMechList();546lazy_init = 1;547}548}549550static void551releaseMechInfo(gss_mech_info *pCf)552{553gss_mech_info cf;554OM_uint32 minor_status;555556if (*pCf == NULL) {557return;558}559560cf = *pCf;561562if (cf->kmodName != NULL)563free(cf->kmodName);564if (cf->uLibName != NULL)565free(cf->uLibName);566if (cf->mechNameStr != NULL)567free(cf->mechNameStr);568if (cf->optionStr != NULL)569free(cf->optionStr);570if (cf->mech_type != GSS_C_NO_OID &&571cf->mech_type != &cf->mech->mech_type)572generic_gss_release_oid(&minor_status, &cf->mech_type);573if (cf->freeMech)574zapfree(cf->mech, sizeof(*cf->mech));575if (cf->dl_handle != NULL)576krb5int_close_plugin(cf->dl_handle);577if (cf->int_mech_type != GSS_C_NO_OID)578generic_gss_release_oid(&minor_status, &cf->int_mech_type);579580memset(cf, 0, sizeof(*cf));581free(cf);582583*pCf = NULL;584}585586#ifdef _GSS_STATIC_LINK587/*588* Register a mechanism. Called with g_mechListLock held.589*/590int591gssint_register_mechinfo(gss_mech_info template)592{593gss_mech_info cf, new_cf;594595new_cf = calloc(1, sizeof(*new_cf));596if (new_cf == NULL) {597return ENOMEM;598}599600new_cf->dl_handle = template->dl_handle;601/* copy mech so we can rewrite canonical mechanism OID */602new_cf->mech = (gss_mechanism)calloc(1, sizeof(struct gss_config));603if (new_cf->mech == NULL) {604releaseMechInfo(&new_cf);605return ENOMEM;606}607*new_cf->mech = *template->mech;608if (template->mech_type != NULL)609new_cf->mech->mech_type = *(template->mech_type);610new_cf->mech_type = &new_cf->mech->mech_type;611new_cf->priority = template->priority;612new_cf->freeMech = 1;613new_cf->next = NULL;614615if (template->kmodName != NULL) {616new_cf->kmodName = strdup(template->kmodName);617if (new_cf->kmodName == NULL) {618releaseMechInfo(&new_cf);619return ENOMEM;620}621}622if (template->uLibName != NULL) {623new_cf->uLibName = strdup(template->uLibName);624if (new_cf->uLibName == NULL) {625releaseMechInfo(&new_cf);626return ENOMEM;627}628}629if (template->mechNameStr != NULL) {630new_cf->mechNameStr = strdup(template->mechNameStr);631if (new_cf->mechNameStr == NULL) {632releaseMechInfo(&new_cf);633return ENOMEM;634}635}636if (template->optionStr != NULL) {637new_cf->optionStr = strdup(template->optionStr);638if (new_cf->optionStr == NULL) {639releaseMechInfo(&new_cf);640return ENOMEM;641}642}643if (g_mechList == NULL) {644g_mechList = new_cf;645g_mechListTail = new_cf;646return 0;647} else if (new_cf->priority < g_mechList->priority) {648new_cf->next = g_mechList;649g_mechList = new_cf;650return 0;651}652653for (cf = g_mechList; cf != NULL; cf = cf->next) {654if (cf->next == NULL ||655new_cf->priority < cf->next->priority) {656new_cf->next = cf->next;657cf->next = new_cf;658if (g_mechListTail == cf) {659g_mechListTail = new_cf;660}661break;662}663}664665return 0;666}667#endif /* _GSS_STATIC_LINK */668669#define GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol) \670do { \671struct errinfo errinfo; \672\673memset(&errinfo, 0, sizeof(errinfo)); \674if (krb5int_get_plugin_func(_dl, \675#_symbol, \676(void (**)(void)) \677&(_mech)->_symbol, \678&errinfo) || errinfo.code) { \679(_mech)->_symbol = NULL; \680k5_clear_error(&errinfo); \681} \682} while (0)683684/*685* If _symbol is undefined in the shared object but the shared object686* is linked against the mechanism glue, it's possible for dlsym() to687* return the mechanism glue implementation. Guard against that.688*/689#define GSS_ADD_DYNAMIC_METHOD_NOLOOP(_dl, _mech, _symbol) \690do { \691GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol); \692if ((_mech)->_symbol == _symbol) \693(_mech)->_symbol = NULL; \694} while (0)695696static gss_mechanism697build_dynamicMech(void *dl, const gss_OID mech_type)698{699gss_mechanism mech;700701mech = (gss_mechanism)calloc(1, sizeof(*mech));702if (mech == NULL) {703return NULL;704}705706GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred);707GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_cred);708GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_init_sec_context);709GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_accept_sec_context);710GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_process_context_token);711GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_sec_context);712GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_context_time);713GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic);714GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_verify_mic);715GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap);716GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap);717GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_status);718GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_indicate_mechs);719GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_compare_name);720GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name);721GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_name);722GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_name);723GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred);724GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred);725GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_sec_context);726GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_sec_context);727GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_mech);728GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_names_for_mech);729GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_context);730GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_internal_release_oid);731GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_size_limit);732GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_localname);733GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_authorize_localname);734GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name);735GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_duplicate_name);736GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred);737GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_sec_context_by_oid);738GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_oid);739GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_sec_context_option);740GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_set_cred_option);741GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_mech_invoke);742GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_aead);743GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_aead);744GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov);745GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_iov);746GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov_length);747GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_complete_auth_token);748/* Services4User (introduced in 1.8) */749GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_impersonate_name);750GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred_impersonate_name);751/* Naming extensions (introduced in 1.8) */752GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name_ext);753GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_name);754GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_name_attribute);755GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_name_attribute);756GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_name_attribute);757GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name_composite);758GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_map_name_to_any);759GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_any_name_mapping);760/* RFC 4401 (introduced in 1.8) */761GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_pseudo_random);762/* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */763GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_neg_mechs);764/* draft-ietf-sasl-gs2 */765GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_saslname_for_mech);766GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_mech_for_saslname);767/* RFC 5587 */768GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_attrs_for_mech);769GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_from);770GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred_into);771GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_acquire_cred_with_password);772GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_cred);773GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_cred);774GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_sec_context_by_mech);775GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_name_by_mech);776GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_cred_by_mech);777/* draft-zhu-negoex */778GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_query_meta_data);779GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_exchange_meta_data);780GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_query_mechanism_info);781/* gss_get_mic_iov extensions (added 1.12, implementable 1.20) */782GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic_iov);783GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_verify_mic_iov);784GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic_iov_length);785786assert(mech_type != GSS_C_NO_OID);787788mech->mech_type = *(mech_type);789790return mech;791}792793#define RESOLVE_GSSI_SYMBOL(_dl, _mech, _psym, _nsym) \794do { \795struct errinfo errinfo; \796memset(&errinfo, 0, sizeof(errinfo)); \797if (krb5int_get_plugin_func(_dl, \798"gssi" #_nsym, \799(void (**)(void))&(_mech)->_psym \800## _nsym, \801&errinfo) || errinfo.code) { \802(_mech)->_psym ## _nsym = NULL; \803k5_clear_error(&errinfo); \804} \805} while (0)806807/* Build an interposer mechanism function table from dl. */808static gss_mechanism809build_interMech(void *dl, const gss_OID mech_type)810{811gss_mechanism mech;812813mech = calloc(1, sizeof(*mech));814if (mech == NULL) {815return NULL;816}817818RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred);819RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_cred);820RESOLVE_GSSI_SYMBOL(dl, mech, gss, _init_sec_context);821RESOLVE_GSSI_SYMBOL(dl, mech, gss, _accept_sec_context);822RESOLVE_GSSI_SYMBOL(dl, mech, gss, _process_context_token);823RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_sec_context);824RESOLVE_GSSI_SYMBOL(dl, mech, gss, _context_time);825RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic);826RESOLVE_GSSI_SYMBOL(dl, mech, gss, _verify_mic);827RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap);828RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap);829RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_status);830RESOLVE_GSSI_SYMBOL(dl, mech, gss, _indicate_mechs);831RESOLVE_GSSI_SYMBOL(dl, mech, gss, _compare_name);832RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name);833RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_name);834RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_name);835RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred);836RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred);837RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_sec_context);838RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_sec_context);839RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_mech);840RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_names_for_mech);841RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_context);842RESOLVE_GSSI_SYMBOL(dl, mech, gss, _internal_release_oid);843RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_size_limit);844RESOLVE_GSSI_SYMBOL(dl, mech, gss, _localname);845RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _authorize_localname);846RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name);847RESOLVE_GSSI_SYMBOL(dl, mech, gss, _duplicate_name);848RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred);849RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_sec_context_by_oid);850RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_oid);851RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_sec_context_option);852RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _set_cred_option);853RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _mech_invoke);854RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_aead);855RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_aead);856RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov);857RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_iov);858RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov_length);859RESOLVE_GSSI_SYMBOL(dl, mech, gss, _complete_auth_token);860/* Services4User (introduced in 1.8) */861RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_impersonate_name);862RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred_impersonate_name);863/* Naming extensions (introduced in 1.8) */864RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name_ext);865RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_name);866RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_name_attribute);867RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_name_attribute);868RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_name_attribute);869RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name_composite);870RESOLVE_GSSI_SYMBOL(dl, mech, gss, _map_name_to_any);871RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_any_name_mapping);872/* RFC 4401 (introduced in 1.8) */873RESOLVE_GSSI_SYMBOL(dl, mech, gss, _pseudo_random);874/* RFC 4178 (introduced in 1.8; get_neg_mechs not implemented) */875RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_neg_mechs);876/* draft-ietf-sasl-gs2 */877RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_saslname_for_mech);878RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_mech_for_saslname);879/* RFC 5587 */880RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_attrs_for_mech);881RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_from);882RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred_into);883RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _acquire_cred_with_password);884RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_cred);885RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_cred);886RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_sec_context_by_mech);887RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_name_by_mech);888RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_cred_by_mech);889/* gss_get_mic_iov extensions (added 1.12, implementable 1.20) */890RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic_iov);891RESOLVE_GSSI_SYMBOL(dl, mech, gss, _verify_mic_iov);892RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic_iov_length);893894mech->mech_type = *mech_type;895return mech;896}897898/*899* Concatenate an interposer mech OID and a real mech OID to create an900* identifier for the interposed mech. (The concatenation will not be a valid901* DER OID encoding, but the OID is only used internally.)902*/903static gss_OID904interposed_oid(gss_OID pre, gss_OID real)905{906gss_OID o;907908o = (gss_OID)malloc(sizeof(gss_OID_desc));909if (!o)910return NULL;911912o->length = pre->length + real->length;913o->elements = malloc(o->length);914if (!o->elements) {915free(o);916return NULL;917}918919memcpy(o->elements, pre->elements, pre->length);920memcpy((char *)o->elements + pre->length, real->elements,921real->length);922923return o;924}925926static void927loadInterMech(gss_mech_info minfo)928{929struct plugin_file_handle *dl = NULL;930struct errinfo errinfo;931gss_OID_set (*isym)(const gss_OID);932gss_OID_set list;933gss_OID oid;934OM_uint32 min;935gss_mech_info mi;936size_t i;937938memset(&errinfo, 0, sizeof(errinfo));939940if (krb5int_open_plugin(minfo->uLibName, &dl, &errinfo) != 0 ||941errinfo.code != 0) {942return;943}944945if (krb5int_get_plugin_func(dl, MECH_INTERPOSER_SYM,946(void (**)(void))&isym, &errinfo) != 0)947goto cleanup;948949/* Get a list of mechs to interpose. */950list = (*isym)(minfo->mech_type);951if (!list)952goto cleanup;953minfo->mech = build_interMech(dl, minfo->mech_type);954if (minfo->mech == NULL)955goto cleanup;956minfo->freeMech = 1;957958/* Add interposer fields for each interposed mech. */959for (i = 0; i < list->count; i++) {960/* Skip this mech if it doesn't exist or is already961* interposed. */962oid = &list->elements[i];963mi = searchMechList(oid);964if (mi == NULL || mi->int_mech_type != NULL)965continue;966967/* Construct a special OID to represent the interposed mech. */968mi->int_mech_type = interposed_oid(minfo->mech_type, oid);969if (mi->int_mech_type == NULL)970continue;971972/* Save an alias to the interposer's function table. */973mi->int_mech = minfo->mech;974}975(void)gss_release_oid_set(&min, &list);976977minfo->dl_handle = dl;978dl = NULL;979980cleanup:981if (dl != NULL)982krb5int_close_plugin(dl);983k5_clear_error(&errinfo);984}985986static void987freeMechList(void)988{989gss_mech_info cf, next_cf;990991for (cf = g_mechList; cf != NULL; cf = next_cf) {992next_cf = cf->next;993releaseMechInfo(&cf);994}995}996997/*998* Determine the mechanism to use for a caller-specified mech OID. For the999* real mech OID of an interposed mech, return the interposed OID. For an1000* interposed mech OID (which an interposer mech uses when re-entering the1001* mechglue), return the real mech OID. The returned OID is an alias and1002* should not be modified or freed.1003*/1004OM_uint321005gssint_select_mech_type(OM_uint32 *minor, gss_const_OID oid,1006gss_OID *selected_oid)1007{1008gss_mech_info minfo;1009OM_uint32 status;10101011*selected_oid = GSS_C_NO_OID;10121013if (gssint_mechglue_initialize_library() != 0)1014return GSS_S_FAILURE;10151016k5_mutex_lock(&g_mechListLock);10171018/* Read conf file at least once so that interposer plugins have a1019* chance of getting initialized. */1020initMechList();10211022minfo = g_mechList;1023if (oid == GSS_C_NULL_OID)1024oid = minfo->mech_type;1025while (minfo != NULL) {1026if (g_OID_equal(minfo->mech_type, oid)) {1027if (minfo->int_mech_type != GSS_C_NO_OID)1028*selected_oid = minfo->int_mech_type;1029else1030*selected_oid = minfo->mech_type;1031status = GSS_S_COMPLETE;1032goto done;1033} else if ((minfo->int_mech_type != GSS_C_NO_OID) &&1034(g_OID_equal(minfo->int_mech_type, oid))) {1035*selected_oid = minfo->mech_type;1036status = GSS_S_COMPLETE;1037goto done;1038}1039minfo = minfo->next;1040}1041status = GSS_S_BAD_MECH;10421043done:1044k5_mutex_unlock(&g_mechListLock);1045return status;1046}10471048/* If oid is an interposed OID, return the corresponding real mech OID. If1049* it's a real mech OID, return it unmodified. Otherwised return null. */1050gss_OID1051gssint_get_public_oid(gss_const_OID oid)1052{1053gss_mech_info minfo;1054gss_OID public_oid = GSS_C_NO_OID;10551056/* if oid is null -> then get default which is the first in the list */1057if (oid == GSS_C_NO_OID)1058return GSS_C_NO_OID;10591060if (gssint_mechglue_initialize_library() != 0)1061return GSS_C_NO_OID;10621063k5_mutex_lock(&g_mechListLock);10641065for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {1066if (minfo->is_interposer)1067continue;1068if (g_OID_equal(minfo->mech_type, oid) ||1069((minfo->int_mech_type != GSS_C_NO_OID) &&1070(g_OID_equal(minfo->int_mech_type, oid)))) {1071public_oid = minfo->mech_type;1072break;1073}1074}10751076k5_mutex_unlock(&g_mechListLock);1077return public_oid;1078}10791080/* Translate a vector of oids (as from a union cred struct) into a set of1081* public OIDs using gssint_get_public_oid. */1082OM_uint321083gssint_make_public_oid_set(OM_uint32 *minor_status, gss_OID oids, int count,1084gss_OID_set *public_set)1085{1086OM_uint32 status, tmpmin;1087gss_OID_set set;1088gss_OID public_oid;1089int i;10901091*public_set = GSS_C_NO_OID_SET;10921093status = generic_gss_create_empty_oid_set(minor_status, &set);1094if (GSS_ERROR(status))1095return status;10961097for (i = 0; i < count; i++) {1098public_oid = gssint_get_public_oid(&oids[i]);1099if (public_oid == GSS_C_NO_OID)1100continue;1101status = generic_gss_add_oid_set_member(minor_status,1102public_oid, &set);1103if (GSS_ERROR(status)) {1104(void) generic_gss_release_oid_set(&tmpmin, &set);1105return status;1106}1107}11081109*public_set = set;1110return GSS_S_COMPLETE;1111}11121113/*1114* Register a mechanism. Called with g_mechListLock held.1115*/11161117/*1118* given the mechanism type, return the mechanism structure1119* containing the mechanism library entry points.1120* will return NULL if mech type is not found1121* This function will also trigger the loading of the mechanism1122* module if it has not been already loaded.1123*/1124gss_mechanism1125gssint_get_mechanism(gss_const_OID oid)1126{1127gss_mech_info aMech;1128gss_mechanism (*sym)(const gss_OID);1129struct plugin_file_handle *dl;1130struct errinfo errinfo;11311132if (gssint_mechglue_initialize_library() != 0)1133return (NULL);11341135k5_mutex_lock(&g_mechListLock);11361137/* Check if the mechanism is already loaded. */1138aMech = g_mechList;1139if (oid == GSS_C_NULL_OID)1140oid = aMech->mech_type;1141while (aMech != NULL) {1142if (g_OID_equal(aMech->mech_type, oid) && aMech->mech) {1143k5_mutex_unlock(&g_mechListLock);1144return aMech->mech;1145} else if (aMech->int_mech_type != GSS_C_NO_OID &&1146g_OID_equal(aMech->int_mech_type, oid)) {1147k5_mutex_unlock(&g_mechListLock);1148return aMech->int_mech;1149}1150aMech = aMech->next;1151}11521153/*1154* might need to re-read the configuration file before loading1155* the mechanism to ensure we have the latest info.1156*/1157updateMechList();11581159aMech = searchMechList(oid);11601161/* is the mechanism present in the list ? */1162if (aMech == NULL) {1163k5_mutex_unlock(&g_mechListLock);1164return ((gss_mechanism)NULL);1165}11661167/* has another thread loaded the mech */1168if (aMech->mech) {1169k5_mutex_unlock(&g_mechListLock);1170return (aMech->mech);1171}11721173memset(&errinfo, 0, sizeof(errinfo));11741175if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||1176errinfo.code != 0) {1177k5_clear_error(&errinfo);1178k5_mutex_unlock(&g_mechListLock);1179return ((gss_mechanism)NULL);1180}11811182if (krb5int_get_plugin_func(dl, MECH_SYM, (void (**)(void))&sym,1183&errinfo) == 0) {1184/* Call the symbol to get the mechanism table */1185aMech->mech = (*sym)(aMech->mech_type);1186} else {1187/* Try dynamic dispatch table */1188k5_clear_error(&errinfo);1189aMech->mech = build_dynamicMech(dl, aMech->mech_type);1190aMech->freeMech = 1;1191}1192if (aMech->mech == NULL) {1193(void) krb5int_close_plugin(dl);1194k5_mutex_unlock(&g_mechListLock);1195return ((gss_mechanism)NULL);1196}11971198aMech->dl_handle = dl;11991200k5_mutex_unlock(&g_mechListLock);1201return (aMech->mech);1202} /* gssint_get_mechanism */12031204/*1205* this routine is used for searching the list of mechanism data.1206*1207* this needs to be called with g_mechListLock held.1208*/1209static gss_mech_info searchMechList(gss_const_OID oid)1210{1211gss_mech_info aMech = g_mechList;12121213/* if oid is null -> then get default which is the first in the list */1214if (oid == GSS_C_NULL_OID)1215return (aMech);12161217while (aMech != NULL) {1218if (g_OID_equal(aMech->mech_type, oid))1219return (aMech);1220aMech = aMech->next;1221}12221223/* none found */1224return ((gss_mech_info) NULL);1225} /* searchMechList */12261227/* Return the first non-whitespace character starting from str. */1228static char *1229skip_whitespace(char *str)1230{1231while (isspace(*str))1232str++;1233return str;1234}12351236/* Truncate str at the first whitespace character and return the first1237* non-whitespace character after that point. */1238static char *1239delimit_ws(char *str)1240{1241while (*str != '\0' && !isspace(*str))1242str++;1243if (*str != '\0')1244*str++ = '\0';1245return skip_whitespace(str);1246}12471248/* Truncate str at the first occurrence of delimiter and return the first1249* non-whitespace character after that point. */1250static char *1251delimit(char *str, char delimiter)1252{1253while (*str != '\0' && *str != delimiter)1254str++;1255if (*str != '\0')1256*str++ = '\0';1257return skip_whitespace(str);1258}12591260/*1261* loads the configuration file1262* this is called while having a mutex lock on the mechanism list1263* entries for libraries that have been loaded can't be modified1264* mechNameStr and mech_type fields are not updated during updates1265*/1266static void1267loadConfigFile(const char *fileName)1268{1269char *sharedLib, *kernMod, *modOptions, *modType, *oid, *next;1270char buffer[BUFSIZ], *oidStr;1271FILE *confFile;12721273if ((confFile = fopen(fileName, "r")) == NULL) {1274return;1275}12761277(void) memset(buffer, 0, sizeof (buffer));1278while (fgets(buffer, BUFSIZ, confFile) != NULL) {12791280/* ignore lines beginning with # */1281if (*buffer == '#')1282continue;12831284/* Parse out the name, oid, and shared library path. */1285oidStr = buffer;1286oid = delimit_ws(oidStr);1287if (*oid == '\0')1288continue;1289sharedLib = delimit_ws(oid);1290if (*sharedLib == '\0')1291continue;1292next = delimit_ws(sharedLib);12931294/* Parse out the kernel module name if present. */1295if (*next != '\0' && *next != '[' && *next != '<') {1296kernMod = next;1297next = delimit_ws(kernMod);1298} else {1299kernMod = NULL;1300}13011302/* Parse out the module options if present. */1303if (*next == '[') {1304modOptions = next + 1;1305next = delimit(modOptions, ']');1306} else {1307modOptions = NULL;1308}13091310/* Parse out the module type if present. */1311if (*next == '<') {1312modType = next + 1;1313(void)delimit(modType, '>');1314} else {1315modType = NULL;1316}13171318addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,1319modType);1320} /* while */1321(void) fclose(confFile);1322} /* loadConfigFile */13231324#if defined(_WIN32)13251326static time_t1327filetimeToTimet(const FILETIME *ft)1328{1329ULARGE_INTEGER ull;13301331ull.LowPart = ft->dwLowDateTime;1332ull.HighPart = ft->dwHighDateTime;1333return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);1334}13351336static time_t1337getRegConfigModTime(const char *keyPath)1338{1339time_t currentUserModTime = getRegKeyModTime(HKEY_CURRENT_USER,1340keyPath);1341time_t localMachineModTime = getRegKeyModTime(HKEY_LOCAL_MACHINE,1342keyPath);13431344return currentUserModTime > localMachineModTime ? currentUserModTime :1345localMachineModTime;1346}13471348static time_t1349getRegKeyModTime(HKEY hBaseKey, const char *keyPath)1350{1351HKEY hConfigKey;1352HRESULT rc;1353int iSubKey = 0;1354time_t modTime = 0, keyModTime;1355FILETIME keyLastWriteTime;1356char subKeyName[256];13571358if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS,1359&hConfigKey)) != ERROR_SUCCESS) {1360/* TODO: log error message */1361return 0;1362}1363do {1364int subKeyNameSize=sizeof(subKeyName)/sizeof(subKeyName[0]);1365if ((rc = RegEnumKeyEx(hConfigKey, iSubKey++, subKeyName,1366&subKeyNameSize, NULL, NULL, NULL,1367&keyLastWriteTime)) != ERROR_SUCCESS) {1368break;1369}1370keyModTime = filetimeToTimet(&keyLastWriteTime);1371if (modTime < keyModTime) {1372modTime = keyModTime;1373}1374} while (1);1375RegCloseKey(hConfigKey);1376return modTime;1377}13781379static void1380getRegKeyValue(HKEY hKey, const char *keyPath, const char *valueName,1381void **data, DWORD* dataLen)1382{1383DWORD sizeRequired=*dataLen;1384HRESULT hr;1385/* Get data length required */1386if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,1387NULL, &sizeRequired)) != ERROR_SUCCESS) {1388/* TODO: LOG registry error */1389return;1390}1391/* adjust data buffer size if necessary */1392if (*dataLen < sizeRequired) {1393*dataLen = sizeRequired;1394*data = realloc(*data, sizeRequired);1395if (!*data) {1396*dataLen = 0;1397/* TODO: LOG OOM ERROR! */1398return;1399}1400}1401/* get data */1402if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,1403*data, &sizeRequired)) != ERROR_SUCCESS) {1404/* LOG registry error */1405return;1406}1407}14081409static void1410loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)1411{1412HKEY hConfigKey;1413DWORD iSubKey, nSubKeys, maxSubKeyNameLen, modTypeLen;1414char *oidStr = NULL, *oid = NULL, *sharedLib = NULL, *kernMod = NULL;1415char *modOptions = NULL, *modType = NULL;1416DWORD oidStrLen = 0, oidLen = 0, sharedLibLen = 0, kernModLen = 0;1417DWORD modOptionsLen = 0;1418HRESULT rc;14191420if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0,1421KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,1422&hConfigKey)) != ERROR_SUCCESS) {1423/* TODO: log registry error */1424return;1425}14261427if ((rc = RegQueryInfoKey(hConfigKey,1428NULL, /* lpClass */1429NULL, /* lpcClass */1430NULL, /* lpReserved */1431&nSubKeys,1432&maxSubKeyNameLen,1433NULL, /* lpcMaxClassLen */1434NULL, /* lpcValues */1435NULL, /* lpcMaxValueNameLen */1436NULL, /* lpcMaxValueLen */1437NULL, /* lpcbSecurityDescriptor */1438NULL /* lpftLastWriteTime */ )) != ERROR_SUCCESS) {1439goto cleanup;1440}1441oidStr = malloc(++maxSubKeyNameLen);1442if (!oidStr) {1443goto cleanup;1444}1445for (iSubKey=0; iSubKey<nSubKeys; iSubKey++) {1446oidStrLen = maxSubKeyNameLen;1447if ((rc = RegEnumKeyEx(hConfigKey, iSubKey, oidStr, &oidStrLen,1448NULL, NULL, NULL, NULL)) !=1449ERROR_SUCCESS) {1450/* TODO: log registry error */1451continue;1452}1453getRegKeyValue(hConfigKey, oidStr, "OID", &oid, &oidLen);1454getRegKeyValue(hConfigKey, oidStr, "Shared Library",1455&sharedLib, &sharedLibLen);1456getRegKeyValue(hConfigKey, oidStr, "Kernel Module", &kernMod,1457&kernModLen);1458getRegKeyValue(hConfigKey, oidStr, "Options", &modOptions,1459&modOptionsLen);1460getRegKeyValue(hConfigKey, oidStr, "Type", &modType,1461&modTypeLen);1462addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,1463modType);1464}1465cleanup:1466RegCloseKey(hConfigKey);1467if (oidStr) {1468free(oidStr);1469}1470if (oid) {1471free(oid);1472}1473if (sharedLib) {1474free(sharedLib);1475}1476if (kernMod) {1477free(kernMod);1478}1479if (modOptions) {1480free(modOptions);1481}1482}1483#endif14841485static void1486addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,1487const char *kernMod, const char *modOptions,1488const char *modType)1489{1490#if defined(_WIN32)1491const char *sharedPath;1492#else1493char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];1494#endif1495char *tmpStr;1496gss_OID mechOid;1497gss_mech_info aMech, tmp;1498OM_uint32 minor;1499gss_buffer_desc oidBuf;15001501if ((!oid) || (!oidStr)) {1502return;1503}1504/*1505* check if an entry for this oid already exists1506* if it does, and the library is already loaded then1507* we can't modify it, so skip it1508*/1509oidBuf.value = (void *)oid;1510oidBuf.length = strlen(oid);1511if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)1512!= GSS_S_COMPLETE) {1513return;1514}15151516aMech = searchMechList(mechOid);1517if (aMech && aMech->mech) {1518generic_gss_release_oid(&minor, &mechOid);1519return;1520}15211522/*1523* If that's all, then this is a corrupt entry. Skip it.1524*/1525if (! *sharedLib) {1526generic_gss_release_oid(&minor, &mechOid);1527return;1528}1529#if defined(_WIN32)1530sharedPath = sharedLib;1531#else1532if (sharedLib[0] == '/')1533snprintf(sharedPath, sizeof(sharedPath), "%s", sharedLib);1534else1535snprintf(sharedPath, sizeof(sharedPath), "%s%s",1536MECH_LIB_PREFIX, sharedLib);1537#endif1538/*1539* are we creating a new mechanism entry or1540* just modifying existing (non loaded) mechanism entry1541*/1542if (aMech) {1543/*1544* delete any old values and set new1545* mechNameStr and mech_type are not modified1546*/1547if (aMech->kmodName) {1548free(aMech->kmodName);1549aMech->kmodName = NULL;1550}15511552if (aMech->optionStr) {1553free(aMech->optionStr);1554aMech->optionStr = NULL;1555}15561557if ((tmpStr = strdup(sharedPath)) != NULL) {1558if (aMech->uLibName)1559free(aMech->uLibName);1560aMech->uLibName = tmpStr;1561}15621563if (kernMod) /* this is an optional parameter */1564aMech->kmodName = strdup(kernMod);15651566if (modOptions) /* optional module options */1567aMech->optionStr = strdup(modOptions);15681569/* the oid is already set */1570generic_gss_release_oid(&minor, &mechOid);1571return;1572}15731574/* adding a new entry */1575aMech = calloc(1, sizeof (struct gss_mech_config));1576if (aMech == NULL) {1577generic_gss_release_oid(&minor, &mechOid);1578return;1579}1580aMech->mech_type = mechOid;1581aMech->uLibName = strdup(sharedPath);1582aMech->mechNameStr = strdup(oidStr);1583aMech->freeMech = 0;15841585/* check if any memory allocations failed - bad news */1586if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {1587if (aMech->uLibName)1588free(aMech->uLibName);1589if (aMech->mechNameStr)1590free(aMech->mechNameStr);1591generic_gss_release_oid(&minor, &mechOid);1592free(aMech);1593return;1594}1595if (kernMod) /* this is an optional parameter */1596aMech->kmodName = strdup(kernMod);15971598if (modOptions)1599aMech->optionStr = strdup(modOptions);16001601if (modType && strcmp(modType, "interposer") == 0)1602aMech->is_interposer = 1;16031604/*1605* add the new entry to the end of the list - make sure1606* that only complete entries are added because other1607* threads might currently be searching the list.1608*/1609tmp = g_mechListTail;1610g_mechListTail = aMech;16111612if (tmp != NULL)1613tmp->next = aMech;16141615if (g_mechList == NULL)1616g_mechList = aMech;1617}1618161916201621