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