Coverage Report

Created: 2025-04-22 06:15

/src/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
1
{
217
1
    CK_C_INITIALIZE_ARGS moduleArgs;
218
1
    CK_VOID_PTR pInitArgs;
219
1
    CK_RV crv;
220
221
1
    if (reload) {
222
1
        *reload = NULL;
223
1
    }
224
225
1
    if (!mod || !alreadyLoaded) {
226
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
227
0
        return SECFailure;
228
0
    }
229
230
1
    if (mod->libraryParams == NULL) {
231
0
        if (mod->isThreadSafe) {
232
0
            pInitArgs = (void *)&secmodLockFunctions;
233
0
        } else {
234
0
            pInitArgs = NULL;
235
0
        }
236
1
    } else {
237
1
        if (mod->isThreadSafe) {
238
1
            moduleArgs = secmodLockFunctions;
239
1
        } else {
240
0
            moduleArgs = secmodNoLockArgs;
241
0
        }
242
1
        moduleArgs.LibraryParameters = (void *)mod->libraryParams;
243
1
        pInitArgs = &moduleArgs;
244
1
    }
245
1
    crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
246
1
    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
1
    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
1
    return SECSuccess;
313
1
}
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
2
{
322
2
    PK11PreSlotInfo *psi = NULL;
323
2
    int i;
324
325
2
    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
2
}
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
SECStatus
391
secmod_DetermineModuleFunctionList(SECMODModule *mod)
392
2
{
393
2
    PRLibrary *library = NULL;
394
2
    CK_C_GetInterface ientry = NULL;
395
2
    CK_C_GetFunctionList fentry = NULL;
396
2
    char *disableUnload = NULL;
397
#ifndef NSS_STATIC_SOFTOKEN
398
    const char *nss_interface;
399
    const char *nss_function;
400
#endif
401
2
    CK_INTERFACE_PTR interface;
402
403
    /* internal modules get loaded from their internal list */
404
2
    if (mod->internal && (mod->dllName == NULL)) {
405
2
#ifdef NSS_STATIC_SOFTOKEN
406
2
        ientry = (CK_C_GetInterface)NSC_GetInterface;
407
#else
408
        /*
409
         * Loads softoken as a dynamic library,
410
         * even though the rest of NSS assumes this as the "internal" module.
411
         */
412
        if (!softokenLib &&
413
            PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
414
            return SECFailure;
415
416
        PR_ATOMIC_INCREMENT(&softokenLoadCount);
417
418
        if (mod->isFIPS) {
419
            nss_interface = "FC_GetInterface";
420
            nss_function = "FC_GetFunctionList";
421
        } else {
422
            nss_interface = "NSC_GetInterface";
423
            nss_function = "NSC_GetFunctionList";
424
        }
425
426
        ientry = (CK_C_GetInterface)
427
            PR_FindSymbol(softokenLib, nss_interface);
428
        if (!ientry) {
429
            fentry = (CK_C_GetFunctionList)
430
                PR_FindSymbol(softokenLib, nss_function);
431
            if (!fentry) {
432
                return SECFailure;
433
            }
434
        }
435
#endif
436
437
2
        if (mod->isModuleDB) {
438
1
            mod->moduleDBFunc = (CK_C_GetFunctionList)
439
1
#ifdef NSS_STATIC_SOFTOKEN
440
1
                NSC_ModuleDBFunc;
441
#else
442
                PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
443
#endif
444
1
        }
445
446
2
        if (mod->moduleDBOnly) {
447
1
            mod->loaded = PR_TRUE;
448
1
            return SECSuccess;
449
1
        }
450
2
    } else {
451
        /* Not internal, load the DLL and look up C_GetFunctionList */
452
0
        if (mod->dllName == NULL) {
453
0
            return SECFailure;
454
0
        }
455
456
/* load the library. If this succeeds, then we have to remember to
457
 * unload the library if anything goes wrong from here on out...
458
 */
459
#if defined(_WIN32)
460
        if (nssUTF8_Length(mod->dllName, NULL)) {
461
            wchar_t *dllNameWide = _NSSUTIL_UTF8ToWide(mod->dllName);
462
            if (dllNameWide) {
463
                PRLibSpec libSpec;
464
                libSpec.type = PR_LibSpec_PathnameU;
465
                libSpec.value.pathname_u = dllNameWide;
466
                library = PR_LoadLibraryWithFlags(libSpec, 0);
467
                PORT_Free(dllNameWide);
468
            }
469
        }
470
        if (library == NULL) {
471
            // fallback to system code page
472
            library = PR_LoadLibrary(mod->dllName);
473
        }
474
#else
475
0
        library = PR_LoadLibrary(mod->dllName);
476
0
#endif // defined(_WIN32)
477
0
        mod->library = (void *)library;
478
479
0
        if (library == NULL) {
480
0
            return SECFailure;
481
0
        }
482
483
        /*
484
         * now we need to get the entry point to find the function pointers
485
         */
486
0
        if (!mod->moduleDBOnly) {
487
0
            ientry = (CK_C_GetInterface)
488
0
                PR_FindSymbol(library, "C_GetInterface");
489
0
            if (!ientry) {
490
0
                fentry = (CK_C_GetFunctionList)
491
0
                    PR_FindSymbol(library, "C_GetFunctionList");
492
0
            }
493
0
        }
494
0
        if (mod->isModuleDB) {
495
0
            mod->moduleDBFunc = (void *)
496
0
                PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
497
0
        }
498
0
        if (mod->moduleDBFunc == NULL)
499
0
            mod->isModuleDB = PR_FALSE;
500
0
        if ((ientry == NULL) && (fentry == NULL)) {
501
0
            if (mod->isModuleDB) {
502
0
                mod->loaded = PR_TRUE;
503
0
                mod->moduleDBOnly = PR_TRUE;
504
0
                return SECSuccess;
505
0
            }
506
0
            PR_UnloadLibrary(library);
507
0
            return SECFailure;
508
0
        }
509
0
    }
510
511
    /*
512
     * We need to get the function list
513
     */
514
1
    if (ientry) {
515
        /* we first try to get a FORK_SAFE interface */
516
1
        if ((*ientry)((CK_UTF8CHAR_PTR) "PKCS 11", NULL, &interface,
517
1
                      CKF_INTERFACE_FORK_SAFE) != CKR_OK) {
518
            /* one is not appearantly available, get a non-fork safe version */
519
0
            if ((*ientry)((CK_UTF8CHAR_PTR) "PKCS 11", NULL, &interface, 0) != CKR_OK) {
520
0
                goto fail;
521
0
            }
522
0
        }
523
1
        mod->functionList = interface->pFunctionList;
524
1
        mod->flags = interface->flags;
525
        /* if we have a fips indicator, grab it */
526
1
        if ((*ientry)((CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", NULL,
527
1
                      &interface, 0) == CKR_OK) {
528
1
            mod->fipsIndicator = ((CK_NSS_FIPS_FUNCTIONS *)(interface->pFunctionList))->NSC_NSSGetFIPSStatus;
529
1
        }
530
1
    } else {
531
0
        if ((*fentry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
532
0
            goto fail;
533
0
        mod->flags = 0;
534
0
    }
535
536
1
#ifdef DEBUG_MODULE
537
1
    modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE");
538
1
    if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
539
0
        mod->functionList = (void *)nss_InsertDeviceLog(
540
0
            (CK_FUNCTION_LIST_3_0_PTR)mod->functionList);
541
0
    }
542
1
#endif
543
544
1
    return SECSuccess;
545
546
0
fail:
547
0
    mod->functionList = NULL;
548
0
    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
549
0
    if (library && !disableUnload) {
550
0
        PR_UnloadLibrary(library);
551
0
    }
552
0
    return SECFailure;
553
1
}
554
555
SECStatus
556
secmod_InitializeModuleAndGetSlotInfo(SECMODModule *mod, SECMODModule **oldModule)
557
1
{
558
1
    CK_INFO info;
559
1
    CK_ULONG slotCount = 0;
560
1
    SECStatus rv;
561
1
    PRBool alreadyLoaded = PR_FALSE;
562
563
    /* This test operation makes sure our locking system is
564
     * consistent even if we are using non-thread safe tokens by
565
     * simulating unsafe tokens with safe ones. */
566
1
    mod->isThreadSafe = !PR_GetEnvSecure("NSS_FORCE_TOKEN_LOCK");
567
568
    /* Now we initialize the module */
569
1
    rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded);
570
1
    if (rv != SECSuccess) {
571
0
        goto fail;
572
0
    }
573
574
    /* module has been reloaded, this module itself is done,
575
     * return to the caller */
576
1
    if (mod->functionList == NULL) {
577
0
        mod->loaded = PR_TRUE; /* technically the module is loaded.. */
578
0
        return SECSuccess;
579
0
    }
580
581
    /* check the version number */
582
1
    if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK)
583
0
        goto fail2;
584
1
    if (info.cryptokiVersion.major < 2)
585
0
        goto fail2;
586
    /* all 2.0 are a priori *not* thread safe */
587
1
    if ((info.cryptokiVersion.major == 2) && (info.cryptokiVersion.minor < 1)) {
588
0
        if (!loadSingleThreadedModules) {
589
0
            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
590
0
            goto fail2;
591
0
        } else {
592
0
            mod->isThreadSafe = PR_FALSE;
593
0
        }
594
0
    }
595
1
    mod->cryptokiVersion = info.cryptokiVersion;
596
597
    /* If we don't have a common name, get it from the PKCS 11 module */
598
1
    if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
599
0
        mod->commonName = PK11_MakeString(mod->arena, NULL,
600
0
                                          (char *)info.libraryDescription, sizeof(info.libraryDescription));
601
0
        if (mod->commonName == NULL)
602
0
            goto fail2;
603
0
    }
604
605
    /* initialize the Slots */
606
1
    if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
607
1
        CK_SLOT_ID *slotIDs;
608
1
        int i;
609
1
        CK_RV crv;
610
611
1
        mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
612
1
                                                      sizeof(PK11SlotInfo *) * slotCount);
613
1
        if (mod->slots == NULL)
614
0
            goto fail2;
615
616
1
        slotIDs = (CK_SLOT_ID *)PORT_Alloc(sizeof(CK_SLOT_ID) * slotCount);
617
1
        if (slotIDs == NULL) {
618
0
            goto fail2;
619
0
        }
620
1
        crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
621
1
        if (crv != CKR_OK) {
622
0
            PORT_Free(slotIDs);
623
0
            goto fail2;
624
0
        }
625
626
        /* Initialize each slot */
627
3
        for (i = 0; i < (int)slotCount; i++) {
628
2
            mod->slots[i] = PK11_NewSlotInfo(mod);
629
2
            PK11_InitSlot(mod, slotIDs[i], mod->slots[i]);
630
            /* look down the slot info table */
631
2
            PK11_LoadSlotList(mod->slots[i], mod->slotInfo, mod->slotInfoCount);
632
2
            SECMOD_SetRootCerts(mod->slots[i], mod);
633
            /* explicitly mark the internal slot as such if IsInternalKeySlot()
634
             * is set */
635
2
            if (secmod_IsInternalKeySlot(mod) && (i == (mod->isFIPS ? 0 : 1))) {
636
1
                pk11_SetInternalKeySlotIfFirst(mod->slots[i]);
637
1
            }
638
2
        }
639
1
        mod->slotCount = slotCount;
640
1
        mod->slotInfoCount = 0;
641
1
        PORT_Free(slotIDs);
642
1
    }
643
644
1
    mod->loaded = PR_TRUE;
645
1
    mod->moduleID = nextModuleID++;
646
1
    return SECSuccess;
647
0
fail2:
648
0
    if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
649
0
        PK11_GETTAB(mod)->C_Finalize(NULL);
650
0
    }
651
0
fail:
652
0
    mod->functionList = NULL;
653
0
    return SECFailure;
654
0
}
655
656
/*
657
 * load a new module into our address space and initialize it.
658
 */
659
SECStatus
660
secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule)
661
2
{
662
2
    SECStatus rv = SECFailure;
663
2
    if (mod->loaded) {
664
0
        return SECSuccess;
665
0
    }
666
667
2
    mod->fipsIndicator = NULL;
668
669
2
    rv = secmod_DetermineModuleFunctionList(mod);
670
2
    if (rv != SECSuccess) { // The error code is set up by secmod_DetermineModuleFunctionList.
671
0
        return rv;
672
0
    }
673
674
2
    if (mod->loaded == PR_TRUE) {
675
1
        return SECSuccess;
676
1
    }
677
678
1
    rv = secmod_InitializeModuleAndGetSlotInfo(mod, oldModule);
679
1
    if (rv != SECSuccess) { // The error code is set up by secmod_InitializeModuleAndGetSlotInfo
680
0
        return rv;
681
0
    }
682
683
1
    return SECSuccess;
684
1
}
685
686
/*
687
 * load a new module using provided fentry function
688
 */
689
SECStatus
690
secmod_LoadPKCS11ModuleFromFunction(SECMODModule *mod, SECMODModule **oldModule,
691
                                    CK_C_GetFunctionList fentry)
692
0
{
693
0
    SECStatus rv = SECFailure;
694
0
    CK_RV crv;
695
0
    if (mod->loaded) {
696
0
        return SECSuccess;
697
0
    }
698
699
0
    mod->fipsIndicator = NULL;
700
701
0
    if (!fentry) {
702
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
703
0
        return SECFailure;
704
0
    }
705
706
0
    crv = fentry((CK_FUNCTION_LIST_PTR *)&mod->functionList);
707
0
    if (crv != CKR_OK) {
708
0
        mod->functionList = NULL;
709
0
        PORT_SetError(PK11_MapError(crv));
710
0
        return SECFailure;
711
0
    }
712
713
0
    if (mod->functionList == NULL) {
714
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
715
0
        return SECFailure;
716
0
    }
717
718
0
    mod->flags = 0;
719
0
    rv = secmod_InitializeModuleAndGetSlotInfo(mod, oldModule);
720
0
    if (rv != SECSuccess) {
721
0
        return rv;
722
0
    }
723
724
0
    return SECSuccess;
725
0
}
726
727
SECStatus
728
SECMOD_UnloadModule(SECMODModule *mod)
729
2
{
730
2
    PRLibrary *library;
731
2
    char *disableUnload = NULL;
732
733
2
    if (!mod->loaded) {
734
0
        return SECFailure;
735
0
    }
736
2
    if (finalizeModules) {
737
2
        if (mod->functionList && !mod->moduleDBOnly) {
738
1
            PK11_GETTAB(mod)->C_Finalize(NULL);
739
1
        }
740
2
    }
741
2
    mod->moduleID = 0;
742
2
    mod->loaded = PR_FALSE;
743
744
    /* do we want the semantics to allow unloading the internal library?
745
     * if not, we should change this to SECFailure and move it above the
746
     * mod->loaded = PR_FALSE; */
747
2
    if (mod->internal && (mod->dllName == NULL)) {
748
#ifndef NSS_STATIC_SOFTOKEN
749
        if (0 == PR_ATOMIC_DECREMENT(&softokenLoadCount)) {
750
            if (softokenLib) {
751
                disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
752
                if (!disableUnload) {
753
#ifdef DEBUG
754
                    PRStatus status = PR_UnloadLibrary(softokenLib);
755
                    PORT_Assert(PR_SUCCESS == status);
756
#else
757
                    PR_UnloadLibrary(softokenLib);
758
#endif
759
                }
760
                softokenLib = NULL;
761
            }
762
            loadSoftokenOnce = pristineCallOnce;
763
        }
764
#endif
765
2
        return SECSuccess;
766
2
    }
767
768
0
    library = (PRLibrary *)mod->library;
769
    /* if no library, then we should not unload it */
770
0
    if (library == NULL) {
771
0
        return SECSuccess;
772
0
    }
773
774
0
    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
775
0
    if (!disableUnload) {
776
0
        PR_UnloadLibrary(library);
777
0
    }
778
0
    return SECSuccess;
779
0
}
780
781
void
782
nss_DumpModuleLog(void)
783
1
{
784
1
#ifdef DEBUG_MODULE
785
1
    if (modToDBG) {
786
0
        print_final_statistics();
787
0
    }
788
1
#endif
789
1
}