Coverage Report

Created: 2026-08-18 06:34

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