Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | } |