1
/* #pragma ident "@(#)g_initialize.c 1.36 05/02/02 SMI" */
4
* Copyright 1996 by Sun Microsystems, Inc.
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.
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.
26
* This function will initialize the gssapi mechglue library
33
#ifdef HAVE_SYS_STAT_H
36
#ifdef HAVE_SYS_PARAM_H
37
#include <sys/param.h>
45
#define M_DEFAULT "default"
47
#include "k5-thread.h"
48
#include "k5-plugin.h"
50
#ifdef _GSS_STATIC_LINK
51
#include "gssapiP_krb5.h"
52
#include "gssapiP_spnego.h"
55
#define MECH_SYM "gss_mech_initialize"
58
#define MECH_CONF "/etc/gss/mech"
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 *);
67
#define MECH_KEY "SOFTWARE\\gss\\mech"
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);
74
static void updateMechList(void);
75
static void freeMechList(void);
77
static OM_uint32 build_mechSet(void);
78
static void free_mechSet(void);
81
* list of mechanism libraries and their entry points.
82
* the list also maintains state of the mech libraries (loaded or not).
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;
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;
93
MAKE_INIT_FUNCTION(gssint_mechglue_init);
94
MAKE_FINI_FUNCTION(gssint_mechglue_fini);
97
gssint_mechglue_init(void)
101
#ifdef SHOW_INITFINI_FUNCS
102
printf("gssint_mechglue_init\n");
105
add_error_table(&et_ggss_error_table);
107
err = k5_mutex_finish_init(&g_mechSetLock);
108
err = k5_mutex_finish_init(&g_mechListLock);
110
#ifdef _GSS_STATIC_LINK
111
err = gss_krb5int_lib_init();
112
err = gss_spnegoint_lib_init();
115
err = gssint_mecherrmap_init();
120
gssint_mechglue_fini(void)
122
if (!INITIALIZER_RAN(gssint_mechglue_init) || PROGRAM_EXITING()) {
123
#ifdef SHOW_INITFINI_FUNCS
124
printf("gssint_mechglue_fini: skipping\n");
129
#ifdef SHOW_INITFINI_FUNCS
130
printf("gssint_mechglue_fini\n");
132
#ifdef _GSS_STATIC_LINK
133
gss_spnegoint_lib_fini();
134
gss_krb5int_lib_fini();
136
k5_mutex_destroy(&g_mechSetLock);
137
k5_mutex_destroy(&g_mechListLock);
140
remove_error_table(&et_ggss_error_table);
141
gssint_mecherrmap_destroy();
145
gssint_mechglue_initialize_library(void)
147
return CALL_INIT_FUNCTION(gssint_mechglue_init);
151
* function used to reclaim the memory used by a gss_OID structure.
152
* This routine requires direct access to the mechList.
154
OM_uint32 KRB5_CALLCONV
155
gss_release_oid(minor_status, oid)
156
OM_uint32 *minor_status;
162
if (minor_status == NULL)
163
return (GSS_S_CALL_INACCESSIBLE_WRITE);
165
*minor_status = gssint_mechglue_initialize_library();
166
if (*minor_status != 0)
167
return (GSS_S_FAILURE);
169
*minor_status = k5_mutex_lock(&g_mechListLock);
171
return GSS_S_FAILURE;
173
while (aMech != NULL) {
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.
182
if (aMech->mech && aMech->mech->gss_internal_release_oid) {
183
major = aMech->mech->gss_internal_release_oid(
185
if (major == GSS_S_COMPLETE) {
186
k5_mutex_unlock(&g_mechListLock);
187
return (GSS_S_COMPLETE);
189
map_error(minor_status, aMech->mech);
193
k5_mutex_unlock(&g_mechListLock);
195
return (generic_gss_release_oid(minor_status, oid));
196
} /* gss_release_oid */
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.
208
OM_uint32 KRB5_CALLCONV
209
gss_indicate_mechs(minorStatus, mechSet_out)
210
OM_uint32 *minorStatus;
211
gss_OID_set *mechSet_out;
214
struct stat fileInfo;
217
/* Initialize outputs. */
219
if (minorStatus != NULL)
222
if (mechSet_out != NULL)
223
*mechSet_out = GSS_C_NO_OID_SET;
225
/* Validate arguments. */
226
if (minorStatus == NULL || mechSet_out == NULL)
227
return (GSS_S_CALL_INACCESSIBLE_WRITE);
229
*minorStatus = gssint_mechglue_initialize_library();
230
if (*minorStatus != 0)
231
return (GSS_S_FAILURE);
233
fileName = MECH_CONF;
236
* If we have already computed the mechanisms supported and if it
237
* is still valid; make a copy and return to caller,
238
* otherwise build it first.
240
if ((stat(fileName, &fileInfo) == 0 &&
241
fileInfo.st_mtime > g_mechSetTime)) {
242
} /* if g_mechSet is out of date or not initialized */
244
return GSS_S_FAILURE;
247
* need to lock the g_mechSet in case someone tries to update it while
250
*minorStatus = k5_mutex_lock(&g_mechSetLock);
252
return GSS_S_FAILURE;
255
status = generic_gss_copy_oid_set(minorStatus, &g_mechSet, mechSet_out);
256
(void) k5_mutex_unlock(&g_mechSetLock);
258
} /* gss_indicate_mechs */
261
/* Call with g_mechSetLock held, or during final cleanup. */
267
if (g_mechSet.count != 0) {
268
for (i = 0; i < g_mechSet.count; i++)
269
free(g_mechSet.elements[i].elements);
270
free(g_mechSet.elements);
271
g_mechSet.elements = NULL;
285
* lock the mutex since we will be updating
286
* the mechList structure
287
* we need to keep the lock while we build the mechanism list
288
* since we are accessing parts of the mechList which could be
291
if (k5_mutex_lock(&g_mechListLock) != 0)
292
return GSS_S_FAILURE;
296
* this checks for the case when we need to re-construct the
297
* g_mechSet structure, but the mechanism list is upto date
298
* (because it has been read by someone calling
299
* gssint_get_mechanism)
301
if (fileInfo.st_mtime > g_confFileModTime)
303
g_confFileModTime = fileInfo.st_mtime;
304
loadConfigFile(fileName);
311
* we need to lock the mech set so that no one else will
312
* try to read it as we are re-creating it
314
if (k5_mutex_lock(&g_mechSetLock) != 0)
315
return GSS_S_FAILURE;
317
/* if the oid list already exists we must free it first */
320
/* determine how many elements to have in the list */
323
while (mList != NULL) {
328
/* this should always be true, but.... */
331
(gss_OID) calloc(count, sizeof (gss_OID_desc));
332
if (g_mechSet.elements == NULL) {
333
(void) k5_mutex_unlock(&g_mechSetLock);
334
(void) k5_mutex_unlock(&g_mechListLock);
335
return (GSS_S_FAILURE);
338
(void) memset(g_mechSet.elements, 0,
339
count * sizeof (gss_OID_desc));
341
/* now copy each oid element */
342
g_mechSet.count = count;
345
while (mList != NULL) {
346
curItem = &(g_mechSet.elements[count]);
347
curItem->elements = (void*)
348
malloc(mList->mech_type->length);
349
if (curItem->elements == NULL) {
351
* this is nasty - we must delete the
352
* part of the array already copied
354
for (i = 0; i < count; i++) {
355
free(g_mechSet.elements[i].
358
free(g_mechSet.elements);
360
g_mechSet.elements = NULL;
361
(void) k5_mutex_unlock(&g_mechSetLock);
362
(void) k5_mutex_unlock(&g_mechListLock);
363
return (GSS_S_FAILURE);
365
g_OID_copy(curItem, mList->mech_type);
372
g_mechSetTime = fileInfo.st_mtime;
374
(void) k5_mutex_unlock(&g_mechSetLock);
375
(void) k5_mutex_unlock(&g_mechListLock);
377
return GSS_S_COMPLETE;
382
* this function has been added for use by modules that need to
383
* know what (if any) optional parameters are supplied in the
384
* config file (MECH_CONF).
385
* It will return the option string for a specified mechanism.
386
* caller is responsible for freeing the memory
389
gssint_get_modOptions(oid)
393
char *modOptions = NULL;
395
if (gssint_mechglue_initialize_library() != 0)
398
/* make sure we have fresh data */
399
if (k5_mutex_lock(&g_mechListLock) != 0)
403
if ((aMech = searchMechList(oid)) == NULL ||
404
aMech->optionStr == NULL) {
405
(void) k5_mutex_unlock(&g_mechListLock);
409
if (aMech->optionStr)
410
modOptions = strdup(aMech->optionStr);
411
(void) k5_mutex_unlock(&g_mechListLock);
414
} /* gssint_get_modOptions */
417
* given a mechanism string return the mechanism oid
420
gssint_mech_to_oid(const char *mechStr, gss_OID* oid)
425
return (GSS_S_CALL_INACCESSIBLE_WRITE);
427
*oid = GSS_C_NULL_OID;
429
if (gssint_mechglue_initialize_library() != 0)
430
return (GSS_S_FAILURE);
432
if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
433
(strcasecmp(mechStr, M_DEFAULT) == 0))
434
return (GSS_S_COMPLETE);
436
/* ensure we have fresh data */
437
if (k5_mutex_lock(&g_mechListLock) != 0)
438
return GSS_S_FAILURE;
440
(void) k5_mutex_unlock(&g_mechListLock);
444
/* no lock required - only looking at fields that are not updated */
445
while (aMech != NULL) {
446
if ((aMech->mechNameStr) &&
447
strcmp(aMech->mechNameStr, mechStr) == 0) {
448
*oid = aMech->mech_type;
449
return (GSS_S_COMPLETE);
453
return (GSS_S_FAILURE);
454
} /* gssint_mech_to_oid */
458
* Given the mechanism oid, return the readable mechanism name
459
* associated with that oid from the mech config file
463
gssint_oid_to_mech(const gss_OID oid)
467
if (oid == GSS_C_NULL_OID)
470
if (gssint_mechglue_initialize_library() != 0)
473
/* ensure we have fresh data */
474
if (k5_mutex_lock(&g_mechListLock) != 0)
477
aMech = searchMechList(oid);
478
(void) k5_mutex_unlock(&g_mechListLock);
483
return (aMech->mechNameStr);
484
} /* gssint_oid_to_mech */
488
* return a list of mechanism strings supported
489
* upon return the array is terminated with a NULL entry
492
gssint_get_mechanisms(char *mechArray[], int arrayLen)
497
if (mechArray == NULL || arrayLen < 1)
498
return (GSS_S_CALL_INACCESSIBLE_WRITE);
500
if (gssint_mechglue_initialize_library() != 0)
501
return (GSS_S_FAILURE);
503
/* ensure we have fresh data */
504
if (k5_mutex_lock(&g_mechListLock) != 0)
505
return GSS_S_FAILURE;
507
(void) k5_mutex_unlock(&g_mechListLock);
511
/* no lock required - only looking at fields that are not updated */
512
for (i = 1; i < arrayLen; i++) {
514
*mechArray = aMech->mechNameStr;
521
return (GSS_S_COMPLETE);
522
} /* gss_get_mechanisms */
525
* determines if the mechList needs to be updated from file
526
* and performs the update.
527
* this functions must be called with a lock of g_mechListLock
533
time_t lastConfModTime = getRegConfigModTime(MECH_KEY);
534
if (g_confFileModTime < lastConfModTime) {
535
g_confFileModTime = lastConfModTime;
536
loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY);
537
loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY);
541
struct stat fileInfo;
543
fileName = MECH_CONF;
545
/* check if mechList needs updating */
546
if (stat(fileName, &fileInfo) == 0 &&
547
(fileInfo.st_mtime > g_confFileModTime)) {
548
loadConfigFile(fileName);
549
g_confFileModTime = fileInfo.st_mtime;
555
} /* updateMechList */
557
#ifdef _GSS_STATIC_LINK
559
releaseMechInfo(gss_mech_info *pCf)
562
OM_uint32 minor_status;
570
if (cf->kmodName != NULL)
572
if (cf->uLibName != NULL)
574
if (cf->mechNameStr != NULL)
575
free(cf->mechNameStr);
576
if (cf->optionStr != NULL)
578
if (cf->mech_type != GSS_C_NO_OID &&
579
cf->mech_type != &cf->mech->mech_type)
580
generic_gss_release_oid(&minor_status, &cf->mech_type);
581
if (cf->mech != NULL) {
582
memset(cf->mech, 0, sizeof(*cf->mech));
585
if (cf->mech_ext != NULL) {
586
memset(cf->mech_ext, 0, sizeof(*cf->mech_ext));
589
if (cf->dl_handle != NULL)
590
krb5int_close_plugin(cf->dl_handle);
592
memset(cf, 0, sizeof(*cf));
599
* Register a mechanism. Called with g_mechListLock held.
602
gssint_register_mechinfo(gss_mech_info template)
604
gss_mech_info cf, new_cf;
606
new_cf = calloc(1, sizeof(*new_cf));
607
if (new_cf == NULL) {
611
new_cf->dl_handle = template->dl_handle;
612
/* copy mech so we can rewrite canonical mechanism OID */
613
new_cf->mech = (gss_mechanism)calloc(1, sizeof(struct gss_config));
614
if (new_cf->mech == NULL) {
615
releaseMechInfo(&new_cf);
618
*new_cf->mech = *template->mech;
619
if (template->mech_type != NULL)
620
new_cf->mech->mech_type = *(template->mech_type);
621
new_cf->mech_type = &new_cf->mech->mech_type;
622
new_cf->priority = template->priority;
623
new_cf->freeMech = 1;
626
if (template->mech_ext != NULL) {
627
new_cf->mech_ext = (gss_mechanism_ext)calloc(1,
628
sizeof(struct gss_config_ext));
629
if (new_cf->mech_ext == NULL) {
630
releaseMechInfo(&new_cf);
633
*new_cf->mech_ext = *template->mech_ext;
636
if (template->kmodName != NULL) {
637
new_cf->kmodName = strdup(template->kmodName);
638
if (new_cf->kmodName == NULL) {
639
releaseMechInfo(&new_cf);
643
if (template->uLibName != NULL) {
644
new_cf->uLibName = strdup(template->uLibName);
645
if (new_cf->uLibName == NULL) {
646
releaseMechInfo(&new_cf);
650
if (template->mechNameStr != NULL) {
651
new_cf->mechNameStr = strdup(template->mechNameStr);
652
if (new_cf->mechNameStr == NULL) {
653
releaseMechInfo(&new_cf);
657
if (template->optionStr != NULL) {
658
new_cf->optionStr = strdup(template->optionStr);
659
if (new_cf->optionStr == NULL) {
660
releaseMechInfo(&new_cf);
664
if (g_mechList == NULL) {
666
g_mechListTail = new_cf;
668
} else if (new_cf->priority < g_mechList->priority) {
669
new_cf->next = g_mechList;
674
for (cf = g_mechList; cf != NULL; cf = cf->next) {
675
if (cf->next == NULL ||
676
new_cf->priority < cf->next->priority) {
677
new_cf->next = cf->next;
679
if (g_mechListTail == cf) {
680
g_mechListTail = new_cf;
688
#endif /* _GSS_STATIC_LINK */
690
#define GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol) \
692
struct errinfo errinfo; \
694
memset(&errinfo, 0, sizeof(errinfo)); \
695
if (krb5int_get_plugin_func(_dl, \
697
(void (**)())&(_mech)->_symbol, \
698
&errinfo) || errinfo.code) \
699
(_mech)->_symbol = NULL; \
703
* If _symbol is undefined in the shared object but the shared object
704
* is linked against the mechanism glue, it's possible for dlsym() to
705
* return the mechanism glue implementation. Guard against that.
707
#define GSS_ADD_DYNAMIC_METHOD_NOLOOP(_dl, _mech, _symbol) \
709
GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol); \
710
if ((_mech)->_symbol == _symbol) \
711
(_mech)->_symbol = NULL; \
715
build_dynamicMech(void *dl, const gss_OID mech_type)
719
mech = (gss_mechanism)calloc(1, sizeof(*mech));
724
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred);
725
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_cred);
726
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_init_sec_context);
727
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_accept_sec_context);
728
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_process_context_token);
729
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_sec_context);
730
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_context_time);
731
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_mic);
732
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_verify_mic);
733
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap);
734
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap);
735
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_status);
736
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_indicate_mechs);
737
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_compare_name);
738
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name);
739
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_name);
740
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_name);
741
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred);
742
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred);
743
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_sec_context);
744
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_import_sec_context);
745
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_mech);
746
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_names_for_mech);
747
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_context);
748
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_internal_release_oid);
749
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_size_limit);
750
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_localname);
751
GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_authorize_localname);
752
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name);
753
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_duplicate_name);
754
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_store_cred);
755
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_sec_context_by_oid);
756
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_cred_by_oid);
757
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_sec_context_option);
758
GSS_ADD_DYNAMIC_METHOD(dl, mech, gssspi_set_cred_option);
759
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gssspi_mech_invoke);
760
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_aead);
761
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_aead);
762
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov);
763
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_unwrap_iov);
764
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_wrap_iov_length);
765
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_complete_auth_token);
766
/* Services4User (introduced in 1.8) */
767
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_acquire_cred_impersonate_name);
768
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_add_cred_impersonate_name);
769
/* Naming extensions (introduced in 1.8) */
770
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_display_name_ext);
771
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_name);
772
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_get_name_attribute);
773
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_name_attribute);
774
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_delete_name_attribute);
775
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_export_name_composite);
776
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_map_name_to_any);
777
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_release_any_name_mapping);
778
/* RFC 4401 (introduced in 1.8) */
779
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_pseudo_random);
780
/* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */
781
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_set_neg_mechs);
782
/* draft-ietf-sasl-gs2 */
783
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_saslname_for_mech);
784
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_mech_for_saslname);
786
GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_attrs_for_mech);
788
assert(mech_type != GSS_C_NO_OID);
790
mech->mech_type = *(mech_type);
795
static gss_mechanism_ext
796
build_dynamicMechExt(void *dl, const gss_OID mech_type)
798
gss_mechanism_ext mech_ext;
800
mech_ext = (gss_mechanism_ext)calloc(1, sizeof(*mech_ext));
801
if (mech_ext == NULL) {
805
GSS_ADD_DYNAMIC_METHOD(dl, mech_ext, gssspi_acquire_cred_with_password);
813
gss_mech_info cf, next_cf;
816
for (cf = g_mechList; cf != NULL; cf = next_cf) {
818
if (cf->kmodName != NULL)
820
if (cf->uLibName != NULL)
822
if (cf->mechNameStr != NULL)
823
free(cf->mechNameStr);
824
if (cf->optionStr != NULL)
826
if (cf->mech_type != &cf->mech->mech_type)
827
generic_gss_release_oid(&minor, &cf->mech_type);
828
if (cf->mech != NULL && cf->freeMech)
830
if (cf->mech_ext != NULL && cf->freeMech)
832
if (cf->dl_handle != NULL)
833
(void) krb5int_close_plugin(cf->dl_handle);
839
* Register a mechanism. Called with g_mechListLock held.
843
* given the mechanism type, return the mechanism structure
844
* containing the mechanism library entry points.
845
* will return NULL if mech type is not found
846
* This function will also trigger the loading of the mechanism
847
* module if it has not been already loaded.
850
gssint_get_mechanism(gss_const_OID oid)
853
gss_mechanism (*sym)(const gss_OID);
854
struct plugin_file_handle *dl;
855
struct errinfo errinfo;
857
if (gssint_mechglue_initialize_library() != 0)
860
if (k5_mutex_lock(&g_mechListLock) != 0)
862
/* check if the mechanism is already loaded */
863
if ((aMech = searchMechList(oid)) != NULL && aMech->mech) {
864
(void) k5_mutex_unlock(&g_mechListLock);
865
return (aMech->mech);
869
* might need to re-read the configuration file before loading
870
* the mechanism to ensure we have the latest info.
874
aMech = searchMechList(oid);
876
/* is the mechanism present in the list ? */
878
(void) k5_mutex_unlock(&g_mechListLock);
879
return ((gss_mechanism)NULL);
882
/* has another thread loaded the mech */
884
(void) k5_mutex_unlock(&g_mechListLock);
885
return (aMech->mech);
888
memset(&errinfo, 0, sizeof(errinfo));
890
if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||
893
(void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
894
aMech->uLibName, dlerror());
896
(void) k5_mutex_unlock(&g_mechListLock);
897
return ((gss_mechanism)NULL);
900
if (krb5int_get_plugin_func(dl, MECH_SYM, (void (**)())&sym,
902
/* Call the symbol to get the mechanism table */
903
aMech->mech = (*sym)(aMech->mech_type);
905
/* Try dynamic dispatch table */
906
aMech->mech = build_dynamicMech(dl, aMech->mech_type);
909
if (aMech->mech == NULL) {
910
(void) krb5int_close_plugin(dl);
912
(void) syslog(LOG_INFO, "unable to initialize mechanism"
913
" library [%s]\n", aMech->uLibName);
915
(void) k5_mutex_unlock(&g_mechListLock);
916
return ((gss_mechanism)NULL);
919
aMech->dl_handle = dl;
921
(void) k5_mutex_unlock(&g_mechListLock);
922
return (aMech->mech);
923
} /* gssint_get_mechanism */
926
gssint_get_mechanism_ext(oid)
931
if (gssint_mechglue_initialize_library() != 0)
934
if (k5_mutex_lock(&g_mechListLock) != 0)
936
/* check if the mechanism is already loaded */
937
if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext) {
938
(void) k5_mutex_unlock(&g_mechListLock);
939
return (aMech->mech_ext);
943
* might need to re-read the configuration file before loading
944
* the mechanism to ensure we have the latest info.
948
aMech = searchMechList(oid);
950
/* is the mechanism present in the list ? */
951
if (aMech == NULL || aMech->dl_handle == NULL) {
952
(void) k5_mutex_unlock(&g_mechListLock);
953
return ((gss_mechanism_ext)NULL);
956
/* has another thread loaded the mech */
957
if (aMech->mech_ext) {
958
(void) k5_mutex_unlock(&g_mechListLock);
959
return (aMech->mech_ext);
962
/* Try dynamic dispatch table */
963
aMech->mech_ext = build_dynamicMechExt(aMech->dl_handle,
965
if (aMech->mech_ext == NULL) {
966
(void) k5_mutex_unlock(&g_mechListLock);
967
return ((gss_mechanism_ext)NULL);
970
(void) k5_mutex_unlock(&g_mechListLock);
971
return (aMech->mech_ext);
972
} /* gssint_get_mechanism_ext */
975
* this routine is used for searching the list of mechanism data.
977
* this needs to be called with g_mechListLock held.
979
static gss_mech_info searchMechList(gss_const_OID oid)
981
gss_mech_info aMech = g_mechList;
983
/* if oid is null -> then get default which is the first in the list */
984
if (oid == GSS_C_NULL_OID)
987
while (aMech != NULL) {
988
if (g_OID_equal(aMech->mech_type, oid))
994
return ((gss_mech_info) NULL);
995
} /* searchMechList */
998
* loads the configuration file
999
* this is called while having a mutex lock on the mechanism list
1000
* entries for libraries that have been loaded can't be modified
1001
* mechNameStr and mech_type fields are not updated during updates
1003
static void loadConfigFile(fileName)
1004
const char *fileName;
1006
char *sharedLib, *kernMod, *modOptions, *oid, *endp;
1007
char buffer[BUFSIZ], *oidStr;
1010
if ((confFile = fopen(fileName, "r")) == NULL) {
1014
(void) memset(buffer, 0, sizeof (buffer));
1015
while (fgets(buffer, BUFSIZ, confFile) != NULL) {
1017
/* ignore lines beginning with # */
1022
* find the first white-space character after
1023
* the mechanism name
1026
for (endp = buffer; *endp && !isspace(*endp); endp++);
1028
/* Now find the first non-white-space character */
1032
while (*endp && isspace(*endp))
1037
* If that's all, then this is a corrupt entry. Skip it.
1042
/* Find the end of the oid and make sure it is NULL-ended */
1043
for (oid = endp; *endp && !isspace(*endp); endp++)
1051
/* Find the start of the shared lib name */
1052
for (sharedLib = endp; *sharedLib && isspace(*sharedLib);
1057
* Find the end of the shared lib name and make sure it is
1060
for (endp = sharedLib; *endp && !isspace(*endp); endp++)
1068
/* Find the start of the optional kernel module lib name */
1069
for (kernMod = endp; *kernMod && isspace(*kernMod);
1074
* If this item starts with a bracket "[", then
1075
* it is not a kernel module, but is a list of
1076
* options for the user module to parse later.
1078
if (*kernMod && *kernMod != '[') {
1080
* Find the end of the shared lib name and make sure
1081
* it is NULL-terminated.
1083
for (endp = kernMod; *endp && !isspace(*endp); endp++)
1093
/* Find the start of the optional module options list */
1094
for (modOptions = endp; *modOptions && isspace(*modOptions);
1097
if (*modOptions == '[') {
1098
/* move past the opening bracket */
1099
for (modOptions = modOptions+1;
1100
*modOptions && isspace(*modOptions);
1103
/* Find the closing bracket */
1104
for (endp = modOptions;
1105
*endp && *endp != ']'; endp++);
1112
addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions);
1114
(void) fclose(confFile);
1115
} /* loadConfigFile */
1120
filetimeToTimet(const FILETIME *ft)
1124
ull.LowPart = ft->dwLowDateTime;
1125
ull.HighPart = ft->dwHighDateTime;
1126
return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
1130
getRegConfigModTime(const char *keyPath)
1132
time_t currentUserModTime = getRegKeyModTime(HKEY_CURRENT_USER,
1134
time_t localMachineModTime = getRegKeyModTime(HKEY_LOCAL_MACHINE,
1137
return currentUserModTime > localMachineModTime ? currentUserModTime :
1138
localMachineModTime;
1142
getRegKeyModTime(HKEY hBaseKey, const char *keyPath)
1147
time_t modTime = 0, keyModTime;
1148
FILETIME keyLastWriteTime;
1149
char subKeyName[256];
1151
if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS,
1152
&hConfigKey)) != ERROR_SUCCESS) {
1153
/* TODO: log error message */
1157
int subKeyNameSize=sizeof(subKeyName)/sizeof(subKeyName[0]);
1158
if ((rc = RegEnumKeyEx(hConfigKey, iSubKey++, subKeyName,
1159
&subKeyNameSize, NULL, NULL, NULL,
1160
&keyLastWriteTime)) != ERROR_SUCCESS) {
1163
keyModTime = filetimeToTimet(&keyLastWriteTime);
1164
if (modTime < keyModTime) {
1165
modTime = keyModTime;
1168
RegCloseKey(hConfigKey);
1173
getRegKeyValue(HKEY hKey, const char *keyPath, const char *valueName,
1174
void **data, DWORD* dataLen)
1176
DWORD sizeRequired=*dataLen;
1178
/* Get data length required */
1179
if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
1180
NULL, &sizeRequired)) != ERROR_SUCCESS) {
1181
/* TODO: LOG registry error */
1184
/* adjust data buffer size if necessary */
1185
if (*dataLen < sizeRequired) {
1186
*dataLen = sizeRequired;
1187
*data = realloc(*data, sizeRequired);
1190
/* TODO: LOG OOM ERROR! */
1195
if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
1196
*data, &sizeRequired)) != ERROR_SUCCESS) {
1197
/* LOG registry error */
1203
loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)
1206
DWORD iSubKey, nSubKeys, maxSubKeyNameLen;
1207
char *oidStr = NULL, *oid = NULL, *sharedLib = NULL, *kernMod = NULL;
1208
char *modOptions = NULL;
1209
DWORD oidStrLen = 0, oidLen = 0, sharedLibLen = 0, kernModLen = 0;
1210
DWORD modOptionsLen = 0;
1213
if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0,
1214
KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,
1215
&hConfigKey)) != ERROR_SUCCESS) {
1216
/* TODO: log registry error */
1220
if ((rc = RegQueryInfoKey(hConfigKey,
1222
NULL, /* lpcClass */
1223
NULL, /* lpReserved */
1226
NULL, /* lpcMaxClassLen */
1227
NULL, /* lpcValues */
1228
NULL, /* lpcMaxValueNameLen */
1229
NULL, /* lpcMaxValueLen */
1230
NULL, /* lpcbSecurityDescriptor */
1231
NULL /* lpftLastWriteTime */ )) != ERROR_SUCCESS) {
1234
oidStr = malloc(++maxSubKeyNameLen);
1238
for (iSubKey=0; iSubKey<nSubKeys; iSubKey++) {
1239
oidStrLen = maxSubKeyNameLen;
1240
if ((rc = RegEnumKeyEx(hConfigKey, iSubKey, oidStr, &oidStrLen,
1241
NULL, NULL, NULL, NULL)) !=
1243
/* TODO: log registry error */
1246
getRegKeyValue(hConfigKey, oidStr, "OID", &oid, &oidLen);
1247
getRegKeyValue(hConfigKey, oidStr, "Shared Library",
1248
&sharedLib, &sharedLibLen);
1249
getRegKeyValue(hConfigKey, oidStr, "Kernel Module", &kernMod,
1251
getRegKeyValue(hConfigKey, oidStr, "Options", &modOptions,
1253
addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions);
1256
RegCloseKey(hConfigKey);
1276
addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
1277
const char *kernMod, const char *modOptions)
1280
const char *sharedPath;
1282
char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
1286
gss_mech_info aMech, tmp;
1288
gss_buffer_desc oidBuf;
1290
if ((!oid) || (!oidStr)) {
1294
* check if an entry for this oid already exists
1295
* if it does, and the library is already loaded then
1296
* we can't modify it, so skip it
1298
oidBuf.value = (void *)oid;
1299
oidBuf.length = strlen(oid);
1300
if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
1301
!= GSS_S_COMPLETE) {
1303
(void) syslog(LOG_INFO, "invalid mechanism oid"
1304
" [%s] in configuration file", oid);
1309
aMech = searchMechList(mechOid);
1310
if (aMech && aMech->mech) {
1311
generic_gss_release_oid(&minor, &mechOid);
1316
* If that's all, then this is a corrupt entry. Skip it.
1319
generic_gss_release_oid(&minor, &mechOid);
1323
sharedPath = sharedLib;
1325
if (sharedLib[0] == '/')
1326
snprintf(sharedPath, sizeof(sharedPath), "%s", sharedLib);
1328
snprintf(sharedPath, sizeof(sharedPath), "%s%s",
1329
MECH_LIB_PREFIX, sharedLib);
1332
* are we creating a new mechanism entry or
1333
* just modifying existing (non loaded) mechanism entry
1337
* delete any old values and set new
1338
* mechNameStr and mech_type are not modified
1340
if (aMech->kmodName) {
1341
free(aMech->kmodName);
1342
aMech->kmodName = NULL;
1345
if (aMech->optionStr) {
1346
free(aMech->optionStr);
1347
aMech->optionStr = NULL;
1350
if ((tmpStr = strdup(sharedPath)) != NULL) {
1351
if (aMech->uLibName)
1352
free(aMech->uLibName);
1353
aMech->uLibName = tmpStr;
1356
if (kernMod) /* this is an optional parameter */
1357
aMech->kmodName = strdup(kernMod);
1359
if (modOptions) /* optional module options */
1360
aMech->optionStr = strdup(modOptions);
1362
/* the oid is already set */
1363
generic_gss_release_oid(&minor, &mechOid);
1367
/* adding a new entry */
1368
aMech = calloc(1, sizeof (struct gss_mech_config));
1369
if (aMech == NULL) {
1370
generic_gss_release_oid(&minor, &mechOid);
1373
aMech->mech_type = mechOid;
1374
aMech->uLibName = strdup(sharedPath);
1375
aMech->mechNameStr = strdup(oidStr);
1376
aMech->freeMech = 0;
1378
/* check if any memory allocations failed - bad news */
1379
if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
1380
if (aMech->uLibName)
1381
free(aMech->uLibName);
1382
if (aMech->mechNameStr)
1383
free(aMech->mechNameStr);
1384
generic_gss_release_oid(&minor, &mechOid);
1388
if (kernMod) /* this is an optional parameter */
1389
aMech->kmodName = strdup(kernMod);
1392
aMech->optionStr = strdup(modOptions);
1394
* add the new entry to the end of the list - make sure
1395
* that only complete entries are added because other
1396
* threads might currently be searching the list.
1398
tmp = g_mechListTail;
1399
g_mechListTail = aMech;
1404
if (g_mechList == NULL)