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