Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/pk11wrap/pk11load.c
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
/*
5
 * The following handles the loading, unloading and management of
6
 * various PCKS #11 modules
7
 */
8
#define FORCE_PR_LOG 1
9
#include "base.h"
10
#include "seccomon.h"
11
#include "pkcs11.h"
12
#include "secmod.h"
13
#include "prlink.h"
14
#include "pk11func.h"
15
#include "secmodi.h"
16
#include "secmodti.h"
17
#include "nssilock.h"
18
#include "secerr.h"
19
#include "prenv.h"
20
#include "utilpars.h"
21
#include "prio.h"
22
#include "prprf.h"
23
#include <stdio.h>
24
#include "prsystem.h"
25
26
#define DEBUG_MODULE 1
27
28
#ifdef DEBUG_MODULE
29
static char *modToDBG = NULL;
30
31
#include "debug_module.c"
32
#endif
33
34
/* build the PKCS #11 2.01 lock files */
35
CK_RV PR_CALLBACK
36
secmodCreateMutext(CK_VOID_PTR_PTR pmutex)
37
0
{
38
0
    *pmutex = (CK_VOID_PTR)PZ_NewLock(nssILockOther);
39
0
    if (*pmutex)
40
0
        return CKR_OK;
41
0
    return CKR_HOST_MEMORY;
42
0
}
43
44
CK_RV PR_CALLBACK
45
secmodDestroyMutext(CK_VOID_PTR mutext)
46
0
{
47
0
    PZ_DestroyLock((PZLock *)mutext);
48
0
    return CKR_OK;
49
0
}
50
51
CK_RV PR_CALLBACK
52
secmodLockMutext(CK_VOID_PTR mutext)
53
0
{
54
0
    PZ_Lock((PZLock *)mutext);
55
0
    return CKR_OK;
56
0
}
57
58
CK_RV PR_CALLBACK
59
secmodUnlockMutext(CK_VOID_PTR mutext)
60
0
{
61
0
    PZ_Unlock((PZLock *)mutext);
62
0
    return CKR_OK;
63
0
}
64
65
static SECMODModuleID nextModuleID = 1;
66
static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
67
    secmodCreateMutext, secmodDestroyMutext, secmodLockMutext,
68
    secmodUnlockMutext, CKF_LIBRARY_CANT_CREATE_OS_THREADS | CKF_OS_LOCKING_OK,
69
    NULL
70
};
71
static const CK_C_INITIALIZE_ARGS secmodNoLockArgs = {
72
    NULL, NULL, NULL, NULL,
73
    CKF_LIBRARY_CANT_CREATE_OS_THREADS, NULL
74
};
75
76
static PRBool loadSingleThreadedModules = PR_TRUE;
77
static PRBool enforceAlreadyInitializedError = PR_TRUE;
78
static PRBool finalizeModules = PR_TRUE;
79
80
/* set global options for NSS PKCS#11 module loader */
81
SECStatus
82
pk11_setGlobalOptions(PRBool noSingleThreadedModules,
83
                      PRBool allowAlreadyInitializedModules,
84
                      PRBool dontFinalizeModules)
85
0
{
86
0
    if (noSingleThreadedModules) {
87
0
        loadSingleThreadedModules = PR_FALSE;
88
0
    } else {
89
0
        loadSingleThreadedModules = PR_TRUE;
90
0
    }
91
0
    if (allowAlreadyInitializedModules) {
92
0
        enforceAlreadyInitializedError = PR_FALSE;
93
0
    } else {
94
0
        enforceAlreadyInitializedError = PR_TRUE;
95
0
    }
96
0
    if (dontFinalizeModules) {
97
0
        finalizeModules = PR_FALSE;
98
0
    } else {
99
0
        finalizeModules = PR_TRUE;
100
0
    }
101
0
    return SECSuccess;
102
0
}
103
104
PRBool
105
pk11_getFinalizeModulesOption(void)
106
0
{
107
0
    return finalizeModules;
108
0
}
109
110
/*
111
 * Allow specification loading the same module more than once at init time.
112
 * This enables 2 things.
113
 *
114
 *    1) we can load additional databases by manipulating secmod.db/pkcs11.txt.
115
 *    2) we can handle the case where some library has already initialized NSS
116
 *    before the main application.
117
 *
118
 * oldModule is the module we have already initialized.
119
 * char *modulespec is the full module spec for the library we want to
120
 * initialize.
121
 */
122
static SECStatus
123
secmod_handleReload(SECMODModule *oldModule, SECMODModule *newModule)
124
0
{
125
0
    PK11SlotInfo *slot;
126
0
    char *modulespec;
127
0
    char *newModuleSpec;
128
0
    char **children;
129
0
    CK_SLOT_ID *ids;
130
0
    SECMODConfigList *conflist = NULL;
131
0
    SECStatus rv = SECFailure;
132
0
    int count = 0;
133
134
    /* first look for tokens= key words from the module spec */
135
0
    modulespec = newModule->libraryParams;
136
0
    newModuleSpec = secmod_ParseModuleSpecForTokens(PR_TRUE,
137
0
                                                    newModule->isFIPS, modulespec, &children, &ids);
138
0
    if (!newModuleSpec) {
139
0
        return SECFailure;
140
0
    }
141
142
    /*
143
     * We are now trying to open a new slot on an already loaded module.
144
     * If that slot represents a cert/key database, we don't want to open
145
     * multiple copies of that same database. Unfortunately we understand
146
     * the softoken flags well enough to be able to do this, so we can only get
147
     * the list of already loaded databases if we are trying to open another
148
     * internal module.
149
     */
150
0
    if (oldModule->internal) {
151
0
        conflist = secmod_GetConfigList(oldModule->isFIPS,
152
0
                                        oldModule->libraryParams, &count);
153
0
    }
154
155
    /* don't open multiple of the same db */
156
0
    if (conflist && secmod_MatchConfigList(newModuleSpec, conflist, count)) {
157
0
        rv = SECSuccess;
158
0
        goto loser;
159
0
    }
160
0
    slot = SECMOD_OpenNewSlot(oldModule, newModuleSpec);
161
0
    if (slot) {
162
0
        int newID;
163
0
        char **thisChild;
164
0
        CK_SLOT_ID *thisID;
165
0
        char *oldModuleSpec;
166
167
0
        if (secmod_IsInternalKeySlot(newModule)) {
168
0
            pk11_SetInternalKeySlotIfFirst(slot);
169
0
        }
170
0
        newID = slot->slotID;
171
0
        PK11_FreeSlot(slot);
172
0
        for (thisChild = children, thisID = ids; thisChild && *thisChild;
173
0
             thisChild++, thisID++) {
174
0
            if (conflist &&
175
0
                secmod_MatchConfigList(*thisChild, conflist, count)) {
176
0
                *thisID = (CK_SLOT_ID)-1;
177
0
                continue;
178
0
            }
179
0
            slot = SECMOD_OpenNewSlot(oldModule, *thisChild);
180
0
            if (slot) {
181
0
                *thisID = slot->slotID;
182
0
                PK11_FreeSlot(slot);
183
0
            } else {
184
0
                *thisID = (CK_SLOT_ID)-1;
185
0
            }
186
0
        }
187
188
        /* update the old module initialization string in case we need to
189
         * shutdown and reinit the whole mess (this is rare, but can happen
190
         * when trying to stop smart card insertion/removal threads)... */
191
0
        oldModuleSpec = secmod_MkAppendTokensList(oldModule->arena,
192
0
                                                  oldModule->libraryParams, newModuleSpec, newID,
193
0
                                                  children, ids);
194
0
        if (oldModuleSpec) {
195
0
            oldModule->libraryParams = oldModuleSpec;
196
0
        }
197
198
0
        rv = SECSuccess;
199
0
    }
200
201
0
loser:
202
0
    secmod_FreeChildren(children, ids);
203
0
    PORT_Free(newModuleSpec);
204
0
    if (conflist) {
205
0
        secmod_FreeConfigList(conflist, count);
206
0
    }
207
0
    return rv;
208
0
}
209
210
/*
211
 * collect the steps we need to initialize a module in a single function
212
 */
213
SECStatus
214
secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload,
215
                  PRBool *alreadyLoaded)
216
2
{
217
2
    CK_C_INITIALIZE_ARGS moduleArgs;
218
2
    CK_VOID_PTR pInitArgs;
219
2
    CK_RV crv;
220
221
2
    if (reload) {
222
2
        *reload = NULL;
223
2
    }
224
225
2
    if (!mod || !alreadyLoaded) {
226
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
227
0
        return SECFailure;
228
0
    }
229
230
2
    if (mod->libraryParams == NULL) {
231
0
        if (mod->isThreadSafe) {
232
0
            pInitArgs = (void *)&secmodLockFunctions;
233
0
        } else {
234
0
            pInitArgs = NULL;
235
0
        }
236
2
    } else {
237
2
        if (mod->isThreadSafe) {
238
2
            moduleArgs = secmodLockFunctions;
239
2
        } else {
240
0
            moduleArgs = secmodNoLockArgs;
241
0
        }
242
2
        moduleArgs.LibraryParameters = (void *)mod->libraryParams;
243
2
        pInitArgs = &moduleArgs;
244
2
    }
245
2
    crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
246
2
    if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) {
247
0
        SECMODModule *oldModule = NULL;
248
249
        /* Library has already been loaded once, if caller expects it, and it
250
         * has additional configuration, try reloading it as well. */
251
0
        if (reload != NULL && mod->libraryParams) {
252
0
            oldModule = secmod_FindModuleByFuncPtr(mod->functionList);
253
0
        }
254
        /* Library has been loaded by NSS. It means it may be capable of
255
         * reloading */
256
0
        if (oldModule) {
257
0
            SECStatus rv;
258
0
            rv = secmod_handleReload(oldModule, mod);
259
0
            if (rv == SECSuccess) {
260
                /* This module should go away soon, since we've
261
                 * simply expanded the slots on the old module.
262
                 * When it goes away, it should not Finalize since
263
                 * that will close our old module as well. Setting
264
                 * the function list to NULL will prevent that close */
265
0
                mod->functionList = NULL;
266
0
                *reload = oldModule;
267
0
                return SECSuccess;
268
0
            }
269
0
            SECMOD_DestroyModule(oldModule);
270
0
        }
271
        /* reload not possible, fall back to old semantics */
272
0
        if (!enforceAlreadyInitializedError) {
273
0
            *alreadyLoaded = PR_TRUE;
274
0
            return SECSuccess;
275
0
        }
276
0
    }
277
2
    if (crv != CKR_OK) {
278
0
        if (!mod->isThreadSafe ||
279
0
            crv == CKR_NSS_CERTDB_FAILED ||
280
0
            crv == CKR_NSS_KEYDB_FAILED) {
281
0
            PORT_SetError(PK11_MapError(crv));
282
0
            return SECFailure;
283
0
        }
284
        /* If we had attempted to init a single threaded module "with"
285
         * parameters and it failed, should we retry "without" parameters?
286
         * (currently we don't retry in this scenario) */
287
288
0
        if (!loadSingleThreadedModules) {
289
0
            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
290
0
            return SECFailure;
291
0
        }
292
        /* If we arrive here, the module failed a ThreadSafe init. */
293
0
        mod->isThreadSafe = PR_FALSE;
294
0
        if (!mod->libraryParams) {
295
0
            pInitArgs = NULL;
296
0
        } else {
297
0
            moduleArgs = secmodNoLockArgs;
298
0
            moduleArgs.LibraryParameters = (void *)mod->libraryParams;
299
0
            pInitArgs = &moduleArgs;
300
0
        }
301
0
        crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
302
0
        if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
303
0
            (!enforceAlreadyInitializedError)) {
304
0
            *alreadyLoaded = PR_TRUE;
305
0
            return SECSuccess;
306
0
        }
307
0
        if (crv != CKR_OK) {
308
0
            PORT_SetError(PK11_MapError(crv));
309
0
            return SECFailure;
310
0
        }
311
0
    }
312
2
    return SECSuccess;
313
2
}
314
315
/*
316
 * set the hasRootCerts flags in the module so it can be stored back
317
 * into the database.
318
 */
319
void
320
SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod)
321
4
{
322
4
    PK11PreSlotInfo *psi = NULL;
323
4
    int i;
324
325
4
    if (slot->hasRootCerts) {
326
0
        for (i = 0; i < mod->slotInfoCount; i++) {
327
0
            if (slot->slotID == mod->slotInfo[i].slotID) {
328
0
                psi = &mod->slotInfo[i];
329
0
                break;
330
0
            }
331
0
        }
332
0
        if (psi == NULL) {
333
            /* allocate more slots */
334
0
            PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
335
0
                PORT_ArenaAlloc(mod->arena,
336
0
                                (mod->slotInfoCount + 1) * sizeof(PK11PreSlotInfo));
337
            /* copy the old ones */
338
0
            if (mod->slotInfoCount > 0) {
339
0
                PORT_Memcpy(psi_list, mod->slotInfo,
340
0
                            (mod->slotInfoCount) * sizeof(PK11PreSlotInfo));
341
0
            }
342
            /* assign psi to the last new slot */
343
0
            psi = &psi_list[mod->slotInfoCount];
344
0
            psi->slotID = slot->slotID;
345
0
            psi->askpw = 0;
346
0
            psi->timeout = 0;
347
0
            psi->defaultFlags = 0;
348
349
            /* increment module count & store new list */
350
0
            mod->slotInfo = psi_list;
351
0
            mod->slotInfoCount++;
352
0
        }
353
0
        psi->hasRootCerts = 1;
354
0
    }
355
4
}
356
357
#ifndef NSS_STATIC_SOFTOKEN
358
static const char *my_shlib_name =
359
    SHLIB_PREFIX "nss" NSS_SHLIB_VERSION "." SHLIB_SUFFIX;
360
static const char *softoken_shlib_name =
361
    SHLIB_PREFIX "softokn" SOFTOKEN_SHLIB_VERSION "." SHLIB_SUFFIX;
362
static const PRCallOnceType pristineCallOnce;
363
static PRCallOnceType loadSoftokenOnce;
364
static PRLibrary *softokenLib;
365
static PRInt32 softokenLoadCount;
366
367
/* This function must be run only once. */
368
/*  determine if hybrid platform, then actually load the DSO. */
369
static PRStatus
370
softoken_LoadDSO(void)
371
{
372
    PRLibrary *handle;
373
374
    handle = PORT_LoadLibraryFromOrigin(my_shlib_name,
375
                                        (PRFuncPtr)&softoken_LoadDSO,
376
                                        softoken_shlib_name);
377
    if (handle) {
378
        softokenLib = handle;
379
        return PR_SUCCESS;
380
    }
381
    return PR_FAILURE;
382
}
383
#else
384
CK_RV NSC_GetInterface(CK_UTF8CHAR_PTR pInterfaceName,
385
                       CK_VERSION_PTR pVersion,
386
                       CK_INTERFACE_PTR_PTR *ppInterface, CK_FLAGS flags);
387
char **NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args);
388
#endif
389
390
/*
391
 * load a new module into our address space and initialize it.
392
 */
393
SECStatus
394
secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule)
395
4
{
396
4
    PRLibrary *library = NULL;
397
4
    CK_C_GetInterface ientry = NULL;
398
4
    CK_C_GetFunctionList fentry = NULL;
399
4
    CK_INFO info;
400
4
    CK_ULONG slotCount = 0;
401
4
    SECStatus rv;
402
4
    PRBool alreadyLoaded = PR_FALSE;
403
4
    char *disableUnload = NULL;
404
#ifndef NSS_STATIC_SOFTOKEN
405
    const char *nss_interface;
406
    const char *nss_function;
407
#endif
408
4
    CK_INTERFACE_PTR interface;
409
410
4
    if (mod->loaded)
411
0
        return SECSuccess;
412
413
4
    mod->fipsIndicator = NULL;
414
415
    /* internal modules get loaded from their internal list */
416
4
    if (mod->internal && (mod->dllName == NULL)) {
417
4
#ifdef NSS_STATIC_SOFTOKEN
418
4
        ientry = (CK_C_GetInterface)NSC_GetInterface;
419
#else
420
        /*
421
         * Loads softoken as a dynamic library,
422
         * even though the rest of NSS assumes this as the "internal" module.
423
         */
424
        if (!softokenLib &&
425
            PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
426
            return SECFailure;
427
428
        PR_ATOMIC_INCREMENT(&softokenLoadCount);
429
430
        if (mod->isFIPS) {
431
            nss_interface = "FC_GetInterface";
432
            nss_function = "FC_GetFunctionList";
433
        } else {
434
            nss_interface = "NSC_GetInterface";
435
            nss_function = "NSC_GetFunctionList";
436
        }
437
438
        ientry = (CK_C_GetInterface)
439
            PR_FindSymbol(softokenLib, nss_interface);
440
        if (!ientry) {
441
            fentry = (CK_C_GetFunctionList)
442
                PR_FindSymbol(softokenLib, nss_function);
443
            if (!fentry) {
444
                return SECFailure;
445
            }
446
        }
447
#endif
448
449
4
        if (mod->isModuleDB) {
450
2
            mod->moduleDBFunc = (CK_C_GetFunctionList)
451
2
#ifdef NSS_STATIC_SOFTOKEN
452
2
                NSC_ModuleDBFunc;
453
#else
454
                PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
455
#endif
456
2
        }
457
458
4
        if (mod->moduleDBOnly) {
459
2
            mod->loaded = PR_TRUE;
460
2
            return SECSuccess;
461
2
        }
462
4
    } else {
463
        /* Not internal, load the DLL and look up C_GetFunctionList */
464
0
        if (mod->dllName == NULL) {
465
0
            return SECFailure;
466
0
        }
467
468
/* load the library. If this succeeds, then we have to remember to
469
 * unload the library if anything goes wrong from here on out...
470
 */
471
#if defined(_WIN32)
472
        if (nssUTF8_Length(mod->dllName, NULL)) {
473
            wchar_t *dllNameWide = _NSSUTIL_UTF8ToWide(mod->dllName);
474
            if (dllNameWide) {
475
                PRLibSpec libSpec;
476
                libSpec.type = PR_LibSpec_PathnameU;
477
                libSpec.value.pathname_u = dllNameWide;
478
                library = PR_LoadLibraryWithFlags(libSpec, 0);
479
                PORT_Free(dllNameWide);
480
            }
481
        }
482
        if (library == NULL) {
483
            // fallback to system code page
484
            library = PR_LoadLibrary(mod->dllName);
485
        }
486
#else
487
0
        library = PR_LoadLibrary(mod->dllName);
488
0
#endif // defined(_WIN32)
489
0
        mod->library = (void *)library;
490
491
0
        if (library == NULL) {
492
0
            return SECFailure;
493
0
        }
494
495
        /*
496
         * now we need to get the entry point to find the function pointers
497
         */
498
0
        if (!mod->moduleDBOnly) {
499
0
            ientry = (CK_C_GetInterface)
500
0
                PR_FindSymbol(library, "C_GetInterface");
501
0
            if (!ientry) {
502
0
                fentry = (CK_C_GetFunctionList)
503
0
                    PR_FindSymbol(library, "C_GetFunctionList");
504
0
            }
505
0
        }
506
0
        if (mod->isModuleDB) {
507
0
            mod->moduleDBFunc = (void *)
508
0
                PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
509
0
        }
510
0
        if (mod->moduleDBFunc == NULL)
511
0
            mod->isModuleDB = PR_FALSE;
512
0
        if ((ientry == NULL) && (fentry == NULL)) {
513
0
            if (mod->isModuleDB) {
514
0
                mod->loaded = PR_TRUE;
515
0
                mod->moduleDBOnly = PR_TRUE;
516
0
                return SECSuccess;
517
0
            }
518
0
            PR_UnloadLibrary(library);
519
0
            return SECFailure;
520
0
        }
521
0
    }
522
523
    /*
524
     * We need to get the function list
525
     */
526
2
    if (ientry) {
527
        /* we first try to get a FORK_SAFE interface */
528
2
        if ((*ientry)((CK_UTF8CHAR_PTR) "PKCS 11", NULL, &interface,
529
2
                      CKF_INTERFACE_FORK_SAFE) != CKR_OK) {
530
            /* one is not appearantly available, get a non-fork safe version */
531
0
            if ((*ientry)((CK_UTF8CHAR_PTR) "PKCS 11", NULL, &interface, 0) != CKR_OK) {
532
0
                goto fail;
533
0
            }
534
0
        }
535
2
        mod->functionList = interface->pFunctionList;
536
2
        mod->flags = interface->flags;
537
        /* if we have a fips indicator, grab it */
538
2
        if ((*ientry)((CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", NULL,
539
2
                      &interface, 0) == CKR_OK) {
540
2
            mod->fipsIndicator = ((CK_NSS_FIPS_FUNCTIONS *)(interface->pFunctionList))->NSC_NSSGetFIPSStatus;
541
2
        }
542
2
    } else {
543
0
        if ((*fentry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
544
0
            goto fail;
545
0
        mod->flags = 0;
546
0
    }
547
548
2
#ifdef DEBUG_MODULE
549
2
    modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE");
550
2
    if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
551
0
        mod->functionList = (void *)nss_InsertDeviceLog(
552
0
            (CK_FUNCTION_LIST_3_0_PTR)mod->functionList);
553
0
    }
554
2
#endif
555
556
    /* This test operation makes sure our locking system is
557
     * consistent even if we are using non-thread safe tokens by
558
     * simulating unsafe tokens with safe ones. */
559
2
    mod->isThreadSafe = !PR_GetEnvSecure("NSS_FORCE_TOKEN_LOCK");
560
561
    /* Now we initialize the module */
562
2
    rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded);
563
2
    if (rv != SECSuccess) {
564
0
        goto fail;
565
0
    }
566
567
    /* module has been reloaded, this module itself is done,
568
     * return to the caller */
569
2
    if (mod->functionList == NULL) {
570
0
        mod->loaded = PR_TRUE; /* technically the module is loaded.. */
571
0
        return SECSuccess;
572
0
    }
573
574
    /* check the version number */
575
2
    if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK)
576
0
        goto fail2;
577
2
    if (info.cryptokiVersion.major < 2)
578
0
        goto fail2;
579
    /* all 2.0 are a priori *not* thread safe */
580
2
    if ((info.cryptokiVersion.major == 2) && (info.cryptokiVersion.minor < 1)) {
581
0
        if (!loadSingleThreadedModules) {
582
0
            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
583
0
            goto fail2;
584
0
        } else {
585
0
            mod->isThreadSafe = PR_FALSE;
586
0
        }
587
0
    }
588
2
    mod->cryptokiVersion = info.cryptokiVersion;
589
590
    /* If we don't have a common name, get it from the PKCS 11 module */
591
2
    if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
592
0
        mod->commonName = PK11_MakeString(mod->arena, NULL,
593
0
                                          (char *)info.libraryDescription, sizeof(info.libraryDescription));
594
0
        if (mod->commonName == NULL)
595
0
            goto fail2;
596
0
    }
597
598
    /* initialize the Slots */
599
2
    if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
600
2
        CK_SLOT_ID *slotIDs;
601
2
        int i;
602
2
        CK_RV crv;
603
604
2
        mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
605
2
                                                      sizeof(PK11SlotInfo *) * slotCount);
606
2
        if (mod->slots == NULL)
607
0
            goto fail2;
608
609
2
        slotIDs = (CK_SLOT_ID *)PORT_Alloc(sizeof(CK_SLOT_ID) * slotCount);
610
2
        if (slotIDs == NULL) {
611
0
            goto fail2;
612
0
        }
613
2
        crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
614
2
        if (crv != CKR_OK) {
615
0
            PORT_Free(slotIDs);
616
0
            goto fail2;
617
0
        }
618
619
        /* Initialize each slot */
620
6
        for (i = 0; i < (int)slotCount; i++) {
621
4
            mod->slots[i] = PK11_NewSlotInfo(mod);
622
4
            PK11_InitSlot(mod, slotIDs[i], mod->slots[i]);
623
            /* look down the slot info table */
624
4
            PK11_LoadSlotList(mod->slots[i], mod->slotInfo, mod->slotInfoCount);
625
4
            SECMOD_SetRootCerts(mod->slots[i], mod);
626
            /* explicitly mark the internal slot as such if IsInternalKeySlot()
627
             * is set */
628
4
            if (secmod_IsInternalKeySlot(mod) && (i == (mod->isFIPS ? 0 : 1))) {
629
2
                pk11_SetInternalKeySlotIfFirst(mod->slots[i]);
630
2
            }
631
4
        }
632
2
        mod->slotCount = slotCount;
633
2
        mod->slotInfoCount = 0;
634
2
        PORT_Free(slotIDs);
635
2
    }
636
637
2
    mod->loaded = PR_TRUE;
638
2
    mod->moduleID = nextModuleID++;
639
2
    return SECSuccess;
640
0
fail2:
641
0
    if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
642
0
        PK11_GETTAB(mod)->C_Finalize(NULL);
643
0
    }
644
0
fail:
645
0
    mod->functionList = NULL;
646
0
    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
647
0
    if (library && !disableUnload) {
648
0
        PR_UnloadLibrary(library);
649
0
    }
650
0
    return SECFailure;
651
0
}
652
653
SECStatus
654
SECMOD_UnloadModule(SECMODModule *mod)
655
0
{
656
0
    PRLibrary *library;
657
0
    char *disableUnload = NULL;
658
659
0
    if (!mod->loaded) {
660
0
        return SECFailure;
661
0
    }
662
0
    if (finalizeModules) {
663
0
        if (mod->functionList && !mod->moduleDBOnly) {
664
0
            PK11_GETTAB(mod)->C_Finalize(NULL);
665
0
        }
666
0
    }
667
0
    mod->moduleID = 0;
668
0
    mod->loaded = PR_FALSE;
669
670
    /* do we want the semantics to allow unloading the internal library?
671
     * if not, we should change this to SECFailure and move it above the
672
     * mod->loaded = PR_FALSE; */
673
0
    if (mod->internal && (mod->dllName == NULL)) {
674
#ifndef NSS_STATIC_SOFTOKEN
675
        if (0 == PR_ATOMIC_DECREMENT(&softokenLoadCount)) {
676
            if (softokenLib) {
677
                disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
678
                if (!disableUnload) {
679
#ifdef DEBUG
680
                    PRStatus status = PR_UnloadLibrary(softokenLib);
681
                    PORT_Assert(PR_SUCCESS == status);
682
#else
683
                    PR_UnloadLibrary(softokenLib);
684
#endif
685
                }
686
                softokenLib = NULL;
687
            }
688
            loadSoftokenOnce = pristineCallOnce;
689
        }
690
#endif
691
0
        return SECSuccess;
692
0
    }
693
694
0
    library = (PRLibrary *)mod->library;
695
    /* paranoia */
696
0
    if (library == NULL) {
697
0
        return SECFailure;
698
0
    }
699
700
0
    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
701
0
    if (!disableUnload) {
702
0
        PR_UnloadLibrary(library);
703
0
    }
704
0
    return SECSuccess;
705
0
}
706
707
void
708
nss_DumpModuleLog(void)
709
0
{
710
0
#ifdef DEBUG_MODULE
711
0
    if (modToDBG) {
712
0
        print_final_statistics();
713
0
    }
714
0
#endif
715
0
}