~ubuntu-branches/ubuntu/trusty/krb5/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/0020-gssapi-never-unload-mechanisms.patch/src/lib/gssapi/mechglue/g_initialize.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-11-10 02:20:12 UTC
  • mfrom: (53.1.3 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20131110022012-b8ojkqhcxos55kln
Add alternate dependency on libverto-libevent1 as that's the package
ABI name in ubuntu.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
        OM_uint32 status;
216
 
 
217
 
        /* Initialize outputs. */
218
 
 
219
 
        if (minorStatus != NULL)
220
 
                *minorStatus = 0;
221
 
 
222
 
        if (mechSet_out != NULL)
223
 
                *mechSet_out = GSS_C_NO_OID_SET;
224
 
 
225
 
        /* Validate arguments. */
226
 
        if (minorStatus == NULL || mechSet_out == NULL)
227
 
                return (GSS_S_CALL_INACCESSIBLE_WRITE);
228
 
 
229
 
        *minorStatus = gssint_mechglue_initialize_library();
230
 
        if (*minorStatus != 0)
231
 
                return (GSS_S_FAILURE);
232
 
 
233
 
        fileName = MECH_CONF;
234
 
 
235
 
        /*
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.
239
 
         */
240
 
        if ((stat(fileName, &fileInfo) == 0 &&
241
 
                fileInfo.st_mtime > g_mechSetTime)) {
242
 
        } /* if g_mechSet is out of date or not initialized */
243
 
        if (build_mechSet())
244
 
                return GSS_S_FAILURE;
245
 
 
246
 
        /*
247
 
         * need to lock the g_mechSet in case someone tries to update it while
248
 
         * I'm copying it.
249
 
         */
250
 
        *minorStatus = k5_mutex_lock(&g_mechSetLock);
251
 
        if (*minorStatus) {
252
 
                return GSS_S_FAILURE;
253
 
        }
254
 
 
255
 
        status = generic_gss_copy_oid_set(minorStatus, &g_mechSet, mechSet_out);
256
 
        (void) k5_mutex_unlock(&g_mechSetLock);
257
 
        return (status);
258
 
} /* gss_indicate_mechs */
259
 
 
260
 
 
261
 
/* Call with g_mechSetLock held, or during final cleanup.  */
262
 
static void
263
 
free_mechSet(void)
264
 
{
265
 
        unsigned int i;
266
 
 
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;
272
 
                g_mechSet.count = 0;
273
 
        }
274
 
}
275
 
 
276
 
static OM_uint32
277
 
build_mechSet(void)
278
 
{
279
 
        gss_mech_info mList;
280
 
        size_t i;
281
 
        size_t count;
282
 
        gss_OID curItem;
283
 
 
284
 
        /*
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
289
 
         * modified.
290
 
         */
291
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
292
 
                return GSS_S_FAILURE;
293
 
 
294
 
#if 0
295
 
        /*
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)
300
 
         */
301
 
        if (fileInfo.st_mtime > g_confFileModTime)
302
 
        {
303
 
                g_confFileModTime = fileInfo.st_mtime;
304
 
                loadConfigFile(fileName);
305
 
        }
306
 
#endif
307
 
 
308
 
        updateMechList();
309
 
 
310
 
        /*
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
313
 
         */
314
 
        if (k5_mutex_lock(&g_mechSetLock) != 0)
315
 
                return GSS_S_FAILURE;
316
 
 
317
 
        /* if the oid list already exists we must free it first */
318
 
        free_mechSet();
319
 
 
320
 
        /* determine how many elements to have in the list */
321
 
        mList = g_mechList;
322
 
        count = 0;
323
 
        while (mList != NULL) {
324
 
                count++;
325
 
                mList = mList->next;
326
 
        }
327
 
 
328
 
        /* this should always be true, but.... */
329
 
        if (count > 0) {
330
 
                g_mechSet.elements =
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);
336
 
                }
337
 
 
338
 
                (void) memset(g_mechSet.elements, 0,
339
 
                              count * sizeof (gss_OID_desc));
340
 
 
341
 
                /* now copy each oid element */
342
 
                g_mechSet.count = count;
343
 
                count = 0;
344
 
                mList = g_mechList;
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) {
350
 
                                /*
351
 
                                 * this is nasty - we must delete the
352
 
                                 * part of the array already copied
353
 
                                 */
354
 
                                for (i = 0; i < count; i++) {
355
 
                                        free(g_mechSet.elements[i].
356
 
                                             elements);
357
 
                                }
358
 
                                free(g_mechSet.elements);
359
 
                                g_mechSet.count = 0;
360
 
                                g_mechSet.elements = NULL;
361
 
                                (void) k5_mutex_unlock(&g_mechSetLock);
362
 
                                (void) k5_mutex_unlock(&g_mechListLock);
363
 
                                return (GSS_S_FAILURE);
364
 
                        }
365
 
                        g_OID_copy(curItem, mList->mech_type);
366
 
                        count++;
367
 
                        mList = mList->next;
368
 
                }
369
 
        }
370
 
 
371
 
#if 0
372
 
        g_mechSetTime = fileInfo.st_mtime;
373
 
#endif
374
 
        (void) k5_mutex_unlock(&g_mechSetLock);
375
 
        (void) k5_mutex_unlock(&g_mechListLock);
376
 
 
377
 
        return GSS_S_COMPLETE;
378
 
}
379
 
 
380
 
 
381
 
/*
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
387
 
 */
388
 
char *
389
 
gssint_get_modOptions(oid)
390
 
const gss_OID oid;
391
 
{
392
 
        gss_mech_info aMech;
393
 
        char *modOptions = NULL;
394
 
 
395
 
        if (gssint_mechglue_initialize_library() != 0)
396
 
                return (NULL);
397
 
 
398
 
        /* make sure we have fresh data */
399
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
400
 
                return NULL;
401
 
        updateMechList();
402
 
 
403
 
        if ((aMech = searchMechList(oid)) == NULL ||
404
 
                aMech->optionStr == NULL) {
405
 
                (void) k5_mutex_unlock(&g_mechListLock);
406
 
                return (NULL);
407
 
        }
408
 
 
409
 
        if (aMech->optionStr)
410
 
                modOptions = strdup(aMech->optionStr);
411
 
        (void) k5_mutex_unlock(&g_mechListLock);
412
 
 
413
 
        return (modOptions);
414
 
} /* gssint_get_modOptions */
415
 
 
416
 
/*
417
 
 * given a mechanism string return the mechanism oid
418
 
 */
419
 
OM_uint32
420
 
gssint_mech_to_oid(const char *mechStr, gss_OID* oid)
421
 
{
422
 
        gss_mech_info aMech;
423
 
 
424
 
        if (oid == NULL)
425
 
                return (GSS_S_CALL_INACCESSIBLE_WRITE);
426
 
 
427
 
        *oid = GSS_C_NULL_OID;
428
 
 
429
 
        if (gssint_mechglue_initialize_library() != 0)
430
 
                return (GSS_S_FAILURE);
431
 
 
432
 
        if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
433
 
                (strcasecmp(mechStr, M_DEFAULT) == 0))
434
 
                return (GSS_S_COMPLETE);
435
 
 
436
 
        /* ensure we have fresh data */
437
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
438
 
                return GSS_S_FAILURE;
439
 
        updateMechList();
440
 
        (void) k5_mutex_unlock(&g_mechListLock);
441
 
 
442
 
        aMech = g_mechList;
443
 
 
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);
450
 
                }
451
 
                aMech = aMech->next;
452
 
        }
453
 
        return (GSS_S_FAILURE);
454
 
} /* gssint_mech_to_oid */
455
 
 
456
 
 
457
 
/*
458
 
 * Given the mechanism oid, return the readable mechanism name
459
 
 * associated with that oid from the mech config file
460
 
 * (/etc/gss/mech).
461
 
 */
462
 
const char *
463
 
gssint_oid_to_mech(const gss_OID oid)
464
 
{
465
 
        gss_mech_info aMech;
466
 
 
467
 
        if (oid == GSS_C_NULL_OID)
468
 
                return (M_DEFAULT);
469
 
 
470
 
        if (gssint_mechglue_initialize_library() != 0)
471
 
                return (NULL);
472
 
 
473
 
        /* ensure we have fresh data */
474
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
475
 
                return NULL;
476
 
        updateMechList();
477
 
        aMech = searchMechList(oid);
478
 
        (void) k5_mutex_unlock(&g_mechListLock);
479
 
 
480
 
        if (aMech == NULL)
481
 
                return (NULL);
482
 
 
483
 
        return (aMech->mechNameStr);
484
 
} /* gssint_oid_to_mech */
485
 
 
486
 
 
487
 
/*
488
 
 * return a list of mechanism strings supported
489
 
 * upon return the array is terminated with a NULL entry
490
 
 */
491
 
OM_uint32
492
 
gssint_get_mechanisms(char *mechArray[], int arrayLen)
493
 
{
494
 
        gss_mech_info aMech;
495
 
        int i;
496
 
 
497
 
        if (mechArray == NULL || arrayLen < 1)
498
 
                return (GSS_S_CALL_INACCESSIBLE_WRITE);
499
 
 
500
 
        if (gssint_mechglue_initialize_library() != 0)
501
 
                return (GSS_S_FAILURE);
502
 
 
503
 
        /* ensure we have fresh data */
504
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
505
 
                return GSS_S_FAILURE;
506
 
        updateMechList();
507
 
        (void) k5_mutex_unlock(&g_mechListLock);
508
 
 
509
 
        aMech = g_mechList;
510
 
 
511
 
        /* no lock required - only looking at fields that are not updated */
512
 
        for (i = 1; i < arrayLen; i++) {
513
 
                if (aMech != NULL) {
514
 
                        *mechArray = aMech->mechNameStr;
515
 
                        mechArray++;
516
 
                        aMech = aMech->next;
517
 
                } else
518
 
                        break;
519
 
        }
520
 
        *mechArray = NULL;
521
 
        return (GSS_S_COMPLETE);
522
 
} /* gss_get_mechanisms */
523
 
 
524
 
/*
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
528
 
 */
529
 
static void
530
 
updateMechList(void)
531
 
{
532
 
#if defined(_WIN32)
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);
538
 
        }
539
 
#else /* _WIN32 */
540
 
        char *fileName;
541
 
        struct stat fileInfo;
542
 
 
543
 
        fileName = MECH_CONF;
544
 
 
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;
550
 
        }
551
 
#if 0
552
 
        init_hardcoded();
553
 
#endif
554
 
#endif /* !_WIN32 */
555
 
} /* updateMechList */
556
 
 
557
 
#ifdef _GSS_STATIC_LINK
558
 
static void
559
 
releaseMechInfo(gss_mech_info *pCf)
560
 
{
561
 
        gss_mech_info cf;
562
 
        OM_uint32 minor_status;
563
 
 
564
 
        if (*pCf == NULL) {
565
 
                return;
566
 
        }
567
 
 
568
 
        cf = *pCf;
569
 
 
570
 
        if (cf->kmodName != NULL)
571
 
                free(cf->kmodName);
572
 
        if (cf->uLibName != NULL)
573
 
                free(cf->uLibName);
574
 
        if (cf->mechNameStr != NULL)
575
 
                free(cf->mechNameStr);
576
 
        if (cf->optionStr != NULL)
577
 
                free(cf->optionStr);
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));
583
 
                free(cf->mech);
584
 
        }
585
 
        if (cf->mech_ext != NULL) {
586
 
                memset(cf->mech_ext, 0, sizeof(*cf->mech_ext));
587
 
                free(cf->mech_ext);
588
 
        }
589
 
        if (cf->dl_handle != NULL)
590
 
                krb5int_close_plugin(cf->dl_handle);
591
 
 
592
 
        memset(cf, 0, sizeof(*cf));
593
 
        free(cf);
594
 
 
595
 
        *pCf = NULL;
596
 
}
597
 
 
598
 
/*
599
 
 * Register a mechanism.  Called with g_mechListLock held.
600
 
 */
601
 
int
602
 
gssint_register_mechinfo(gss_mech_info template)
603
 
{
604
 
        gss_mech_info cf, new_cf;
605
 
 
606
 
        new_cf = calloc(1, sizeof(*new_cf));
607
 
        if (new_cf == NULL) {
608
 
                return ENOMEM;
609
 
        }
610
 
 
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);
616
 
                return ENOMEM;
617
 
        }
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;
624
 
        new_cf->next = NULL;
625
 
 
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);
631
 
                        return ENOMEM;
632
 
                }
633
 
                *new_cf->mech_ext = *template->mech_ext;
634
 
        }
635
 
 
636
 
        if (template->kmodName != NULL) {
637
 
                new_cf->kmodName = strdup(template->kmodName);
638
 
                if (new_cf->kmodName == NULL) {
639
 
                        releaseMechInfo(&new_cf);
640
 
                        return ENOMEM;
641
 
                }
642
 
        }
643
 
        if (template->uLibName != NULL) {
644
 
                new_cf->uLibName = strdup(template->uLibName);
645
 
                if (new_cf->uLibName == NULL) {
646
 
                        releaseMechInfo(&new_cf);
647
 
                        return ENOMEM;
648
 
                }
649
 
        }
650
 
        if (template->mechNameStr != NULL) {
651
 
                new_cf->mechNameStr = strdup(template->mechNameStr);
652
 
                if (new_cf->mechNameStr == NULL) {
653
 
                        releaseMechInfo(&new_cf);
654
 
                        return ENOMEM;
655
 
                }
656
 
        }
657
 
        if (template->optionStr != NULL) {
658
 
                new_cf->optionStr = strdup(template->optionStr);
659
 
                if (new_cf->optionStr == NULL) {
660
 
                        releaseMechInfo(&new_cf);
661
 
                        return ENOMEM;
662
 
                }
663
 
        }
664
 
        if (g_mechList == NULL) {
665
 
                g_mechList = new_cf;
666
 
                g_mechListTail = new_cf;
667
 
                return 0;
668
 
        } else if (new_cf->priority < g_mechList->priority) {
669
 
                new_cf->next = g_mechList;
670
 
                g_mechList = new_cf;
671
 
                return 0;
672
 
        }
673
 
 
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;
678
 
                        cf->next = new_cf;
679
 
                        if (g_mechListTail == cf) {
680
 
                                g_mechListTail = new_cf;
681
 
                        }
682
 
                        break;
683
 
                }
684
 
        }
685
 
 
686
 
        return 0;
687
 
}
688
 
#endif /* _GSS_STATIC_LINK */
689
 
 
690
 
#define GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol) \
691
 
        do { \
692
 
                struct errinfo errinfo; \
693
 
                \
694
 
                memset(&errinfo, 0, sizeof(errinfo)); \
695
 
                if (krb5int_get_plugin_func(_dl, \
696
 
                                            #_symbol, \
697
 
                                            (void (**)())&(_mech)->_symbol, \
698
 
                                            &errinfo) || errinfo.code) \
699
 
                        (_mech)->_symbol = NULL; \
700
 
        } while (0)
701
 
 
702
 
/*
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.
706
 
 */
707
 
#define GSS_ADD_DYNAMIC_METHOD_NOLOOP(_dl, _mech, _symbol)      \
708
 
        do {                                                    \
709
 
                GSS_ADD_DYNAMIC_METHOD(_dl, _mech, _symbol);    \
710
 
                if ((_mech)->_symbol == _symbol)                \
711
 
                    (_mech)->_symbol = NULL;                    \
712
 
        } while (0)
713
 
 
714
 
static gss_mechanism
715
 
build_dynamicMech(void *dl, const gss_OID mech_type)
716
 
{
717
 
        gss_mechanism mech;
718
 
 
719
 
        mech = (gss_mechanism)calloc(1, sizeof(*mech));
720
 
        if (mech == NULL) {
721
 
                return NULL;
722
 
        }
723
 
 
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);
785
 
        /* RFC 5587 */
786
 
        GSS_ADD_DYNAMIC_METHOD_NOLOOP(dl, mech, gss_inquire_attrs_for_mech);
787
 
 
788
 
        assert(mech_type != GSS_C_NO_OID);
789
 
 
790
 
        mech->mech_type = *(mech_type);
791
 
 
792
 
        return mech;
793
 
}
794
 
 
795
 
static gss_mechanism_ext
796
 
build_dynamicMechExt(void *dl, const gss_OID mech_type)
797
 
{
798
 
        gss_mechanism_ext mech_ext;
799
 
 
800
 
        mech_ext = (gss_mechanism_ext)calloc(1, sizeof(*mech_ext));
801
 
        if (mech_ext == NULL) {
802
 
                return NULL;
803
 
        }
804
 
 
805
 
        GSS_ADD_DYNAMIC_METHOD(dl, mech_ext, gssspi_acquire_cred_with_password);
806
 
 
807
 
        return mech_ext;
808
 
}
809
 
 
810
 
static void
811
 
freeMechList(void)
812
 
{
813
 
        gss_mech_info cf, next_cf;
814
 
        OM_uint32 minor;
815
 
 
816
 
        for (cf = g_mechList; cf != NULL; cf = next_cf) {
817
 
                next_cf = cf->next;
818
 
                if (cf->kmodName != NULL)
819
 
                        free(cf->kmodName);
820
 
                if (cf->uLibName != NULL)
821
 
                        free(cf->uLibName);
822
 
                if (cf->mechNameStr != NULL)
823
 
                        free(cf->mechNameStr);
824
 
                if (cf->optionStr != NULL)
825
 
                        free(cf->optionStr);
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)
829
 
                        free(cf->mech);
830
 
                if (cf->mech_ext != NULL && cf->freeMech)
831
 
                        free(cf->mech_ext);
832
 
                if (cf->dl_handle != NULL)
833
 
                        (void) krb5int_close_plugin(cf->dl_handle);
834
 
                free(cf);
835
 
        }
836
 
}
837
 
 
838
 
/*
839
 
 * Register a mechanism.  Called with g_mechListLock held.
840
 
 */
841
 
 
842
 
/*
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.
848
 
 */
849
 
gss_mechanism
850
 
gssint_get_mechanism(gss_const_OID oid)
851
 
{
852
 
        gss_mech_info aMech;
853
 
        gss_mechanism (*sym)(const gss_OID);
854
 
        struct plugin_file_handle *dl;
855
 
        struct errinfo errinfo;
856
 
 
857
 
        if (gssint_mechglue_initialize_library() != 0)
858
 
                return (NULL);
859
 
 
860
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
861
 
                return NULL;
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);
866
 
        }
867
 
 
868
 
        /*
869
 
         * might need to re-read the configuration file before loading
870
 
         * the mechanism to ensure we have the latest info.
871
 
         */
872
 
        updateMechList();
873
 
 
874
 
        aMech = searchMechList(oid);
875
 
 
876
 
        /* is the mechanism present in the list ? */
877
 
        if (aMech == NULL) {
878
 
                (void) k5_mutex_unlock(&g_mechListLock);
879
 
                return ((gss_mechanism)NULL);
880
 
        }
881
 
 
882
 
        /* has another thread loaded the mech */
883
 
        if (aMech->mech) {
884
 
                (void) k5_mutex_unlock(&g_mechListLock);
885
 
                return (aMech->mech);
886
 
        }
887
 
 
888
 
        memset(&errinfo, 0, sizeof(errinfo));
889
 
 
890
 
        if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||
891
 
            errinfo.code != 0) {
892
 
#if 0
893
 
                (void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
894
 
                                aMech->uLibName, dlerror());
895
 
#endif
896
 
                (void) k5_mutex_unlock(&g_mechListLock);
897
 
                return ((gss_mechanism)NULL);
898
 
        }
899
 
 
900
 
        if (krb5int_get_plugin_func(dl, MECH_SYM, (void (**)())&sym,
901
 
                                    &errinfo) == 0) {
902
 
                /* Call the symbol to get the mechanism table */
903
 
                aMech->mech = (*sym)(aMech->mech_type);
904
 
        } else {
905
 
                /* Try dynamic dispatch table */
906
 
                aMech->mech = build_dynamicMech(dl, aMech->mech_type);
907
 
                aMech->freeMech = 1;
908
 
        }
909
 
        if (aMech->mech == NULL) {
910
 
                (void) krb5int_close_plugin(dl);
911
 
#if 0
912
 
                (void) syslog(LOG_INFO, "unable to initialize mechanism"
913
 
                                " library [%s]\n", aMech->uLibName);
914
 
#endif
915
 
                (void) k5_mutex_unlock(&g_mechListLock);
916
 
                return ((gss_mechanism)NULL);
917
 
        }
918
 
 
919
 
        aMech->dl_handle = dl;
920
 
 
921
 
        (void) k5_mutex_unlock(&g_mechListLock);
922
 
        return (aMech->mech);
923
 
} /* gssint_get_mechanism */
924
 
 
925
 
gss_mechanism_ext
926
 
gssint_get_mechanism_ext(oid)
927
 
const gss_OID oid;
928
 
{
929
 
        gss_mech_info aMech;
930
 
 
931
 
        if (gssint_mechglue_initialize_library() != 0)
932
 
                return (NULL);
933
 
 
934
 
        if (k5_mutex_lock(&g_mechListLock) != 0)
935
 
                return NULL;
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);
940
 
        }
941
 
 
942
 
        /*
943
 
         * might need to re-read the configuration file before loading
944
 
         * the mechanism to ensure we have the latest info.
945
 
         */
946
 
        updateMechList();
947
 
 
948
 
        aMech = searchMechList(oid);
949
 
 
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);
954
 
        }
955
 
 
956
 
        /* has another thread loaded the mech */
957
 
        if (aMech->mech_ext) {
958
 
                (void) k5_mutex_unlock(&g_mechListLock);
959
 
                return (aMech->mech_ext);
960
 
        }
961
 
 
962
 
        /* Try dynamic dispatch table */
963
 
        aMech->mech_ext = build_dynamicMechExt(aMech->dl_handle,
964
 
                                               aMech->mech_type);
965
 
        if (aMech->mech_ext == NULL) {
966
 
                (void) k5_mutex_unlock(&g_mechListLock);
967
 
                return ((gss_mechanism_ext)NULL);
968
 
        }
969
 
 
970
 
        (void) k5_mutex_unlock(&g_mechListLock);
971
 
        return (aMech->mech_ext);
972
 
} /* gssint_get_mechanism_ext */
973
 
 
974
 
/*
975
 
 * this routine is used for searching the list of mechanism data.
976
 
 *
977
 
 * this needs to be called with g_mechListLock held.
978
 
 */
979
 
static gss_mech_info searchMechList(gss_const_OID oid)
980
 
{
981
 
        gss_mech_info aMech = g_mechList;
982
 
 
983
 
        /* if oid is null -> then get default which is the first in the list */
984
 
        if (oid == GSS_C_NULL_OID)
985
 
                return (aMech);
986
 
 
987
 
        while (aMech != NULL) {
988
 
                if (g_OID_equal(aMech->mech_type, oid))
989
 
                        return (aMech);
990
 
                aMech = aMech->next;
991
 
        }
992
 
 
993
 
        /* none found */
994
 
        return ((gss_mech_info) NULL);
995
 
} /* searchMechList */
996
 
 
997
 
/*
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
1002
 
 */
1003
 
static void loadConfigFile(fileName)
1004
 
const char *fileName;
1005
 
{
1006
 
        char *sharedLib, *kernMod, *modOptions, *oid, *endp;
1007
 
        char buffer[BUFSIZ], *oidStr;
1008
 
        FILE *confFile;
1009
 
 
1010
 
        if ((confFile = fopen(fileName, "r")) == NULL) {
1011
 
                return;
1012
 
        }
1013
 
 
1014
 
        (void) memset(buffer, 0, sizeof (buffer));
1015
 
        while (fgets(buffer, BUFSIZ, confFile) != NULL) {
1016
 
 
1017
 
                /* ignore lines beginning with # */
1018
 
                if (*buffer == '#')
1019
 
                        continue;
1020
 
 
1021
 
                /*
1022
 
                 * find the first white-space character after
1023
 
                 * the mechanism name
1024
 
                 */
1025
 
                oidStr = buffer;
1026
 
                for (endp = buffer; *endp && !isspace(*endp); endp++);
1027
 
 
1028
 
                /* Now find the first non-white-space character */
1029
 
                if (*endp) {
1030
 
                        *endp = '\0';
1031
 
                        endp++;
1032
 
                        while (*endp && isspace(*endp))
1033
 
                                endp++;
1034
 
                }
1035
 
 
1036
 
                /*
1037
 
                 * If that's all, then this is a corrupt entry. Skip it.
1038
 
                 */
1039
 
                if (! *endp)
1040
 
                        continue;
1041
 
 
1042
 
                /* Find the end of the oid and make sure it is NULL-ended */
1043
 
                for (oid = endp; *endp && !isspace(*endp); endp++)
1044
 
                        ;
1045
 
 
1046
 
                if (*endp) {
1047
 
                        *endp = '\0';
1048
 
                        endp++;
1049
 
                }
1050
 
 
1051
 
                /* Find the start of the shared lib name */
1052
 
                for (sharedLib = endp; *sharedLib && isspace(*sharedLib);
1053
 
                     sharedLib++)
1054
 
                        ;
1055
 
 
1056
 
                /*
1057
 
                 * Find the end of the shared lib name and make sure it is
1058
 
                 *  NULL-terminated.
1059
 
                 */
1060
 
                for (endp = sharedLib; *endp && !isspace(*endp); endp++)
1061
 
                        ;
1062
 
 
1063
 
                if (*endp) {
1064
 
                        *endp = '\0';
1065
 
                        endp++;
1066
 
                }
1067
 
 
1068
 
                /* Find the start of the optional kernel module lib name */
1069
 
                for (kernMod = endp; *kernMod && isspace(*kernMod);
1070
 
                     kernMod++)
1071
 
                        ;
1072
 
 
1073
 
                /*
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.
1077
 
                 */
1078
 
                if (*kernMod && *kernMod != '[') {
1079
 
                        /*
1080
 
                         * Find the end of the shared lib name and make sure
1081
 
                         * it is NULL-terminated.
1082
 
                         */
1083
 
                        for (endp = kernMod; *endp && !isspace(*endp); endp++)
1084
 
                                ;
1085
 
 
1086
 
                        if (*endp) {
1087
 
                                *endp = '\0';
1088
 
                                endp++;
1089
 
                        }
1090
 
                } else
1091
 
                        kernMod = NULL;
1092
 
 
1093
 
                /* Find the start of the optional module options list */
1094
 
                for (modOptions = endp; *modOptions && isspace(*modOptions);
1095
 
                     modOptions++);
1096
 
 
1097
 
                if (*modOptions == '[')  {
1098
 
                        /* move past the opening bracket */
1099
 
                        for (modOptions = modOptions+1;
1100
 
                             *modOptions && isspace(*modOptions);
1101
 
                             modOptions++);
1102
 
 
1103
 
                        /* Find the closing bracket */
1104
 
                        for (endp = modOptions;
1105
 
                             *endp && *endp != ']'; endp++);
1106
 
 
1107
 
                        *endp = '\0';
1108
 
                } else {
1109
 
                        modOptions = NULL;
1110
 
                }
1111
 
 
1112
 
                addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions);
1113
 
        } /* while */
1114
 
        (void) fclose(confFile);
1115
 
} /* loadConfigFile */
1116
 
 
1117
 
#if defined(_WIN32)
1118
 
 
1119
 
static time_t
1120
 
filetimeToTimet(const FILETIME *ft)
1121
 
{
1122
 
        ULARGE_INTEGER ull;
1123
 
 
1124
 
        ull.LowPart = ft->dwLowDateTime;
1125
 
        ull.HighPart = ft->dwHighDateTime;
1126
 
        return (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
1127
 
}
1128
 
 
1129
 
static time_t
1130
 
getRegConfigModTime(const char *keyPath)
1131
 
{
1132
 
        time_t currentUserModTime = getRegKeyModTime(HKEY_CURRENT_USER,
1133
 
                                                     keyPath);
1134
 
        time_t localMachineModTime = getRegKeyModTime(HKEY_LOCAL_MACHINE,
1135
 
                                                      keyPath);
1136
 
 
1137
 
        return currentUserModTime > localMachineModTime ? currentUserModTime :
1138
 
                localMachineModTime;
1139
 
}
1140
 
 
1141
 
static time_t
1142
 
getRegKeyModTime(HKEY hBaseKey, const char *keyPath)
1143
 
{
1144
 
        HKEY hConfigKey;
1145
 
        HRESULT rc;
1146
 
        int iSubKey = 0;
1147
 
        time_t modTime = 0, keyModTime;
1148
 
        FILETIME keyLastWriteTime;
1149
 
        char subKeyName[256];
1150
 
 
1151
 
        if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0, KEY_ENUMERATE_SUB_KEYS,
1152
 
                               &hConfigKey)) != ERROR_SUCCESS) {
1153
 
                /* TODO: log error message */
1154
 
                return 0;
1155
 
        }
1156
 
        do {
1157
 
                int subKeyNameSize=sizeof(subKeyName)/sizeof(subKeyName[0]);
1158
 
                if ((rc = RegEnumKeyEx(hConfigKey, iSubKey++, subKeyName,
1159
 
                                       &subKeyNameSize, NULL, NULL, NULL,
1160
 
                                       &keyLastWriteTime)) != ERROR_SUCCESS) {
1161
 
                        break;
1162
 
                }
1163
 
                keyModTime = filetimeToTimet(&keyLastWriteTime);
1164
 
                if (modTime < keyModTime) {
1165
 
                        modTime = keyModTime;
1166
 
                }
1167
 
        } while (1);
1168
 
        RegCloseKey(hConfigKey);
1169
 
        return modTime;
1170
 
}
1171
 
 
1172
 
static void
1173
 
getRegKeyValue(HKEY hKey, const char *keyPath, const char *valueName,
1174
 
               void **data, DWORD* dataLen)
1175
 
{
1176
 
        DWORD sizeRequired=*dataLen;
1177
 
        HRESULT hr;
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 */
1182
 
                return;
1183
 
        }
1184
 
        /* adjust data buffer size if necessary */
1185
 
        if (*dataLen < sizeRequired) {
1186
 
                *dataLen = sizeRequired;
1187
 
                *data = realloc(*data, sizeRequired);
1188
 
                if (!*data) {
1189
 
                        *dataLen = 0;
1190
 
                        /* TODO: LOG OOM ERROR! */
1191
 
                        return;
1192
 
                }
1193
 
        }
1194
 
        /* get data */
1195
 
        if ((hr = RegGetValue(hKey, keyPath, valueName, RRF_RT_REG_SZ, NULL,
1196
 
                              *data, &sizeRequired)) != ERROR_SUCCESS) {
1197
 
                /* LOG registry error */
1198
 
                return;
1199
 
        }
1200
 
}
1201
 
 
1202
 
static void
1203
 
loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)
1204
 
{
1205
 
        HKEY hConfigKey;
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;
1211
 
        HRESULT rc;
1212
 
 
1213
 
        if ((rc = RegOpenKeyEx(hBaseKey, keyPath, 0,
1214
 
                               KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,
1215
 
                               &hConfigKey)) != ERROR_SUCCESS) {
1216
 
                /* TODO: log registry error */
1217
 
                return;
1218
 
        }
1219
 
 
1220
 
        if ((rc = RegQueryInfoKey(hConfigKey,
1221
 
                NULL, /* lpClass */
1222
 
                NULL, /* lpcClass */
1223
 
                NULL, /* lpReserved */
1224
 
                &nSubKeys,
1225
 
                &maxSubKeyNameLen,
1226
 
                NULL, /* lpcMaxClassLen */
1227
 
                NULL, /* lpcValues */
1228
 
                NULL, /* lpcMaxValueNameLen */
1229
 
                NULL, /* lpcMaxValueLen */
1230
 
                NULL, /* lpcbSecurityDescriptor */
1231
 
                NULL  /* lpftLastWriteTime */ )) != ERROR_SUCCESS) {
1232
 
                goto cleanup;
1233
 
        }
1234
 
        oidStr = malloc(++maxSubKeyNameLen);
1235
 
        if (!oidStr) {
1236
 
                goto cleanup;
1237
 
        }
1238
 
        for (iSubKey=0; iSubKey<nSubKeys; iSubKey++) {
1239
 
                oidStrLen = maxSubKeyNameLen;
1240
 
                if ((rc = RegEnumKeyEx(hConfigKey, iSubKey, oidStr, &oidStrLen,
1241
 
                                       NULL, NULL, NULL, NULL)) !=
1242
 
                    ERROR_SUCCESS) {
1243
 
                        /* TODO: log registry error */
1244
 
                        continue;
1245
 
                }
1246
 
                getRegKeyValue(hConfigKey, oidStr, "OID", &oid, &oidLen);
1247
 
                getRegKeyValue(hConfigKey, oidStr, "Shared Library",
1248
 
                               &sharedLib, &sharedLibLen);
1249
 
                getRegKeyValue(hConfigKey, oidStr, "Kernel Module", &kernMod,
1250
 
                               &kernModLen);
1251
 
                getRegKeyValue(hConfigKey, oidStr, "Options", &modOptions,
1252
 
                               &modOptionsLen);
1253
 
                addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions);
1254
 
        }
1255
 
cleanup:
1256
 
        RegCloseKey(hConfigKey);
1257
 
        if (oidStr) {
1258
 
                free(oidStr);
1259
 
        }
1260
 
        if (oid) {
1261
 
                free(oid);
1262
 
        }
1263
 
        if (sharedLib) {
1264
 
                free(sharedLib);
1265
 
        }
1266
 
        if (kernMod) {
1267
 
                free(kernMod);
1268
 
        }
1269
 
        if (modOptions) {
1270
 
                free(modOptions);
1271
 
        }
1272
 
}
1273
 
#endif
1274
 
 
1275
 
static void
1276
 
addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
1277
 
               const char *kernMod, const char *modOptions)
1278
 
{
1279
 
#if defined(_WIN32)
1280
 
        const char *sharedPath;
1281
 
#else
1282
 
        char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
1283
 
#endif
1284
 
        char *tmpStr;
1285
 
        gss_OID mechOid;
1286
 
        gss_mech_info aMech, tmp;
1287
 
        OM_uint32 minor;
1288
 
        gss_buffer_desc oidBuf;
1289
 
 
1290
 
        if ((!oid) || (!oidStr)) {
1291
 
                return;
1292
 
        }
1293
 
        /*
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
1297
 
         */
1298
 
        oidBuf.value = (void *)oid;
1299
 
        oidBuf.length = strlen(oid);
1300
 
        if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
1301
 
                != GSS_S_COMPLETE) {
1302
 
#if 0
1303
 
                (void) syslog(LOG_INFO, "invalid mechanism oid"
1304
 
                                " [%s] in configuration file", oid);
1305
 
#endif
1306
 
                return;
1307
 
        }
1308
 
 
1309
 
        aMech = searchMechList(mechOid);
1310
 
        if (aMech && aMech->mech) {
1311
 
                generic_gss_release_oid(&minor, &mechOid);
1312
 
                return;
1313
 
        }
1314
 
 
1315
 
        /*
1316
 
         * If that's all, then this is a corrupt entry. Skip it.
1317
 
         */
1318
 
        if (! *sharedLib) {
1319
 
                generic_gss_release_oid(&minor, &mechOid);
1320
 
                return;
1321
 
        }
1322
 
#if defined(_WIN32)
1323
 
        sharedPath = sharedLib;
1324
 
#else
1325
 
        if (sharedLib[0] == '/')
1326
 
                snprintf(sharedPath, sizeof(sharedPath), "%s", sharedLib);
1327
 
        else
1328
 
                snprintf(sharedPath, sizeof(sharedPath), "%s%s",
1329
 
                         MECH_LIB_PREFIX, sharedLib);
1330
 
#endif
1331
 
        /*
1332
 
         * are we creating a new mechanism entry or
1333
 
         * just modifying existing (non loaded) mechanism entry
1334
 
         */
1335
 
        if (aMech) {
1336
 
                /*
1337
 
                 * delete any old values and set new
1338
 
                 * mechNameStr and mech_type are not modified
1339
 
                 */
1340
 
                if (aMech->kmodName) {
1341
 
                        free(aMech->kmodName);
1342
 
                        aMech->kmodName = NULL;
1343
 
                }
1344
 
 
1345
 
                if (aMech->optionStr) {
1346
 
                        free(aMech->optionStr);
1347
 
                        aMech->optionStr = NULL;
1348
 
                }
1349
 
 
1350
 
                if ((tmpStr = strdup(sharedPath)) != NULL) {
1351
 
                        if (aMech->uLibName)
1352
 
                                free(aMech->uLibName);
1353
 
                        aMech->uLibName = tmpStr;
1354
 
                }
1355
 
 
1356
 
                if (kernMod) /* this is an optional parameter */
1357
 
                        aMech->kmodName = strdup(kernMod);
1358
 
 
1359
 
                if (modOptions) /* optional module options */
1360
 
                        aMech->optionStr = strdup(modOptions);
1361
 
 
1362
 
                /* the oid is already set */
1363
 
                generic_gss_release_oid(&minor, &mechOid);
1364
 
                return;
1365
 
        }
1366
 
 
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);
1371
 
                return;
1372
 
        }
1373
 
        aMech->mech_type = mechOid;
1374
 
        aMech->uLibName = strdup(sharedPath);
1375
 
        aMech->mechNameStr = strdup(oidStr);
1376
 
        aMech->freeMech = 0;
1377
 
 
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);
1385
 
                free(aMech);
1386
 
                return;
1387
 
        }
1388
 
        if (kernMod)    /* this is an optional parameter */
1389
 
                aMech->kmodName = strdup(kernMod);
1390
 
 
1391
 
        if (modOptions)
1392
 
                aMech->optionStr = strdup(modOptions);
1393
 
        /*
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.
1397
 
         */
1398
 
        tmp = g_mechListTail;
1399
 
        g_mechListTail = aMech;
1400
 
 
1401
 
        if (tmp != NULL)
1402
 
                tmp->next = aMech;
1403
 
 
1404
 
        if (g_mechList == NULL)
1405
 
                g_mechList = aMech;
1406
 
}
1407