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