xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_initialize.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* #pragma ident	"@(#)g_initialize.c	1.36	05/02/02 SMI" */
2*7f2fe78bSCy Schubert 
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 1996 by Sun Microsystems, Inc.
5*7f2fe78bSCy Schubert  *
6*7f2fe78bSCy Schubert  * Permission to use, copy, modify, distribute, and sell this software
7*7f2fe78bSCy Schubert  * and its documentation for any purpose is hereby granted without fee,
8*7f2fe78bSCy Schubert  * provided that the above copyright notice appears in all copies and
9*7f2fe78bSCy Schubert  * that both that copyright notice and this permission notice appear in
10*7f2fe78bSCy Schubert  * supporting documentation, and that the name of Sun Microsystems not be used
11*7f2fe78bSCy Schubert  * in advertising or publicity pertaining to distribution of the software
12*7f2fe78bSCy Schubert  * without specific, written prior permission. Sun Microsystems makes no
13*7f2fe78bSCy Schubert  * representations about the suitability of this software for any
14*7f2fe78bSCy Schubert  * purpose.  It is provided "as is" without express or implied warranty.
15*7f2fe78bSCy Schubert  *
16*7f2fe78bSCy Schubert  * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17*7f2fe78bSCy Schubert  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18*7f2fe78bSCy Schubert  * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19*7f2fe78bSCy Schubert  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20*7f2fe78bSCy Schubert  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21*7f2fe78bSCy Schubert  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22*7f2fe78bSCy Schubert  * PERFORMANCE OF THIS SOFTWARE.
23*7f2fe78bSCy Schubert  */
24*7f2fe78bSCy Schubert 
25*7f2fe78bSCy Schubert /*
26*7f2fe78bSCy Schubert  * This function will initialize the gssapi mechglue library
27*7f2fe78bSCy Schubert  */
28*7f2fe78bSCy Schubert 
29*7f2fe78bSCy Schubert #include "mglueP.h"
30*7f2fe78bSCy Schubert #ifdef HAVE_STDLIB_H
31*7f2fe78bSCy Schubert #include <stdlib.h>
32*7f2fe78bSCy Schubert #endif
33*7f2fe78bSCy Schubert #ifdef HAVE_SYS_STAT_H
34*7f2fe78bSCy Schubert #include <sys/stat.h>
35*7f2fe78bSCy Schubert #endif
36*7f2fe78bSCy Schubert #ifdef HAVE_SYS_PARAM_H
37*7f2fe78bSCy Schubert #include <sys/param.h>
38*7f2fe78bSCy Schubert #endif
39*7f2fe78bSCy Schubert 
40*7f2fe78bSCy Schubert #include <stdio.h>
41*7f2fe78bSCy Schubert #include <string.h>
42*7f2fe78bSCy Schubert #include <ctype.h>
43*7f2fe78bSCy Schubert #include <errno.h>
44*7f2fe78bSCy Schubert #ifndef _WIN32
45*7f2fe78bSCy Schubert #include <glob.h>
46*7f2fe78bSCy Schubert #endif
47*7f2fe78bSCy Schubert 
48*7f2fe78bSCy Schubert #define	M_DEFAULT	"default"
49*7f2fe78bSCy Schubert 
50*7f2fe78bSCy Schubert #include "k5-thread.h"
51*7f2fe78bSCy Schubert #include "k5-plugin.h"
52*7f2fe78bSCy Schubert #include "osconf.h"
53*7f2fe78bSCy Schubert #ifdef _GSS_STATIC_LINK
54*7f2fe78bSCy Schubert #include "gssapiP_krb5.h"
55*7f2fe78bSCy Schubert #include "gssapiP_spnego.h"
56*7f2fe78bSCy Schubert #endif
57*7f2fe78bSCy Schubert 
58*7f2fe78bSCy Schubert #define MECH_SYM "gss_mech_initialize"
59*7f2fe78bSCy Schubert #define MECH_INTERPOSER_SYM "gss_mech_interposer"
60*7f2fe78bSCy Schubert 
61*7f2fe78bSCy Schubert #ifndef MECH_CONF
62*7f2fe78bSCy Schubert #define	MECH_CONF "/etc/gss/mech"
63*7f2fe78bSCy Schubert #endif
64*7f2fe78bSCy Schubert #define MECH_CONF_PATTERN MECH_CONF ".d/*.conf"
65*7f2fe78bSCy Schubert 
66*7f2fe78bSCy Schubert /* Local functions */
67*7f2fe78bSCy Schubert static void addConfigEntry(const char *oidStr, const char *oid,
68*7f2fe78bSCy Schubert 			   const char *sharedLib, const char *kernMod,
69*7f2fe78bSCy Schubert 			   const char *modOptions, const char *modType);
70*7f2fe78bSCy Schubert static gss_mech_info searchMechList(gss_const_OID);
71*7f2fe78bSCy Schubert static void loadConfigFile(const char *);
72*7f2fe78bSCy Schubert #if defined(_WIN32)
73*7f2fe78bSCy Schubert #ifndef MECH_KEY
74*7f2fe78bSCy Schubert #define MECH_KEY "SOFTWARE\\gss\\mech"
75*7f2fe78bSCy Schubert #endif
76*7f2fe78bSCy Schubert static time_t getRegKeyModTime(HKEY hBaseKey, const char *keyPath);
77*7f2fe78bSCy Schubert static time_t getRegConfigModTime(const char *keyPath);
78*7f2fe78bSCy Schubert static void getRegKeyValue(HKEY key, const char *keyPath, const char *valueName, void **data, DWORD *dataLen);
79*7f2fe78bSCy Schubert static void loadConfigFromRegistry(HKEY keyBase, const char *keyPath);
80*7f2fe78bSCy Schubert #endif
81*7f2fe78bSCy Schubert static void updateMechList(void);
82*7f2fe78bSCy Schubert static void initMechList(void);
83*7f2fe78bSCy Schubert static void loadInterMech(gss_mech_info aMech);
84*7f2fe78bSCy Schubert static void freeMechList(void);
85*7f2fe78bSCy Schubert 
86*7f2fe78bSCy Schubert static OM_uint32 build_mechSet(void);
87*7f2fe78bSCy Schubert static void free_mechSet(void);
88*7f2fe78bSCy Schubert 
89*7f2fe78bSCy Schubert /*
90*7f2fe78bSCy Schubert  * list of mechanism libraries and their entry points.
91*7f2fe78bSCy Schubert  * the list also maintains state of the mech libraries (loaded or not).
92*7f2fe78bSCy Schubert  */
93*7f2fe78bSCy Schubert static gss_mech_info g_mechList = NULL;
94*7f2fe78bSCy Schubert static gss_mech_info g_mechListTail = NULL;
95*7f2fe78bSCy Schubert static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
96*7f2fe78bSCy Schubert static time_t g_confFileModTime = (time_t)-1;
97*7f2fe78bSCy Schubert static time_t g_confLastCall = (time_t)0;
98*7f2fe78bSCy Schubert 
99*7f2fe78bSCy Schubert static gss_OID_set_desc g_mechSet = { 0, NULL };
100*7f2fe78bSCy Schubert static k5_mutex_t g_mechSetLock = K5_MUTEX_PARTIAL_INITIALIZER;
101*7f2fe78bSCy Schubert 
102*7f2fe78bSCy Schubert MAKE_INIT_FUNCTION(gssint_mechglue_init);
103*7f2fe78bSCy Schubert MAKE_FINI_FUNCTION(gssint_mechglue_fini);
104*7f2fe78bSCy Schubert 
105*7f2fe78bSCy Schubert int
gssint_mechglue_init(void)106*7f2fe78bSCy Schubert gssint_mechglue_init(void)
107*7f2fe78bSCy Schubert {
108*7f2fe78bSCy Schubert 	int err;
109*7f2fe78bSCy Schubert 
110*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
111*7f2fe78bSCy Schubert 	printf("gssint_mechglue_init\n");
112*7f2fe78bSCy Schubert #endif
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert 	add_error_table(&et_ggss_error_table);
115*7f2fe78bSCy Schubert 
116*7f2fe78bSCy Schubert 	err = k5_mutex_finish_init(&g_mechSetLock);
117*7f2fe78bSCy Schubert 	if (err)
118*7f2fe78bSCy Schubert 		return err;
119*7f2fe78bSCy Schubert 	err = k5_mutex_finish_init(&g_mechListLock);
120*7f2fe78bSCy Schubert 	if (err)
121*7f2fe78bSCy Schubert 		return err;
122*7f2fe78bSCy Schubert 
123*7f2fe78bSCy Schubert #ifdef _GSS_STATIC_LINK
124*7f2fe78bSCy Schubert 	err = gss_krb5int_lib_init();
125*7f2fe78bSCy Schubert 	if (err)
126*7f2fe78bSCy Schubert 		return err;
127*7f2fe78bSCy Schubert 	err = gss_spnegoint_lib_init();
128*7f2fe78bSCy Schubert 	if (err)
129*7f2fe78bSCy Schubert 		return err;
130*7f2fe78bSCy Schubert #endif
131*7f2fe78bSCy Schubert 
132*7f2fe78bSCy Schubert 	err = gssint_mecherrmap_init();
133*7f2fe78bSCy Schubert 	return err;
134*7f2fe78bSCy Schubert }
135*7f2fe78bSCy Schubert 
136*7f2fe78bSCy Schubert void
gssint_mechglue_fini(void)137*7f2fe78bSCy Schubert gssint_mechglue_fini(void)
138*7f2fe78bSCy Schubert {
139*7f2fe78bSCy Schubert 	if (!INITIALIZER_RAN(gssint_mechglue_init) || PROGRAM_EXITING()) {
140*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
141*7f2fe78bSCy Schubert 		printf("gssint_mechglue_fini: skipping\n");
142*7f2fe78bSCy Schubert #endif
143*7f2fe78bSCy Schubert 		return;
144*7f2fe78bSCy Schubert 	}
145*7f2fe78bSCy Schubert 
146*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
147*7f2fe78bSCy Schubert 	printf("gssint_mechglue_fini\n");
148*7f2fe78bSCy Schubert #endif
149*7f2fe78bSCy Schubert #ifdef _GSS_STATIC_LINK
150*7f2fe78bSCy Schubert 	gss_spnegoint_lib_fini();
151*7f2fe78bSCy Schubert 	gss_krb5int_lib_fini();
152*7f2fe78bSCy Schubert #endif
153*7f2fe78bSCy Schubert 	k5_mutex_destroy(&g_mechSetLock);
154*7f2fe78bSCy Schubert 	k5_mutex_destroy(&g_mechListLock);
155*7f2fe78bSCy Schubert 	free_mechSet();
156*7f2fe78bSCy Schubert 	freeMechList();
157*7f2fe78bSCy Schubert 	remove_error_table(&et_ggss_error_table);
158*7f2fe78bSCy Schubert 	gssint_mecherrmap_destroy();
159*7f2fe78bSCy Schubert }
160*7f2fe78bSCy Schubert 
161*7f2fe78bSCy Schubert int
gssint_mechglue_initialize_library(void)162*7f2fe78bSCy Schubert gssint_mechglue_initialize_library(void)
163*7f2fe78bSCy Schubert {
164*7f2fe78bSCy Schubert 	return CALL_INIT_FUNCTION(gssint_mechglue_init);
165*7f2fe78bSCy Schubert }
166*7f2fe78bSCy Schubert 
167*7f2fe78bSCy Schubert /*
168*7f2fe78bSCy Schubert  * function used to reclaim the memory used by a gss_OID structure.
169*7f2fe78bSCy Schubert  * This routine requires direct access to the mechList.
170*7f2fe78bSCy Schubert  */
171*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
gss_release_oid(minor_status,oid)172*7f2fe78bSCy Schubert gss_release_oid(minor_status, oid)
173*7f2fe78bSCy Schubert OM_uint32 *minor_status;
174*7f2fe78bSCy Schubert gss_OID *oid;
175*7f2fe78bSCy Schubert {
176*7f2fe78bSCy Schubert 	OM_uint32 major;
177*7f2fe78bSCy Schubert 	gss_mech_info aMech;
178*7f2fe78bSCy Schubert 
179*7f2fe78bSCy Schubert 	if (minor_status != NULL)
180*7f2fe78bSCy Schubert 	    *minor_status = 0;
181*7f2fe78bSCy Schubert 
182*7f2fe78bSCy Schubert 	if (minor_status == NULL || oid == NULL)
183*7f2fe78bSCy Schubert 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
184*7f2fe78bSCy Schubert 
185*7f2fe78bSCy Schubert 	*minor_status = gssint_mechglue_initialize_library();
186*7f2fe78bSCy Schubert 	if (*minor_status != 0)
187*7f2fe78bSCy Schubert 		return (GSS_S_FAILURE);
188*7f2fe78bSCy Schubert 
189*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechListLock);
190*7f2fe78bSCy Schubert 	aMech = g_mechList;
191*7f2fe78bSCy Schubert 	while (aMech != NULL) {
192*7f2fe78bSCy Schubert 
193*7f2fe78bSCy Schubert 		/*
194*7f2fe78bSCy Schubert 		 * look through the loaded mechanism libraries for
195*7f2fe78bSCy Schubert 		 * gss_internal_release_oid until one returns success.
196*7f2fe78bSCy Schubert 		 * gss_internal_release_oid will only return success when
197*7f2fe78bSCy Schubert 		 * the OID was recognized as an internal mechanism OID. if no
198*7f2fe78bSCy Schubert 		 * mechanisms recognize the OID, then call the generic version.
199*7f2fe78bSCy Schubert 		 */
200*7f2fe78bSCy Schubert 		if (aMech->mech && aMech->mech->gss_internal_release_oid) {
201*7f2fe78bSCy Schubert 			major = aMech->mech->gss_internal_release_oid(
202*7f2fe78bSCy Schubert 					minor_status, oid);
203*7f2fe78bSCy Schubert 			if (major == GSS_S_COMPLETE) {
204*7f2fe78bSCy Schubert 				k5_mutex_unlock(&g_mechListLock);
205*7f2fe78bSCy Schubert 				return (GSS_S_COMPLETE);
206*7f2fe78bSCy Schubert 			}
207*7f2fe78bSCy Schubert 			map_error(minor_status, aMech->mech);
208*7f2fe78bSCy Schubert 		}
209*7f2fe78bSCy Schubert 		aMech = aMech->next;
210*7f2fe78bSCy Schubert 	} /* while */
211*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechListLock);
212*7f2fe78bSCy Schubert 
213*7f2fe78bSCy Schubert 	return (generic_gss_release_oid(minor_status, oid));
214*7f2fe78bSCy Schubert } /* gss_release_oid */
215*7f2fe78bSCy Schubert 
216*7f2fe78bSCy Schubert /*
217*7f2fe78bSCy Schubert  * Wrapper around inquire_attrs_for_mech to determine whether a mechanism has
218*7f2fe78bSCy Schubert  * the deprecated attribute.  Must be called without g_mechSetLock since it
219*7f2fe78bSCy Schubert  * will call into the mechglue.
220*7f2fe78bSCy Schubert  */
221*7f2fe78bSCy Schubert static int
is_deprecated(gss_OID element)222*7f2fe78bSCy Schubert is_deprecated(gss_OID element)
223*7f2fe78bSCy Schubert {
224*7f2fe78bSCy Schubert 	OM_uint32 major, minor;
225*7f2fe78bSCy Schubert 	gss_OID_set mech_attrs = GSS_C_NO_OID_SET;
226*7f2fe78bSCy Schubert 	int deprecated = 0;
227*7f2fe78bSCy Schubert 
228*7f2fe78bSCy Schubert 	major = gss_inquire_attrs_for_mech(&minor, element, &mech_attrs, NULL);
229*7f2fe78bSCy Schubert 	if (major == GSS_S_COMPLETE) {
230*7f2fe78bSCy Schubert 		gss_test_oid_set_member(&minor, (gss_OID)GSS_C_MA_DEPRECATED,
231*7f2fe78bSCy Schubert 					mech_attrs, &deprecated);
232*7f2fe78bSCy Schubert 	}
233*7f2fe78bSCy Schubert 
234*7f2fe78bSCy Schubert 	if (mech_attrs != GSS_C_NO_OID_SET)
235*7f2fe78bSCy Schubert 		gss_release_oid_set(&minor, &mech_attrs);
236*7f2fe78bSCy Schubert 
237*7f2fe78bSCy Schubert 	return deprecated;
238*7f2fe78bSCy Schubert }
239*7f2fe78bSCy Schubert 
240*7f2fe78bSCy Schubert /*
241*7f2fe78bSCy Schubert  * Removes mechs with the deprecated attribute from an OID set.  Must be
242*7f2fe78bSCy Schubert  * called without g_mechSetLock held since it calls into the mechglue.
243*7f2fe78bSCy Schubert  */
244*7f2fe78bSCy Schubert static void
prune_deprecated(gss_OID_set mech_set)245*7f2fe78bSCy Schubert prune_deprecated(gss_OID_set mech_set)
246*7f2fe78bSCy Schubert {
247*7f2fe78bSCy Schubert 	OM_uint32 i, j;
248*7f2fe78bSCy Schubert 
249*7f2fe78bSCy Schubert 	j = 0;
250*7f2fe78bSCy Schubert 	for (i = 0; i < mech_set->count; i++) {
251*7f2fe78bSCy Schubert 	    if (!is_deprecated(&mech_set->elements[i]))
252*7f2fe78bSCy Schubert 		mech_set->elements[j++] = mech_set->elements[i];
253*7f2fe78bSCy Schubert 	    else
254*7f2fe78bSCy Schubert 		gssalloc_free(mech_set->elements[i].elements);
255*7f2fe78bSCy Schubert 	}
256*7f2fe78bSCy Schubert 	mech_set->count = j;
257*7f2fe78bSCy Schubert }
258*7f2fe78bSCy Schubert 
259*7f2fe78bSCy Schubert /*
260*7f2fe78bSCy Schubert  * this function will return an oid set indicating available mechanisms.
261*7f2fe78bSCy Schubert  * The set returned is based on configuration file entries and
262*7f2fe78bSCy Schubert  * NOT on the loaded mechanisms.  This function does not check if any
263*7f2fe78bSCy Schubert  * of these can actually be loaded.
264*7f2fe78bSCy Schubert  * Deprecated mechanisms will not be returned.
265*7f2fe78bSCy Schubert  * This routine needs direct access to the mechanism list.
266*7f2fe78bSCy Schubert  * To avoid reading the configuration file each call, we will save a
267*7f2fe78bSCy Schubert  * a mech oid set, and only update it once the file has changed.
268*7f2fe78bSCy Schubert  */
269*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
gss_indicate_mechs(minorStatus,mechSet_out)270*7f2fe78bSCy Schubert gss_indicate_mechs(minorStatus, mechSet_out)
271*7f2fe78bSCy Schubert OM_uint32 *minorStatus;
272*7f2fe78bSCy Schubert gss_OID_set *mechSet_out;
273*7f2fe78bSCy Schubert {
274*7f2fe78bSCy Schubert 	OM_uint32 status;
275*7f2fe78bSCy Schubert 
276*7f2fe78bSCy Schubert 	/* Initialize outputs. */
277*7f2fe78bSCy Schubert 
278*7f2fe78bSCy Schubert 	if (minorStatus != NULL)
279*7f2fe78bSCy Schubert 		*minorStatus = 0;
280*7f2fe78bSCy Schubert 
281*7f2fe78bSCy Schubert 	if (mechSet_out != NULL)
282*7f2fe78bSCy Schubert 		*mechSet_out = GSS_C_NO_OID_SET;
283*7f2fe78bSCy Schubert 
284*7f2fe78bSCy Schubert 	/* Validate arguments. */
285*7f2fe78bSCy Schubert 	if (minorStatus == NULL || mechSet_out == NULL)
286*7f2fe78bSCy Schubert 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
287*7f2fe78bSCy Schubert 
288*7f2fe78bSCy Schubert 	*minorStatus = gssint_mechglue_initialize_library();
289*7f2fe78bSCy Schubert 	if (*minorStatus != 0)
290*7f2fe78bSCy Schubert 		return (GSS_S_FAILURE);
291*7f2fe78bSCy Schubert 
292*7f2fe78bSCy Schubert 	if (build_mechSet())
293*7f2fe78bSCy Schubert 		return GSS_S_FAILURE;
294*7f2fe78bSCy Schubert 
295*7f2fe78bSCy Schubert 	/*
296*7f2fe78bSCy Schubert 	 * need to lock the g_mechSet in case someone tries to update it while
297*7f2fe78bSCy Schubert 	 * I'm copying it.
298*7f2fe78bSCy Schubert 	 */
299*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechSetLock);
300*7f2fe78bSCy Schubert 	status = generic_gss_copy_oid_set(minorStatus, &g_mechSet, mechSet_out);
301*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechSetLock);
302*7f2fe78bSCy Schubert 
303*7f2fe78bSCy Schubert 	if (*mechSet_out != GSS_C_NO_OID_SET)
304*7f2fe78bSCy Schubert 		prune_deprecated(*mechSet_out);
305*7f2fe78bSCy Schubert 
306*7f2fe78bSCy Schubert 	return (status);
307*7f2fe78bSCy Schubert } /* gss_indicate_mechs */
308*7f2fe78bSCy Schubert 
309*7f2fe78bSCy Schubert 
310*7f2fe78bSCy Schubert /* Call with g_mechSetLock held, or during final cleanup.  */
311*7f2fe78bSCy Schubert static void
free_mechSet(void)312*7f2fe78bSCy Schubert free_mechSet(void)
313*7f2fe78bSCy Schubert {
314*7f2fe78bSCy Schubert 	unsigned int i;
315*7f2fe78bSCy Schubert 
316*7f2fe78bSCy Schubert 	if (g_mechSet.count != 0) {
317*7f2fe78bSCy Schubert 		for (i = 0; i < g_mechSet.count; i++)
318*7f2fe78bSCy Schubert 			free(g_mechSet.elements[i].elements);
319*7f2fe78bSCy Schubert 		free(g_mechSet.elements);
320*7f2fe78bSCy Schubert 		g_mechSet.elements = NULL;
321*7f2fe78bSCy Schubert 		g_mechSet.count = 0;
322*7f2fe78bSCy Schubert 	}
323*7f2fe78bSCy Schubert }
324*7f2fe78bSCy Schubert 
325*7f2fe78bSCy Schubert static OM_uint32
build_mechSet(void)326*7f2fe78bSCy Schubert build_mechSet(void)
327*7f2fe78bSCy Schubert {
328*7f2fe78bSCy Schubert 	gss_mech_info mList;
329*7f2fe78bSCy Schubert 	size_t i;
330*7f2fe78bSCy Schubert 	size_t count;
331*7f2fe78bSCy Schubert 	gss_OID curItem;
332*7f2fe78bSCy Schubert 
333*7f2fe78bSCy Schubert 	/*
334*7f2fe78bSCy Schubert 	 * lock the mutex since we will be updating
335*7f2fe78bSCy Schubert 	 * the mechList structure
336*7f2fe78bSCy Schubert 	 * we need to keep the lock while we build the mechanism list
337*7f2fe78bSCy Schubert 	 * since we are accessing parts of the mechList which could be
338*7f2fe78bSCy Schubert 	 * modified.
339*7f2fe78bSCy Schubert 	 */
340*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechListLock);
341*7f2fe78bSCy Schubert 
342*7f2fe78bSCy Schubert 	updateMechList();
343*7f2fe78bSCy Schubert 
344*7f2fe78bSCy Schubert 	/*
345*7f2fe78bSCy Schubert 	 * we need to lock the mech set so that no one else will
346*7f2fe78bSCy Schubert 	 * try to read it as we are re-creating it
347*7f2fe78bSCy Schubert 	 */
348*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechSetLock);
349*7f2fe78bSCy Schubert 
350*7f2fe78bSCy Schubert 	/* if the oid list already exists we must free it first */
351*7f2fe78bSCy Schubert 	free_mechSet();
352*7f2fe78bSCy Schubert 
353*7f2fe78bSCy Schubert 	/* determine how many elements to have in the list */
354*7f2fe78bSCy Schubert 	mList = g_mechList;
355*7f2fe78bSCy Schubert 	count = 0;
356*7f2fe78bSCy Schubert 	while (mList != NULL) {
357*7f2fe78bSCy Schubert 		count++;
358*7f2fe78bSCy Schubert 		mList = mList->next;
359*7f2fe78bSCy Schubert 	}
360*7f2fe78bSCy Schubert 
361*7f2fe78bSCy Schubert 	/* this should always be true, but.... */
362*7f2fe78bSCy Schubert 	if (count > 0) {
363*7f2fe78bSCy Schubert 		g_mechSet.elements =
364*7f2fe78bSCy Schubert 			(gss_OID) calloc(count, sizeof (gss_OID_desc));
365*7f2fe78bSCy Schubert 		if (g_mechSet.elements == NULL) {
366*7f2fe78bSCy Schubert 			k5_mutex_unlock(&g_mechSetLock);
367*7f2fe78bSCy Schubert 			k5_mutex_unlock(&g_mechListLock);
368*7f2fe78bSCy Schubert 			return (GSS_S_FAILURE);
369*7f2fe78bSCy Schubert 		}
370*7f2fe78bSCy Schubert 
371*7f2fe78bSCy Schubert 		(void) memset(g_mechSet.elements, 0,
372*7f2fe78bSCy Schubert 			      count * sizeof (gss_OID_desc));
373*7f2fe78bSCy Schubert 
374*7f2fe78bSCy Schubert 		/* now copy each oid element */
375*7f2fe78bSCy Schubert 		count = 0;
376*7f2fe78bSCy Schubert 		for (mList = g_mechList; mList != NULL; mList = mList->next) {
377*7f2fe78bSCy Schubert 			/* Don't expose interposer mechanisms. */
378*7f2fe78bSCy Schubert 			if (mList->is_interposer)
379*7f2fe78bSCy Schubert 				continue;
380*7f2fe78bSCy Schubert 			curItem = &(g_mechSet.elements[count]);
381*7f2fe78bSCy Schubert 			curItem->elements = (void*)
382*7f2fe78bSCy Schubert 				malloc(mList->mech_type->length);
383*7f2fe78bSCy Schubert 			if (curItem->elements == NULL) {
384*7f2fe78bSCy Schubert 				/*
385*7f2fe78bSCy Schubert 				 * this is nasty - we must delete the
386*7f2fe78bSCy Schubert 				 * part of the array already copied
387*7f2fe78bSCy Schubert 				 */
388*7f2fe78bSCy Schubert 				for (i = 0; i < count; i++) {
389*7f2fe78bSCy Schubert 					free(g_mechSet.elements[i].
390*7f2fe78bSCy Schubert 					     elements);
391*7f2fe78bSCy Schubert 				}
392*7f2fe78bSCy Schubert 				free(g_mechSet.elements);
393*7f2fe78bSCy Schubert 				g_mechSet.count = 0;
394*7f2fe78bSCy Schubert 				g_mechSet.elements = NULL;
395*7f2fe78bSCy Schubert 				k5_mutex_unlock(&g_mechSetLock);
396*7f2fe78bSCy Schubert 				k5_mutex_unlock(&g_mechListLock);
397*7f2fe78bSCy Schubert 				return (GSS_S_FAILURE);
398*7f2fe78bSCy Schubert 			}
399*7f2fe78bSCy Schubert 			g_OID_copy(curItem, mList->mech_type);
400*7f2fe78bSCy Schubert 			count++;
401*7f2fe78bSCy Schubert 		}
402*7f2fe78bSCy Schubert 		g_mechSet.count = count;
403*7f2fe78bSCy Schubert 	}
404*7f2fe78bSCy Schubert 
405*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechSetLock);
406*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechListLock);
407*7f2fe78bSCy Schubert 
408*7f2fe78bSCy Schubert 	return GSS_S_COMPLETE;
409*7f2fe78bSCy Schubert }
410*7f2fe78bSCy Schubert 
411*7f2fe78bSCy Schubert 
412*7f2fe78bSCy Schubert /*
413*7f2fe78bSCy Schubert  * this function has been added for use by modules that need to
414*7f2fe78bSCy Schubert  * know what (if any) optional parameters are supplied in the
415*7f2fe78bSCy Schubert  * config file (MECH_CONF).
416*7f2fe78bSCy Schubert  * It will return the option string for a specified mechanism.
417*7f2fe78bSCy Schubert  * caller is responsible for freeing the memory
418*7f2fe78bSCy Schubert  */
419*7f2fe78bSCy Schubert char *
gssint_get_modOptions(oid)420*7f2fe78bSCy Schubert gssint_get_modOptions(oid)
421*7f2fe78bSCy Schubert const gss_OID oid;
422*7f2fe78bSCy Schubert {
423*7f2fe78bSCy Schubert 	gss_mech_info aMech;
424*7f2fe78bSCy Schubert 	char *modOptions = NULL;
425*7f2fe78bSCy Schubert 
426*7f2fe78bSCy Schubert 	if (gssint_mechglue_initialize_library() != 0)
427*7f2fe78bSCy Schubert 		return (NULL);
428*7f2fe78bSCy Schubert 
429*7f2fe78bSCy Schubert 	/* make sure we have fresh data */
430*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechListLock);
431*7f2fe78bSCy Schubert 	updateMechList();
432*7f2fe78bSCy Schubert 
433*7f2fe78bSCy Schubert 	if ((aMech = searchMechList(oid)) == NULL ||
434*7f2fe78bSCy Schubert 		aMech->optionStr == NULL) {
435*7f2fe78bSCy Schubert 		k5_mutex_unlock(&g_mechListLock);
436*7f2fe78bSCy Schubert 		return (NULL);
437*7f2fe78bSCy Schubert 	}
438*7f2fe78bSCy Schubert 
439*7f2fe78bSCy Schubert 	if (aMech->optionStr)
440*7f2fe78bSCy Schubert 		modOptions = strdup(aMech->optionStr);
441*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechListLock);
442*7f2fe78bSCy Schubert 
443*7f2fe78bSCy Schubert 	return (modOptions);
444*7f2fe78bSCy Schubert } /* gssint_get_modOptions */
445*7f2fe78bSCy Schubert 
446*7f2fe78bSCy Schubert /* Return the mtime of filename or its eventual symlink target (if it is a
447*7f2fe78bSCy Schubert  * symlink), whichever is larger.  Return (time_t)-1 if lstat or stat fails. */
448*7f2fe78bSCy Schubert static time_t
check_link_mtime(const char * filename,time_t * mtime_out)449*7f2fe78bSCy Schubert check_link_mtime(const char *filename, time_t *mtime_out)
450*7f2fe78bSCy Schubert {
451*7f2fe78bSCy Schubert 	struct stat st1, st2;
452*7f2fe78bSCy Schubert 
453*7f2fe78bSCy Schubert 	if (lstat(filename, &st1) != 0)
454*7f2fe78bSCy Schubert 		return (time_t)-1;
455*7f2fe78bSCy Schubert 	if (!S_ISLNK(st1.st_mode))
456*7f2fe78bSCy Schubert 		return st1.st_mtime;
457*7f2fe78bSCy Schubert 	if (stat(filename, &st2) != 0)
458*7f2fe78bSCy Schubert 		return (time_t)-1;
459*7f2fe78bSCy Schubert 	return (st1.st_mtime > st2.st_mtime) ? st1.st_mtime : st2.st_mtime;
460*7f2fe78bSCy Schubert }
461*7f2fe78bSCy Schubert 
462*7f2fe78bSCy Schubert /* Load pathname if it is newer than last.  Update *highest to the maximum of
463*7f2fe78bSCy Schubert  * its current value and pathname's mod time. */
464*7f2fe78bSCy Schubert static void
load_if_changed(const char * pathname,time_t last,time_t * highest)465*7f2fe78bSCy Schubert load_if_changed(const char *pathname, time_t last, time_t *highest)
466*7f2fe78bSCy Schubert {
467*7f2fe78bSCy Schubert 	time_t mtime;
468*7f2fe78bSCy Schubert 
469*7f2fe78bSCy Schubert 	mtime = check_link_mtime(pathname, &mtime);
470*7f2fe78bSCy Schubert 	if (mtime == (time_t)-1)
471*7f2fe78bSCy Schubert 		return;
472*7f2fe78bSCy Schubert 	if (mtime > *highest || *highest == (time_t)-1)
473*7f2fe78bSCy Schubert 		*highest = mtime;
474*7f2fe78bSCy Schubert 	if (mtime > last || last == (time_t)-1)
475*7f2fe78bSCy Schubert 		loadConfigFile(pathname);
476*7f2fe78bSCy Schubert }
477*7f2fe78bSCy Schubert 
478*7f2fe78bSCy Schubert #ifndef _WIN32
479*7f2fe78bSCy Schubert /* Try to load any config files which have changed since the last call.  Config
480*7f2fe78bSCy Schubert  * files are MECH_CONF and any files matching MECH_CONF_PATTERN. */
481*7f2fe78bSCy Schubert static void
loadConfigFiles()482*7f2fe78bSCy Schubert loadConfigFiles()
483*7f2fe78bSCy Schubert {
484*7f2fe78bSCy Schubert 	glob_t globbuf;
485*7f2fe78bSCy Schubert 	time_t highest = (time_t)-1, now;
486*7f2fe78bSCy Schubert 	char **path;
487*7f2fe78bSCy Schubert 	const char *val;
488*7f2fe78bSCy Schubert 
489*7f2fe78bSCy Schubert 	/* Don't glob and stat more than once per second. */
490*7f2fe78bSCy Schubert 	if (time(&now) == (time_t)-1 || now == g_confLastCall)
491*7f2fe78bSCy Schubert 		return;
492*7f2fe78bSCy Schubert 	g_confLastCall = now;
493*7f2fe78bSCy Schubert 
494*7f2fe78bSCy Schubert 	val = secure_getenv("GSS_MECH_CONFIG");
495*7f2fe78bSCy Schubert 	if (val != NULL) {
496*7f2fe78bSCy Schubert 		load_if_changed(val, g_confFileModTime, &g_confFileModTime);
497*7f2fe78bSCy Schubert 		return;
498*7f2fe78bSCy Schubert 	}
499*7f2fe78bSCy Schubert 
500*7f2fe78bSCy Schubert 	load_if_changed(MECH_CONF, g_confFileModTime, &highest);
501*7f2fe78bSCy Schubert 
502*7f2fe78bSCy Schubert 	memset(&globbuf, 0, sizeof(globbuf));
503*7f2fe78bSCy Schubert 	if (glob(MECH_CONF_PATTERN, 0, NULL, &globbuf) == 0) {
504*7f2fe78bSCy Schubert 		for (path = globbuf.gl_pathv; *path != NULL; path++)
505*7f2fe78bSCy Schubert 			load_if_changed(*path, g_confFileModTime, &highest);
506*7f2fe78bSCy Schubert 	}
507*7f2fe78bSCy Schubert 	globfree(&globbuf);
508*7f2fe78bSCy Schubert 
509*7f2fe78bSCy Schubert 	g_confFileModTime = highest;
510*7f2fe78bSCy Schubert }
511*7f2fe78bSCy Schubert #endif
512*7f2fe78bSCy Schubert 
513*7f2fe78bSCy Schubert /*
514*7f2fe78bSCy Schubert  * determines if the mechList needs to be updated from file
515*7f2fe78bSCy Schubert  * and performs the update.
516*7f2fe78bSCy Schubert  * this functions must be called with a lock of g_mechListLock
517*7f2fe78bSCy Schubert  */
518*7f2fe78bSCy Schubert static void
updateMechList(void)519*7f2fe78bSCy Schubert updateMechList(void)
520*7f2fe78bSCy Schubert {
521*7f2fe78bSCy Schubert 	gss_mech_info minfo;
522*7f2fe78bSCy Schubert 
523*7f2fe78bSCy Schubert #if defined(_WIN32)
524*7f2fe78bSCy Schubert 	time_t lastConfModTime = getRegConfigModTime(MECH_KEY);
525*7f2fe78bSCy Schubert 	if (g_confFileModTime >= lastConfModTime &&
526*7f2fe78bSCy Schubert 	    g_confFileModTime != (time_t)-1)
527*7f2fe78bSCy Schubert 		return;
528*7f2fe78bSCy Schubert 	g_confFileModTime = lastConfModTime;
529*7f2fe78bSCy Schubert 	loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY);
530*7f2fe78bSCy Schubert 	loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY);
531*7f2fe78bSCy Schubert #else /* _WIN32 */
532*7f2fe78bSCy Schubert 	loadConfigFiles();
533*7f2fe78bSCy Schubert #endif /* !_WIN32 */
534*7f2fe78bSCy Schubert 
535*7f2fe78bSCy Schubert 	/* Load any unloaded interposer mechanisms immediately, to make sure we
536*7f2fe78bSCy Schubert 	 * interpose other mechanisms before they are used. */
537*7f2fe78bSCy Schubert 	for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {
538*7f2fe78bSCy Schubert 		if (minfo->is_interposer && minfo->mech == NULL)
539*7f2fe78bSCy Schubert 			loadInterMech(minfo);
540*7f2fe78bSCy Schubert 	}
541*7f2fe78bSCy Schubert } /* updateMechList */
542*7f2fe78bSCy Schubert 
543*7f2fe78bSCy Schubert /* Update the mech list from system configuration if we have never done so.
544*7f2fe78bSCy Schubert  * Must be invoked with the g_mechListLock mutex held. */
545*7f2fe78bSCy Schubert static void
initMechList(void)546*7f2fe78bSCy Schubert initMechList(void)
547*7f2fe78bSCy Schubert {
548*7f2fe78bSCy Schubert 	static int lazy_init = 0;
549*7f2fe78bSCy Schubert 
550*7f2fe78bSCy Schubert 	if (lazy_init == 0) {
551*7f2fe78bSCy Schubert 		updateMechList();
552*7f2fe78bSCy Schubert 		lazy_init = 1;
553*7f2fe78bSCy Schubert 	}
554*7f2fe78bSCy Schubert }
555*7f2fe78bSCy Schubert 
556*7f2fe78bSCy Schubert static void
releaseMechInfo(gss_mech_info * pCf)557*7f2fe78bSCy Schubert releaseMechInfo(gss_mech_info *pCf)
558*7f2fe78bSCy Schubert {
559*7f2fe78bSCy Schubert 	gss_mech_info cf;
560*7f2fe78bSCy Schubert 	OM_uint32 minor_status;
561*7f2fe78bSCy Schubert 
562*7f2fe78bSCy Schubert 	if (*pCf == NULL) {
563*7f2fe78bSCy Schubert 		return;
564*7f2fe78bSCy Schubert 	}
565*7f2fe78bSCy Schubert 
566*7f2fe78bSCy Schubert 	cf = *pCf;
567*7f2fe78bSCy Schubert 
568*7f2fe78bSCy Schubert 	if (cf->kmodName != NULL)
569*7f2fe78bSCy Schubert 		free(cf->kmodName);
570*7f2fe78bSCy Schubert 	if (cf->uLibName != NULL)
571*7f2fe78bSCy Schubert 		free(cf->uLibName);
572*7f2fe78bSCy Schubert 	if (cf->mechNameStr != NULL)
573*7f2fe78bSCy Schubert 		free(cf->mechNameStr);
574*7f2fe78bSCy Schubert 	if (cf->optionStr != NULL)
575*7f2fe78bSCy Schubert 		free(cf->optionStr);
576*7f2fe78bSCy Schubert 	if (cf->mech_type != GSS_C_NO_OID &&
577*7f2fe78bSCy Schubert 	    cf->mech_type != &cf->mech->mech_type)
578*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor_status, &cf->mech_type);
579*7f2fe78bSCy Schubert 	if (cf->freeMech)
580*7f2fe78bSCy Schubert 		zapfree(cf->mech, sizeof(*cf->mech));
581*7f2fe78bSCy Schubert 	if (cf->dl_handle != NULL)
582*7f2fe78bSCy Schubert 		krb5int_close_plugin(cf->dl_handle);
583*7f2fe78bSCy Schubert 	if (cf->int_mech_type != GSS_C_NO_OID)
584*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor_status, &cf->int_mech_type);
585*7f2fe78bSCy Schubert 
586*7f2fe78bSCy Schubert 	memset(cf, 0, sizeof(*cf));
587*7f2fe78bSCy Schubert 	free(cf);
588*7f2fe78bSCy Schubert 
589*7f2fe78bSCy Schubert 	*pCf = NULL;
590*7f2fe78bSCy Schubert }
591*7f2fe78bSCy Schubert 
592*7f2fe78bSCy Schubert #ifdef _GSS_STATIC_LINK
593*7f2fe78bSCy Schubert /*
594*7f2fe78bSCy Schubert  * Register a mechanism.  Called with g_mechListLock held.
595*7f2fe78bSCy Schubert  */
596*7f2fe78bSCy Schubert int
gssint_register_mechinfo(gss_mech_info template)597*7f2fe78bSCy Schubert gssint_register_mechinfo(gss_mech_info template)
598*7f2fe78bSCy Schubert {
599*7f2fe78bSCy Schubert 	gss_mech_info cf, new_cf;
600*7f2fe78bSCy Schubert 
601*7f2fe78bSCy Schubert 	new_cf = calloc(1, sizeof(*new_cf));
602*7f2fe78bSCy Schubert 	if (new_cf == NULL) {
603*7f2fe78bSCy Schubert 		return ENOMEM;
604*7f2fe78bSCy Schubert 	}
605*7f2fe78bSCy Schubert 
606*7f2fe78bSCy Schubert 	new_cf->dl_handle = template->dl_handle;
607*7f2fe78bSCy Schubert 	/* copy mech so we can rewrite canonical mechanism OID */
608*7f2fe78bSCy Schubert 	new_cf->mech = (gss_mechanism)calloc(1, sizeof(struct gss_config));
609*7f2fe78bSCy Schubert 	if (new_cf->mech == NULL) {
610*7f2fe78bSCy Schubert 		releaseMechInfo(&new_cf);
611*7f2fe78bSCy Schubert 		return ENOMEM;
612*7f2fe78bSCy Schubert 	}
613*7f2fe78bSCy Schubert 	*new_cf->mech = *template->mech;
614*7f2fe78bSCy Schubert 	if (template->mech_type != NULL)
615*7f2fe78bSCy Schubert 		new_cf->mech->mech_type = *(template->mech_type);
616*7f2fe78bSCy Schubert 	new_cf->mech_type = &new_cf->mech->mech_type;
617*7f2fe78bSCy Schubert 	new_cf->priority = template->priority;
618*7f2fe78bSCy Schubert 	new_cf->freeMech = 1;
619*7f2fe78bSCy Schubert 	new_cf->next = NULL;
620*7f2fe78bSCy Schubert 
621*7f2fe78bSCy Schubert 	if (template->kmodName != NULL) {
622*7f2fe78bSCy Schubert 		new_cf->kmodName = strdup(template->kmodName);
623*7f2fe78bSCy Schubert 		if (new_cf->kmodName == NULL) {
624*7f2fe78bSCy Schubert 			releaseMechInfo(&new_cf);
625*7f2fe78bSCy Schubert 			return ENOMEM;
626*7f2fe78bSCy Schubert 		}
627*7f2fe78bSCy Schubert 	}
628*7f2fe78bSCy Schubert 	if (template->uLibName != NULL) {
629*7f2fe78bSCy Schubert 		new_cf->uLibName = strdup(template->uLibName);
630*7f2fe78bSCy Schubert 		if (new_cf->uLibName == NULL) {
631*7f2fe78bSCy Schubert 			releaseMechInfo(&new_cf);
632*7f2fe78bSCy Schubert 			return ENOMEM;
633*7f2fe78bSCy Schubert 		}
634*7f2fe78bSCy Schubert 	}
635*7f2fe78bSCy Schubert 	if (template->mechNameStr != NULL) {
636*7f2fe78bSCy Schubert 		new_cf->mechNameStr = strdup(template->mechNameStr);
637*7f2fe78bSCy Schubert 		if (new_cf->mechNameStr == NULL) {
638*7f2fe78bSCy Schubert 			releaseMechInfo(&new_cf);
639*7f2fe78bSCy Schubert 			return ENOMEM;
640*7f2fe78bSCy Schubert 		}
641*7f2fe78bSCy Schubert 	}
642*7f2fe78bSCy Schubert 	if (template->optionStr != NULL) {
643*7f2fe78bSCy Schubert 		new_cf->optionStr = strdup(template->optionStr);
644*7f2fe78bSCy Schubert 		if (new_cf->optionStr == NULL) {
645*7f2fe78bSCy Schubert 			releaseMechInfo(&new_cf);
646*7f2fe78bSCy Schubert 			return ENOMEM;
647*7f2fe78bSCy Schubert 		}
648*7f2fe78bSCy Schubert 	}
649*7f2fe78bSCy Schubert 	if (g_mechList == NULL) {
650*7f2fe78bSCy Schubert 		g_mechList = new_cf;
651*7f2fe78bSCy Schubert 		g_mechListTail = new_cf;
652*7f2fe78bSCy Schubert 		return 0;
653*7f2fe78bSCy Schubert 	} else if (new_cf->priority < g_mechList->priority) {
654*7f2fe78bSCy Schubert 		new_cf->next = g_mechList;
655*7f2fe78bSCy Schubert 		g_mechList = new_cf;
656*7f2fe78bSCy Schubert 		return 0;
657*7f2fe78bSCy Schubert 	}
658*7f2fe78bSCy Schubert 
659*7f2fe78bSCy Schubert 	for (cf = g_mechList; cf != NULL; cf = cf->next) {
660*7f2fe78bSCy Schubert 		if (cf->next == NULL ||
661*7f2fe78bSCy Schubert 		    new_cf->priority < cf->next->priority) {
662*7f2fe78bSCy Schubert 			new_cf->next = cf->next;
663*7f2fe78bSCy Schubert 			cf->next = new_cf;
664*7f2fe78bSCy Schubert 			if (g_mechListTail == cf) {
665*7f2fe78bSCy Schubert 				g_mechListTail = new_cf;
666*7f2fe78bSCy Schubert 			}
667*7f2fe78bSCy Schubert 			break;
668*7f2fe78bSCy Schubert 		}
669*7f2fe78bSCy Schubert 	}
670*7f2fe78bSCy Schubert 
671*7f2fe78bSCy Schubert 	return 0;
672*7f2fe78bSCy Schubert }
673*7f2fe78bSCy Schubert #endif /* _GSS_STATIC_LINK */
674*7f2fe78bSCy Schubert 
675*7f2fe78bSCy Schubert #define GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol) \
676*7f2fe78bSCy Schubert 	do { \
677*7f2fe78bSCy Schubert 		struct errinfo errinfo; \
678*7f2fe78bSCy Schubert 		\
679*7f2fe78bSCy Schubert 		memset(&errinfo, 0, sizeof(errinfo)); \
680*7f2fe78bSCy Schubert 		if (krb5int_get_plugin_func(_dl, \
681*7f2fe78bSCy Schubert 					    #_symbol, \
682*7f2fe78bSCy Schubert 					    (void (**)())&(_mech)->_symbol, \
683*7f2fe78bSCy Schubert 					    &errinfo) || errinfo.code) {  \
684*7f2fe78bSCy Schubert 			(_mech)->_symbol = NULL; \
685*7f2fe78bSCy Schubert 			k5_clear_error(&errinfo); \
686*7f2fe78bSCy Schubert 			} \
687*7f2fe78bSCy Schubert 	} while (0)
688*7f2fe78bSCy Schubert 
689*7f2fe78bSCy Schubert /*
690*7f2fe78bSCy Schubert  * If _symbol is undefined in the shared object but the shared object
691*7f2fe78bSCy Schubert  * is linked against the mechanism glue, it's possible for dlsym() to
692*7f2fe78bSCy Schubert  * return the mechanism glue implementation. Guard against that.
693*7f2fe78bSCy Schubert  */
694*7f2fe78bSCy Schubert #define GSS_ADD_DYNAMIC_METHOD_NOLOOP(_dl, _mech, _symbol)	\
695*7f2fe78bSCy Schubert 	do {							\
696*7f2fe78bSCy Schubert 		GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol);	\
697*7f2fe78bSCy Schubert 		if ((_mech)->_symbol == _symbol)		\
698*7f2fe78bSCy Schubert 		    (_mech)->_symbol = NULL;			\
699*7f2fe78bSCy Schubert 	} while (0)
700*7f2fe78bSCy Schubert 
701*7f2fe78bSCy Schubert static gss_mechanism
build_dynamicMech(void * dl,const gss_OID mech_type)702*7f2fe78bSCy Schubert build_dynamicMech(void *dl, const gss_OID mech_type)
703*7f2fe78bSCy Schubert {
704*7f2fe78bSCy Schubert 	gss_mechanism mech;
705*7f2fe78bSCy Schubert 
706*7f2fe78bSCy Schubert 	mech = (gss_mechanism)calloc(1, sizeof(*mech));
707*7f2fe78bSCy Schubert 	if (mech == NULL) {
708*7f2fe78bSCy Schubert 		return NULL;
709*7f2fe78bSCy Schubert 	}
710*7f2fe78bSCy Schubert 
711*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred);
712*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_cred);
713*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_init_sec_context);
714*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_accept_sec_context);
715*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_process_context_token);
716*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_sec_context);
717*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_context_time);
718*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic);
719*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_verify_mic);
720*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap);
721*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap);
722*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_status);
723*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_indicate_mechs);
724*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_compare_name);
725*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name);
726*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_name);
727*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_name);
728*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred);
729*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred);
730*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_sec_context);
731*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_sec_context);
732*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_mech);
733*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_names_for_mech);
734*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_context);
735*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_internal_release_oid);
736*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_size_limit);
737*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_localname);
738*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_authorize_localname);
739*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name);
740*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_duplicate_name);
741*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred);
742*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_sec_context_by_oid);
743*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_oid);
744*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_sec_context_option);
745*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_set_cred_option);
746*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_mech_invoke);
747*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_aead);
748*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_aead);
749*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov);
750*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_iov);
751*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov_length);
752*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_complete_auth_token);
753*7f2fe78bSCy Schubert 	/* Services4User (introduced in 1.8) */
754*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_impersonate_name);
755*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred_impersonate_name);
756*7f2fe78bSCy Schubert 	/* Naming extensions (introduced in 1.8) */
757*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name_ext);
758*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_name);
759*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_name_attribute);
760*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_name_attribute);
761*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_name_attribute);
762*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name_composite);
763*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_map_name_to_any);
764*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_any_name_mapping);
765*7f2fe78bSCy Schubert         /* RFC 4401 (introduced in 1.8) */
766*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_pseudo_random);
767*7f2fe78bSCy Schubert 	/* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */
768*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_neg_mechs);
769*7f2fe78bSCy Schubert         /* draft-ietf-sasl-gs2 */
770*7f2fe78bSCy Schubert         GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_saslname_for_mech);
771*7f2fe78bSCy Schubert         GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_mech_for_saslname);
772*7f2fe78bSCy Schubert         /* RFC 5587 */
773*7f2fe78bSCy Schubert         GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_attrs_for_mech);
774*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_from);
775*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred_into);
776*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_acquire_cred_with_password);
777*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_cred);
778*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_cred);
779*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_sec_context_by_mech);
780*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_name_by_mech);
781*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_import_cred_by_mech);
782*7f2fe78bSCy Schubert 	/* draft-zhu-negoex */
783*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_query_meta_data);
784*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_exchange_meta_data);
785*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_query_mechanism_info);
786*7f2fe78bSCy Schubert 	/* gss_get_mic_iov extensions (added 1.12, implementable 1.20) */
787*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic_iov);
788*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_verify_mic_iov);
789*7f2fe78bSCy Schubert 	GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic_iov_length);
790*7f2fe78bSCy Schubert 
791*7f2fe78bSCy Schubert 	assert(mech_type != GSS_C_NO_OID);
792*7f2fe78bSCy Schubert 
793*7f2fe78bSCy Schubert 	mech->mech_type = *(mech_type);
794*7f2fe78bSCy Schubert 
795*7f2fe78bSCy Schubert 	return mech;
796*7f2fe78bSCy Schubert }
797*7f2fe78bSCy Schubert 
798*7f2fe78bSCy Schubert #define RESOLVE_GSSI_SYMBOL(_dl, _mech, _psym, _nsym)			\
799*7f2fe78bSCy Schubert 	do {								\
800*7f2fe78bSCy Schubert 		struct errinfo errinfo;					\
801*7f2fe78bSCy Schubert 		memset(&errinfo, 0, sizeof(errinfo));			\
802*7f2fe78bSCy Schubert 		if (krb5int_get_plugin_func(_dl,			\
803*7f2fe78bSCy Schubert 					    "gssi" #_nsym,		\
804*7f2fe78bSCy Schubert 					    (void (**)())&(_mech)->_psym \
805*7f2fe78bSCy Schubert 					    ## _nsym,			\
806*7f2fe78bSCy Schubert 					    &errinfo) || errinfo.code) { \
807*7f2fe78bSCy Schubert 			(_mech)->_psym ## _nsym = NULL;			\
808*7f2fe78bSCy Schubert 			k5_clear_error(&errinfo);			\
809*7f2fe78bSCy Schubert 		}							\
810*7f2fe78bSCy Schubert 	} while (0)
811*7f2fe78bSCy Schubert 
812*7f2fe78bSCy Schubert /* Build an interposer mechanism function table from dl. */
813*7f2fe78bSCy Schubert static gss_mechanism
build_interMech(void * dl,const gss_OID mech_type)814*7f2fe78bSCy Schubert build_interMech(void *dl, const gss_OID mech_type)
815*7f2fe78bSCy Schubert {
816*7f2fe78bSCy Schubert 	gss_mechanism mech;
817*7f2fe78bSCy Schubert 
818*7f2fe78bSCy Schubert 	mech = calloc(1, sizeof(*mech));
819*7f2fe78bSCy Schubert 	if (mech == NULL) {
820*7f2fe78bSCy Schubert 		return NULL;
821*7f2fe78bSCy Schubert 	}
822*7f2fe78bSCy Schubert 
823*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred);
824*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_cred);
825*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _init_sec_context);
826*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _accept_sec_context);
827*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _process_context_token);
828*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_sec_context);
829*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _context_time);
830*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic);
831*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _verify_mic);
832*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap);
833*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap);
834*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_status);
835*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _indicate_mechs);
836*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _compare_name);
837*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name);
838*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_name);
839*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_name);
840*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred);
841*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred);
842*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_sec_context);
843*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_sec_context);
844*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_mech);
845*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_names_for_mech);
846*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_context);
847*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _internal_release_oid);
848*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_size_limit);
849*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _localname);
850*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _authorize_localname);
851*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name);
852*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _duplicate_name);
853*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred);
854*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_sec_context_by_oid);
855*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_oid);
856*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_sec_context_option);
857*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _set_cred_option);
858*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _mech_invoke);
859*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_aead);
860*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_aead);
861*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov);
862*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_iov);
863*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov_length);
864*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _complete_auth_token);
865*7f2fe78bSCy Schubert 	/* Services4User (introduced in 1.8) */
866*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_impersonate_name);
867*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred_impersonate_name);
868*7f2fe78bSCy Schubert 	/* Naming extensions (introduced in 1.8) */
869*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name_ext);
870*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_name);
871*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_name_attribute);
872*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_name_attribute);
873*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_name_attribute);
874*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name_composite);
875*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _map_name_to_any);
876*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_any_name_mapping);
877*7f2fe78bSCy Schubert 	/* RFC 4401 (introduced in 1.8) */
878*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _pseudo_random);
879*7f2fe78bSCy Schubert 	/* RFC 4178 (introduced in 1.8; get_neg_mechs not implemented) */
880*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_neg_mechs);
881*7f2fe78bSCy Schubert 	/* draft-ietf-sasl-gs2 */
882*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_saslname_for_mech);
883*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_mech_for_saslname);
884*7f2fe78bSCy Schubert 	/* RFC 5587 */
885*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_attrs_for_mech);
886*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_from);
887*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred_into);
888*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _acquire_cred_with_password);
889*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_cred);
890*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_cred);
891*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_sec_context_by_mech);
892*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_name_by_mech);
893*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _import_cred_by_mech);
894*7f2fe78bSCy Schubert 	/* gss_get_mic_iov extensions (added 1.12, implementable 1.20) */
895*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic_iov);
896*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _verify_mic_iov);
897*7f2fe78bSCy Schubert 	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic_iov_length);
898*7f2fe78bSCy Schubert 
899*7f2fe78bSCy Schubert 	mech->mech_type = *mech_type;
900*7f2fe78bSCy Schubert 	return mech;
901*7f2fe78bSCy Schubert }
902*7f2fe78bSCy Schubert 
903*7f2fe78bSCy Schubert /*
904*7f2fe78bSCy Schubert  * Concatenate an interposer mech OID and a real mech OID to create an
905*7f2fe78bSCy Schubert  * identifier for the interposed mech.  (The concatenation will not be a valid
906*7f2fe78bSCy Schubert  * DER OID encoding, but the OID is only used internally.)
907*7f2fe78bSCy Schubert  */
908*7f2fe78bSCy Schubert static gss_OID
interposed_oid(gss_OID pre,gss_OID real)909*7f2fe78bSCy Schubert interposed_oid(gss_OID pre, gss_OID real)
910*7f2fe78bSCy Schubert {
911*7f2fe78bSCy Schubert 	gss_OID o;
912*7f2fe78bSCy Schubert 
913*7f2fe78bSCy Schubert 	o = (gss_OID)malloc(sizeof(gss_OID_desc));
914*7f2fe78bSCy Schubert 	if (!o)
915*7f2fe78bSCy Schubert 		return NULL;
916*7f2fe78bSCy Schubert 
917*7f2fe78bSCy Schubert 	o->length = pre->length + real->length;
918*7f2fe78bSCy Schubert 	o->elements = malloc(o->length);
919*7f2fe78bSCy Schubert 	if (!o->elements) {
920*7f2fe78bSCy Schubert 		free(o);
921*7f2fe78bSCy Schubert 		return NULL;
922*7f2fe78bSCy Schubert 	}
923*7f2fe78bSCy Schubert 
924*7f2fe78bSCy Schubert 	memcpy(o->elements, pre->elements, pre->length);
925*7f2fe78bSCy Schubert 	memcpy((char *)o->elements + pre->length, real->elements,
926*7f2fe78bSCy Schubert 	       real->length);
927*7f2fe78bSCy Schubert 
928*7f2fe78bSCy Schubert 	return o;
929*7f2fe78bSCy Schubert }
930*7f2fe78bSCy Schubert 
931*7f2fe78bSCy Schubert static void
loadInterMech(gss_mech_info minfo)932*7f2fe78bSCy Schubert loadInterMech(gss_mech_info minfo)
933*7f2fe78bSCy Schubert {
934*7f2fe78bSCy Schubert 	struct plugin_file_handle *dl = NULL;
935*7f2fe78bSCy Schubert 	struct errinfo errinfo;
936*7f2fe78bSCy Schubert 	gss_OID_set (*isym)(const gss_OID);
937*7f2fe78bSCy Schubert 	gss_OID_set list;
938*7f2fe78bSCy Schubert 	gss_OID oid;
939*7f2fe78bSCy Schubert 	OM_uint32 min;
940*7f2fe78bSCy Schubert 	gss_mech_info mi;
941*7f2fe78bSCy Schubert 	size_t i;
942*7f2fe78bSCy Schubert 
943*7f2fe78bSCy Schubert 	memset(&errinfo, 0, sizeof(errinfo));
944*7f2fe78bSCy Schubert 
945*7f2fe78bSCy Schubert 	if (krb5int_open_plugin(minfo->uLibName, &dl, &errinfo) != 0 ||
946*7f2fe78bSCy Schubert 	    errinfo.code != 0) {
947*7f2fe78bSCy Schubert 		return;
948*7f2fe78bSCy Schubert 	}
949*7f2fe78bSCy Schubert 
950*7f2fe78bSCy Schubert 	if (krb5int_get_plugin_func(dl, MECH_INTERPOSER_SYM,
951*7f2fe78bSCy Schubert 				    (void (**)())&isym, &errinfo) != 0)
952*7f2fe78bSCy Schubert 		goto cleanup;
953*7f2fe78bSCy Schubert 
954*7f2fe78bSCy Schubert 	/* Get a list of mechs to interpose. */
955*7f2fe78bSCy Schubert 	list = (*isym)(minfo->mech_type);
956*7f2fe78bSCy Schubert 	if (!list)
957*7f2fe78bSCy Schubert 		goto cleanup;
958*7f2fe78bSCy Schubert 	minfo->mech = build_interMech(dl, minfo->mech_type);
959*7f2fe78bSCy Schubert 	if (minfo->mech == NULL)
960*7f2fe78bSCy Schubert 		goto cleanup;
961*7f2fe78bSCy Schubert 	minfo->freeMech = 1;
962*7f2fe78bSCy Schubert 
963*7f2fe78bSCy Schubert 	/* Add interposer fields for each interposed mech. */
964*7f2fe78bSCy Schubert 	for (i = 0; i < list->count; i++) {
965*7f2fe78bSCy Schubert 		/* Skip this mech if it doesn't exist or is already
966*7f2fe78bSCy Schubert 		 * interposed. */
967*7f2fe78bSCy Schubert 		oid = &list->elements[i];
968*7f2fe78bSCy Schubert 		mi = searchMechList(oid);
969*7f2fe78bSCy Schubert 		if (mi == NULL || mi->int_mech_type != NULL)
970*7f2fe78bSCy Schubert 			continue;
971*7f2fe78bSCy Schubert 
972*7f2fe78bSCy Schubert 		/* Construct a special OID to represent the interposed mech. */
973*7f2fe78bSCy Schubert 		mi->int_mech_type = interposed_oid(minfo->mech_type, oid);
974*7f2fe78bSCy Schubert 		if (mi->int_mech_type == NULL)
975*7f2fe78bSCy Schubert 			continue;
976*7f2fe78bSCy Schubert 
977*7f2fe78bSCy Schubert 		/* Save an alias to the interposer's function table. */
978*7f2fe78bSCy Schubert 		mi->int_mech = minfo->mech;
979*7f2fe78bSCy Schubert 	}
980*7f2fe78bSCy Schubert 	(void)gss_release_oid_set(&min, &list);
981*7f2fe78bSCy Schubert 
982*7f2fe78bSCy Schubert 	minfo->dl_handle = dl;
983*7f2fe78bSCy Schubert 	dl = NULL;
984*7f2fe78bSCy Schubert 
985*7f2fe78bSCy Schubert cleanup:
986*7f2fe78bSCy Schubert 	if (dl != NULL)
987*7f2fe78bSCy Schubert 		krb5int_close_plugin(dl);
988*7f2fe78bSCy Schubert 	k5_clear_error(&errinfo);
989*7f2fe78bSCy Schubert }
990*7f2fe78bSCy Schubert 
991*7f2fe78bSCy Schubert static void
freeMechList(void)992*7f2fe78bSCy Schubert freeMechList(void)
993*7f2fe78bSCy Schubert {
994*7f2fe78bSCy Schubert 	gss_mech_info cf, next_cf;
995*7f2fe78bSCy Schubert 
996*7f2fe78bSCy Schubert 	for (cf = g_mechList; cf != NULL; cf = next_cf) {
997*7f2fe78bSCy Schubert 		next_cf = cf->next;
998*7f2fe78bSCy Schubert 		releaseMechInfo(&cf);
999*7f2fe78bSCy Schubert 	}
1000*7f2fe78bSCy Schubert }
1001*7f2fe78bSCy Schubert 
1002*7f2fe78bSCy Schubert /*
1003*7f2fe78bSCy Schubert  * Determine the mechanism to use for a caller-specified mech OID.  For the
1004*7f2fe78bSCy Schubert  * real mech OID of an interposed mech, return the interposed OID.  For an
1005*7f2fe78bSCy Schubert  * interposed mech OID (which an interposer mech uses when re-entering the
1006*7f2fe78bSCy Schubert  * mechglue), return the real mech OID.  The returned OID is an alias and
1007*7f2fe78bSCy Schubert  * should not be modified or freed.
1008*7f2fe78bSCy Schubert  */
1009*7f2fe78bSCy Schubert OM_uint32
gssint_select_mech_type(OM_uint32 * minor,gss_const_OID oid,gss_OID * selected_oid)1010*7f2fe78bSCy Schubert gssint_select_mech_type(OM_uint32 *minor, gss_const_OID oid,
1011*7f2fe78bSCy Schubert 			gss_OID *selected_oid)
1012*7f2fe78bSCy Schubert {
1013*7f2fe78bSCy Schubert 	gss_mech_info minfo;
1014*7f2fe78bSCy Schubert 	OM_uint32 status;
1015*7f2fe78bSCy Schubert 
1016*7f2fe78bSCy Schubert 	*selected_oid = GSS_C_NO_OID;
1017*7f2fe78bSCy Schubert 
1018*7f2fe78bSCy Schubert 	if (gssint_mechglue_initialize_library() != 0)
1019*7f2fe78bSCy Schubert 		return GSS_S_FAILURE;
1020*7f2fe78bSCy Schubert 
1021*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechListLock);
1022*7f2fe78bSCy Schubert 
1023*7f2fe78bSCy Schubert 	/* Read conf file at least once so that interposer plugins have a
1024*7f2fe78bSCy Schubert 	 * chance of getting initialized. */
1025*7f2fe78bSCy Schubert 	initMechList();
1026*7f2fe78bSCy Schubert 
1027*7f2fe78bSCy Schubert 	minfo = g_mechList;
1028*7f2fe78bSCy Schubert 	if (oid == GSS_C_NULL_OID)
1029*7f2fe78bSCy Schubert 		oid = minfo->mech_type;
1030*7f2fe78bSCy Schubert 	while (minfo != NULL) {
1031*7f2fe78bSCy Schubert 		if (g_OID_equal(minfo->mech_type, oid)) {
1032*7f2fe78bSCy Schubert 			if (minfo->int_mech_type != GSS_C_NO_OID)
1033*7f2fe78bSCy Schubert 				*selected_oid = minfo->int_mech_type;
1034*7f2fe78bSCy Schubert 			else
1035*7f2fe78bSCy Schubert 				*selected_oid = minfo->mech_type;
1036*7f2fe78bSCy Schubert 			status = GSS_S_COMPLETE;
1037*7f2fe78bSCy Schubert 			goto done;
1038*7f2fe78bSCy Schubert 		} else if ((minfo->int_mech_type != GSS_C_NO_OID) &&
1039*7f2fe78bSCy Schubert 			   (g_OID_equal(minfo->int_mech_type, oid))) {
1040*7f2fe78bSCy Schubert 			*selected_oid = minfo->mech_type;
1041*7f2fe78bSCy Schubert 			status = GSS_S_COMPLETE;
1042*7f2fe78bSCy Schubert 			goto done;
1043*7f2fe78bSCy Schubert 		}
1044*7f2fe78bSCy Schubert 		minfo = minfo->next;
1045*7f2fe78bSCy Schubert 	}
1046*7f2fe78bSCy Schubert 	status = GSS_S_BAD_MECH;
1047*7f2fe78bSCy Schubert 
1048*7f2fe78bSCy Schubert done:
1049*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechListLock);
1050*7f2fe78bSCy Schubert 	return status;
1051*7f2fe78bSCy Schubert }
1052*7f2fe78bSCy Schubert 
1053*7f2fe78bSCy Schubert /* If oid is an interposed OID, return the corresponding real mech OID.  If
1054*7f2fe78bSCy Schubert  * it's a real mech OID, return it unmodified.  Otherwised return null. */
1055*7f2fe78bSCy Schubert gss_OID
gssint_get_public_oid(gss_const_OID oid)1056*7f2fe78bSCy Schubert gssint_get_public_oid(gss_const_OID oid)
1057*7f2fe78bSCy Schubert {
1058*7f2fe78bSCy Schubert 	gss_mech_info minfo;
1059*7f2fe78bSCy Schubert 	gss_OID public_oid = GSS_C_NO_OID;
1060*7f2fe78bSCy Schubert 
1061*7f2fe78bSCy Schubert 	/* if oid is null -> then get default which is the first in the list */
1062*7f2fe78bSCy Schubert 	if (oid == GSS_C_NO_OID)
1063*7f2fe78bSCy Schubert 		return GSS_C_NO_OID;
1064*7f2fe78bSCy Schubert 
1065*7f2fe78bSCy Schubert 	if (gssint_mechglue_initialize_library() != 0)
1066*7f2fe78bSCy Schubert 		return GSS_C_NO_OID;
1067*7f2fe78bSCy Schubert 
1068*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechListLock);
1069*7f2fe78bSCy Schubert 
1070*7f2fe78bSCy Schubert 	for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {
1071*7f2fe78bSCy Schubert 		if (minfo->is_interposer)
1072*7f2fe78bSCy Schubert 			continue;
1073*7f2fe78bSCy Schubert 		if (g_OID_equal(minfo->mech_type, oid) ||
1074*7f2fe78bSCy Schubert 		    ((minfo->int_mech_type != GSS_C_NO_OID) &&
1075*7f2fe78bSCy Schubert 		     (g_OID_equal(minfo->int_mech_type, oid)))) {
1076*7f2fe78bSCy Schubert 			public_oid = minfo->mech_type;
1077*7f2fe78bSCy Schubert 			break;
1078*7f2fe78bSCy Schubert 		}
1079*7f2fe78bSCy Schubert 	}
1080*7f2fe78bSCy Schubert 
1081*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechListLock);
1082*7f2fe78bSCy Schubert 	return public_oid;
1083*7f2fe78bSCy Schubert }
1084*7f2fe78bSCy Schubert 
1085*7f2fe78bSCy Schubert /* Translate a vector of oids (as from a union cred struct) into a set of
1086*7f2fe78bSCy Schubert  * public OIDs using gssint_get_public_oid. */
1087*7f2fe78bSCy Schubert OM_uint32
gssint_make_public_oid_set(OM_uint32 * minor_status,gss_OID oids,int count,gss_OID_set * public_set)1088*7f2fe78bSCy Schubert gssint_make_public_oid_set(OM_uint32 *minor_status, gss_OID oids, int count,
1089*7f2fe78bSCy Schubert 			   gss_OID_set *public_set)
1090*7f2fe78bSCy Schubert {
1091*7f2fe78bSCy Schubert 	OM_uint32 status, tmpmin;
1092*7f2fe78bSCy Schubert 	gss_OID_set set;
1093*7f2fe78bSCy Schubert 	gss_OID public_oid;
1094*7f2fe78bSCy Schubert 	int i;
1095*7f2fe78bSCy Schubert 
1096*7f2fe78bSCy Schubert 	*public_set = GSS_C_NO_OID_SET;
1097*7f2fe78bSCy Schubert 
1098*7f2fe78bSCy Schubert 	status = generic_gss_create_empty_oid_set(minor_status, &set);
1099*7f2fe78bSCy Schubert 	if (GSS_ERROR(status))
1100*7f2fe78bSCy Schubert 		return status;
1101*7f2fe78bSCy Schubert 
1102*7f2fe78bSCy Schubert 	for (i = 0; i < count; i++) {
1103*7f2fe78bSCy Schubert 		public_oid = gssint_get_public_oid(&oids[i]);
1104*7f2fe78bSCy Schubert 		if (public_oid == GSS_C_NO_OID)
1105*7f2fe78bSCy Schubert 			continue;
1106*7f2fe78bSCy Schubert 		status = generic_gss_add_oid_set_member(minor_status,
1107*7f2fe78bSCy Schubert 							public_oid, &set);
1108*7f2fe78bSCy Schubert 		if (GSS_ERROR(status)) {
1109*7f2fe78bSCy Schubert 			(void) generic_gss_release_oid_set(&tmpmin, &set);
1110*7f2fe78bSCy Schubert 			return status;
1111*7f2fe78bSCy Schubert 		}
1112*7f2fe78bSCy Schubert 	}
1113*7f2fe78bSCy Schubert 
1114*7f2fe78bSCy Schubert 	*public_set = set;
1115*7f2fe78bSCy Schubert 	return GSS_S_COMPLETE;
1116*7f2fe78bSCy Schubert }
1117*7f2fe78bSCy Schubert 
1118*7f2fe78bSCy Schubert /*
1119*7f2fe78bSCy Schubert  * Register a mechanism.  Called with g_mechListLock held.
1120*7f2fe78bSCy Schubert  */
1121*7f2fe78bSCy Schubert 
1122*7f2fe78bSCy Schubert /*
1123*7f2fe78bSCy Schubert  * given the mechanism type, return the mechanism structure
1124*7f2fe78bSCy Schubert  * containing the mechanism library entry points.
1125*7f2fe78bSCy Schubert  * will return NULL if mech type is not found
1126*7f2fe78bSCy Schubert  * This function will also trigger the loading of the mechanism
1127*7f2fe78bSCy Schubert  * module if it has not been already loaded.
1128*7f2fe78bSCy Schubert  */
1129*7f2fe78bSCy Schubert gss_mechanism
gssint_get_mechanism(gss_const_OID oid)1130*7f2fe78bSCy Schubert gssint_get_mechanism(gss_const_OID oid)
1131*7f2fe78bSCy Schubert {
1132*7f2fe78bSCy Schubert 	gss_mech_info aMech;
1133*7f2fe78bSCy Schubert 	gss_mechanism (*sym)(const gss_OID);
1134*7f2fe78bSCy Schubert 	struct plugin_file_handle *dl;
1135*7f2fe78bSCy Schubert 	struct errinfo errinfo;
1136*7f2fe78bSCy Schubert 
1137*7f2fe78bSCy Schubert 	if (gssint_mechglue_initialize_library() != 0)
1138*7f2fe78bSCy Schubert 		return (NULL);
1139*7f2fe78bSCy Schubert 
1140*7f2fe78bSCy Schubert 	k5_mutex_lock(&g_mechListLock);
1141*7f2fe78bSCy Schubert 
1142*7f2fe78bSCy Schubert 	/* Check if the mechanism is already loaded. */
1143*7f2fe78bSCy Schubert 	aMech = g_mechList;
1144*7f2fe78bSCy Schubert 	if (oid == GSS_C_NULL_OID)
1145*7f2fe78bSCy Schubert 		oid = aMech->mech_type;
1146*7f2fe78bSCy Schubert 	while (aMech != NULL) {
1147*7f2fe78bSCy Schubert 		if (g_OID_equal(aMech->mech_type, oid) && aMech->mech) {
1148*7f2fe78bSCy Schubert 			k5_mutex_unlock(&g_mechListLock);
1149*7f2fe78bSCy Schubert 			return aMech->mech;
1150*7f2fe78bSCy Schubert 		} else if (aMech->int_mech_type != GSS_C_NO_OID &&
1151*7f2fe78bSCy Schubert 			   g_OID_equal(aMech->int_mech_type, oid)) {
1152*7f2fe78bSCy Schubert 			k5_mutex_unlock(&g_mechListLock);
1153*7f2fe78bSCy Schubert 			return aMech->int_mech;
1154*7f2fe78bSCy Schubert 		}
1155*7f2fe78bSCy Schubert 		aMech = aMech->next;
1156*7f2fe78bSCy Schubert 	}
1157*7f2fe78bSCy Schubert 
1158*7f2fe78bSCy Schubert 	/*
1159*7f2fe78bSCy Schubert 	 * might need to re-read the configuration file before loading
1160*7f2fe78bSCy Schubert 	 * the mechanism to ensure we have the latest info.
1161*7f2fe78bSCy Schubert 	 */
1162*7f2fe78bSCy Schubert 	updateMechList();
1163*7f2fe78bSCy Schubert 
1164*7f2fe78bSCy Schubert 	aMech = searchMechList(oid);
1165*7f2fe78bSCy Schubert 
1166*7f2fe78bSCy Schubert 	/* is the mechanism present in the list ? */
1167*7f2fe78bSCy Schubert 	if (aMech == NULL) {
1168*7f2fe78bSCy Schubert 		k5_mutex_unlock(&g_mechListLock);
1169*7f2fe78bSCy Schubert 		return ((gss_mechanism)NULL);
1170*7f2fe78bSCy Schubert 	}
1171*7f2fe78bSCy Schubert 
1172*7f2fe78bSCy Schubert 	/* has another thread loaded the mech */
1173*7f2fe78bSCy Schubert 	if (aMech->mech) {
1174*7f2fe78bSCy Schubert 		k5_mutex_unlock(&g_mechListLock);
1175*7f2fe78bSCy Schubert 		return (aMech->mech);
1176*7f2fe78bSCy Schubert 	}
1177*7f2fe78bSCy Schubert 
1178*7f2fe78bSCy Schubert 	memset(&errinfo, 0, sizeof(errinfo));
1179*7f2fe78bSCy Schubert 
1180*7f2fe78bSCy Schubert 	if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||
1181*7f2fe78bSCy Schubert 	    errinfo.code != 0) {
1182*7f2fe78bSCy Schubert 		k5_clear_error(&errinfo);
1183*7f2fe78bSCy Schubert 		k5_mutex_unlock(&g_mechListLock);
1184*7f2fe78bSCy Schubert 		return ((gss_mechanism)NULL);
1185*7f2fe78bSCy Schubert 	}
1186*7f2fe78bSCy Schubert 
1187*7f2fe78bSCy Schubert 	if (krb5int_get_plugin_func(dl, MECH_SYM, (void (**)())&sym,
1188*7f2fe78bSCy Schubert 				    &errinfo) == 0) {
1189*7f2fe78bSCy Schubert 		/* Call the symbol to get the mechanism table */
1190*7f2fe78bSCy Schubert 		aMech->mech = (*sym)(aMech->mech_type);
1191*7f2fe78bSCy Schubert 	} else {
1192*7f2fe78bSCy Schubert 		/* Try dynamic dispatch table */
1193*7f2fe78bSCy Schubert 		k5_clear_error(&errinfo);
1194*7f2fe78bSCy Schubert 		aMech->mech = build_dynamicMech(dl, aMech->mech_type);
1195*7f2fe78bSCy Schubert 		aMech->freeMech = 1;
1196*7f2fe78bSCy Schubert 	}
1197*7f2fe78bSCy Schubert 	if (aMech->mech == NULL) {
1198*7f2fe78bSCy Schubert 		(void) krb5int_close_plugin(dl);
1199*7f2fe78bSCy Schubert 		k5_mutex_unlock(&g_mechListLock);
1200*7f2fe78bSCy Schubert 		return ((gss_mechanism)NULL);
1201*7f2fe78bSCy Schubert 	}
1202*7f2fe78bSCy Schubert 
1203*7f2fe78bSCy Schubert 	aMech->dl_handle = dl;
1204*7f2fe78bSCy Schubert 
1205*7f2fe78bSCy Schubert 	k5_mutex_unlock(&g_mechListLock);
1206*7f2fe78bSCy Schubert 	return (aMech->mech);
1207*7f2fe78bSCy Schubert } /* gssint_get_mechanism */
1208*7f2fe78bSCy Schubert 
1209*7f2fe78bSCy Schubert /*
1210*7f2fe78bSCy Schubert  * this routine is used for searching the list of mechanism data.
1211*7f2fe78bSCy Schubert  *
1212*7f2fe78bSCy Schubert  * this needs to be called with g_mechListLock held.
1213*7f2fe78bSCy Schubert  */
searchMechList(gss_const_OID oid)1214*7f2fe78bSCy Schubert static gss_mech_info searchMechList(gss_const_OID oid)
1215*7f2fe78bSCy Schubert {
1216*7f2fe78bSCy Schubert 	gss_mech_info aMech = g_mechList;
1217*7f2fe78bSCy Schubert 
1218*7f2fe78bSCy Schubert 	/* if oid is null -> then get default which is the first in the list */
1219*7f2fe78bSCy Schubert 	if (oid == GSS_C_NULL_OID)
1220*7f2fe78bSCy Schubert 		return (aMech);
1221*7f2fe78bSCy Schubert 
1222*7f2fe78bSCy Schubert 	while (aMech != NULL) {
1223*7f2fe78bSCy Schubert 		if (g_OID_equal(aMech->mech_type, oid))
1224*7f2fe78bSCy Schubert 			return (aMech);
1225*7f2fe78bSCy Schubert 		aMech = aMech->next;
1226*7f2fe78bSCy Schubert 	}
1227*7f2fe78bSCy Schubert 
1228*7f2fe78bSCy Schubert 	/* none found */
1229*7f2fe78bSCy Schubert 	return ((gss_mech_info) NULL);
1230*7f2fe78bSCy Schubert } /* searchMechList */
1231*7f2fe78bSCy Schubert 
1232*7f2fe78bSCy Schubert /* Return the first non-whitespace character starting from str. */
1233*7f2fe78bSCy Schubert static char *
skip_whitespace(char * str)1234*7f2fe78bSCy Schubert skip_whitespace(char *str)
1235*7f2fe78bSCy Schubert {
1236*7f2fe78bSCy Schubert 	while (isspace(*str))
1237*7f2fe78bSCy Schubert 		str++;
1238*7f2fe78bSCy Schubert 	return str;
1239*7f2fe78bSCy Schubert }
1240*7f2fe78bSCy Schubert 
1241*7f2fe78bSCy Schubert /* Truncate str at the first whitespace character and return the first
1242*7f2fe78bSCy Schubert  * non-whitespace character after that point. */
1243*7f2fe78bSCy Schubert static char *
delimit_ws(char * str)1244*7f2fe78bSCy Schubert delimit_ws(char *str)
1245*7f2fe78bSCy Schubert {
1246*7f2fe78bSCy Schubert 	while (*str != '\0' && !isspace(*str))
1247*7f2fe78bSCy Schubert 		str++;
1248*7f2fe78bSCy Schubert 	if (*str != '\0')
1249*7f2fe78bSCy Schubert 		*str++ = '\0';
1250*7f2fe78bSCy Schubert 	return skip_whitespace(str);
1251*7f2fe78bSCy Schubert }
1252*7f2fe78bSCy Schubert 
1253*7f2fe78bSCy Schubert /* Truncate str at the first occurrence of delimiter and return the first
1254*7f2fe78bSCy Schubert  * non-whitespace character after that point. */
1255*7f2fe78bSCy Schubert static char *
delimit(char * str,char delimiter)1256*7f2fe78bSCy Schubert delimit(char *str, char delimiter)
1257*7f2fe78bSCy Schubert {
1258*7f2fe78bSCy Schubert 	while (*str != '\0' && *str != delimiter)
1259*7f2fe78bSCy Schubert 		str++;
1260*7f2fe78bSCy Schubert 	if (*str != '\0')
1261*7f2fe78bSCy Schubert 		*str++ = '\0';
1262*7f2fe78bSCy Schubert 	return skip_whitespace(str);
1263*7f2fe78bSCy Schubert }
1264*7f2fe78bSCy Schubert 
1265*7f2fe78bSCy Schubert /*
1266*7f2fe78bSCy Schubert  * loads the configuration file
1267*7f2fe78bSCy Schubert  * this is called while having a mutex lock on the mechanism list
1268*7f2fe78bSCy Schubert  * entries for libraries that have been loaded can't be modified
1269*7f2fe78bSCy Schubert  * mechNameStr and mech_type fields are not updated during updates
1270*7f2fe78bSCy Schubert  */
1271*7f2fe78bSCy Schubert static void
loadConfigFile(const char * fileName)1272*7f2fe78bSCy Schubert loadConfigFile(const char *fileName)
1273*7f2fe78bSCy Schubert {
1274*7f2fe78bSCy Schubert 	char *sharedLib, *kernMod, *modOptions, *modType, *oid, *next;
1275*7f2fe78bSCy Schubert 	char buffer[BUFSIZ], *oidStr;
1276*7f2fe78bSCy Schubert 	FILE *confFile;
1277*7f2fe78bSCy Schubert 
1278*7f2fe78bSCy Schubert 	if ((confFile = fopen(fileName, "r")) == NULL) {
1279*7f2fe78bSCy Schubert 		return;
1280*7f2fe78bSCy Schubert 	}
1281*7f2fe78bSCy Schubert 
1282*7f2fe78bSCy Schubert 	(void) memset(buffer, 0, sizeof (buffer));
1283*7f2fe78bSCy Schubert 	while (fgets(buffer, BUFSIZ, confFile) != NULL) {
1284*7f2fe78bSCy Schubert 
1285*7f2fe78bSCy Schubert 		/* ignore lines beginning with # */
1286*7f2fe78bSCy Schubert 		if (*buffer == '#')
1287*7f2fe78bSCy Schubert 			continue;
1288*7f2fe78bSCy Schubert 
1289*7f2fe78bSCy Schubert 		/* Parse out the name, oid, and shared library path. */
1290*7f2fe78bSCy Schubert 		oidStr = buffer;
1291*7f2fe78bSCy Schubert 		oid = delimit_ws(oidStr);
1292*7f2fe78bSCy Schubert 		if (*oid == '\0')
1293*7f2fe78bSCy Schubert 			continue;
1294*7f2fe78bSCy Schubert 		sharedLib = delimit_ws(oid);
1295*7f2fe78bSCy Schubert 		if (*sharedLib == '\0')
1296*7f2fe78bSCy Schubert 			continue;
1297*7f2fe78bSCy Schubert 		next = delimit_ws(sharedLib);
1298*7f2fe78bSCy Schubert 
1299*7f2fe78bSCy Schubert 		/* Parse out the kernel module name if present. */
1300*7f2fe78bSCy Schubert 		if (*next != '\0' && *next != '[' && *next != '<') {
1301*7f2fe78bSCy Schubert 			kernMod = next;
1302*7f2fe78bSCy Schubert 			next = delimit_ws(kernMod);
1303*7f2fe78bSCy Schubert 		} else {
1304*7f2fe78bSCy Schubert 			kernMod = NULL;
1305*7f2fe78bSCy Schubert 		}
1306*7f2fe78bSCy Schubert 
1307*7f2fe78bSCy Schubert 		/* Parse out the module options if present. */
1308*7f2fe78bSCy Schubert 		if (*next == '[') {
1309*7f2fe78bSCy Schubert 			modOptions = next + 1;
1310*7f2fe78bSCy Schubert 			next = delimit(modOptions, ']');
1311*7f2fe78bSCy Schubert 		} else {
1312*7f2fe78bSCy Schubert 			modOptions = NULL;
1313*7f2fe78bSCy Schubert 		}
1314*7f2fe78bSCy Schubert 
1315*7f2fe78bSCy Schubert 		/* Parse out the module type if present. */
1316*7f2fe78bSCy Schubert 		if (*next == '<') {
1317*7f2fe78bSCy Schubert 			modType = next + 1;
1318*7f2fe78bSCy Schubert 			(void)delimit(modType, '>');
1319*7f2fe78bSCy Schubert 		} else {
1320*7f2fe78bSCy Schubert 			modType = NULL;
1321*7f2fe78bSCy Schubert 		}
1322*7f2fe78bSCy Schubert 
1323*7f2fe78bSCy Schubert 		addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,
1324*7f2fe78bSCy Schubert 			       modType);
1325*7f2fe78bSCy Schubert 	} /* while */
1326*7f2fe78bSCy Schubert 	(void) fclose(confFile);
1327*7f2fe78bSCy Schubert } /* loadConfigFile */
1328*7f2fe78bSCy Schubert 
1329*7f2fe78bSCy Schubert #if defined(_WIN32)
1330*7f2fe78bSCy Schubert 
1331*7f2fe78bSCy Schubert static time_t
filetimeToTimet(const FILETIME * ft)1332*7f2fe78bSCy Schubert filetimeToTimet(const FILETIME *ft)
1333*7f2fe78bSCy Schubert {
1334*7f2fe78bSCy Schubert 	ULARGE_INTEGER ull;
1335*7f2fe78bSCy Schubert 
1336*7f2fe78bSCy Schubert 	ull.LowPart = ft->dwLowDateTime;
1337*7f2fe78bSCy Schubert 	ull.HighPart = ft->dwHighDateTime;
1338*7f2fe78bSCy Schubert 	return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
1339*7f2fe78bSCy Schubert }
1340*7f2fe78bSCy Schubert 
1341*7f2fe78bSCy Schubert static time_t
getRegConfigModTime(const char * keyPath)1342*7f2fe78bSCy Schubert getRegConfigModTime(const char *keyPath)
1343*7f2fe78bSCy Schubert {
1344*7f2fe78bSCy Schubert 	time_t currentUserModTime = getRegKeyModTime(HKEY_CURRENT_USER,
1345*7f2fe78bSCy Schubert 						     keyPath);
1346*7f2fe78bSCy Schubert 	time_t localMachineModTime = getRegKeyModTime(HKEY_LOCAL_MACHINE,
1347*7f2fe78bSCy Schubert 						      keyPath);
1348*7f2fe78bSCy Schubert 
1349*7f2fe78bSCy Schubert 	return currentUserModTime > localMachineModTime ? currentUserModTime :
1350*7f2fe78bSCy Schubert 		localMachineModTime;
1351*7f2fe78bSCy Schubert }
1352*7f2fe78bSCy Schubert 
1353*7f2fe78bSCy Schubert static time_t
getRegKeyModTime(HKEY hBaseKey,const char * keyPath)1354*7f2fe78bSCy Schubert getRegKeyModTime(HKEY hBaseKey, const char *keyPath)
1355*7f2fe78bSCy Schubert {
1356*7f2fe78bSCy Schubert 	HKEY hConfigKey;
1357*7f2fe78bSCy Schubert 	HRESULT rc;
1358*7f2fe78bSCy Schubert 	int iSubKey = 0;
1359*7f2fe78bSCy Schubert 	time_t modTime = 0, keyModTime;
1360*7f2fe78bSCy Schubert 	FILETIME keyLastWriteTime;
1361*7f2fe78bSCy Schubert 	char subKeyName[256];
1362*7f2fe78bSCy Schubert 
1363*7f2fe78bSCy Schubert 	if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS,
1364*7f2fe78bSCy Schubert 			       &hConfigKey)) != ERROR_SUCCESS) {
1365*7f2fe78bSCy Schubert 		/* TODO: log error message */
1366*7f2fe78bSCy Schubert 		return 0;
1367*7f2fe78bSCy Schubert 	}
1368*7f2fe78bSCy Schubert 	do {
1369*7f2fe78bSCy Schubert 		int subKeyNameSize=sizeof(subKeyName)/sizeof(subKeyName[0]);
1370*7f2fe78bSCy Schubert 		if ((rc = RegEnumKeyEx(hConfigKey, iSubKey++, subKeyName,
1371*7f2fe78bSCy Schubert 				       &subKeyNameSize, NULL, NULL, NULL,
1372*7f2fe78bSCy Schubert 				       &keyLastWriteTime)) != ERROR_SUCCESS) {
1373*7f2fe78bSCy Schubert 			break;
1374*7f2fe78bSCy Schubert 		}
1375*7f2fe78bSCy Schubert 		keyModTime = filetimeToTimet(&keyLastWriteTime);
1376*7f2fe78bSCy Schubert 		if (modTime < keyModTime) {
1377*7f2fe78bSCy Schubert 			modTime = keyModTime;
1378*7f2fe78bSCy Schubert 		}
1379*7f2fe78bSCy Schubert 	} while (1);
1380*7f2fe78bSCy Schubert 	RegCloseKey(hConfigKey);
1381*7f2fe78bSCy Schubert 	return modTime;
1382*7f2fe78bSCy Schubert }
1383*7f2fe78bSCy Schubert 
1384*7f2fe78bSCy Schubert static void
getRegKeyValue(HKEY hKey,const char * keyPath,const char * valueName,void ** data,DWORD * dataLen)1385*7f2fe78bSCy Schubert getRegKeyValue(HKEY hKey, const char *keyPath, const char *valueName,
1386*7f2fe78bSCy Schubert 	       void **data, DWORD* dataLen)
1387*7f2fe78bSCy Schubert {
1388*7f2fe78bSCy Schubert 	DWORD sizeRequired=*dataLen;
1389*7f2fe78bSCy Schubert 	HRESULT hr;
1390*7f2fe78bSCy Schubert 	/* Get data length required */
1391*7f2fe78bSCy Schubert 	if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
1392*7f2fe78bSCy Schubert 			      NULL, &sizeRequired)) != ERROR_SUCCESS) {
1393*7f2fe78bSCy Schubert 		/* TODO: LOG registry error */
1394*7f2fe78bSCy Schubert 		return;
1395*7f2fe78bSCy Schubert 	}
1396*7f2fe78bSCy Schubert 	/* adjust data buffer size if necessary */
1397*7f2fe78bSCy Schubert 	if (*dataLen < sizeRequired) {
1398*7f2fe78bSCy Schubert 		*dataLen = sizeRequired;
1399*7f2fe78bSCy Schubert 		*data = realloc(*data, sizeRequired);
1400*7f2fe78bSCy Schubert 		if (!*data) {
1401*7f2fe78bSCy Schubert 			*dataLen = 0;
1402*7f2fe78bSCy Schubert 			/* TODO: LOG OOM ERROR! */
1403*7f2fe78bSCy Schubert 			return;
1404*7f2fe78bSCy Schubert 		}
1405*7f2fe78bSCy Schubert 	}
1406*7f2fe78bSCy Schubert 	/* get data */
1407*7f2fe78bSCy Schubert 	if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
1408*7f2fe78bSCy Schubert 			      *data, &sizeRequired)) != ERROR_SUCCESS) {
1409*7f2fe78bSCy Schubert 		/* LOG registry error */
1410*7f2fe78bSCy Schubert 		return;
1411*7f2fe78bSCy Schubert 	}
1412*7f2fe78bSCy Schubert }
1413*7f2fe78bSCy Schubert 
1414*7f2fe78bSCy Schubert static void
loadConfigFromRegistry(HKEY hBaseKey,const char * keyPath)1415*7f2fe78bSCy Schubert loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)
1416*7f2fe78bSCy Schubert {
1417*7f2fe78bSCy Schubert 	HKEY hConfigKey;
1418*7f2fe78bSCy Schubert 	DWORD iSubKey, nSubKeys, maxSubKeyNameLen, modTypeLen;
1419*7f2fe78bSCy Schubert 	char *oidStr = NULL, *oid = NULL, *sharedLib = NULL, *kernMod = NULL;
1420*7f2fe78bSCy Schubert 	char *modOptions = NULL, *modType = NULL;
1421*7f2fe78bSCy Schubert 	DWORD oidStrLen = 0, oidLen = 0, sharedLibLen = 0, kernModLen = 0;
1422*7f2fe78bSCy Schubert 	DWORD modOptionsLen = 0;
1423*7f2fe78bSCy Schubert 	HRESULT rc;
1424*7f2fe78bSCy Schubert 
1425*7f2fe78bSCy Schubert 	if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0,
1426*7f2fe78bSCy Schubert 			       KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,
1427*7f2fe78bSCy Schubert 			       &hConfigKey)) != ERROR_SUCCESS) {
1428*7f2fe78bSCy Schubert 		/* TODO: log registry error */
1429*7f2fe78bSCy Schubert 		return;
1430*7f2fe78bSCy Schubert 	}
1431*7f2fe78bSCy Schubert 
1432*7f2fe78bSCy Schubert 	if ((rc = RegQueryInfoKey(hConfigKey,
1433*7f2fe78bSCy Schubert 		NULL, /* lpClass */
1434*7f2fe78bSCy Schubert 		NULL, /* lpcClass */
1435*7f2fe78bSCy Schubert 		NULL, /* lpReserved */
1436*7f2fe78bSCy Schubert 		&nSubKeys,
1437*7f2fe78bSCy Schubert 		&maxSubKeyNameLen,
1438*7f2fe78bSCy Schubert 		NULL, /* lpcMaxClassLen */
1439*7f2fe78bSCy Schubert 		NULL, /* lpcValues */
1440*7f2fe78bSCy Schubert 		NULL, /* lpcMaxValueNameLen */
1441*7f2fe78bSCy Schubert 		NULL, /* lpcMaxValueLen */
1442*7f2fe78bSCy Schubert 		NULL, /* lpcbSecurityDescriptor */
1443*7f2fe78bSCy Schubert 		NULL  /* lpftLastWriteTime */ )) != ERROR_SUCCESS) {
1444*7f2fe78bSCy Schubert 		goto cleanup;
1445*7f2fe78bSCy Schubert 	}
1446*7f2fe78bSCy Schubert 	oidStr = malloc(++maxSubKeyNameLen);
1447*7f2fe78bSCy Schubert 	if (!oidStr) {
1448*7f2fe78bSCy Schubert 		goto cleanup;
1449*7f2fe78bSCy Schubert 	}
1450*7f2fe78bSCy Schubert 	for (iSubKey=0; iSubKey<nSubKeys; iSubKey++) {
1451*7f2fe78bSCy Schubert 		oidStrLen = maxSubKeyNameLen;
1452*7f2fe78bSCy Schubert 		if ((rc = RegEnumKeyEx(hConfigKey, iSubKey, oidStr, &oidStrLen,
1453*7f2fe78bSCy Schubert 				       NULL, NULL, NULL, NULL)) !=
1454*7f2fe78bSCy Schubert 		    ERROR_SUCCESS) {
1455*7f2fe78bSCy Schubert 			/* TODO: log registry error */
1456*7f2fe78bSCy Schubert 			continue;
1457*7f2fe78bSCy Schubert 		}
1458*7f2fe78bSCy Schubert 		getRegKeyValue(hConfigKey, oidStr, "OID", &oid, &oidLen);
1459*7f2fe78bSCy Schubert 		getRegKeyValue(hConfigKey, oidStr, "Shared Library",
1460*7f2fe78bSCy Schubert 			       &sharedLib, &sharedLibLen);
1461*7f2fe78bSCy Schubert 		getRegKeyValue(hConfigKey, oidStr, "Kernel Module", &kernMod,
1462*7f2fe78bSCy Schubert 			       &kernModLen);
1463*7f2fe78bSCy Schubert 		getRegKeyValue(hConfigKey, oidStr, "Options", &modOptions,
1464*7f2fe78bSCy Schubert 			       &modOptionsLen);
1465*7f2fe78bSCy Schubert 		getRegKeyValue(hConfigKey, oidStr, "Type", &modType,
1466*7f2fe78bSCy Schubert 			       &modTypeLen);
1467*7f2fe78bSCy Schubert 		addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,
1468*7f2fe78bSCy Schubert 			       modType);
1469*7f2fe78bSCy Schubert 	}
1470*7f2fe78bSCy Schubert cleanup:
1471*7f2fe78bSCy Schubert 	RegCloseKey(hConfigKey);
1472*7f2fe78bSCy Schubert 	if (oidStr) {
1473*7f2fe78bSCy Schubert 		free(oidStr);
1474*7f2fe78bSCy Schubert 	}
1475*7f2fe78bSCy Schubert 	if (oid) {
1476*7f2fe78bSCy Schubert 		free(oid);
1477*7f2fe78bSCy Schubert 	}
1478*7f2fe78bSCy Schubert 	if (sharedLib) {
1479*7f2fe78bSCy Schubert 		free(sharedLib);
1480*7f2fe78bSCy Schubert 	}
1481*7f2fe78bSCy Schubert 	if (kernMod) {
1482*7f2fe78bSCy Schubert 		free(kernMod);
1483*7f2fe78bSCy Schubert 	}
1484*7f2fe78bSCy Schubert 	if (modOptions) {
1485*7f2fe78bSCy Schubert 		free(modOptions);
1486*7f2fe78bSCy Schubert 	}
1487*7f2fe78bSCy Schubert }
1488*7f2fe78bSCy Schubert #endif
1489*7f2fe78bSCy Schubert 
1490*7f2fe78bSCy Schubert static void
addConfigEntry(const char * oidStr,const char * oid,const char * sharedLib,const char * kernMod,const char * modOptions,const char * modType)1491*7f2fe78bSCy Schubert addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
1492*7f2fe78bSCy Schubert 	       const char *kernMod, const char *modOptions,
1493*7f2fe78bSCy Schubert 	       const char *modType)
1494*7f2fe78bSCy Schubert {
1495*7f2fe78bSCy Schubert #if defined(_WIN32)
1496*7f2fe78bSCy Schubert 	const char *sharedPath;
1497*7f2fe78bSCy Schubert #else
1498*7f2fe78bSCy Schubert 	char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
1499*7f2fe78bSCy Schubert #endif
1500*7f2fe78bSCy Schubert 	char *tmpStr;
1501*7f2fe78bSCy Schubert 	gss_OID mechOid;
1502*7f2fe78bSCy Schubert 	gss_mech_info aMech, tmp;
1503*7f2fe78bSCy Schubert 	OM_uint32 minor;
1504*7f2fe78bSCy Schubert 	gss_buffer_desc oidBuf;
1505*7f2fe78bSCy Schubert 
1506*7f2fe78bSCy Schubert 	if ((!oid) || (!oidStr)) {
1507*7f2fe78bSCy Schubert 		return;
1508*7f2fe78bSCy Schubert 	}
1509*7f2fe78bSCy Schubert 	/*
1510*7f2fe78bSCy Schubert 	 * check if an entry for this oid already exists
1511*7f2fe78bSCy Schubert 	 * if it does, and the library is already loaded then
1512*7f2fe78bSCy Schubert 	 * we can't modify it, so skip it
1513*7f2fe78bSCy Schubert 	 */
1514*7f2fe78bSCy Schubert 	oidBuf.value = (void *)oid;
1515*7f2fe78bSCy Schubert 	oidBuf.length = strlen(oid);
1516*7f2fe78bSCy Schubert 	if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
1517*7f2fe78bSCy Schubert 		!= GSS_S_COMPLETE) {
1518*7f2fe78bSCy Schubert 		return;
1519*7f2fe78bSCy Schubert 	}
1520*7f2fe78bSCy Schubert 
1521*7f2fe78bSCy Schubert 	aMech = searchMechList(mechOid);
1522*7f2fe78bSCy Schubert 	if (aMech && aMech->mech) {
1523*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor, &mechOid);
1524*7f2fe78bSCy Schubert 		return;
1525*7f2fe78bSCy Schubert 	}
1526*7f2fe78bSCy Schubert 
1527*7f2fe78bSCy Schubert 	/*
1528*7f2fe78bSCy Schubert 	 * If that's all, then this is a corrupt entry. Skip it.
1529*7f2fe78bSCy Schubert 	 */
1530*7f2fe78bSCy Schubert 	if (! *sharedLib) {
1531*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor, &mechOid);
1532*7f2fe78bSCy Schubert 		return;
1533*7f2fe78bSCy Schubert 	}
1534*7f2fe78bSCy Schubert #if defined(_WIN32)
1535*7f2fe78bSCy Schubert 	sharedPath = sharedLib;
1536*7f2fe78bSCy Schubert #else
1537*7f2fe78bSCy Schubert 	if (sharedLib[0] == '/')
1538*7f2fe78bSCy Schubert 		snprintf(sharedPath, sizeof(sharedPath), "%s", sharedLib);
1539*7f2fe78bSCy Schubert 	else
1540*7f2fe78bSCy Schubert 		snprintf(sharedPath, sizeof(sharedPath), "%s%s",
1541*7f2fe78bSCy Schubert 			 MECH_LIB_PREFIX, sharedLib);
1542*7f2fe78bSCy Schubert #endif
1543*7f2fe78bSCy Schubert 	/*
1544*7f2fe78bSCy Schubert 	 * are we creating a new mechanism entry or
1545*7f2fe78bSCy Schubert 	 * just modifying existing (non loaded) mechanism entry
1546*7f2fe78bSCy Schubert 	 */
1547*7f2fe78bSCy Schubert 	if (aMech) {
1548*7f2fe78bSCy Schubert 		/*
1549*7f2fe78bSCy Schubert 		 * delete any old values and set new
1550*7f2fe78bSCy Schubert 		 * mechNameStr and mech_type are not modified
1551*7f2fe78bSCy Schubert 		 */
1552*7f2fe78bSCy Schubert 		if (aMech->kmodName) {
1553*7f2fe78bSCy Schubert 			free(aMech->kmodName);
1554*7f2fe78bSCy Schubert 			aMech->kmodName = NULL;
1555*7f2fe78bSCy Schubert 		}
1556*7f2fe78bSCy Schubert 
1557*7f2fe78bSCy Schubert 		if (aMech->optionStr) {
1558*7f2fe78bSCy Schubert 			free(aMech->optionStr);
1559*7f2fe78bSCy Schubert 			aMech->optionStr = NULL;
1560*7f2fe78bSCy Schubert 		}
1561*7f2fe78bSCy Schubert 
1562*7f2fe78bSCy Schubert 		if ((tmpStr = strdup(sharedPath)) != NULL) {
1563*7f2fe78bSCy Schubert 			if (aMech->uLibName)
1564*7f2fe78bSCy Schubert 				free(aMech->uLibName);
1565*7f2fe78bSCy Schubert 			aMech->uLibName = tmpStr;
1566*7f2fe78bSCy Schubert 		}
1567*7f2fe78bSCy Schubert 
1568*7f2fe78bSCy Schubert 		if (kernMod) /* this is an optional parameter */
1569*7f2fe78bSCy Schubert 			aMech->kmodName = strdup(kernMod);
1570*7f2fe78bSCy Schubert 
1571*7f2fe78bSCy Schubert 		if (modOptions) /* optional module options */
1572*7f2fe78bSCy Schubert 			aMech->optionStr = strdup(modOptions);
1573*7f2fe78bSCy Schubert 
1574*7f2fe78bSCy Schubert 		/* the oid is already set */
1575*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor, &mechOid);
1576*7f2fe78bSCy Schubert 		return;
1577*7f2fe78bSCy Schubert 	}
1578*7f2fe78bSCy Schubert 
1579*7f2fe78bSCy Schubert 	/* adding a new entry */
1580*7f2fe78bSCy Schubert 	aMech = calloc(1, sizeof (struct gss_mech_config));
1581*7f2fe78bSCy Schubert 	if (aMech == NULL) {
1582*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor, &mechOid);
1583*7f2fe78bSCy Schubert 		return;
1584*7f2fe78bSCy Schubert 	}
1585*7f2fe78bSCy Schubert 	aMech->mech_type = mechOid;
1586*7f2fe78bSCy Schubert 	aMech->uLibName = strdup(sharedPath);
1587*7f2fe78bSCy Schubert 	aMech->mechNameStr = strdup(oidStr);
1588*7f2fe78bSCy Schubert 	aMech->freeMech = 0;
1589*7f2fe78bSCy Schubert 
1590*7f2fe78bSCy Schubert 	/* check if any memory allocations failed - bad news */
1591*7f2fe78bSCy Schubert 	if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
1592*7f2fe78bSCy Schubert 		if (aMech->uLibName)
1593*7f2fe78bSCy Schubert 			free(aMech->uLibName);
1594*7f2fe78bSCy Schubert 		if (aMech->mechNameStr)
1595*7f2fe78bSCy Schubert 			free(aMech->mechNameStr);
1596*7f2fe78bSCy Schubert 		generic_gss_release_oid(&minor, &mechOid);
1597*7f2fe78bSCy Schubert 		free(aMech);
1598*7f2fe78bSCy Schubert 		return;
1599*7f2fe78bSCy Schubert 	}
1600*7f2fe78bSCy Schubert 	if (kernMod)	/* this is an optional parameter */
1601*7f2fe78bSCy Schubert 		aMech->kmodName = strdup(kernMod);
1602*7f2fe78bSCy Schubert 
1603*7f2fe78bSCy Schubert 	if (modOptions)
1604*7f2fe78bSCy Schubert 		aMech->optionStr = strdup(modOptions);
1605*7f2fe78bSCy Schubert 
1606*7f2fe78bSCy Schubert 	if (modType && strcmp(modType, "interposer") == 0)
1607*7f2fe78bSCy Schubert 		aMech->is_interposer = 1;
1608*7f2fe78bSCy Schubert 
1609*7f2fe78bSCy Schubert 	/*
1610*7f2fe78bSCy Schubert 	 * add the new entry to the end of the list - make sure
1611*7f2fe78bSCy Schubert 	 * that only complete entries are added because other
1612*7f2fe78bSCy Schubert 	 * threads might currently be searching the list.
1613*7f2fe78bSCy Schubert 	 */
1614*7f2fe78bSCy Schubert 	tmp = g_mechListTail;
1615*7f2fe78bSCy Schubert 	g_mechListTail = aMech;
1616*7f2fe78bSCy Schubert 
1617*7f2fe78bSCy Schubert 	if (tmp != NULL)
1618*7f2fe78bSCy Schubert 		tmp->next = aMech;
1619*7f2fe78bSCy Schubert 
1620*7f2fe78bSCy Schubert 	if (g_mechList == NULL)
1621*7f2fe78bSCy Schubert 		g_mechList = aMech;
1622*7f2fe78bSCy Schubert }
1623*7f2fe78bSCy Schubert 
1624