security/nss/lib/pk11wrap/pk11load.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial