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