1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pk11wrap/pk11load.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,623 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * The following handles the loading, unloading and management of 1.9 + * various PCKS #11 modules 1.10 + */ 1.11 +#define FORCE_PR_LOG 1 1.12 +#include "seccomon.h" 1.13 +#include "pkcs11.h" 1.14 +#include "secmod.h" 1.15 +#include "prlink.h" 1.16 +#include "pk11func.h" 1.17 +#include "secmodi.h" 1.18 +#include "secmodti.h" 1.19 +#include "nssilock.h" 1.20 +#include "secerr.h" 1.21 +#include "prenv.h" 1.22 +#include "utilparst.h" 1.23 + 1.24 +#define DEBUG_MODULE 1 1.25 + 1.26 +#ifdef DEBUG_MODULE 1.27 +static char *modToDBG = NULL; 1.28 + 1.29 +#include "debug_module.c" 1.30 +#endif 1.31 + 1.32 +/* build the PKCS #11 2.01 lock files */ 1.33 +CK_RV PR_CALLBACK secmodCreateMutext(CK_VOID_PTR_PTR pmutex) { 1.34 + *pmutex = (CK_VOID_PTR) PZ_NewLock(nssILockOther); 1.35 + if ( *pmutex ) return CKR_OK; 1.36 + return CKR_HOST_MEMORY; 1.37 +} 1.38 + 1.39 +CK_RV PR_CALLBACK secmodDestroyMutext(CK_VOID_PTR mutext) { 1.40 + PZ_DestroyLock((PZLock *)mutext); 1.41 + return CKR_OK; 1.42 +} 1.43 + 1.44 +CK_RV PR_CALLBACK secmodLockMutext(CK_VOID_PTR mutext) { 1.45 + PZ_Lock((PZLock *)mutext); 1.46 + return CKR_OK; 1.47 +} 1.48 + 1.49 +CK_RV PR_CALLBACK secmodUnlockMutext(CK_VOID_PTR mutext) { 1.50 + PZ_Unlock((PZLock *)mutext); 1.51 + return CKR_OK; 1.52 +} 1.53 + 1.54 +static SECMODModuleID nextModuleID = 1; 1.55 +static const CK_C_INITIALIZE_ARGS secmodLockFunctions = { 1.56 + secmodCreateMutext, secmodDestroyMutext, secmodLockMutext, 1.57 + secmodUnlockMutext, CKF_LIBRARY_CANT_CREATE_OS_THREADS| 1.58 + CKF_OS_LOCKING_OK 1.59 + ,NULL 1.60 +}; 1.61 +static const CK_C_INITIALIZE_ARGS secmodNoLockArgs = { 1.62 + NULL, NULL, NULL, NULL, 1.63 + CKF_LIBRARY_CANT_CREATE_OS_THREADS 1.64 + ,NULL 1.65 +}; 1.66 + 1.67 +static PRBool loadSingleThreadedModules = PR_TRUE; 1.68 +static PRBool enforceAlreadyInitializedError = PR_TRUE; 1.69 +static PRBool finalizeModules = PR_TRUE; 1.70 + 1.71 +/* set global options for NSS PKCS#11 module loader */ 1.72 +SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules, 1.73 + PRBool allowAlreadyInitializedModules, 1.74 + PRBool dontFinalizeModules) 1.75 +{ 1.76 + if (noSingleThreadedModules) { 1.77 + loadSingleThreadedModules = PR_FALSE; 1.78 + } else { 1.79 + loadSingleThreadedModules = PR_TRUE; 1.80 + } 1.81 + if (allowAlreadyInitializedModules) { 1.82 + enforceAlreadyInitializedError = PR_FALSE; 1.83 + } else { 1.84 + enforceAlreadyInitializedError = PR_TRUE; 1.85 + } 1.86 + if (dontFinalizeModules) { 1.87 + finalizeModules = PR_FALSE; 1.88 + } else { 1.89 + finalizeModules = PR_TRUE; 1.90 + } 1.91 + return SECSuccess; 1.92 +} 1.93 + 1.94 +PRBool pk11_getFinalizeModulesOption(void) 1.95 +{ 1.96 + return finalizeModules; 1.97 +} 1.98 + 1.99 +/* 1.100 + * Allow specification loading the same module more than once at init time. 1.101 + * This enables 2 things. 1.102 + * 1.103 + * 1) we can load additional databases by manipulating secmod.db/pkcs11.txt. 1.104 + * 2) we can handle the case where some library has already initialized NSS 1.105 + * before the main application. 1.106 + * 1.107 + * oldModule is the module we have already initialized. 1.108 + * char *modulespec is the full module spec for the library we want to 1.109 + * initialize. 1.110 + */ 1.111 +static SECStatus 1.112 +secmod_handleReload(SECMODModule *oldModule, SECMODModule *newModule) 1.113 +{ 1.114 + PK11SlotInfo *slot; 1.115 + char *modulespec; 1.116 + char *newModuleSpec; 1.117 + char **children; 1.118 + CK_SLOT_ID *ids; 1.119 + SECMODConfigList *conflist = NULL; 1.120 + SECStatus rv = SECFailure; 1.121 + int count = 0; 1.122 + 1.123 + /* first look for tokens= key words from the module spec */ 1.124 + modulespec = newModule->libraryParams; 1.125 + newModuleSpec = secmod_ParseModuleSpecForTokens(PR_TRUE, 1.126 + newModule->isFIPS, modulespec, &children, &ids); 1.127 + if (!newModuleSpec) { 1.128 + return SECFailure; 1.129 + } 1.130 + 1.131 + /* 1.132 + * We are now trying to open a new slot on an already loaded module. 1.133 + * If that slot represents a cert/key database, we don't want to open 1.134 + * multiple copies of that same database. Unfortunately we understand 1.135 + * the softoken flags well enough to be able to do this, so we can only get 1.136 + * the list of already loaded databases if we are trying to open another 1.137 + * internal module. 1.138 + */ 1.139 + if (oldModule->internal) { 1.140 + conflist = secmod_GetConfigList(oldModule->isFIPS, 1.141 + oldModule->libraryParams, &count); 1.142 + } 1.143 + 1.144 + 1.145 + /* don't open multiple of the same db */ 1.146 + if (conflist && secmod_MatchConfigList(newModuleSpec, conflist, count)) { 1.147 + rv = SECSuccess; 1.148 + goto loser; 1.149 + } 1.150 + slot = SECMOD_OpenNewSlot(oldModule, newModuleSpec); 1.151 + if (slot) { 1.152 + int newID; 1.153 + char **thisChild; 1.154 + CK_SLOT_ID *thisID; 1.155 + char *oldModuleSpec; 1.156 + 1.157 + if (secmod_IsInternalKeySlot(newModule)) { 1.158 + pk11_SetInternalKeySlotIfFirst(slot); 1.159 + } 1.160 + newID = slot->slotID; 1.161 + PK11_FreeSlot(slot); 1.162 + for (thisChild=children, thisID=ids; thisChild && *thisChild; 1.163 + thisChild++,thisID++) { 1.164 + if (conflist && 1.165 + secmod_MatchConfigList(*thisChild, conflist, count)) { 1.166 + *thisID = (CK_SLOT_ID) -1; 1.167 + continue; 1.168 + } 1.169 + slot = SECMOD_OpenNewSlot(oldModule, *thisChild); 1.170 + if (slot) { 1.171 + *thisID = slot->slotID; 1.172 + PK11_FreeSlot(slot); 1.173 + } else { 1.174 + *thisID = (CK_SLOT_ID) -1; 1.175 + } 1.176 + } 1.177 + 1.178 + /* update the old module initialization string in case we need to 1.179 + * shutdown and reinit the whole mess (this is rare, but can happen 1.180 + * when trying to stop smart card insertion/removal threads)... */ 1.181 + oldModuleSpec = secmod_MkAppendTokensList(oldModule->arena, 1.182 + oldModule->libraryParams, newModuleSpec, newID, 1.183 + children, ids); 1.184 + if (oldModuleSpec) { 1.185 + oldModule->libraryParams = oldModuleSpec; 1.186 + } 1.187 + 1.188 + rv = SECSuccess; 1.189 + } 1.190 + 1.191 +loser: 1.192 + secmod_FreeChildren(children, ids); 1.193 + PORT_Free(newModuleSpec); 1.194 + if (conflist) { 1.195 + secmod_FreeConfigList(conflist, count); 1.196 + } 1.197 + return rv; 1.198 +} 1.199 + 1.200 +/* 1.201 + * collect the steps we need to initialize a module in a single function 1.202 + */ 1.203 +SECStatus 1.204 +secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload, 1.205 + PRBool* alreadyLoaded) 1.206 +{ 1.207 + CK_C_INITIALIZE_ARGS moduleArgs; 1.208 + CK_VOID_PTR pInitArgs; 1.209 + CK_RV crv; 1.210 + 1.211 + if (reload) { 1.212 + *reload = NULL; 1.213 + } 1.214 + 1.215 + if (!mod || !alreadyLoaded) { 1.216 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.217 + return SECFailure; 1.218 + } 1.219 + 1.220 + if (mod->libraryParams == NULL) { 1.221 + if (mod->isThreadSafe) { 1.222 + pInitArgs = (void *) &secmodLockFunctions; 1.223 + } else { 1.224 + pInitArgs = NULL; 1.225 + } 1.226 + } else { 1.227 + if (mod->isThreadSafe) { 1.228 + moduleArgs = secmodLockFunctions; 1.229 + } else { 1.230 + moduleArgs = secmodNoLockArgs; 1.231 + } 1.232 + moduleArgs.LibraryParameters = (void *) mod->libraryParams; 1.233 + pInitArgs = &moduleArgs; 1.234 + } 1.235 + crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs); 1.236 + if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) { 1.237 + SECMODModule *oldModule = NULL; 1.238 + 1.239 + /* Library has already been loaded once, if caller expects it, and it 1.240 + * has additional configuration, try reloading it as well. */ 1.241 + if (reload != NULL && mod->libraryParams) { 1.242 + oldModule = secmod_FindModuleByFuncPtr(mod->functionList); 1.243 + } 1.244 + /* Library has been loaded by NSS. It means it may be capable of 1.245 + * reloading */ 1.246 + if (oldModule) { 1.247 + SECStatus rv; 1.248 + rv = secmod_handleReload(oldModule, mod); 1.249 + if (rv == SECSuccess) { 1.250 + /* This module should go away soon, since we've 1.251 + * simply expanded the slots on the old module. 1.252 + * When it goes away, it should not Finalize since 1.253 + * that will close our old module as well. Setting 1.254 + * the function list to NULL will prevent that close */ 1.255 + mod->functionList = NULL; 1.256 + *reload = oldModule; 1.257 + return SECSuccess; 1.258 + } 1.259 + SECMOD_DestroyModule(oldModule); 1.260 + } 1.261 + /* reload not possible, fall back to old semantics */ 1.262 + if (!enforceAlreadyInitializedError) { 1.263 + *alreadyLoaded = PR_TRUE; 1.264 + return SECSuccess; 1.265 + } 1.266 + } 1.267 + if (crv != CKR_OK) { 1.268 + if (!mod->isThreadSafe || 1.269 + crv == CKR_NETSCAPE_CERTDB_FAILED || 1.270 + crv == CKR_NETSCAPE_KEYDB_FAILED) { 1.271 + PORT_SetError(PK11_MapError(crv)); 1.272 + return SECFailure; 1.273 + } 1.274 + /* If we had attempted to init a single threaded module "with" 1.275 + * parameters and it failed, should we retry "without" parameters? 1.276 + * (currently we don't retry in this scenario) */ 1.277 + 1.278 + if (!loadSingleThreadedModules) { 1.279 + PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11); 1.280 + return SECFailure; 1.281 + } 1.282 + /* If we arrive here, the module failed a ThreadSafe init. */ 1.283 + mod->isThreadSafe = PR_FALSE; 1.284 + if (!mod->libraryParams) { 1.285 + pInitArgs = NULL; 1.286 + } else { 1.287 + moduleArgs = secmodNoLockArgs; 1.288 + moduleArgs.LibraryParameters = (void *) mod->libraryParams; 1.289 + pInitArgs = &moduleArgs; 1.290 + } 1.291 + crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs); 1.292 + if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) && 1.293 + (!enforceAlreadyInitializedError)) { 1.294 + *alreadyLoaded = PR_TRUE; 1.295 + return SECSuccess; 1.296 + } 1.297 + if (crv != CKR_OK) { 1.298 + PORT_SetError(PK11_MapError(crv)); 1.299 + return SECFailure; 1.300 + } 1.301 + } 1.302 + return SECSuccess; 1.303 +} 1.304 + 1.305 +/* 1.306 + * set the hasRootCerts flags in the module so it can be stored back 1.307 + * into the database. 1.308 + */ 1.309 +void 1.310 +SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod) { 1.311 + PK11PreSlotInfo *psi = NULL; 1.312 + int i; 1.313 + 1.314 + if (slot->hasRootCerts) { 1.315 + for (i=0; i < mod->slotInfoCount; i++) { 1.316 + if (slot->slotID == mod->slotInfo[i].slotID) { 1.317 + psi = &mod->slotInfo[i]; 1.318 + break; 1.319 + } 1.320 + } 1.321 + if (psi == NULL) { 1.322 + /* allocate more slots */ 1.323 + PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *) 1.324 + PORT_ArenaAlloc(mod->arena, 1.325 + (mod->slotInfoCount+1)* sizeof(PK11PreSlotInfo)); 1.326 + /* copy the old ones */ 1.327 + if (mod->slotInfoCount > 0) { 1.328 + PORT_Memcpy(psi_list,mod->slotInfo, 1.329 + (mod->slotInfoCount)*sizeof(PK11PreSlotInfo)); 1.330 + } 1.331 + /* assign psi to the last new slot */ 1.332 + psi = &psi_list[mod->slotInfoCount]; 1.333 + psi->slotID = slot->slotID; 1.334 + psi->askpw = 0; 1.335 + psi->timeout = 0; 1.336 + psi ->defaultFlags = 0; 1.337 + 1.338 + /* increment module count & store new list */ 1.339 + mod->slotInfo = psi_list; 1.340 + mod->slotInfoCount++; 1.341 + 1.342 + } 1.343 + psi->hasRootCerts = 1; 1.344 + } 1.345 +} 1.346 + 1.347 +static const char* my_shlib_name = 1.348 + SHLIB_PREFIX"nss"SHLIB_VERSION"."SHLIB_SUFFIX; 1.349 +static const char* softoken_shlib_name = 1.350 + SHLIB_PREFIX"softokn"SOFTOKEN_SHLIB_VERSION"."SHLIB_SUFFIX; 1.351 +static const PRCallOnceType pristineCallOnce; 1.352 +static PRCallOnceType loadSoftokenOnce; 1.353 +static PRLibrary* softokenLib; 1.354 +static PRInt32 softokenLoadCount; 1.355 + 1.356 +#include "prio.h" 1.357 +#include "prprf.h" 1.358 +#include <stdio.h> 1.359 +#include "prsystem.h" 1.360 + 1.361 +/* This function must be run only once. */ 1.362 +/* determine if hybrid platform, then actually load the DSO. */ 1.363 +static PRStatus 1.364 +softoken_LoadDSO( void ) 1.365 +{ 1.366 + PRLibrary * handle; 1.367 + 1.368 + handle = PORT_LoadLibraryFromOrigin(my_shlib_name, 1.369 + (PRFuncPtr) &softoken_LoadDSO, 1.370 + softoken_shlib_name); 1.371 + if (handle) { 1.372 + softokenLib = handle; 1.373 + return PR_SUCCESS; 1.374 + } 1.375 + return PR_FAILURE; 1.376 +} 1.377 + 1.378 +/* 1.379 + * load a new module into our address space and initialize it. 1.380 + */ 1.381 +SECStatus 1.382 +secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule) { 1.383 + PRLibrary *library = NULL; 1.384 + CK_C_GetFunctionList entry = NULL; 1.385 + CK_INFO info; 1.386 + CK_ULONG slotCount = 0; 1.387 + SECStatus rv; 1.388 + PRBool alreadyLoaded = PR_FALSE; 1.389 + char *disableUnload = NULL; 1.390 + 1.391 + if (mod->loaded) return SECSuccess; 1.392 + 1.393 + /* intenal modules get loaded from their internal list */ 1.394 + if (mod->internal && (mod->dllName == NULL)) { 1.395 + /* 1.396 + * Loads softoken as a dynamic library, 1.397 + * even though the rest of NSS assumes this as the "internal" module. 1.398 + */ 1.399 + if (!softokenLib && 1.400 + PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO)) 1.401 + return SECFailure; 1.402 + 1.403 + PR_ATOMIC_INCREMENT(&softokenLoadCount); 1.404 + 1.405 + if (mod->isFIPS) { 1.406 + entry = (CK_C_GetFunctionList) 1.407 + PR_FindSymbol(softokenLib, "FC_GetFunctionList"); 1.408 + } else { 1.409 + entry = (CK_C_GetFunctionList) 1.410 + PR_FindSymbol(softokenLib, "NSC_GetFunctionList"); 1.411 + } 1.412 + 1.413 + if (!entry) 1.414 + return SECFailure; 1.415 + 1.416 + if (mod->isModuleDB) { 1.417 + mod->moduleDBFunc = (CK_C_GetFunctionList) 1.418 + PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc"); 1.419 + } 1.420 + 1.421 + if (mod->moduleDBOnly) { 1.422 + mod->loaded = PR_TRUE; 1.423 + return SECSuccess; 1.424 + } 1.425 + } else { 1.426 + /* Not internal, load the DLL and look up C_GetFunctionList */ 1.427 + if (mod->dllName == NULL) { 1.428 + return SECFailure; 1.429 + } 1.430 + 1.431 + /* load the library. If this succeeds, then we have to remember to 1.432 + * unload the library if anything goes wrong from here on out... 1.433 + */ 1.434 + library = PR_LoadLibrary(mod->dllName); 1.435 + mod->library = (void *)library; 1.436 + 1.437 + if (library == NULL) { 1.438 + return SECFailure; 1.439 + } 1.440 + 1.441 + /* 1.442 + * now we need to get the entry point to find the function pointers 1.443 + */ 1.444 + if (!mod->moduleDBOnly) { 1.445 + entry = (CK_C_GetFunctionList) 1.446 + PR_FindSymbol(library, "C_GetFunctionList"); 1.447 + } 1.448 + if (mod->isModuleDB) { 1.449 + mod->moduleDBFunc = (void *) 1.450 + PR_FindSymbol(library, "NSS_ReturnModuleSpecData"); 1.451 + } 1.452 + if (mod->moduleDBFunc == NULL) mod->isModuleDB = PR_FALSE; 1.453 + if (entry == NULL) { 1.454 + if (mod->isModuleDB) { 1.455 + mod->loaded = PR_TRUE; 1.456 + mod->moduleDBOnly = PR_TRUE; 1.457 + return SECSuccess; 1.458 + } 1.459 + PR_UnloadLibrary(library); 1.460 + return SECFailure; 1.461 + } 1.462 + } 1.463 + 1.464 + /* 1.465 + * We need to get the function list 1.466 + */ 1.467 + if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK) 1.468 + goto fail; 1.469 + 1.470 +#ifdef DEBUG_MODULE 1.471 + if (PR_TRUE) { 1.472 + modToDBG = PR_GetEnv("NSS_DEBUG_PKCS11_MODULE"); 1.473 + if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) { 1.474 + mod->functionList = (void *)nss_InsertDeviceLog( 1.475 + (CK_FUNCTION_LIST_PTR)mod->functionList); 1.476 + } 1.477 + } 1.478 +#endif 1.479 + 1.480 + mod->isThreadSafe = PR_TRUE; 1.481 + 1.482 + /* Now we initialize the module */ 1.483 + rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded); 1.484 + if (rv != SECSuccess) { 1.485 + goto fail; 1.486 + } 1.487 + 1.488 + /* module has been reloaded, this module itself is done, 1.489 + * return to the caller */ 1.490 + if (mod->functionList == NULL) { 1.491 + mod->loaded = PR_TRUE; /* technically the module is loaded.. */ 1.492 + return SECSuccess; 1.493 + } 1.494 + 1.495 + /* check the version number */ 1.496 + if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2; 1.497 + if (info.cryptokiVersion.major != 2) goto fail2; 1.498 + /* all 2.0 are a priori *not* thread safe */ 1.499 + if (info.cryptokiVersion.minor < 1) { 1.500 + if (!loadSingleThreadedModules) { 1.501 + PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11); 1.502 + goto fail2; 1.503 + } else { 1.504 + mod->isThreadSafe = PR_FALSE; 1.505 + } 1.506 + } 1.507 + mod->cryptokiVersion = info.cryptokiVersion; 1.508 + 1.509 + /* If we don't have a common name, get it from the PKCS 11 module */ 1.510 + if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) { 1.511 + mod->commonName = PK11_MakeString(mod->arena,NULL, 1.512 + (char *)info.libraryDescription, sizeof(info.libraryDescription)); 1.513 + if (mod->commonName == NULL) goto fail2; 1.514 + } 1.515 + 1.516 + 1.517 + /* initialize the Slots */ 1.518 + if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) { 1.519 + CK_SLOT_ID *slotIDs; 1.520 + int i; 1.521 + CK_RV crv; 1.522 + 1.523 + mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena, 1.524 + sizeof(PK11SlotInfo *) * slotCount); 1.525 + if (mod->slots == NULL) goto fail2; 1.526 + 1.527 + slotIDs = (CK_SLOT_ID *) PORT_Alloc(sizeof(CK_SLOT_ID)*slotCount); 1.528 + if (slotIDs == NULL) { 1.529 + goto fail2; 1.530 + } 1.531 + crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount); 1.532 + if (crv != CKR_OK) { 1.533 + PORT_Free(slotIDs); 1.534 + goto fail2; 1.535 + } 1.536 + 1.537 + /* Initialize each slot */ 1.538 + for (i=0; i < (int)slotCount; i++) { 1.539 + mod->slots[i] = PK11_NewSlotInfo(mod); 1.540 + PK11_InitSlot(mod,slotIDs[i],mod->slots[i]); 1.541 + /* look down the slot info table */ 1.542 + PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount); 1.543 + SECMOD_SetRootCerts(mod->slots[i],mod); 1.544 + /* explicitly mark the internal slot as such if IsInternalKeySlot() 1.545 + * is set */ 1.546 + if (secmod_IsInternalKeySlot(mod) && (i == (mod->isFIPS ? 0 : 1))) { 1.547 + pk11_SetInternalKeySlotIfFirst(mod->slots[i]); 1.548 + } 1.549 + } 1.550 + mod->slotCount = slotCount; 1.551 + mod->slotInfoCount = 0; 1.552 + PORT_Free(slotIDs); 1.553 + } 1.554 + 1.555 + mod->loaded = PR_TRUE; 1.556 + mod->moduleID = nextModuleID++; 1.557 + return SECSuccess; 1.558 +fail2: 1.559 + if (enforceAlreadyInitializedError || (!alreadyLoaded)) { 1.560 + PK11_GETTAB(mod)->C_Finalize(NULL); 1.561 + } 1.562 +fail: 1.563 + mod->functionList = NULL; 1.564 + disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); 1.565 + if (library && !disableUnload) { 1.566 + PR_UnloadLibrary(library); 1.567 + } 1.568 + return SECFailure; 1.569 +} 1.570 + 1.571 +SECStatus 1.572 +SECMOD_UnloadModule(SECMODModule *mod) { 1.573 + PRLibrary *library; 1.574 + char *disableUnload = NULL; 1.575 + 1.576 + if (!mod->loaded) { 1.577 + return SECFailure; 1.578 + } 1.579 + if (finalizeModules) { 1.580 + if (mod->functionList &&!mod->moduleDBOnly) { 1.581 + PK11_GETTAB(mod)->C_Finalize(NULL); 1.582 + } 1.583 + } 1.584 + mod->moduleID = 0; 1.585 + mod->loaded = PR_FALSE; 1.586 + 1.587 + /* do we want the semantics to allow unloading the internal library? 1.588 + * if not, we should change this to SECFailure and move it above the 1.589 + * mod->loaded = PR_FALSE; */ 1.590 + if (mod->internal && (mod->dllName == NULL)) { 1.591 + if (0 == PR_ATOMIC_DECREMENT(&softokenLoadCount)) { 1.592 + if (softokenLib) { 1.593 + disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); 1.594 + if (!disableUnload) { 1.595 + PRStatus status = PR_UnloadLibrary(softokenLib); 1.596 + PORT_Assert(PR_SUCCESS == status); 1.597 + } 1.598 + softokenLib = NULL; 1.599 + } 1.600 + loadSoftokenOnce = pristineCallOnce; 1.601 + } 1.602 + return SECSuccess; 1.603 + } 1.604 + 1.605 + library = (PRLibrary *)mod->library; 1.606 + /* paranoia */ 1.607 + if (library == NULL) { 1.608 + return SECFailure; 1.609 + } 1.610 + 1.611 + disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); 1.612 + if (!disableUnload) { 1.613 + PR_UnloadLibrary(library); 1.614 + } 1.615 + return SECSuccess; 1.616 +} 1.617 + 1.618 +void 1.619 +nss_DumpModuleLog(void) 1.620 +{ 1.621 +#ifdef DEBUG_MODULE 1.622 + if (modToDBG) { 1.623 + print_final_statistics(); 1.624 + } 1.625 +#endif 1.626 +}