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