Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/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 "seccomon.h"
10
#include "pkcs11.h"
11
#include "secmod.h"
12
#include "prlink.h"
13
#include "pk11func.h"
14
#include "secmodi.h"
15
#include "secmodti.h"
16
#include "nssilock.h"
17
#include "secerr.h"
18
#include "prenv.h"
19
#include "utilparst.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)PZ_NewLock(nssILockOther);
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
    PZ_DestroyLock((PZLock *)mutext);
47
0
    return CKR_OK;
48
0
}
49
50
CK_RV PR_CALLBACK
51
secmodLockMutext(CK_VOID_PTR mutext)
52
0
{
53
0
    PZ_Lock((PZLock *)mutext);
54
0
    return CKR_OK;
55
0
}
56
57
CK_RV PR_CALLBACK
58
secmodUnlockMutext(CK_VOID_PTR mutext)
59
0
{
60
0
    PZ_Unlock((PZLock *)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
0
133
0
    /* 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
0
141
0
    /*
142
0
     * We are now trying to open a new slot on an already loaded module.
143
0
     * If that slot represents a cert/key database, we don't want to open
144
0
     * multiple copies of that same database. Unfortunately we understand
145
0
     * the softoken flags well enough to be able to do this, so we can only get
146
0
     * the list of already loaded databases if we are trying to open another
147
0
     * internal module.
148
0
     */
149
0
    if (oldModule->internal) {
150
0
        conflist = secmod_GetConfigList(oldModule->isFIPS,
151
0
                                        oldModule->libraryParams, &count);
152
0
    }
153
0
154
0
    /* 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
0
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
0
187
0
        /* update the old module initialization string in case we need to
188
0
         * shutdown and reinit the whole mess (this is rare, but can happen
189
0
         * 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
0
197
0
        rv = SECSuccess;
198
0
    }
199
0
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
0
{
216
0
    CK_C_INITIALIZE_ARGS moduleArgs;
217
0
    CK_VOID_PTR pInitArgs;
218
0
    CK_RV crv;
219
0
220
0
    if (reload) {
221
0
        *reload = NULL;
222
0
    }
223
0
224
0
    if (!mod || !alreadyLoaded) {
225
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
226
0
        return SECFailure;
227
0
    }
228
0
229
0
    if (mod->libraryParams == NULL) {
230
0
        if (mod->isThreadSafe) {
231
0
            pInitArgs = (void *)&secmodLockFunctions;
232
0
        } else {
233
0
            pInitArgs = NULL;
234
0
        }
235
0
    } else {
236
0
        if (mod->isThreadSafe) {
237
0
            moduleArgs = secmodLockFunctions;
238
0
        } else {
239
0
            moduleArgs = secmodNoLockArgs;
240
0
        }
241
0
        moduleArgs.LibraryParameters = (void *)mod->libraryParams;
242
0
        pInitArgs = &moduleArgs;
243
0
    }
244
0
    crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
245
0
    if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) {
246
0
        SECMODModule *oldModule = NULL;
247
0
248
0
        /* Library has already been loaded once, if caller expects it, and it
249
0
         * 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
0
        /* Library has been loaded by NSS. It means it may be capable of
254
0
         * reloading */
255
0
        if (oldModule) {
256
0
            SECStatus rv;
257
0
            rv = secmod_handleReload(oldModule, mod);
258
0
            if (rv == SECSuccess) {
259
0
                /* This module should go away soon, since we've
260
0
                 * simply expanded the slots on the old module.
261
0
                 * When it goes away, it should not Finalize since
262
0
                 * that will close our old module as well. Setting
263
0
                 * 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
0
        /* 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
0
    if (crv != CKR_OK) {
277
0
        if (!mod->isThreadSafe ||
278
0
            crv == CKR_NETSCAPE_CERTDB_FAILED ||
279
0
            crv == CKR_NETSCAPE_KEYDB_FAILED) {
280
0
            PORT_SetError(PK11_MapError(crv));
281
0
            return SECFailure;
282
0
        }
283
0
        /* If we had attempted to init a single threaded module "with"
284
0
         * parameters and it failed, should we retry "without" parameters?
285
0
         * (currently we don't retry in this scenario) */
286
0
287
0
        if (!loadSingleThreadedModules) {
288
0
            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
289
0
            return SECFailure;
290
0
        }
291
0
        /* 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
0
    return SECSuccess;
312
0
}
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
0
{
321
0
    PK11PreSlotInfo *psi = NULL;
322
0
    int i;
323
0
324
0
    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
0
            /* allocate more slots */
333
0
            PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
334
0
                PORT_ArenaAlloc(mod->arena,
335
0
                                (mod->slotInfoCount + 1) * sizeof(PK11PreSlotInfo));
336
0
            /* 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
0
            /* 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
0
348
0
            /* 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
0
}
355
356
#ifndef NSS_TEST_BUILD
357
static const char *my_shlib_name =
358
    SHLIB_PREFIX "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
0
{
371
0
    PRLibrary *handle;
372
0
373
0
    handle = PORT_LoadLibraryFromOrigin(my_shlib_name,
374
0
                                        (PRFuncPtr)&softoken_LoadDSO,
375
0
                                        softoken_shlib_name);
376
0
    if (handle) {
377
0
        softokenLib = handle;
378
0
        return PR_SUCCESS;
379
0
    }
380
0
    return PR_FAILURE;
381
0
}
382
#else
383
CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList);
384
char **NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args);
385
#endif
386
387
/*
388
 * load a new module into our address space and initialize it.
389
 */
390
SECStatus
391
secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule)
392
0
{
393
0
    PRLibrary *library = NULL;
394
0
    CK_C_GetFunctionList entry = NULL;
395
0
    CK_INFO info;
396
0
    CK_ULONG slotCount = 0;
397
0
    SECStatus rv;
398
0
    PRBool alreadyLoaded = PR_FALSE;
399
0
    char *disableUnload = NULL;
400
0
401
0
    if (mod->loaded)
402
0
        return SECSuccess;
403
0
404
0
    /* internal modules get loaded from their internal list */
405
0
    if (mod->internal && (mod->dllName == NULL)) {
406
#ifdef NSS_TEST_BUILD
407
        entry = (CK_C_GetFunctionList)NSC_GetFunctionList;
408
#else
409
        /*
410
0
         * Loads softoken as a dynamic library,
411
0
         * even though the rest of NSS assumes this as the "internal" module.
412
0
         */
413
0
        if (!softokenLib &&
414
0
            PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
415
0
            return SECFailure;
416
0
417
0
        PR_ATOMIC_INCREMENT(&softokenLoadCount);
418
0
419
0
        if (mod->isFIPS) {
420
0
            entry = (CK_C_GetFunctionList)
421
0
                PR_FindSymbol(softokenLib, "FC_GetFunctionList");
422
0
        } else {
423
0
            entry = (CK_C_GetFunctionList)
424
0
                PR_FindSymbol(softokenLib, "NSC_GetFunctionList");
425
0
        }
426
0
427
0
        if (!entry)
428
0
            return SECFailure;
429
0
#endif
430
0
431
0
        if (mod->isModuleDB) {
432
0
            mod->moduleDBFunc = (CK_C_GetFunctionList)
433
#ifdef NSS_TEST_BUILD
434
                NSC_ModuleDBFunc;
435
#else
436
                PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
437
0
#endif
438
0
        }
439
0
440
0
        if (mod->moduleDBOnly) {
441
0
            mod->loaded = PR_TRUE;
442
0
            return SECSuccess;
443
0
        }
444
0
    } else {
445
0
        /* Not internal, load the DLL and look up C_GetFunctionList */
446
0
        if (mod->dllName == NULL) {
447
0
            return SECFailure;
448
0
        }
449
0
450
0
        /* load the library. If this succeeds, then we have to remember to
451
0
         * unload the library if anything goes wrong from here on out...
452
0
         */
453
0
        library = PR_LoadLibrary(mod->dllName);
454
0
        mod->library = (void *)library;
455
0
456
0
        if (library == NULL) {
457
0
            return SECFailure;
458
0
        }
459
0
460
0
        /*
461
0
         * now we need to get the entry point to find the function pointers
462
0
         */
463
0
        if (!mod->moduleDBOnly) {
464
0
            entry = (CK_C_GetFunctionList)
465
0
                PR_FindSymbol(library, "C_GetFunctionList");
466
0
        }
467
0
        if (mod->isModuleDB) {
468
0
            mod->moduleDBFunc = (void *)
469
0
                PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
470
0
        }
471
0
        if (mod->moduleDBFunc == NULL)
472
0
            mod->isModuleDB = PR_FALSE;
473
0
        if (entry == NULL) {
474
0
            if (mod->isModuleDB) {
475
0
                mod->loaded = PR_TRUE;
476
0
                mod->moduleDBOnly = PR_TRUE;
477
0
                return SECSuccess;
478
0
            }
479
0
            PR_UnloadLibrary(library);
480
0
            return SECFailure;
481
0
        }
482
0
    }
483
0
484
0
    /*
485
0
     * We need to get the function list
486
0
     */
487
0
    if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
488
0
        goto fail;
489
0
490
0
#ifdef DEBUG_MODULE
491
0
    if (PR_TRUE) {
492
0
        modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE");
493
0
        if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
494
0
            mod->functionList = (void *)nss_InsertDeviceLog(
495
0
                (CK_FUNCTION_LIST_PTR)mod->functionList);
496
0
        }
497
0
    }
498
0
#endif
499
0
500
0
    mod->isThreadSafe = PR_TRUE;
501
0
502
0
    /* Now we initialize the module */
503
0
    rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded);
504
0
    if (rv != SECSuccess) {
505
0
        goto fail;
506
0
    }
507
0
508
0
    /* module has been reloaded, this module itself is done,
509
0
     * return to the caller */
510
0
    if (mod->functionList == NULL) {
511
0
        mod->loaded = PR_TRUE; /* technically the module is loaded.. */
512
0
        return SECSuccess;
513
0
    }
514
0
515
0
    /* check the version number */
516
0
    if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK)
517
0
        goto fail2;
518
0
    if (info.cryptokiVersion.major != 2)
519
0
        goto fail2;
520
0
    /* all 2.0 are a priori *not* thread safe */
521
0
    if (info.cryptokiVersion.minor < 1) {
522
0
        if (!loadSingleThreadedModules) {
523
0
            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
524
0
            goto fail2;
525
0
        } else {
526
0
            mod->isThreadSafe = PR_FALSE;
527
0
        }
528
0
    }
529
0
    mod->cryptokiVersion = info.cryptokiVersion;
530
0
531
0
    /* If we don't have a common name, get it from the PKCS 11 module */
532
0
    if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
533
0
        mod->commonName = PK11_MakeString(mod->arena, NULL,
534
0
                                          (char *)info.libraryDescription, sizeof(info.libraryDescription));
535
0
        if (mod->commonName == NULL)
536
0
            goto fail2;
537
0
    }
538
0
539
0
    /* initialize the Slots */
540
0
    if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
541
0
        CK_SLOT_ID *slotIDs;
542
0
        int i;
543
0
        CK_RV crv;
544
0
545
0
        mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
546
0
                                                      sizeof(PK11SlotInfo *) * slotCount);
547
0
        if (mod->slots == NULL)
548
0
            goto fail2;
549
0
550
0
        slotIDs = (CK_SLOT_ID *)PORT_Alloc(sizeof(CK_SLOT_ID) * slotCount);
551
0
        if (slotIDs == NULL) {
552
0
            goto fail2;
553
0
        }
554
0
        crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
555
0
        if (crv != CKR_OK) {
556
0
            PORT_Free(slotIDs);
557
0
            goto fail2;
558
0
        }
559
0
560
0
        /* Initialize each slot */
561
0
        for (i = 0; i < (int)slotCount; i++) {
562
0
            mod->slots[i] = PK11_NewSlotInfo(mod);
563
0
            PK11_InitSlot(mod, slotIDs[i], mod->slots[i]);
564
0
            /* look down the slot info table */
565
0
            PK11_LoadSlotList(mod->slots[i], mod->slotInfo, mod->slotInfoCount);
566
0
            SECMOD_SetRootCerts(mod->slots[i], mod);
567
0
            /* explicitly mark the internal slot as such if IsInternalKeySlot()
568
0
             * is set */
569
0
            if (secmod_IsInternalKeySlot(mod) && (i == (mod->isFIPS ? 0 : 1))) {
570
0
                pk11_SetInternalKeySlotIfFirst(mod->slots[i]);
571
0
            }
572
0
        }
573
0
        mod->slotCount = slotCount;
574
0
        mod->slotInfoCount = 0;
575
0
        PORT_Free(slotIDs);
576
0
    }
577
0
578
0
    mod->loaded = PR_TRUE;
579
0
    mod->moduleID = nextModuleID++;
580
0
    return SECSuccess;
581
0
fail2:
582
0
    if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
583
0
        PK11_GETTAB(mod)->C_Finalize(NULL);
584
0
    }
585
0
fail:
586
0
    mod->functionList = NULL;
587
0
    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
588
0
    if (library && !disableUnload) {
589
0
        PR_UnloadLibrary(library);
590
0
    }
591
0
    return SECFailure;
592
0
}
593
594
SECStatus
595
SECMOD_UnloadModule(SECMODModule *mod)
596
0
{
597
0
    PRLibrary *library;
598
0
    char *disableUnload = NULL;
599
0
600
0
    if (!mod->loaded) {
601
0
        return SECFailure;
602
0
    }
603
0
    if (finalizeModules) {
604
0
        if (mod->functionList && !mod->moduleDBOnly) {
605
0
            PK11_GETTAB(mod)->C_Finalize(NULL);
606
0
        }
607
0
    }
608
0
    mod->moduleID = 0;
609
0
    mod->loaded = PR_FALSE;
610
0
611
0
    /* do we want the semantics to allow unloading the internal library?
612
0
     * if not, we should change this to SECFailure and move it above the
613
0
     * mod->loaded = PR_FALSE; */
614
0
    if (mod->internal && (mod->dllName == NULL)) {
615
0
#ifndef NSS_TEST_BUILD
616
0
        if (0 == PR_ATOMIC_DECREMENT(&softokenLoadCount)) {
617
0
            if (softokenLib) {
618
0
                disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
619
0
                if (!disableUnload) {
620
#ifdef DEBUG
621
                    PRStatus status = PR_UnloadLibrary(softokenLib);
622
                    PORT_Assert(PR_SUCCESS == status);
623
#else
624
                    PR_UnloadLibrary(softokenLib);
625
0
#endif
626
0
                }
627
0
                softokenLib = NULL;
628
0
            }
629
0
            loadSoftokenOnce = pristineCallOnce;
630
0
        }
631
0
#endif
632
0
        return SECSuccess;
633
0
    }
634
0
635
0
    library = (PRLibrary *)mod->library;
636
0
    /* paranoia */
637
0
    if (library == NULL) {
638
0
        return SECFailure;
639
0
    }
640
0
641
0
    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
642
0
    if (!disableUnload) {
643
0
        PR_UnloadLibrary(library);
644
0
    }
645
0
    return SECSuccess;
646
0
}
647
648
void
649
nss_DumpModuleLog(void)
650
0
{
651
0
#ifdef DEBUG_MODULE
652
0
    if (modToDBG) {
653
0
        print_final_statistics();
654
0
    }
655
0
#endif
656
0
}