| File: | root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c |
| Warning: | line 375, column 18 Access to field 'internal' results in a dereference of a null pointer (loaded from field 'module') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | * Initialize the PCKS 11 subsystem | |||
| 6 | */ | |||
| 7 | #include "seccomon.h" | |||
| 8 | #include "secmod.h" | |||
| 9 | #include "nssilock.h" | |||
| 10 | #include "secmodi.h" | |||
| 11 | #include "secmodti.h" | |||
| 12 | #include "pk11func.h" | |||
| 13 | #include "pki3hack.h" | |||
| 14 | #include "secerr.h" | |||
| 15 | #include "dev.h" | |||
| 16 | #include "dev3hack.h" | |||
| 17 | #include "utilpars.h" | |||
| 18 | #include "pkcs11uri.h" | |||
| 19 | ||||
| 20 | /* these are for displaying error messages */ | |||
| 21 | ||||
| 22 | static SECMODModuleList *modules = NULL((void*)0); | |||
| 23 | static SECMODModuleList *modulesDB = NULL((void*)0); | |||
| 24 | static SECMODModuleList *modulesUnload = NULL((void*)0); | |||
| 25 | static SECMODModule *internalModule = NULL((void*)0); | |||
| 26 | static SECMODModule *defaultDBModule = NULL((void*)0); | |||
| 27 | static SECMODModule *pendingModule = NULL((void*)0); | |||
| 28 | static SECMODListLock *moduleLock = NULL((void*)0); | |||
| 29 | ||||
| 30 | int secmod_PrivateModuleCount = 0; | |||
| 31 | ||||
| 32 | extern const PK11DefaultArrayEntry PK11_DefaultArray[]; | |||
| 33 | extern const int num_pk11_default_mechanisms; | |||
| 34 | ||||
| 35 | void | |||
| 36 | SECMOD_Init() | |||
| 37 | { | |||
| 38 | /* don't initialize twice */ | |||
| 39 | if (moduleLock) | |||
| 40 | return; | |||
| 41 | ||||
| 42 | moduleLock = SECMOD_NewListLock(); | |||
| 43 | PK11_InitSlotLists(); | |||
| 44 | } | |||
| 45 | ||||
| 46 | SECStatus | |||
| 47 | SECMOD_Shutdown() | |||
| 48 | { | |||
| 49 | /* destroy the lock */ | |||
| 50 | if (moduleLock) { | |||
| 51 | SECMOD_DestroyListLock(moduleLock); | |||
| 52 | moduleLock = NULL((void*)0); | |||
| 53 | } | |||
| 54 | /* free the internal module */ | |||
| 55 | if (internalModule) { | |||
| 56 | SECMOD_DestroyModule(internalModule); | |||
| 57 | internalModule = NULL((void*)0); | |||
| 58 | } | |||
| 59 | ||||
| 60 | /* free the default database module */ | |||
| 61 | if (defaultDBModule) { | |||
| 62 | SECMOD_DestroyModule(defaultDBModule); | |||
| 63 | defaultDBModule = NULL((void*)0); | |||
| 64 | } | |||
| 65 | ||||
| 66 | /* destroy the list */ | |||
| 67 | if (modules) { | |||
| 68 | SECMOD_DestroyModuleList(modules); | |||
| 69 | modules = NULL((void*)0); | |||
| 70 | } | |||
| 71 | ||||
| 72 | if (modulesDB) { | |||
| 73 | SECMOD_DestroyModuleList(modulesDB); | |||
| 74 | modulesDB = NULL((void*)0); | |||
| 75 | } | |||
| 76 | ||||
| 77 | if (modulesUnload) { | |||
| 78 | SECMOD_DestroyModuleList(modulesUnload); | |||
| 79 | modulesUnload = NULL((void*)0); | |||
| 80 | } | |||
| 81 | ||||
| 82 | /* make all the slots and the lists go away */ | |||
| 83 | PK11_DestroySlotLists(); | |||
| 84 | ||||
| 85 | nss_DumpModuleLog(); | |||
| 86 | ||||
| 87 | #ifdef DEBUG1 | |||
| 88 | if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) { | |||
| 89 | PORT_Assert(secmod_PrivateModuleCount == 0)((secmod_PrivateModuleCount == 0)?((void)0):PR_Assert("secmod_PrivateModuleCount == 0" ,"/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",89 )); | |||
| 90 | } | |||
| 91 | #endif | |||
| 92 | if (secmod_PrivateModuleCount) { | |||
| 93 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BUSY); | |||
| 94 | return SECFailure; | |||
| 95 | } | |||
| 96 | return SECSuccess; | |||
| 97 | } | |||
| 98 | ||||
| 99 | PRBool | |||
| 100 | SECMOD_GetSystemFIPSEnabled(void) | |||
| 101 | { | |||
| 102 | return NSS_GetSystemFIPSEnabled(); | |||
| 103 | } | |||
| 104 | ||||
| 105 | /* | |||
| 106 | * retrieve the internal module | |||
| 107 | */ | |||
| 108 | SECMODModule * | |||
| 109 | SECMOD_GetInternalModule(void) | |||
| 110 | { | |||
| 111 | return internalModule; | |||
| 112 | } | |||
| 113 | ||||
| 114 | SECStatus | |||
| 115 | secmod_AddModuleToList(SECMODModuleList **moduleList, SECMODModule *newModule) | |||
| 116 | { | |||
| 117 | SECMODModuleList *mlp, *newListElement, *last = NULL((void*)0); | |||
| 118 | ||||
| 119 | newListElement = SECMOD_NewModuleListElement(); | |||
| 120 | if (newListElement == NULL((void*)0)) { | |||
| 121 | return SECFailure; | |||
| 122 | } | |||
| 123 | ||||
| 124 | newListElement->module = SECMOD_ReferenceModule(newModule); | |||
| 125 | ||||
| 126 | SECMOD_GetWriteLock(moduleLock); | |||
| 127 | /* Added it to the end (This is very inefficient, but Adding a module | |||
| 128 | * on the fly should happen maybe 2-3 times through the life this program | |||
| 129 | * on a given computer, and this list should be *SHORT*. */ | |||
| 130 | for (mlp = *moduleList; mlp != NULL((void*)0); mlp = mlp->next) { | |||
| 131 | last = mlp; | |||
| 132 | } | |||
| 133 | ||||
| 134 | if (last == NULL((void*)0)) { | |||
| 135 | *moduleList = newListElement; | |||
| 136 | } else { | |||
| 137 | SECMOD_AddList(last, newListElement, NULL((void*)0)); | |||
| 138 | } | |||
| 139 | SECMOD_ReleaseWriteLock(moduleLock); | |||
| 140 | return SECSuccess; | |||
| 141 | } | |||
| 142 | ||||
| 143 | SECStatus | |||
| 144 | SECMOD_AddModuleToList(SECMODModule *newModule) | |||
| 145 | { | |||
| 146 | if (newModule->internal && !internalModule) { | |||
| 147 | internalModule = SECMOD_ReferenceModule(newModule); | |||
| 148 | } | |||
| 149 | return secmod_AddModuleToList(&modules, newModule); | |||
| 150 | } | |||
| 151 | ||||
| 152 | SECStatus | |||
| 153 | SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) | |||
| 154 | { | |||
| 155 | if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) { | |||
| 156 | SECMOD_DestroyModule(defaultDBModule); | |||
| 157 | defaultDBModule = SECMOD_ReferenceModule(newModule); | |||
| 158 | } else if (defaultDBModule == NULL((void*)0)) { | |||
| 159 | defaultDBModule = SECMOD_ReferenceModule(newModule); | |||
| 160 | } | |||
| 161 | return secmod_AddModuleToList(&modulesDB, newModule); | |||
| 162 | } | |||
| 163 | ||||
| 164 | SECStatus | |||
| 165 | SECMOD_AddModuleToUnloadList(SECMODModule *newModule) | |||
| 166 | { | |||
| 167 | return secmod_AddModuleToList(&modulesUnload, newModule); | |||
| 168 | } | |||
| 169 | ||||
| 170 | /* | |||
| 171 | * get the list of PKCS11 modules that are available. | |||
| 172 | */ | |||
| 173 | SECMODModuleList * | |||
| 174 | SECMOD_GetDefaultModuleList() | |||
| 175 | { | |||
| 176 | return modules; | |||
| 177 | } | |||
| 178 | SECMODModuleList * | |||
| 179 | SECMOD_GetDeadModuleList() | |||
| 180 | { | |||
| 181 | return modulesUnload; | |||
| 182 | } | |||
| 183 | SECMODModuleList * | |||
| 184 | SECMOD_GetDBModuleList() | |||
| 185 | { | |||
| 186 | return modulesDB; | |||
| 187 | } | |||
| 188 | ||||
| 189 | /* | |||
| 190 | * This lock protects the global module lists. | |||
| 191 | * it also protects changes to the slot array (module->slots[]) and slot count | |||
| 192 | * (module->slotCount) in each module. It is a read/write lock with multiple | |||
| 193 | * readers or one writer. Writes are uncommon. | |||
| 194 | * Because of legacy considerations protection of the slot array and count is | |||
| 195 | * only necessary in applications if the application calls | |||
| 196 | * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new | |||
| 197 | * applications are encouraged to acquire this lock when reading the | |||
| 198 | * slot array information directly. | |||
| 199 | */ | |||
| 200 | SECMODListLock * | |||
| 201 | SECMOD_GetDefaultModuleListLock() | |||
| 202 | { | |||
| 203 | return moduleLock; | |||
| 204 | } | |||
| 205 | ||||
| 206 | /* | |||
| 207 | * find a module by name, and add a reference to it. | |||
| 208 | * return that module. | |||
| 209 | */ | |||
| 210 | SECMODModule * | |||
| 211 | SECMOD_FindModule(const char *name) | |||
| 212 | { | |||
| 213 | SECMODModuleList *mlp; | |||
| 214 | SECMODModule *module = NULL((void*)0); | |||
| 215 | ||||
| 216 | if (!moduleLock) { | |||
| 217 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 218 | return module; | |||
| 219 | } | |||
| 220 | SECMOD_GetReadLock(moduleLock); | |||
| 221 | for (mlp = modules; mlp != NULL((void*)0); mlp = mlp->next) { | |||
| 222 | if (PORT_Strcmpstrcmp(name, mlp->module->commonName) == 0) { | |||
| 223 | module = mlp->module; | |||
| 224 | SECMOD_ReferenceModule(module); | |||
| 225 | break; | |||
| 226 | } | |||
| 227 | } | |||
| 228 | if (module) { | |||
| 229 | goto found; | |||
| 230 | } | |||
| 231 | for (mlp = modulesUnload; mlp != NULL((void*)0); mlp = mlp->next) { | |||
| 232 | if (PORT_Strcmpstrcmp(name, mlp->module->commonName) == 0) { | |||
| 233 | module = mlp->module; | |||
| 234 | SECMOD_ReferenceModule(module); | |||
| 235 | break; | |||
| 236 | } | |||
| 237 | } | |||
| 238 | ||||
| 239 | found: | |||
| 240 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 241 | ||||
| 242 | return module; | |||
| 243 | } | |||
| 244 | ||||
| 245 | /* | |||
| 246 | * find a module by ID, and add a reference to it. | |||
| 247 | * return that module. | |||
| 248 | */ | |||
| 249 | SECMODModule * | |||
| 250 | SECMOD_FindModuleByID(SECMODModuleID id) | |||
| 251 | { | |||
| 252 | SECMODModuleList *mlp; | |||
| 253 | SECMODModule *module = NULL((void*)0); | |||
| 254 | ||||
| 255 | if (!moduleLock) { | |||
| 256 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 257 | return module; | |||
| 258 | } | |||
| 259 | SECMOD_GetReadLock(moduleLock); | |||
| 260 | for (mlp = modules; mlp != NULL((void*)0); mlp = mlp->next) { | |||
| 261 | if (id == mlp->module->moduleID) { | |||
| 262 | module = mlp->module; | |||
| 263 | SECMOD_ReferenceModule(module); | |||
| 264 | break; | |||
| 265 | } | |||
| 266 | } | |||
| 267 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 268 | if (module == NULL((void*)0)) { | |||
| 269 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MODULE); | |||
| 270 | } | |||
| 271 | return module; | |||
| 272 | } | |||
| 273 | ||||
| 274 | /* | |||
| 275 | * find the function pointer. | |||
| 276 | */ | |||
| 277 | SECMODModule * | |||
| 278 | secmod_FindModuleByFuncPtr(void *funcPtr) | |||
| 279 | { | |||
| 280 | SECMODModuleList *mlp; | |||
| 281 | SECMODModule *module = NULL((void*)0); | |||
| 282 | ||||
| 283 | SECMOD_GetReadLock(moduleLock); | |||
| 284 | for (mlp = modules; mlp != NULL((void*)0); mlp = mlp->next) { | |||
| 285 | /* paranoia, shouldn't ever happen */ | |||
| 286 | if (!mlp->module) { | |||
| 287 | continue; | |||
| 288 | } | |||
| 289 | if (funcPtr == mlp->module->functionList) { | |||
| 290 | module = mlp->module; | |||
| 291 | SECMOD_ReferenceModule(module); | |||
| 292 | break; | |||
| 293 | } | |||
| 294 | } | |||
| 295 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 296 | if (module == NULL((void*)0)) { | |||
| 297 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MODULE); | |||
| 298 | } | |||
| 299 | return module; | |||
| 300 | } | |||
| 301 | ||||
| 302 | /* | |||
| 303 | * Find the Slot based on ID and the module. | |||
| 304 | */ | |||
| 305 | PK11SlotInfo * | |||
| 306 | SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID) | |||
| 307 | { | |||
| 308 | int i; | |||
| 309 | PK11SlotInfo *slot = NULL((void*)0); | |||
| 310 | ||||
| 311 | if (!moduleLock) { | |||
| 312 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 313 | return slot; | |||
| 314 | } | |||
| 315 | SECMOD_GetReadLock(moduleLock); | |||
| 316 | for (i = 0; i < module->slotCount; i++) { | |||
| 317 | PK11SlotInfo *cSlot = module->slots[i]; | |||
| 318 | ||||
| 319 | if (cSlot->slotID == slotID) { | |||
| 320 | slot = PK11_ReferenceSlot(cSlot); | |||
| 321 | break; | |||
| 322 | } | |||
| 323 | } | |||
| 324 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 325 | ||||
| 326 | if (slot == NULL((void*)0)) { | |||
| 327 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_SLOT_SELECTED); | |||
| 328 | } | |||
| 329 | return slot; | |||
| 330 | } | |||
| 331 | ||||
| 332 | /* | |||
| 333 | * lookup the Slot module based on it's module ID and slot ID. | |||
| 334 | */ | |||
| 335 | PK11SlotInfo * | |||
| 336 | SECMOD_LookupSlot(SECMODModuleID moduleID, CK_SLOT_ID slotID) | |||
| 337 | { | |||
| 338 | SECMODModule *module; | |||
| 339 | PK11SlotInfo *slot; | |||
| 340 | ||||
| 341 | module = SECMOD_FindModuleByID(moduleID); | |||
| 342 | if (module == NULL((void*)0)) | |||
| 343 | return NULL((void*)0); | |||
| 344 | ||||
| 345 | slot = SECMOD_FindSlotByID(module, slotID); | |||
| 346 | SECMOD_DestroyModule(module); | |||
| 347 | return slot; | |||
| 348 | } | |||
| 349 | ||||
| 350 | /* | |||
| 351 | * find a module by name or module pointer and delete it off the module list. | |||
| 352 | * optionally remove it from secmod.db. | |||
| 353 | */ | |||
| 354 | SECStatus | |||
| 355 | SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod, | |||
| 356 | int *type, PRBool permdb) | |||
| 357 | { | |||
| 358 | SECMODModuleList *mlp; | |||
| 359 | SECMODModuleList **mlpp; | |||
| 360 | SECStatus rv = SECFailure; | |||
| 361 | ||||
| 362 | if (!moduleLock) { | |||
| 363 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 364 | return rv; | |||
| 365 | } | |||
| 366 | ||||
| 367 | *type = SECMOD_EXTERNAL0; | |||
| 368 | ||||
| 369 | SECMOD_GetWriteLock(moduleLock); | |||
| 370 | for (mlpp = &modules, mlp = modules; | |||
| 371 | mlp != NULL((void*)0); mlpp = &mlp->next, mlp = *mlpp) { | |||
| 372 | if ((name && (PORT_Strcmpstrcmp(name, mlp->module->commonName) == 0)) || | |||
| 373 | mod == mlp->module) { | |||
| 374 | /* don't delete the internal module */ | |||
| 375 | if (!mlp->module->internal) { | |||
| ||||
| 376 | SECMOD_RemoveList(mlpp, mlp); | |||
| 377 | /* delete it after we release the lock */ | |||
| 378 | rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); | |||
| 379 | } else if (mlp->module->isFIPS) { | |||
| 380 | *type = SECMOD_FIPS2; | |||
| 381 | } else { | |||
| 382 | *type = SECMOD_INTERNAL1; | |||
| 383 | } | |||
| 384 | break; | |||
| 385 | } | |||
| 386 | } | |||
| 387 | if (mlp) { | |||
| 388 | goto found; | |||
| 389 | } | |||
| 390 | /* not on the internal list, check the unload list */ | |||
| 391 | for (mlpp = &modulesUnload, mlp = modulesUnload; | |||
| 392 | mlp != NULL((void*)0); mlpp = &mlp->next, mlp = *mlpp) { | |||
| 393 | if ((name && (PORT_Strcmpstrcmp(name, mlp->module->commonName) == 0)) || | |||
| 394 | mod == mlp->module) { | |||
| 395 | /* don't delete the internal module */ | |||
| 396 | if (!mlp->module->internal) { | |||
| 397 | SECMOD_RemoveList(mlpp, mlp); | |||
| 398 | rv = SECSuccess; | |||
| 399 | } else if (mlp->module->isFIPS) { | |||
| 400 | *type = SECMOD_FIPS2; | |||
| 401 | } else { | |||
| 402 | *type = SECMOD_INTERNAL1; | |||
| 403 | } | |||
| 404 | break; | |||
| 405 | } | |||
| 406 | } | |||
| 407 | found: | |||
| 408 | SECMOD_ReleaseWriteLock(moduleLock); | |||
| 409 | ||||
| 410 | if (rv == SECSuccess) { | |||
| 411 | if (permdb) { | |||
| 412 | SECMOD_DeletePermDB(mlp->module); | |||
| 413 | } | |||
| 414 | SECMOD_DestroyModuleListElement(mlp); | |||
| 415 | } | |||
| 416 | return rv; | |||
| 417 | } | |||
| 418 | ||||
| 419 | /* | |||
| 420 | * find a module by name and delete it off the module list | |||
| 421 | */ | |||
| 422 | SECStatus | |||
| 423 | SECMOD_DeleteModule(const char *name, int *type) | |||
| 424 | { | |||
| 425 | return SECMOD_DeleteModuleEx(name, NULL((void*)0), type, PR_TRUE1); | |||
| ||||
| 426 | } | |||
| 427 | ||||
| 428 | /* | |||
| 429 | * find a module by name and delete it off the module list | |||
| 430 | */ | |||
| 431 | SECStatus | |||
| 432 | SECMOD_DeleteInternalModule(const char *name) | |||
| 433 | { | |||
| 434 | #ifndef NSS_FIPS_DISABLED1 | |||
| 435 | SECMODModuleList *mlp; | |||
| 436 | SECMODModuleList **mlpp; | |||
| 437 | #endif | |||
| 438 | SECStatus rv = SECFailure; | |||
| 439 | ||||
| 440 | if (SECMOD_GetSystemFIPSEnabled() || pendingModule) { | |||
| 441 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_MODULE_STUCK); | |||
| 442 | return rv; | |||
| 443 | } | |||
| 444 | if (!moduleLock) { | |||
| 445 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 446 | return rv; | |||
| 447 | } | |||
| 448 | ||||
| 449 | #ifdef NSS_FIPS_DISABLED1 | |||
| 450 | PORT_SetErrorPORT_SetError_Util(PR_OPERATION_NOT_SUPPORTED_ERROR(-5965L)); | |||
| 451 | return rv; | |||
| 452 | #else | |||
| 453 | SECMOD_GetWriteLock(moduleLock); | |||
| 454 | for (mlpp = &modules, mlp = modules; | |||
| 455 | mlp != NULL((void*)0); mlpp = &mlp->next, mlp = *mlpp) { | |||
| 456 | if (PORT_Strcmpstrcmp(name, mlp->module->commonName) == 0) { | |||
| 457 | /* don't delete the internal module */ | |||
| 458 | if (mlp->module->internal) { | |||
| 459 | SECMOD_RemoveList(mlpp, mlp); | |||
| 460 | rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); | |||
| 461 | } | |||
| 462 | break; | |||
| 463 | } | |||
| 464 | } | |||
| 465 | SECMOD_ReleaseWriteLock(moduleLock); | |||
| 466 | ||||
| 467 | if (rv == SECSuccess) { | |||
| 468 | SECMODModule *newModule, *oldModule; | |||
| 469 | ||||
| 470 | if (mlp->module->isFIPS) { | |||
| 471 | newModule = SECMOD_CreateModule(NULL((void*)0), SECMOD_INT_NAME"NSS Internal PKCS #11 Module", | |||
| 472 | NULL((void*)0), SECMOD_INT_FLAGS"Flags=internal,critical" "" " slotparams=(" "1" "={" "slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]" "})"); | |||
| 473 | } else { | |||
| 474 | newModule = SECMOD_CreateModule(NULL((void*)0), SECMOD_FIPS_NAME"NSS Internal FIPS PKCS #11 Module", | |||
| 475 | NULL((void*)0), SECMOD_FIPS_FLAGS"Flags=internal,critical" ",fips" " slotparams=(" "3" "={" "slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]" "})"); | |||
| 476 | } | |||
| 477 | if (newModule) { | |||
| 478 | PK11SlotInfo *slot; | |||
| 479 | newModule->libraryParams = | |||
| 480 | PORT_ArenaStrdupPORT_ArenaStrdup_Util(newModule->arena, mlp->module->libraryParams); | |||
| 481 | /* if an explicit internal key slot has been set, reset it */ | |||
| 482 | slot = pk11_SwapInternalKeySlot(NULL((void*)0)); | |||
| 483 | if (slot) { | |||
| 484 | secmod_SetInternalKeySlotFlag(newModule, PR_TRUE1); | |||
| 485 | } | |||
| 486 | rv = SECMOD_AddModule(newModule); | |||
| 487 | if (rv != SECSuccess) { | |||
| 488 | /* load failed, restore the internal key slot */ | |||
| 489 | pk11_SetInternalKeySlot(slot); | |||
| 490 | SECMOD_DestroyModule(newModule); | |||
| 491 | newModule = NULL((void*)0); | |||
| 492 | } | |||
| 493 | /* free the old explicit internal key slot, we now have a new one */ | |||
| 494 | if (slot) { | |||
| 495 | PK11_FreeSlot(slot); | |||
| 496 | } | |||
| 497 | } | |||
| 498 | if (newModule == NULL((void*)0)) { | |||
| 499 | SECMODModuleList *last = NULL((void*)0), *mlp2; | |||
| 500 | /* we're in pretty deep trouble if this happens...Security | |||
| 501 | * not going to work well... try to put the old module back on | |||
| 502 | * the list */ | |||
| 503 | SECMOD_GetWriteLock(moduleLock); | |||
| 504 | for (mlp2 = modules; mlp2 != NULL((void*)0); mlp2 = mlp->next) { | |||
| 505 | last = mlp2; | |||
| 506 | } | |||
| 507 | ||||
| 508 | if (last == NULL((void*)0)) { | |||
| 509 | modules = mlp; | |||
| 510 | } else { | |||
| 511 | SECMOD_AddList(last, mlp, NULL((void*)0)); | |||
| 512 | } | |||
| 513 | SECMOD_ReleaseWriteLock(moduleLock); | |||
| 514 | return SECFailure; | |||
| 515 | } | |||
| 516 | pendingModule = oldModule = internalModule; | |||
| 517 | internalModule = NULL((void*)0); | |||
| 518 | SECMOD_DestroyModule(oldModule); | |||
| 519 | SECMOD_DeletePermDB(mlp->module); | |||
| 520 | SECMOD_DestroyModuleListElement(mlp); | |||
| 521 | internalModule = newModule; /* adopt the module */ | |||
| 522 | } | |||
| 523 | return rv; | |||
| 524 | #endif | |||
| 525 | } | |||
| 526 | ||||
| 527 | SECStatus | |||
| 528 | SECMOD_AddModule(SECMODModule *newModule) | |||
| 529 | { | |||
| 530 | SECStatus rv; | |||
| 531 | SECMODModule *oldModule; | |||
| 532 | ||||
| 533 | /* Test if a module w/ the same name already exists */ | |||
| 534 | /* and return SECWouldBlock if so. */ | |||
| 535 | /* We should probably add a new return value such as */ | |||
| 536 | /* SECDublicateModule, but to minimize ripples, I'll */ | |||
| 537 | /* give SECWouldBlock a new meaning */ | |||
| 538 | if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL((void*)0)) { | |||
| 539 | SECMOD_DestroyModule(oldModule); | |||
| 540 | return SECWouldBlock; | |||
| 541 | /* module already exists. */ | |||
| 542 | } | |||
| 543 | ||||
| 544 | rv = secmod_LoadPKCS11Module(newModule, NULL((void*)0)); | |||
| 545 | if (rv != SECSuccess) { | |||
| 546 | return rv; | |||
| 547 | } | |||
| 548 | ||||
| 549 | if (newModule->parent == NULL((void*)0)) { | |||
| 550 | newModule->parent = SECMOD_ReferenceModule(defaultDBModule); | |||
| 551 | } | |||
| 552 | ||||
| 553 | SECMOD_AddPermDB(newModule); | |||
| 554 | SECMOD_AddModuleToList(newModule); | |||
| 555 | ||||
| 556 | rv = STAN_AddModuleToDefaultTrustDomain(newModule); | |||
| 557 | ||||
| 558 | return rv; | |||
| 559 | } | |||
| 560 | ||||
| 561 | PK11SlotInfo * | |||
| 562 | SECMOD_FindSlot(SECMODModule *module, const char *name) | |||
| 563 | { | |||
| 564 | int i; | |||
| 565 | char *string; | |||
| 566 | PK11SlotInfo *retSlot = NULL((void*)0); | |||
| 567 | ||||
| 568 | if (!moduleLock) { | |||
| 569 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 570 | return retSlot; | |||
| 571 | } | |||
| 572 | SECMOD_GetReadLock(moduleLock); | |||
| 573 | for (i = 0; i < module->slotCount; i++) { | |||
| 574 | PK11SlotInfo *slot = module->slots[i]; | |||
| 575 | ||||
| 576 | if (PK11_IsPresent(slot)) { | |||
| 577 | string = PK11_GetTokenName(slot); | |||
| 578 | } else { | |||
| 579 | string = PK11_GetSlotName(slot); | |||
| 580 | } | |||
| 581 | if (PORT_Strcmpstrcmp(name, string) == 0) { | |||
| 582 | retSlot = PK11_ReferenceSlot(slot); | |||
| 583 | break; | |||
| 584 | } | |||
| 585 | } | |||
| 586 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 587 | ||||
| 588 | if (retSlot == NULL((void*)0)) { | |||
| 589 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_SLOT_SELECTED); | |||
| 590 | } | |||
| 591 | return retSlot; | |||
| 592 | } | |||
| 593 | ||||
| 594 | SECStatus | |||
| 595 | PK11_GetModInfo(SECMODModule *mod, CK_INFO *info) | |||
| 596 | { | |||
| 597 | CK_RV crv; | |||
| 598 | ||||
| 599 | if (mod->functionList == NULL((void*)0)) | |||
| 600 | return SECFailure; | |||
| 601 | crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_GetInfo(info); | |||
| 602 | if (crv != CKR_OK0x00000000UL) { | |||
| 603 | PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv)); | |||
| 604 | } | |||
| 605 | return (crv == CKR_OK0x00000000UL) ? SECSuccess : SECFailure; | |||
| 606 | } | |||
| 607 | ||||
| 608 | char * | |||
| 609 | PK11_GetModuleURI(SECMODModule *mod) | |||
| 610 | { | |||
| 611 | CK_INFO info; | |||
| 612 | PK11URI *uri; | |||
| 613 | char *ret = NULL((void*)0); | |||
| 614 | PK11URIAttribute attrs[3]; | |||
| 615 | size_t nattrs = 0; | |||
| 616 | char libraryManufacturer[32 + 1], libraryDescription[32 + 1], libraryVersion[8]; | |||
| 617 | ||||
| 618 | if (PK11_GetModInfo(mod, &info) == SECFailure) { | |||
| 619 | return NULL((void*)0); | |||
| 620 | } | |||
| 621 | ||||
| 622 | PK11_MakeString(NULL((void*)0), libraryManufacturer, (char *)info.manufacturerID, | |||
| 623 | sizeof(info.manufacturerID)); | |||
| 624 | if (*libraryManufacturer != '\0') { | |||
| 625 | attrs[nattrs].name = PK11URI_PATTR_LIBRARY_MANUFACTURER"library-manufacturer"; | |||
| 626 | attrs[nattrs].value = libraryManufacturer; | |||
| 627 | nattrs++; | |||
| 628 | } | |||
| 629 | ||||
| 630 | PK11_MakeString(NULL((void*)0), libraryDescription, (char *)info.libraryDescription, | |||
| 631 | sizeof(info.libraryDescription)); | |||
| 632 | if (*libraryDescription != '\0') { | |||
| 633 | attrs[nattrs].name = PK11URI_PATTR_LIBRARY_DESCRIPTION"library-description"; | |||
| 634 | attrs[nattrs].value = libraryDescription; | |||
| 635 | nattrs++; | |||
| 636 | } | |||
| 637 | ||||
| 638 | PR_snprintf(libraryVersion, sizeof(libraryVersion), "%d.%d", | |||
| 639 | info.libraryVersion.major, info.libraryVersion.minor); | |||
| 640 | attrs[nattrs].name = PK11URI_PATTR_LIBRARY_VERSION"library-version"; | |||
| 641 | attrs[nattrs].value = libraryVersion; | |||
| 642 | nattrs++; | |||
| 643 | ||||
| 644 | uri = PK11URI_CreateURI(attrs, nattrs, NULL((void*)0), 0); | |||
| 645 | if (uri == NULL((void*)0)) { | |||
| 646 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE); | |||
| 647 | return NULL((void*)0); | |||
| 648 | } | |||
| 649 | ||||
| 650 | ret = PK11URI_FormatURI(NULL((void*)0), uri); | |||
| 651 | PK11URI_DestroyURI(uri); | |||
| 652 | if (ret == NULL((void*)0)) { | |||
| 653 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE); | |||
| 654 | return NULL((void*)0); | |||
| 655 | } | |||
| 656 | ||||
| 657 | return ret; | |||
| 658 | } | |||
| 659 | ||||
| 660 | /* Determine if we have the FIP's module loaded as the default | |||
| 661 | * module to trigger other bogus FIPS requirements in PKCS #12 and | |||
| 662 | * SSL | |||
| 663 | */ | |||
| 664 | PRBool | |||
| 665 | PK11_IsFIPS(void) | |||
| 666 | { | |||
| 667 | SECMODModule *mod = SECMOD_GetInternalModule(); | |||
| 668 | ||||
| 669 | if (mod && mod->internal) { | |||
| 670 | return mod->isFIPS; | |||
| 671 | } | |||
| 672 | ||||
| 673 | return PR_FALSE0; | |||
| 674 | } | |||
| 675 | ||||
| 676 | /* combines NewModule() & AddModule */ | |||
| 677 | /* give a string for the module name & the full-path for the dll, */ | |||
| 678 | /* installs the PKCS11 module & update registry */ | |||
| 679 | SECStatus | |||
| 680 | SECMOD_AddNewModuleEx(const char *moduleName, const char *dllPath, | |||
| 681 | unsigned long defaultMechanismFlags, | |||
| 682 | unsigned long cipherEnableFlags, | |||
| 683 | char *modparms, char *nssparms) | |||
| 684 | { | |||
| 685 | SECMODModule *module; | |||
| 686 | SECStatus result = SECFailure; | |||
| 687 | int s, i; | |||
| 688 | PK11SlotInfo *slot; | |||
| 689 | ||||
| 690 | PR_SetErrorText(0, NULL((void*)0)); | |||
| 691 | if (!moduleLock) { | |||
| 692 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 693 | return result; | |||
| 694 | } | |||
| 695 | ||||
| 696 | module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms); | |||
| 697 | ||||
| 698 | if (module == NULL((void*)0)) { | |||
| 699 | return result; | |||
| 700 | } | |||
| 701 | ||||
| 702 | if (module->dllName != NULL((void*)0)) { | |||
| 703 | if (module->dllName[0] != 0) { | |||
| 704 | result = SECMOD_AddModule(module); | |||
| 705 | if (result == SECSuccess) { | |||
| 706 | /* turn on SSL cipher enable flags */ | |||
| 707 | module->ssl[0] = cipherEnableFlags; | |||
| 708 | ||||
| 709 | SECMOD_GetReadLock(moduleLock); | |||
| 710 | /* check each slot to turn on appropriate mechanisms */ | |||
| 711 | for (s = 0; s < module->slotCount; s++) { | |||
| 712 | slot = (module->slots)[s]; | |||
| 713 | /* for each possible mechanism */ | |||
| 714 | for (i = 0; i < num_pk11_default_mechanisms; i++) { | |||
| 715 | /* we are told to turn it on by default ? */ | |||
| 716 | PRBool add = | |||
| 717 | (PK11_DefaultArray[i].flag & defaultMechanismFlags) ? PR_TRUE1 : PR_FALSE0; | |||
| 718 | result = PK11_UpdateSlotAttribute(slot, | |||
| 719 | &(PK11_DefaultArray[i]), add); | |||
| 720 | if (result != SECSuccess) { | |||
| 721 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 722 | SECMOD_DestroyModule(module); | |||
| 723 | return result; | |||
| 724 | } | |||
| 725 | } /* for each mechanism */ | |||
| 726 | /* disable each slot if the defaultFlags say so */ | |||
| 727 | if (defaultMechanismFlags & PK11_DISABLE_FLAG0x40000000L) { | |||
| 728 | PK11_UserDisableSlot(slot); | |||
| 729 | } | |||
| 730 | } /* for each slot of this module */ | |||
| 731 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 732 | ||||
| 733 | /* delete and re-add module in order to save changes | |||
| 734 | * to the module */ | |||
| 735 | result = SECMOD_UpdateModule(module); | |||
| 736 | } | |||
| 737 | } | |||
| 738 | } | |||
| 739 | SECMOD_DestroyModule(module); | |||
| 740 | return result; | |||
| 741 | } | |||
| 742 | ||||
| 743 | SECStatus | |||
| 744 | SECMOD_AddNewModule(const char *moduleName, const char *dllPath, | |||
| 745 | unsigned long defaultMechanismFlags, | |||
| 746 | unsigned long cipherEnableFlags) | |||
| 747 | { | |||
| 748 | return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags, | |||
| 749 | cipherEnableFlags, | |||
| 750 | NULL((void*)0), NULL((void*)0)); /* don't pass module or nss params */ | |||
| 751 | } | |||
| 752 | ||||
| 753 | SECStatus | |||
| 754 | SECMOD_UpdateModule(SECMODModule *module) | |||
| 755 | { | |||
| 756 | SECStatus result; | |||
| 757 | ||||
| 758 | result = SECMOD_DeletePermDB(module); | |||
| 759 | ||||
| 760 | if (result == SECSuccess) { | |||
| 761 | result = SECMOD_AddPermDB(module); | |||
| 762 | } | |||
| 763 | return result; | |||
| 764 | } | |||
| 765 | ||||
| 766 | /* Public & Internal(Security Library) representation of | |||
| 767 | * encryption mechanism flags conversion */ | |||
| 768 | ||||
| 769 | /* Currently, the only difference is that internal representation | |||
| 770 | * puts RANDOM_FLAG at bit 31 (Most-significant bit), but | |||
| 771 | * public representation puts this bit at bit 28 | |||
| 772 | */ | |||
| 773 | unsigned long | |||
| 774 | SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) | |||
| 775 | { | |||
| 776 | unsigned long internalFlags = publicFlags; | |||
| 777 | ||||
| 778 | if (publicFlags & PUBLIC_MECH_RANDOM_FLAG0x08000000ul) { | |||
| 779 | internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG0x08000000ul; | |||
| 780 | internalFlags |= SECMOD_RANDOM_FLAG0x80000000L; | |||
| 781 | } | |||
| 782 | return internalFlags; | |||
| 783 | } | |||
| 784 | ||||
| 785 | unsigned long | |||
| 786 | SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) | |||
| 787 | { | |||
| 788 | unsigned long publicFlags = internalFlags; | |||
| 789 | ||||
| 790 | if (internalFlags & SECMOD_RANDOM_FLAG0x80000000L) { | |||
| 791 | publicFlags &= ~SECMOD_RANDOM_FLAG0x80000000L; | |||
| 792 | publicFlags |= PUBLIC_MECH_RANDOM_FLAG0x08000000ul; | |||
| 793 | } | |||
| 794 | return publicFlags; | |||
| 795 | } | |||
| 796 | ||||
| 797 | /* Public & Internal(Security Library) representation of */ | |||
| 798 | /* cipher flags conversion */ | |||
| 799 | /* Note: currently they are just stubs */ | |||
| 800 | unsigned long | |||
| 801 | SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) | |||
| 802 | { | |||
| 803 | return publicFlags; | |||
| 804 | } | |||
| 805 | ||||
| 806 | unsigned long | |||
| 807 | SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) | |||
| 808 | { | |||
| 809 | return internalFlags; | |||
| 810 | } | |||
| 811 | ||||
| 812 | /* Funtion reports true if module of modType is installed/configured */ | |||
| 813 | PRBool | |||
| 814 | SECMOD_IsModulePresent(unsigned long int pubCipherEnableFlags) | |||
| 815 | { | |||
| 816 | PRBool result = PR_FALSE0; | |||
| 817 | SECMODModuleList *mods; | |||
| 818 | ||||
| 819 | if (!moduleLock) { | |||
| 820 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 821 | return result; | |||
| 822 | } | |||
| 823 | SECMOD_GetReadLock(moduleLock); | |||
| 824 | mods = SECMOD_GetDefaultModuleList(); | |||
| 825 | for (; mods != NULL((void*)0); mods = mods->next) { | |||
| 826 | if (mods->module->ssl[0] & | |||
| 827 | SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { | |||
| 828 | result = PR_TRUE1; | |||
| 829 | } | |||
| 830 | } | |||
| 831 | ||||
| 832 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 833 | return result; | |||
| 834 | } | |||
| 835 | ||||
| 836 | /* create a new ModuleListElement */ | |||
| 837 | SECMODModuleList * | |||
| 838 | SECMOD_NewModuleListElement(void) | |||
| 839 | { | |||
| 840 | SECMODModuleList *newModList; | |||
| 841 | ||||
| 842 | newModList = (SECMODModuleList *)PORT_AllocPORT_Alloc_Util(sizeof(SECMODModuleList)); | |||
| 843 | if (newModList) { | |||
| 844 | newModList->next = NULL((void*)0); | |||
| 845 | newModList->module = NULL((void*)0); | |||
| 846 | } | |||
| 847 | return newModList; | |||
| 848 | } | |||
| 849 | ||||
| 850 | /* | |||
| 851 | * make a new reference to a module so It doesn't go away on us | |||
| 852 | */ | |||
| 853 | SECMODModule * | |||
| 854 | SECMOD_ReferenceModule(SECMODModule *module) | |||
| 855 | { | |||
| 856 | PZ_Lock(module->refLock)PR_Lock((module->refLock)); | |||
| 857 | PORT_Assert(module->refCount > 0)((module->refCount > 0)?((void)0):PR_Assert("module->refCount > 0" ,"/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",857 )); | |||
| 858 | ||||
| 859 | module->refCount++; | |||
| 860 | PZ_Unlock(module->refLock)PR_Unlock((module->refLock)); | |||
| 861 | return module; | |||
| 862 | } | |||
| 863 | ||||
| 864 | /* destroy an existing module */ | |||
| 865 | void | |||
| 866 | SECMOD_DestroyModule(SECMODModule *module) | |||
| 867 | { | |||
| 868 | PRBool willfree = PR_FALSE0; | |||
| 869 | int slotCount; | |||
| 870 | int i; | |||
| 871 | ||||
| 872 | PZ_Lock(module->refLock)PR_Lock((module->refLock)); | |||
| 873 | if (module->refCount-- == 1) { | |||
| 874 | willfree = PR_TRUE1; | |||
| 875 | } | |||
| 876 | PORT_Assert(willfree || (module->refCount > 0))((willfree || (module->refCount > 0))?((void)0):PR_Assert ("willfree || (module->refCount > 0)","/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c" ,876)); | |||
| 877 | PZ_Unlock(module->refLock)PR_Unlock((module->refLock)); | |||
| 878 | ||||
| 879 | if (!willfree) { | |||
| 880 | return; | |||
| 881 | } | |||
| 882 | ||||
| 883 | if (module->parent != NULL((void*)0)) { | |||
| 884 | SECMODModule *parent = module->parent; | |||
| 885 | /* paranoia, don't loop forever if the modules are looped */ | |||
| 886 | module->parent = NULL((void*)0); | |||
| 887 | SECMOD_DestroyModule(parent); | |||
| 888 | } | |||
| 889 | ||||
| 890 | /* slots can't really disappear until our module starts freeing them, | |||
| 891 | * so this check is safe */ | |||
| 892 | slotCount = module->slotCount; | |||
| 893 | if (slotCount == 0) { | |||
| 894 | SECMOD_SlotDestroyModule(module, PR_FALSE0); | |||
| 895 | return; | |||
| 896 | } | |||
| 897 | ||||
| 898 | /* now free all out slots, when they are done, they will cause the | |||
| 899 | * module to disappear altogether */ | |||
| 900 | for (i = 0; i < slotCount; i++) { | |||
| 901 | if (!module->slots[i]->disabled) { | |||
| 902 | PK11_ClearSlotList(module->slots[i]); | |||
| 903 | } | |||
| 904 | PK11_FreeSlot(module->slots[i]); | |||
| 905 | } | |||
| 906 | /* WARNING: once the last slot has been freed is it possible (even likely) | |||
| 907 | * that module is no more... touching it now is a good way to go south */ | |||
| 908 | } | |||
| 909 | ||||
| 910 | /* we can only get here if we've destroyed the module, or some one has | |||
| 911 | * erroneously freed a slot that wasn't referenced. */ | |||
| 912 | void | |||
| 913 | SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) | |||
| 914 | { | |||
| 915 | PRBool willfree = PR_FALSE0; | |||
| 916 | if (fromSlot) { | |||
| 917 | PORT_Assert(module->refCount == 0)((module->refCount == 0)?((void)0):PR_Assert("module->refCount == 0" ,"/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",917 )); | |||
| 918 | PZ_Lock(module->refLock)PR_Lock((module->refLock)); | |||
| 919 | if (module->slotCount-- == 1) { | |||
| 920 | willfree = PR_TRUE1; | |||
| 921 | } | |||
| 922 | PORT_Assert(willfree || (module->slotCount > 0))((willfree || (module->slotCount > 0))?((void)0):PR_Assert ("willfree || (module->slotCount > 0)","/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c" ,922)); | |||
| 923 | PZ_Unlock(module->refLock)PR_Unlock((module->refLock)); | |||
| 924 | if (!willfree) | |||
| 925 | return; | |||
| 926 | } | |||
| 927 | ||||
| 928 | if (module == pendingModule) { | |||
| 929 | pendingModule = NULL((void*)0); | |||
| 930 | } | |||
| 931 | ||||
| 932 | if (module->loaded) { | |||
| 933 | SECMOD_UnloadModule(module); | |||
| 934 | } | |||
| 935 | PZ_DestroyLock(module->refLock)PR_DestroyLock((module->refLock)); | |||
| 936 | PORT_FreeArenaPORT_FreeArena_Util(module->arena, PR_FALSE0); | |||
| 937 | secmod_PrivateModuleCount--; | |||
| 938 | } | |||
| 939 | ||||
| 940 | /* destroy a list element | |||
| 941 | * this destroys a single element, and returns the next element | |||
| 942 | * on the chain. It makes it easy to implement for loops to delete | |||
| 943 | * the chain. It also make deleting a single element easy */ | |||
| 944 | SECMODModuleList * | |||
| 945 | SECMOD_DestroyModuleListElement(SECMODModuleList *element) | |||
| 946 | { | |||
| 947 | SECMODModuleList *next = element->next; | |||
| 948 | ||||
| 949 | if (element->module) { | |||
| 950 | SECMOD_DestroyModule(element->module); | |||
| 951 | element->module = NULL((void*)0); | |||
| 952 | } | |||
| 953 | PORT_FreePORT_Free_Util(element); | |||
| 954 | return next; | |||
| 955 | } | |||
| 956 | ||||
| 957 | /* | |||
| 958 | * Destroy an entire module list | |||
| 959 | */ | |||
| 960 | void | |||
| 961 | SECMOD_DestroyModuleList(SECMODModuleList *list) | |||
| 962 | { | |||
| 963 | SECMODModuleList *lp; | |||
| 964 | ||||
| 965 | for (lp = list; lp != NULL((void*)0); lp = SECMOD_DestroyModuleListElement(lp)) | |||
| 966 | ; | |||
| 967 | } | |||
| 968 | ||||
| 969 | PRBool | |||
| 970 | SECMOD_CanDeleteInternalModule(void) | |||
| 971 | { | |||
| 972 | #ifdef NSS_FIPS_DISABLED1 | |||
| 973 | return PR_FALSE0; | |||
| 974 | #else | |||
| 975 | return (PRBool)((pendingModule == NULL((void*)0)) && !SECMOD_GetSystemFIPSEnabled()); | |||
| 976 | #endif | |||
| 977 | } | |||
| 978 | ||||
| 979 | /* | |||
| 980 | * check to see if the module has added new slots. PKCS 11 v2.20 allows for | |||
| 981 | * modules to add new slots, but never remove them. Slots cannot be added | |||
| 982 | * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent | |||
| 983 | * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently | |||
| 984 | * grow on the caller. It is permissible for the slots to increase between | |||
| 985 | * successive calls with NULL to get the size. | |||
| 986 | * | |||
| 987 | * Caller must not hold a module list read lock. | |||
| 988 | */ | |||
| 989 | SECStatus | |||
| 990 | SECMOD_UpdateSlotList(SECMODModule *mod) | |||
| 991 | { | |||
| 992 | CK_RV crv; | |||
| 993 | CK_ULONG count; | |||
| 994 | CK_ULONG i, oldCount; | |||
| 995 | PRBool freeRef = PR_FALSE0; | |||
| 996 | void *mark = NULL((void*)0); | |||
| 997 | CK_ULONG *slotIDs = NULL((void*)0); | |||
| 998 | PK11SlotInfo **newSlots = NULL((void*)0); | |||
| 999 | PK11SlotInfo **oldSlots = NULL((void*)0); | |||
| 1000 | ||||
| 1001 | if (!moduleLock) { | |||
| 1002 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 1003 | return SECFailure; | |||
| 1004 | } | |||
| 1005 | ||||
| 1006 | /* C_GetSlotList is not a session function, make sure | |||
| 1007 | * calls are serialized */ | |||
| 1008 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1009 | freeRef = PR_TRUE1; | |||
| 1010 | /* see if the number of slots have changed */ | |||
| 1011 | crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_GetSlotList(PR_FALSE0, NULL((void*)0), &count); | |||
| 1012 | if (crv != CKR_OK0x00000000UL) { | |||
| 1013 | PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv)); | |||
| 1014 | goto loser; | |||
| 1015 | } | |||
| 1016 | /* nothing new, blow out early, we want this function to be quick | |||
| 1017 | * and cheap in the normal case */ | |||
| 1018 | if (count == mod->slotCount) { | |||
| 1019 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1020 | return SECSuccess; | |||
| 1021 | } | |||
| 1022 | if (count < (CK_ULONG)mod->slotCount) { | |||
| 1023 | /* shouldn't happen with a properly functioning PKCS #11 module */ | |||
| 1024 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INCOMPATIBLE_PKCS11); | |||
| 1025 | goto loser; | |||
| 1026 | } | |||
| 1027 | ||||
| 1028 | /* get the new slot list */ | |||
| 1029 | slotIDs = PORT_NewArray(CK_SLOT_ID, count)(CK_SLOT_ID *)PORT_Alloc_Util(sizeof(CK_SLOT_ID) * (count)); | |||
| 1030 | if (slotIDs == NULL((void*)0)) { | |||
| 1031 | goto loser; | |||
| 1032 | } | |||
| 1033 | ||||
| 1034 | crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_GetSlotList(PR_FALSE0, slotIDs, &count); | |||
| 1035 | if (crv != CKR_OK0x00000000UL) { | |||
| 1036 | PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv)); | |||
| 1037 | goto loser; | |||
| 1038 | } | |||
| 1039 | freeRef = PR_FALSE0; | |||
| 1040 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1041 | mark = PORT_ArenaMarkPORT_ArenaMark_Util(mod->arena); | |||
| 1042 | if (mark == NULL((void*)0)) { | |||
| 1043 | goto loser; | |||
| 1044 | } | |||
| 1045 | newSlots = PORT_ArenaZNewArray(mod->arena, PK11SlotInfo *, count)(PK11SlotInfo * *)PORT_ArenaZAlloc_Util(mod->arena, sizeof (PK11SlotInfo *) * (count)); | |||
| 1046 | ||||
| 1047 | /* walk down the new slot ID list returned from the module. We keep | |||
| 1048 | * the old slots which match a returned ID, and we initialize the new | |||
| 1049 | * slots. */ | |||
| 1050 | for (i = 0; i < count; i++) { | |||
| 1051 | PK11SlotInfo *slot = SECMOD_FindSlotByID(mod, slotIDs[i]); | |||
| 1052 | ||||
| 1053 | if (!slot) { | |||
| 1054 | /* we have a new slot create a new slot data structure */ | |||
| 1055 | slot = PK11_NewSlotInfo(mod); | |||
| 1056 | if (!slot) { | |||
| 1057 | goto loser; | |||
| 1058 | } | |||
| 1059 | PK11_InitSlot(mod, slotIDs[i], slot); | |||
| 1060 | STAN_InitTokenForSlotInfo(NULL((void*)0), slot); | |||
| 1061 | } | |||
| 1062 | newSlots[i] = slot; | |||
| 1063 | } | |||
| 1064 | STAN_ResetTokenInterator(NULL((void*)0)); | |||
| 1065 | PORT_FreePORT_Free_Util(slotIDs); | |||
| 1066 | slotIDs = NULL((void*)0); | |||
| 1067 | PORT_ArenaUnmarkPORT_ArenaUnmark_Util(mod->arena, mark); | |||
| 1068 | ||||
| 1069 | /* until this point we're still using the old slot list. Now we update | |||
| 1070 | * module slot list. We update the slots (array) first then the count, | |||
| 1071 | * since we've already guarrenteed that count has increased (just in case | |||
| 1072 | * someone is looking at the slots field of module without holding the | |||
| 1073 | * moduleLock */ | |||
| 1074 | SECMOD_GetWriteLock(moduleLock); | |||
| 1075 | oldCount = mod->slotCount; | |||
| 1076 | oldSlots = mod->slots; | |||
| 1077 | mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is | |||
| 1078 | * allocated out of the module arena and won't | |||
| 1079 | * be freed until the module is freed */ | |||
| 1080 | mod->slotCount = count; | |||
| 1081 | SECMOD_ReleaseWriteLock(moduleLock); | |||
| 1082 | /* free our old references before forgetting about oldSlot*/ | |||
| 1083 | for (i = 0; i < oldCount; i++) { | |||
| 1084 | PK11_FreeSlot(oldSlots[i]); | |||
| 1085 | } | |||
| 1086 | return SECSuccess; | |||
| 1087 | ||||
| 1088 | loser: | |||
| 1089 | if (freeRef) { | |||
| 1090 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1091 | } | |||
| 1092 | if (slotIDs) { | |||
| 1093 | PORT_FreePORT_Free_Util(slotIDs); | |||
| 1094 | } | |||
| 1095 | /* free all the slots we allocated. newSlots are part of the | |||
| 1096 | * mod arena. NOTE: the newSlots array contain both new and old | |||
| 1097 | * slots, but we kept a reference to the old slots when we built the new | |||
| 1098 | * array, so we need to free all the slots in newSlots array. */ | |||
| 1099 | if (newSlots) { | |||
| 1100 | for (i = 0; i < count; i++) { | |||
| 1101 | if (newSlots[i] == NULL((void*)0)) { | |||
| 1102 | break; /* hit the last one */ | |||
| 1103 | } | |||
| 1104 | PK11_FreeSlot(newSlots[i]); | |||
| 1105 | } | |||
| 1106 | } | |||
| 1107 | /* must come after freeing newSlots */ | |||
| 1108 | if (mark) { | |||
| 1109 | PORT_ArenaReleasePORT_ArenaRelease_Util(mod->arena, mark); | |||
| 1110 | } | |||
| 1111 | return SECFailure; | |||
| 1112 | } | |||
| 1113 | ||||
| 1114 | /* | |||
| 1115 | * this handles modules that do not support C_WaitForSlotEvent(). | |||
| 1116 | * The internal flags are stored. Note that C_WaitForSlotEvent() does not | |||
| 1117 | * have a timeout, so we don't have one for handleWaitForSlotEvent() either. | |||
| 1118 | */ | |||
| 1119 | PK11SlotInfo * | |||
| 1120 | secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, | |||
| 1121 | PRIntervalTime latency) | |||
| 1122 | { | |||
| 1123 | PRBool removableSlotsFound = PR_FALSE0; | |||
| 1124 | int i; | |||
| 1125 | int error = SEC_ERROR_NO_EVENT; | |||
| 1126 | ||||
| 1127 | if (!moduleLock) { | |||
| 1128 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 1129 | return NULL((void*)0); | |||
| 1130 | } | |||
| 1131 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1132 | if (mod->evControlMask & SECMOD_END_WAIT0x01) { | |||
| 1133 | mod->evControlMask &= ~SECMOD_END_WAIT0x01; | |||
| 1134 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1135 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_EVENT); | |||
| 1136 | return NULL((void*)0); | |||
| 1137 | } | |||
| 1138 | mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT0x02; | |||
| 1139 | while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT0x02) { | |||
| 1140 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1141 | /* now is a good time to see if new slots have been added */ | |||
| 1142 | SECMOD_UpdateSlotList(mod); | |||
| 1143 | ||||
| 1144 | /* loop through all the slots on a module */ | |||
| 1145 | SECMOD_GetReadLock(moduleLock); | |||
| 1146 | for (i = 0; i < mod->slotCount; i++) { | |||
| 1147 | PK11SlotInfo *slot = mod->slots[i]; | |||
| 1148 | PRUint16 series; | |||
| 1149 | PRBool present; | |||
| 1150 | ||||
| 1151 | /* perm modules do not change */ | |||
| 1152 | if (slot->isPerm) { | |||
| 1153 | continue; | |||
| 1154 | } | |||
| 1155 | removableSlotsFound = PR_TRUE1; | |||
| 1156 | /* simulate the PKCS #11 module flags. are the flags different | |||
| 1157 | * from the last time we called? */ | |||
| 1158 | series = slot->series; | |||
| 1159 | present = PK11_IsPresent(slot); | |||
| 1160 | if ((slot->flagSeries != series) || (slot->flagState != present)) { | |||
| 1161 | slot->flagState = present; | |||
| 1162 | slot->flagSeries = series; | |||
| 1163 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 1164 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1165 | mod->evControlMask &= ~SECMOD_END_WAIT0x01; | |||
| 1166 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1167 | return PK11_ReferenceSlot(slot); | |||
| 1168 | } | |||
| 1169 | } | |||
| 1170 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 1171 | /* if everything was perm modules, don't lock up forever */ | |||
| 1172 | if ((mod->slotCount != 0) && !removableSlotsFound) { | |||
| 1173 | error = SEC_ERROR_NO_SLOT_SELECTED; | |||
| 1174 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1175 | break; | |||
| 1176 | } | |||
| 1177 | if (flags & CKF_DONT_BLOCK1) { | |||
| 1178 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1179 | break; | |||
| 1180 | } | |||
| 1181 | PR_Sleep(latency); | |||
| 1182 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1183 | } | |||
| 1184 | mod->evControlMask &= ~SECMOD_END_WAIT0x01; | |||
| 1185 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1186 | PORT_SetErrorPORT_SetError_Util(error); | |||
| 1187 | return NULL((void*)0); | |||
| 1188 | } | |||
| 1189 | ||||
| 1190 | /* | |||
| 1191 | * this function waits for a token event on any slot of a given module | |||
| 1192 | * This function should not be called from more than one thread of the | |||
| 1193 | * same process (though other threads can make other library calls | |||
| 1194 | * on this module while this call is blocked). | |||
| 1195 | */ | |||
| 1196 | PK11SlotInfo * | |||
| 1197 | SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, | |||
| 1198 | PRIntervalTime latency) | |||
| 1199 | { | |||
| 1200 | CK_SLOT_ID id; | |||
| 1201 | CK_RV crv; | |||
| 1202 | PK11SlotInfo *slot; | |||
| 1203 | ||||
| 1204 | if (!pk11_getFinalizeModulesOption() || | |||
| 1205 | ((mod->cryptokiVersion.major == 2) && | |||
| 1206 | (mod->cryptokiVersion.minor < 1))) { | |||
| 1207 | /* if we are sharing the module with other software in our | |||
| 1208 | * address space, we can't reliably use C_WaitForSlotEvent(), | |||
| 1209 | * and if the module is version 2.0, C_WaitForSlotEvent() doesn't | |||
| 1210 | * exist */ | |||
| 1211 | return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |||
| 1212 | } | |||
| 1213 | /* first the the PKCS #11 call */ | |||
| 1214 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1215 | if (mod->evControlMask & SECMOD_END_WAIT0x01) { | |||
| 1216 | goto end_wait; | |||
| 1217 | } | |||
| 1218 | mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT0x04; | |||
| 1219 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1220 | crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_WaitForSlotEvent(flags, &id, NULL((void*)0)); | |||
| 1221 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1222 | mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT0x04; | |||
| 1223 | /* if we are in end wait, short circuit now, don't even risk | |||
| 1224 | * going into secmod_HandleWaitForSlotEvent */ | |||
| 1225 | if (mod->evControlMask & SECMOD_END_WAIT0x01) { | |||
| 1226 | goto end_wait; | |||
| 1227 | } | |||
| 1228 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1229 | if (crv == CKR_FUNCTION_NOT_SUPPORTED0x00000054UL) { | |||
| 1230 | /* module doesn't support that call, simulate it */ | |||
| 1231 | return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |||
| 1232 | } | |||
| 1233 | if (crv != CKR_OK0x00000000UL) { | |||
| 1234 | /* we can get this error if finalize was called while we were | |||
| 1235 | * still running. This is the only way to force a C_WaitForSlotEvent() | |||
| 1236 | * to return in PKCS #11. In this case, just return that there | |||
| 1237 | * was no event. */ | |||
| 1238 | if (crv == CKR_CRYPTOKI_NOT_INITIALIZED0x00000190UL) { | |||
| 1239 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_EVENT); | |||
| 1240 | } else { | |||
| 1241 | PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv)); | |||
| 1242 | } | |||
| 1243 | return NULL((void*)0); | |||
| 1244 | } | |||
| 1245 | slot = SECMOD_FindSlotByID(mod, id); | |||
| 1246 | if (slot == NULL((void*)0)) { | |||
| 1247 | /* possibly a new slot that was added? */ | |||
| 1248 | SECMOD_UpdateSlotList(mod); | |||
| 1249 | slot = SECMOD_FindSlotByID(mod, id); | |||
| 1250 | } | |||
| 1251 | /* if we are in the delay period for the "isPresent" call, reset | |||
| 1252 | * the delay since we know things have probably changed... */ | |||
| 1253 | if (slot) { | |||
| 1254 | NSSToken *nssToken = PK11Slot_GetNSSToken(slot); | |||
| 1255 | if (nssToken) { | |||
| 1256 | if (nssToken->slot) { | |||
| 1257 | nssSlot_ResetDelay(nssToken->slot); | |||
| 1258 | } | |||
| 1259 | (void)nssToken_Destroy(nssToken); | |||
| 1260 | } | |||
| 1261 | } | |||
| 1262 | return slot; | |||
| 1263 | ||||
| 1264 | /* must be called with the lock on. */ | |||
| 1265 | end_wait: | |||
| 1266 | mod->evControlMask &= ~SECMOD_END_WAIT0x01; | |||
| 1267 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1268 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_EVENT); | |||
| 1269 | return NULL((void*)0); | |||
| 1270 | } | |||
| 1271 | ||||
| 1272 | /* | |||
| 1273 | * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic | |||
| 1274 | * function, possibly bringing down the pkcs #11 module in question. This | |||
| 1275 | * should be OK because 1) it does reinitialize, and 2) it should only be | |||
| 1276 | * called when we are on our way to tear the whole system down anyway. | |||
| 1277 | */ | |||
| 1278 | SECStatus | |||
| 1279 | SECMOD_CancelWait(SECMODModule *mod) | |||
| 1280 | { | |||
| 1281 | unsigned long controlMask; | |||
| 1282 | SECStatus rv = SECSuccess; | |||
| 1283 | CK_RV crv; | |||
| 1284 | ||||
| 1285 | PZ_Lock(mod->refLock)PR_Lock((mod->refLock)); | |||
| 1286 | mod->evControlMask |= SECMOD_END_WAIT0x01; | |||
| 1287 | controlMask = mod->evControlMask; | |||
| 1288 | if (controlMask & SECMOD_WAIT_PKCS11_EVENT0x04) { | |||
| 1289 | if (!pk11_getFinalizeModulesOption()) { | |||
| 1290 | /* can't get here unless pk11_getFinalizeModulesOption is set */ | |||
| 1291 | PORT_Assert(0)((0)?((void)0):PR_Assert("0","/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c" ,1291)); | |||
| 1292 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE); | |||
| 1293 | rv = SECFailure; | |||
| 1294 | goto loser; | |||
| 1295 | } | |||
| 1296 | /* NOTE: this call will drop all transient keys, in progress | |||
| 1297 | * operations, and any authentication. This is the only documented | |||
| 1298 | * way to get WaitForSlotEvent to return. Also note: for non-thread | |||
| 1299 | * safe tokens, we need to hold the module lock, this is not yet at | |||
| 1300 | * system shutdown/startup time, so we need to protect these calls */ | |||
| 1301 | crv = PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_Finalize(NULL((void*)0)); | |||
| 1302 | /* ok, we slammed the module down, now we need to reinit it in case | |||
| 1303 | * we intend to use it again */ | |||
| 1304 | if (CKR_OK0x00000000UL == crv) { | |||
| 1305 | PRBool alreadyLoaded; | |||
| 1306 | secmod_ModuleInit(mod, NULL((void*)0), &alreadyLoaded); | |||
| 1307 | } else { | |||
| 1308 | /* Finalized failed for some reason, notify the application | |||
| 1309 | * so maybe it has a prayer of recovering... */ | |||
| 1310 | PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv)); | |||
| 1311 | rv = SECFailure; | |||
| 1312 | } | |||
| 1313 | } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT0x02) { | |||
| 1314 | mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT0x02; | |||
| 1315 | /* Simulated events will eventually timeout | |||
| 1316 | * and wake up in the loop */ | |||
| 1317 | } | |||
| 1318 | loser: | |||
| 1319 | PZ_Unlock(mod->refLock)PR_Unlock((mod->refLock)); | |||
| 1320 | return rv; | |||
| 1321 | } | |||
| 1322 | ||||
| 1323 | /* | |||
| 1324 | * check to see if the module has removable slots that we may need to | |||
| 1325 | * watch for. | |||
| 1326 | */ | |||
| 1327 | PRBool | |||
| 1328 | SECMOD_HasRemovableSlots(SECMODModule *mod) | |||
| 1329 | { | |||
| 1330 | PRBool ret = PR_FALSE0; | |||
| 1331 | if (!moduleLock) { | |||
| 1332 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 1333 | return ret; | |||
| 1334 | } | |||
| 1335 | SECMOD_GetReadLock(moduleLock); | |||
| 1336 | ret = SECMOD_LockedModuleHasRemovableSlots(mod); | |||
| 1337 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 1338 | return ret; | |||
| 1339 | } | |||
| 1340 | ||||
| 1341 | PRBool | |||
| 1342 | SECMOD_LockedModuleHasRemovableSlots(SECMODModule *mod) | |||
| 1343 | { | |||
| 1344 | int i; | |||
| 1345 | PRBool ret; | |||
| 1346 | if (mod->slotCount == 0) { | |||
| 1347 | return PR_TRUE1; | |||
| 1348 | } | |||
| 1349 | ||||
| 1350 | ret = PR_FALSE0; | |||
| 1351 | for (i = 0; i < mod->slotCount; i++) { | |||
| 1352 | PK11SlotInfo *slot = mod->slots[i]; | |||
| 1353 | /* perm modules are not inserted or removed */ | |||
| 1354 | if (slot->isPerm) { | |||
| 1355 | continue; | |||
| 1356 | } | |||
| 1357 | ret = PR_TRUE1; | |||
| 1358 | break; | |||
| 1359 | } | |||
| 1360 | return ret; | |||
| 1361 | } | |||
| 1362 | ||||
| 1363 | /* | |||
| 1364 | * helper function to actually create and destroy user defined slots | |||
| 1365 | */ | |||
| 1366 | static SECStatus | |||
| 1367 | secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass, | |||
| 1368 | const char *sendSpec) | |||
| 1369 | { | |||
| 1370 | CK_OBJECT_HANDLE dummy; | |||
| 1371 | CK_ATTRIBUTE template[2]; | |||
| 1372 | CK_ATTRIBUTE *attrs = template; | |||
| 1373 | CK_RV crv; | |||
| 1374 | ||||
| 1375 | PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass))(attrs)->type = (0x00000000UL); (attrs)->pValue = (& objClass); (attrs)->ulValueLen = (sizeof(objClass));; | |||
| 1376 | attrs++; | |||
| 1377 | PK11_SETATTRS(attrs, CKA_NSS_MODULE_SPEC, (unsigned char *)sendSpec,(attrs)->type = (((0x80000000UL | 0x4E534350) + 24)); (attrs )->pValue = ((unsigned char *)sendSpec); (attrs)->ulValueLen = (strlen(sendSpec) + 1); | |||
| 1378 | strlen(sendSpec) + 1)(attrs)->type = (((0x80000000UL | 0x4E534350) + 24)); (attrs )->pValue = ((unsigned char *)sendSpec); (attrs)->ulValueLen = (strlen(sendSpec) + 1);; | |||
| 1379 | attrs++; | |||
| 1380 | ||||
| 1381 | PORT_Assert(attrs - template <= 2)((attrs - template <= 2)?((void)0):PR_Assert("attrs - template <= 2" ,"/root/firefox-clang/security/nss/lib/pk11wrap/pk11util.c",1381 )); | |||
| 1382 | ||||
| 1383 | PK11_EnterSlotMonitor(slot); | |||
| 1384 | crv = PK11_CreateNewObject(slot, slot->session, | |||
| 1385 | template, attrs - template, PR_FALSE0, &dummy); | |||
| 1386 | PK11_ExitSlotMonitor(slot); | |||
| 1387 | ||||
| 1388 | if (crv != CKR_OK0x00000000UL) { | |||
| 1389 | PORT_SetErrorPORT_SetError_Util(PK11_MapError(crv)); | |||
| 1390 | return SECFailure; | |||
| 1391 | } | |||
| 1392 | return SECMOD_UpdateSlotList(slot->module); | |||
| 1393 | } | |||
| 1394 | ||||
| 1395 | /* | |||
| 1396 | * return true if the selected slot ID is not present or doesn't exist | |||
| 1397 | */ | |||
| 1398 | static PRBool | |||
| 1399 | secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID) | |||
| 1400 | { | |||
| 1401 | PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID); | |||
| 1402 | if (slot) { | |||
| 1403 | PRBool present = PK11_IsPresent(slot); | |||
| 1404 | PK11_FreeSlot(slot); | |||
| 1405 | if (present) { | |||
| 1406 | return PR_FALSE0; | |||
| 1407 | } | |||
| 1408 | } | |||
| 1409 | /* it doesn't exist or isn't present, it's available */ | |||
| 1410 | return PR_TRUE1; | |||
| 1411 | } | |||
| 1412 | ||||
| 1413 | /* | |||
| 1414 | * Find an unused slot id in module. | |||
| 1415 | */ | |||
| 1416 | static CK_SLOT_ID | |||
| 1417 | secmod_FindFreeSlot(SECMODModule *mod) | |||
| 1418 | { | |||
| 1419 | CK_SLOT_ID i, minSlotID, maxSlotID; | |||
| 1420 | ||||
| 1421 | /* look for a free slot id on the internal module */ | |||
| 1422 | if (mod->internal && mod->isFIPS) { | |||
| 1423 | minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID101; | |||
| 1424 | maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID127; | |||
| 1425 | } else { | |||
| 1426 | minSlotID = SFTK_MIN_USER_SLOT_ID4; | |||
| 1427 | maxSlotID = SFTK_MAX_USER_SLOT_ID100; | |||
| 1428 | } | |||
| 1429 | for (i = minSlotID; i < maxSlotID; i++) { | |||
| 1430 | if (secmod_SlotIsEmpty(mod, i)) { | |||
| 1431 | return i; | |||
| 1432 | } | |||
| 1433 | } | |||
| 1434 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_SLOT_SELECTED); | |||
| 1435 | return (CK_SLOT_ID)-1; | |||
| 1436 | } | |||
| 1437 | ||||
| 1438 | /* | |||
| 1439 | * Attempt to open a new slot. | |||
| 1440 | * | |||
| 1441 | * This works the same os OpenUserDB except it can be called against | |||
| 1442 | * any module that understands the softoken protocol for opening new | |||
| 1443 | * slots, not just the softoken itself. If the selected module does not | |||
| 1444 | * understand the protocol, C_CreateObject will fail with | |||
| 1445 | * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set | |||
| 1446 | * SEC_ERROR_BAD_DATA. | |||
| 1447 | * | |||
| 1448 | * NewSlots can be closed with SECMOD_CloseUserDB(); | |||
| 1449 | * | |||
| 1450 | * Modulespec is module dependent. | |||
| 1451 | */ | |||
| 1452 | PK11SlotInfo * | |||
| 1453 | SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec) | |||
| 1454 | { | |||
| 1455 | CK_SLOT_ID slotID = 0; | |||
| 1456 | PK11SlotInfo *slot; | |||
| 1457 | char *escSpec; | |||
| 1458 | char *sendSpec; | |||
| 1459 | SECStatus rv; | |||
| 1460 | ||||
| 1461 | slotID = secmod_FindFreeSlot(mod); | |||
| 1462 | if (slotID == (CK_SLOT_ID)-1) { | |||
| 1463 | return NULL((void*)0); | |||
| 1464 | } | |||
| 1465 | ||||
| 1466 | if (mod->slotCount == 0) { | |||
| 1467 | return NULL((void*)0); | |||
| 1468 | } | |||
| 1469 | ||||
| 1470 | /* just grab the first slot in the module, any present slot should work */ | |||
| 1471 | slot = PK11_ReferenceSlot(mod->slots[0]); | |||
| 1472 | if (slot == NULL((void*)0)) { | |||
| 1473 | return NULL((void*)0); | |||
| 1474 | } | |||
| 1475 | ||||
| 1476 | /* we've found the slot, now build the moduleSpec */ | |||
| 1477 | escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']'); | |||
| 1478 | if (escSpec == NULL((void*)0)) { | |||
| 1479 | PK11_FreeSlot(slot); | |||
| 1480 | return NULL((void*)0); | |||
| 1481 | } | |||
| 1482 | sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec); | |||
| 1483 | PORT_FreePORT_Free_Util(escSpec); | |||
| 1484 | ||||
| 1485 | if (sendSpec == NULL((void*)0)) { | |||
| 1486 | /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */ | |||
| 1487 | PK11_FreeSlot(slot); | |||
| 1488 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY); | |||
| 1489 | return NULL((void*)0); | |||
| 1490 | } | |||
| 1491 | rv = secmod_UserDBOp(slot, CKO_NSS_NEWSLOT((0x80000000UL | 0x4E534350) + 5), sendSpec); | |||
| 1492 | PR_smprintf_free(sendSpec); | |||
| 1493 | PK11_FreeSlot(slot); | |||
| 1494 | if (rv != SECSuccess) { | |||
| 1495 | return NULL((void*)0); | |||
| 1496 | } | |||
| 1497 | ||||
| 1498 | slot = SECMOD_FindSlotByID(mod, slotID); | |||
| 1499 | if (slot) { | |||
| 1500 | /* if we are in the delay period for the "isPresent" call, reset | |||
| 1501 | * the delay since we know things have probably changed... */ | |||
| 1502 | NSSToken *nssToken = PK11Slot_GetNSSToken(slot); | |||
| 1503 | if (nssToken) { | |||
| 1504 | if (nssToken->slot) { | |||
| 1505 | nssSlot_ResetDelay(nssToken->slot); | |||
| 1506 | } | |||
| 1507 | (void)nssToken_Destroy(nssToken); | |||
| 1508 | } | |||
| 1509 | /* force the slot info structures to properly reset */ | |||
| 1510 | (void)PK11_IsPresent(slot); | |||
| 1511 | } | |||
| 1512 | return slot; | |||
| 1513 | } | |||
| 1514 | ||||
| 1515 | /* | |||
| 1516 | * given a module spec, find the slot in the module for it. | |||
| 1517 | */ | |||
| 1518 | PK11SlotInfo * | |||
| 1519 | secmod_FindSlotFromModuleSpec(const char *moduleSpec, SECMODModule *module) | |||
| 1520 | { | |||
| 1521 | CK_SLOT_ID slot_id = secmod_GetSlotIDFromModuleSpec(moduleSpec, module); | |||
| 1522 | if (slot_id == -1) { | |||
| 1523 | return NULL((void*)0); | |||
| 1524 | } | |||
| 1525 | ||||
| 1526 | return SECMOD_FindSlotByID(module, slot_id); | |||
| 1527 | } | |||
| 1528 | ||||
| 1529 | /* | |||
| 1530 | * Open a new database using the softoken. The caller is responsible for making | |||
| 1531 | * sure the module spec is correct and usable. The caller should ask for one | |||
| 1532 | * new database per call if the caller wants to get meaningful information | |||
| 1533 | * about the new database. | |||
| 1534 | * | |||
| 1535 | * moduleSpec is the same data that you would pass to softoken at | |||
| 1536 | * initialization time under the 'tokens' options. For example, if you were | |||
| 1537 | * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']> | |||
| 1538 | * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your | |||
| 1539 | * module spec here. The slot ID will be calculated for you by | |||
| 1540 | * SECMOD_OpenUserDB(). | |||
| 1541 | * | |||
| 1542 | * Typical parameters here are configdir, tokenDescription and flags. | |||
| 1543 | * | |||
| 1544 | * a Full list is below: | |||
| 1545 | * | |||
| 1546 | * | |||
| 1547 | * configDir - The location of the databases for this token. If configDir is | |||
| 1548 | * not specified, and noCertDB and noKeyDB is not specified, the load | |||
| 1549 | * will fail. | |||
| 1550 | * certPrefix - Cert prefix for this token. | |||
| 1551 | * keyPrefix - Prefix for the key database for this token. (if not specified, | |||
| 1552 | * certPrefix will be used). | |||
| 1553 | * tokenDescription - The label value for this token returned in the | |||
| 1554 | * CK_TOKEN_INFO structure with an internationalize string (UTF8). | |||
| 1555 | * This value will be truncated at 32 bytes (no NULL, partial UTF8 | |||
| 1556 | * characters dropped). You should specify a user friendly name here | |||
| 1557 | * as this is the value the token will be referred to in most | |||
| 1558 | * application UI's. You should make sure tokenDescription is unique. | |||
| 1559 | * slotDescription - The slotDescription value for this token returned | |||
| 1560 | * in the CK_SLOT_INFO structure with an internationalize string | |||
| 1561 | * (UTF8). This value will be truncated at 64 bytes (no NULL, partial | |||
| 1562 | * UTF8 characters dropped). This name will not change after the | |||
| 1563 | * database is closed. It should have some number to make this unique. | |||
| 1564 | * minPWLen - minimum password length for this token. | |||
| 1565 | * flags - comma separated list of flag values, parsed case-insensitive. | |||
| 1566 | * Valid flags are: | |||
| 1567 | * readOnly - Databases should be opened read only. | |||
| 1568 | * noCertDB - Don't try to open a certificate database. | |||
| 1569 | * noKeyDB - Don't try to open a key database. | |||
| 1570 | * forceOpen - Don't fail to initialize the token if the | |||
| 1571 | * databases could not be opened. | |||
| 1572 | * passwordRequired - zero length passwords are not acceptable | |||
| 1573 | * (valid only if there is a keyDB). | |||
| 1574 | * optimizeSpace - allocate smaller hash tables and lock tables. | |||
| 1575 | * When this flag is not specified, Softoken will allocate | |||
| 1576 | * large tables to prevent lock contention. | |||
| 1577 | */ | |||
| 1578 | PK11SlotInfo * | |||
| 1579 | SECMOD_OpenUserDB(const char *moduleSpec) | |||
| 1580 | { | |||
| 1581 | SECMODModule *mod; | |||
| 1582 | SECMODConfigList *conflist = NULL((void*)0); | |||
| 1583 | int count = 0; | |||
| 1584 | ||||
| 1585 | if (moduleSpec == NULL((void*)0)) { | |||
| 1586 | return NULL((void*)0); | |||
| 1587 | } | |||
| 1588 | ||||
| 1589 | /* NOTE: unlike most PK11 function, this does not return a reference | |||
| 1590 | * to the module */ | |||
| 1591 | mod = SECMOD_GetInternalModule(); | |||
| 1592 | if (!mod) { | |||
| 1593 | /* shouldn't happen */ | |||
| 1594 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LIBRARY_FAILURE); | |||
| 1595 | return NULL((void*)0); | |||
| 1596 | } | |||
| 1597 | ||||
| 1598 | /* make sure we don't open the same database twice. We only understand | |||
| 1599 | * the moduleSpec for internal databases well enough to do this, so only | |||
| 1600 | * do this in OpenUserDB */ | |||
| 1601 | conflist = secmod_GetConfigList(mod->isFIPS, mod->libraryParams, &count); | |||
| 1602 | if (conflist) { | |||
| 1603 | PK11SlotInfo *slot = NULL((void*)0); | |||
| 1604 | if (secmod_MatchConfigList(moduleSpec, conflist, count)) { | |||
| 1605 | slot = secmod_FindSlotFromModuleSpec(moduleSpec, mod); | |||
| 1606 | } | |||
| 1607 | secmod_FreeConfigList(conflist, count); | |||
| 1608 | if (slot) { | |||
| 1609 | return slot; | |||
| 1610 | } | |||
| 1611 | } | |||
| 1612 | return SECMOD_OpenNewSlot(mod, moduleSpec); | |||
| 1613 | } | |||
| 1614 | ||||
| 1615 | /* | |||
| 1616 | * close an already opened user database. NOTE: the database must be | |||
| 1617 | * in the internal token, and must be one created with SECMOD_OpenUserDB(). | |||
| 1618 | * Once the database is closed, the slot will remain as an empty slot | |||
| 1619 | * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot(). | |||
| 1620 | */ | |||
| 1621 | SECStatus | |||
| 1622 | SECMOD_CloseUserDB(PK11SlotInfo *slot) | |||
| 1623 | { | |||
| 1624 | SECStatus rv; | |||
| 1625 | char *sendSpec; | |||
| 1626 | ||||
| 1627 | sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID); | |||
| 1628 | if (sendSpec == NULL((void*)0)) { | |||
| 1629 | /* PR_smprintf does not set no memory error */ | |||
| 1630 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY); | |||
| 1631 | return SECFailure; | |||
| 1632 | } | |||
| 1633 | rv = secmod_UserDBOp(slot, CKO_NSS_DELSLOT((0x80000000UL | 0x4E534350) + 6), sendSpec); | |||
| 1634 | PR_smprintf_free(sendSpec); | |||
| 1635 | /* if we are in the delay period for the "isPresent" call, reset | |||
| 1636 | * the delay since we know things have probably changed... */ | |||
| 1637 | NSSToken *nssToken = PK11Slot_GetNSSToken(slot); | |||
| 1638 | if (nssToken) { | |||
| 1639 | if (nssToken->slot) { | |||
| 1640 | nssSlot_ResetDelay(nssToken->slot); | |||
| 1641 | } | |||
| 1642 | (void)nssToken_Destroy(nssToken); | |||
| 1643 | /* force the slot info structures to properly reset */ | |||
| 1644 | (void)PK11_IsPresent(slot); | |||
| 1645 | } | |||
| 1646 | return rv; | |||
| 1647 | } | |||
| 1648 | ||||
| 1649 | /* | |||
| 1650 | * Restart PKCS #11 modules after a fork(). See secmod.h for more information. | |||
| 1651 | */ | |||
| 1652 | SECStatus | |||
| 1653 | SECMOD_RestartModules(PRBool force) | |||
| 1654 | { | |||
| 1655 | SECMODModuleList *mlp; | |||
| 1656 | SECStatus rrv = SECSuccess; | |||
| 1657 | int lastError = 0; | |||
| 1658 | ||||
| 1659 | if (!moduleLock) { | |||
| 1660 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NOT_INITIALIZED); | |||
| 1661 | return SECFailure; | |||
| 1662 | } | |||
| 1663 | ||||
| 1664 | /* Only need to restart the PKCS #11 modules that were initialized */ | |||
| 1665 | SECMOD_GetReadLock(moduleLock); | |||
| 1666 | for (mlp = modules; mlp != NULL((void*)0); mlp = mlp->next) { | |||
| 1667 | SECMODModule *mod = mlp->module; | |||
| 1668 | CK_ULONG count; | |||
| 1669 | SECStatus rv; | |||
| 1670 | int i; | |||
| 1671 | ||||
| 1672 | /* If the module needs to be reset, do so */ | |||
| 1673 | if (force || (PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_GetSlotList(CK_FALSE0, NULL((void*)0), &count) != CKR_OK0x00000000UL)) { | |||
| 1674 | PRBool alreadyLoaded; | |||
| 1675 | /* first call Finalize. This is not required by PKCS #11, but some | |||
| 1676 | * older modules require it, and it doesn't hurt (compliant modules | |||
| 1677 | * will return CKR_NOT_INITIALIZED */ | |||
| 1678 | (void)PK11_GETTAB(mod)((CK_FUNCTION_LIST_3_0_PTR)((mod)->functionList))->C_Finalize(NULL((void*)0)); | |||
| 1679 | /* now initialize the module, this function reinitializes | |||
| 1680 | * a module in place, preserving existing slots (even if they | |||
| 1681 | * no longer exist) */ | |||
| 1682 | rv = secmod_ModuleInit(mod, NULL((void*)0), &alreadyLoaded); | |||
| 1683 | if (rv != SECSuccess) { | |||
| 1684 | /* save the last error code */ | |||
| 1685 | lastError = PORT_GetErrorPORT_GetError_Util(); | |||
| 1686 | rrv = rv; | |||
| 1687 | /* couldn't reinit the module, disable all its slots */ | |||
| 1688 | for (i = 0; i < mod->slotCount; i++) { | |||
| 1689 | mod->slots[i]->disabled = PR_TRUE1; | |||
| 1690 | mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |||
| 1691 | } | |||
| 1692 | continue; | |||
| 1693 | } | |||
| 1694 | for (i = 0; i < mod->slotCount; i++) { | |||
| 1695 | /* get new token sessions, bump the series up so that | |||
| 1696 | * we refresh other old sessions. This will tell much of | |||
| 1697 | * NSS to flush cached handles it may hold as well */ | |||
| 1698 | rv = PK11_InitToken(mod->slots[i], PR_TRUE1); | |||
| 1699 | /* PK11_InitToken could fail if the slot isn't present. | |||
| 1700 | * If it is present, though, something is wrong and we should | |||
| 1701 | * disable the slot and let the caller know. */ | |||
| 1702 | if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) { | |||
| 1703 | /* save the last error code */ | |||
| 1704 | lastError = PORT_GetErrorPORT_GetError_Util(); | |||
| 1705 | rrv = rv; | |||
| 1706 | /* disable the token */ | |||
| 1707 | mod->slots[i]->disabled = PR_TRUE1; | |||
| 1708 | mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |||
| 1709 | } | |||
| 1710 | } | |||
| 1711 | } | |||
| 1712 | } | |||
| 1713 | SECMOD_ReleaseReadLock(moduleLock); | |||
| 1714 | ||||
| 1715 | /* | |||
| 1716 | * on multiple failures, we are only returning the lastError. The caller | |||
| 1717 | * can determine which slots are bad by calling PK11_IsDisabled(). | |||
| 1718 | */ | |||
| 1719 | if (rrv != SECSuccess) { | |||
| 1720 | /* restore the last error code */ | |||
| 1721 | PORT_SetErrorPORT_SetError_Util(lastError); | |||
| 1722 | } | |||
| 1723 | ||||
| 1724 | return rrv; | |||
| 1725 | } |