security/nss/lib/pk11wrap/pk11util.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial