| Index: mozilla/security/nss/lib/pk11wrap/pk11util.c
|
| ===================================================================
|
| --- mozilla/security/nss/lib/pk11wrap/pk11util.c (revision 191424)
|
| +++ mozilla/security/nss/lib/pk11wrap/pk11util.c (working copy)
|
| @@ -1,1578 +0,0 @@
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -/*
|
| - * Initialize the PCKS 11 subsystem
|
| - */
|
| -#include "seccomon.h"
|
| -#include "secmod.h"
|
| -#include "nssilock.h"
|
| -#include "secmodi.h"
|
| -#include "secmodti.h"
|
| -#include "pk11func.h"
|
| -#include "pki3hack.h"
|
| -#include "secerr.h"
|
| -#include "dev.h"
|
| -#include "utilpars.h"
|
| -
|
| -/* these are for displaying error messages */
|
| -
|
| -static SECMODModuleList *modules = NULL;
|
| -static SECMODModuleList *modulesDB = NULL;
|
| -static SECMODModuleList *modulesUnload = NULL;
|
| -static SECMODModule *internalModule = NULL;
|
| -static SECMODModule *defaultDBModule = NULL;
|
| -static SECMODModule *pendingModule = NULL;
|
| -static SECMODListLock *moduleLock = NULL;
|
| -
|
| -int secmod_PrivateModuleCount = 0;
|
| -
|
| -extern PK11DefaultArrayEntry PK11_DefaultArray[];
|
| -extern int num_pk11_default_mechanisms;
|
| -
|
| -
|
| -void
|
| -SECMOD_Init()
|
| -{
|
| - /* don't initialize twice */
|
| - if (moduleLock) return;
|
| -
|
| - moduleLock = SECMOD_NewListLock();
|
| - PK11_InitSlotLists();
|
| -}
|
| -
|
| -
|
| -SECStatus
|
| -SECMOD_Shutdown()
|
| -{
|
| - /* destroy the lock */
|
| - if (moduleLock) {
|
| - SECMOD_DestroyListLock(moduleLock);
|
| - moduleLock = NULL;
|
| - }
|
| - /* free the internal module */
|
| - if (internalModule) {
|
| - SECMOD_DestroyModule(internalModule);
|
| - internalModule = NULL;
|
| - }
|
| -
|
| - /* free the default database module */
|
| - if (defaultDBModule) {
|
| - SECMOD_DestroyModule(defaultDBModule);
|
| - defaultDBModule = NULL;
|
| - }
|
| -
|
| - /* destroy the list */
|
| - if (modules) {
|
| - SECMOD_DestroyModuleList(modules);
|
| - modules = NULL;
|
| - }
|
| -
|
| - if (modulesDB) {
|
| - SECMOD_DestroyModuleList(modulesDB);
|
| - modulesDB = NULL;
|
| - }
|
| -
|
| - if (modulesUnload) {
|
| - SECMOD_DestroyModuleList(modulesUnload);
|
| - modulesUnload = NULL;
|
| - }
|
| -
|
| - /* make all the slots and the lists go away */
|
| - PK11_DestroySlotLists();
|
| -
|
| - nss_DumpModuleLog();
|
| -
|
| -#ifdef DEBUG
|
| - if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) {
|
| - PORT_Assert(secmod_PrivateModuleCount == 0);
|
| - }
|
| -#endif
|
| - if (secmod_PrivateModuleCount) {
|
| - PORT_SetError(SEC_ERROR_BUSY);
|
| - return SECFailure;
|
| - }
|
| - return SECSuccess;
|
| -}
|
| -
|
| -
|
| -/*
|
| - * retrieve the internal module
|
| - */
|
| -SECMODModule *
|
| -SECMOD_GetInternalModule(void)
|
| -{
|
| - return internalModule;
|
| -}
|
| -
|
| -
|
| -SECStatus
|
| -secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule)
|
| -{
|
| - SECMODModuleList *mlp, *newListElement, *last = NULL;
|
| -
|
| - newListElement = SECMOD_NewModuleListElement();
|
| - if (newListElement == NULL) {
|
| - return SECFailure;
|
| - }
|
| -
|
| - newListElement->module = SECMOD_ReferenceModule(newModule);
|
| -
|
| - SECMOD_GetWriteLock(moduleLock);
|
| - /* Added it to the end (This is very inefficient, but Adding a module
|
| - * on the fly should happen maybe 2-3 times through the life this program
|
| - * on a given computer, and this list should be *SHORT*. */
|
| - for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) {
|
| - last = mlp;
|
| - }
|
| -
|
| - if (last == NULL) {
|
| - *moduleList = newListElement;
|
| - } else {
|
| - SECMOD_AddList(last,newListElement,NULL);
|
| - }
|
| - SECMOD_ReleaseWriteLock(moduleLock);
|
| - return SECSuccess;
|
| -}
|
| -
|
| -SECStatus
|
| -SECMOD_AddModuleToList(SECMODModule *newModule)
|
| -{
|
| - if (newModule->internal && !internalModule) {
|
| - internalModule = SECMOD_ReferenceModule(newModule);
|
| - }
|
| - return secmod_AddModuleToList(&modules,newModule);
|
| -}
|
| -
|
| -SECStatus
|
| -SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule)
|
| -{
|
| - if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) {
|
| - SECMOD_DestroyModule(defaultDBModule);
|
| - defaultDBModule = SECMOD_ReferenceModule(newModule);
|
| - } else if (defaultDBModule == NULL) {
|
| - defaultDBModule = SECMOD_ReferenceModule(newModule);
|
| - }
|
| - return secmod_AddModuleToList(&modulesDB,newModule);
|
| -}
|
| -
|
| -SECStatus
|
| -SECMOD_AddModuleToUnloadList(SECMODModule *newModule)
|
| -{
|
| - return secmod_AddModuleToList(&modulesUnload,newModule);
|
| -}
|
| -
|
| -/*
|
| - * get the list of PKCS11 modules that are available.
|
| - */
|
| -SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; }
|
| -SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; }
|
| -SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; }
|
| -
|
| -/*
|
| - * This lock protects the global module lists.
|
| - * it also protects changes to the slot array (module->slots[]) and slot count
|
| - * (module->slotCount) in each module. It is a read/write lock with multiple
|
| - * readers or one writer. Writes are uncommon.
|
| - * Because of legacy considerations protection of the slot array and count is
|
| - * only necessary in applications if the application calls
|
| - * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new
|
| - * applications are encouraged to acquire this lock when reading the
|
| - * slot array information directly.
|
| - */
|
| -SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; }
|
| -
|
| -
|
| -
|
| -/*
|
| - * find a module by name, and add a reference to it.
|
| - * return that module.
|
| - */
|
| -SECMODModule *
|
| -SECMOD_FindModule(const char *name)
|
| -{
|
| - SECMODModuleList *mlp;
|
| - SECMODModule *module = NULL;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return module;
|
| - }
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
| - if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
|
| - module = mlp->module;
|
| - SECMOD_ReferenceModule(module);
|
| - break;
|
| - }
|
| - }
|
| - if (module) {
|
| - goto found;
|
| - }
|
| - for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) {
|
| - if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
|
| - module = mlp->module;
|
| - SECMOD_ReferenceModule(module);
|
| - break;
|
| - }
|
| - }
|
| -
|
| -found:
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| -
|
| - return module;
|
| -}
|
| -
|
| -/*
|
| - * find a module by ID, and add a reference to it.
|
| - * return that module.
|
| - */
|
| -SECMODModule *
|
| -SECMOD_FindModuleByID(SECMODModuleID id)
|
| -{
|
| - SECMODModuleList *mlp;
|
| - SECMODModule *module = NULL;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return module;
|
| - }
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
| - if (id == mlp->module->moduleID) {
|
| - module = mlp->module;
|
| - SECMOD_ReferenceModule(module);
|
| - break;
|
| - }
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| - if (module == NULL) {
|
| - PORT_SetError(SEC_ERROR_NO_MODULE);
|
| - }
|
| - return module;
|
| -}
|
| -
|
| -/*
|
| - * find the function pointer.
|
| - */
|
| -SECMODModule *
|
| -secmod_FindModuleByFuncPtr(void *funcPtr)
|
| -{
|
| - SECMODModuleList *mlp;
|
| - SECMODModule *module = NULL;
|
| -
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
| - /* paranoia, shouldn't ever happen */
|
| - if (!mlp->module) {
|
| - continue;
|
| - }
|
| - if (funcPtr == mlp->module->functionList) {
|
| - module = mlp->module;
|
| - SECMOD_ReferenceModule(module);
|
| - break;
|
| - }
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| - if (module == NULL) {
|
| - PORT_SetError(SEC_ERROR_NO_MODULE);
|
| - }
|
| - return module;
|
| -}
|
| -
|
| -/*
|
| - * Find the Slot based on ID and the module.
|
| - */
|
| -PK11SlotInfo *
|
| -SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID)
|
| -{
|
| - int i;
|
| - PK11SlotInfo *slot = NULL;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return slot;
|
| - }
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for (i=0; i < module->slotCount; i++) {
|
| - PK11SlotInfo *cSlot = module->slots[i];
|
| -
|
| - if (cSlot->slotID == slotID) {
|
| - slot = PK11_ReferenceSlot(cSlot);
|
| - break;
|
| - }
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| -
|
| - if (slot == NULL) {
|
| - PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
|
| - }
|
| - return slot;
|
| -}
|
| -
|
| -/*
|
| - * lookup the Slot module based on it's module ID and slot ID.
|
| - */
|
| -PK11SlotInfo *
|
| -SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID)
|
| -{
|
| - SECMODModule *module;
|
| - PK11SlotInfo *slot;
|
| -
|
| - module = SECMOD_FindModuleByID(moduleID);
|
| - if (module == NULL) return NULL;
|
| -
|
| - slot = SECMOD_FindSlotByID(module, slotID);
|
| - SECMOD_DestroyModule(module);
|
| - return slot;
|
| -}
|
| -
|
| -
|
| -/*
|
| - * find a module by name or module pointer and delete it off the module list.
|
| - * optionally remove it from secmod.db.
|
| - */
|
| -SECStatus
|
| -SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod,
|
| - int *type, PRBool permdb)
|
| -{
|
| - SECMODModuleList *mlp;
|
| - SECMODModuleList **mlpp;
|
| - SECStatus rv = SECFailure;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return rv;
|
| - }
|
| -
|
| - *type = SECMOD_EXTERNAL;
|
| -
|
| - SECMOD_GetWriteLock(moduleLock);
|
| - for (mlpp = &modules,mlp = modules;
|
| - mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
|
| - if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
|
| - mod == mlp->module) {
|
| - /* don't delete the internal module */
|
| - if (!mlp->module->internal) {
|
| - SECMOD_RemoveList(mlpp,mlp);
|
| - /* delete it after we release the lock */
|
| - rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
|
| - } else if (mlp->module->isFIPS) {
|
| - *type = SECMOD_FIPS;
|
| - } else {
|
| - *type = SECMOD_INTERNAL;
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - if (mlp) {
|
| - goto found;
|
| - }
|
| - /* not on the internal list, check the unload list */
|
| - for (mlpp = &modulesUnload,mlp = modulesUnload;
|
| - mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
|
| - if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
|
| - mod == mlp->module) {
|
| - /* don't delete the internal module */
|
| - if (!mlp->module->internal) {
|
| - SECMOD_RemoveList(mlpp,mlp);
|
| - rv = SECSuccess;
|
| - } else if (mlp->module->isFIPS) {
|
| - *type = SECMOD_FIPS;
|
| - } else {
|
| - *type = SECMOD_INTERNAL;
|
| - }
|
| - break;
|
| - }
|
| - }
|
| -found:
|
| - SECMOD_ReleaseWriteLock(moduleLock);
|
| -
|
| -
|
| - if (rv == SECSuccess) {
|
| - if (permdb) {
|
| - SECMOD_DeletePermDB(mlp->module);
|
| - }
|
| - SECMOD_DestroyModuleListElement(mlp);
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -/*
|
| - * find a module by name and delete it off the module list
|
| - */
|
| -SECStatus
|
| -SECMOD_DeleteModule(const char *name, int *type)
|
| -{
|
| - return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE);
|
| -}
|
| -
|
| -/*
|
| - * find a module by name and delete it off the module list
|
| - */
|
| -SECStatus
|
| -SECMOD_DeleteInternalModule(const char *name)
|
| -{
|
| - SECMODModuleList *mlp;
|
| - SECMODModuleList **mlpp;
|
| - SECStatus rv = SECFailure;
|
| -
|
| - if (pendingModule) {
|
| - PORT_SetError(SEC_ERROR_MODULE_STUCK);
|
| - return rv;
|
| - }
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return rv;
|
| - }
|
| -
|
| - SECMOD_GetWriteLock(moduleLock);
|
| - for(mlpp = &modules,mlp = modules;
|
| - mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
|
| - if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
|
| - /* don't delete the internal module */
|
| - if (mlp->module->internal) {
|
| - SECMOD_RemoveList(mlpp,mlp);
|
| - rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - SECMOD_ReleaseWriteLock(moduleLock);
|
| -
|
| - if (rv == SECSuccess) {
|
| - SECMODModule *newModule,*oldModule;
|
| -
|
| - if (mlp->module->isFIPS) {
|
| - newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME,
|
| - NULL, SECMOD_INT_FLAGS);
|
| - } else {
|
| - newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME,
|
| - NULL, SECMOD_FIPS_FLAGS);
|
| - }
|
| - if (newModule) {
|
| - PK11SlotInfo *slot;
|
| - newModule->libraryParams =
|
| - PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams);
|
| - /* if an explicit internal key slot has been set, reset it */
|
| - slot = pk11_SwapInternalKeySlot(NULL);
|
| - if (slot) {
|
| - secmod_SetInternalKeySlotFlag(newModule, PR_TRUE);
|
| - }
|
| - rv = SECMOD_AddModule(newModule);
|
| - if (rv != SECSuccess) {
|
| - /* load failed, restore the internal key slot */
|
| - pk11_SetInternalKeySlot(slot);
|
| - SECMOD_DestroyModule(newModule);
|
| - newModule = NULL;
|
| - }
|
| - /* free the old explicit internal key slot, we now have a new one */
|
| - if (slot) {
|
| - PK11_FreeSlot(slot);
|
| - }
|
| - }
|
| - if (newModule == NULL) {
|
| - SECMODModuleList *last = NULL,*mlp2;
|
| - /* we're in pretty deep trouble if this happens...Security
|
| - * not going to work well... try to put the old module back on
|
| - * the list */
|
| - SECMOD_GetWriteLock(moduleLock);
|
| - for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) {
|
| - last = mlp2;
|
| - }
|
| -
|
| - if (last == NULL) {
|
| - modules = mlp;
|
| - } else {
|
| - SECMOD_AddList(last,mlp,NULL);
|
| - }
|
| - SECMOD_ReleaseWriteLock(moduleLock);
|
| - return SECFailure;
|
| - }
|
| - pendingModule = oldModule = internalModule;
|
| - internalModule = NULL;
|
| - SECMOD_DestroyModule(oldModule);
|
| - SECMOD_DeletePermDB(mlp->module);
|
| - SECMOD_DestroyModuleListElement(mlp);
|
| - internalModule = newModule; /* adopt the module */
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -SECStatus
|
| -SECMOD_AddModule(SECMODModule *newModule)
|
| -{
|
| - SECStatus rv;
|
| - SECMODModule *oldModule;
|
| -
|
| - /* Test if a module w/ the same name already exists */
|
| - /* and return SECWouldBlock if so. */
|
| - /* We should probably add a new return value such as */
|
| - /* SECDublicateModule, but to minimize ripples, I'll */
|
| - /* give SECWouldBlock a new meaning */
|
| - if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) {
|
| - SECMOD_DestroyModule(oldModule);
|
| - return SECWouldBlock;
|
| - /* module already exists. */
|
| - }
|
| -
|
| - rv = secmod_LoadPKCS11Module(newModule, NULL);
|
| - if (rv != SECSuccess) {
|
| - return rv;
|
| - }
|
| -
|
| - if (newModule->parent == NULL) {
|
| - newModule->parent = SECMOD_ReferenceModule(defaultDBModule);
|
| - }
|
| -
|
| - SECMOD_AddPermDB(newModule);
|
| - SECMOD_AddModuleToList(newModule);
|
| -
|
| - rv = STAN_AddModuleToDefaultTrustDomain(newModule);
|
| -
|
| - return rv;
|
| -}
|
| -
|
| -PK11SlotInfo *
|
| -SECMOD_FindSlot(SECMODModule *module,const char *name)
|
| -{
|
| - int i;
|
| - char *string;
|
| - PK11SlotInfo *retSlot = NULL;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return retSlot;
|
| - }
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for (i=0; i < module->slotCount; i++) {
|
| - PK11SlotInfo *slot = module->slots[i];
|
| -
|
| - if (PK11_IsPresent(slot)) {
|
| - string = PK11_GetTokenName(slot);
|
| - } else {
|
| - string = PK11_GetSlotName(slot);
|
| - }
|
| - if (PORT_Strcmp(name,string) == 0) {
|
| - retSlot = PK11_ReferenceSlot(slot);
|
| - break;
|
| - }
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| -
|
| - if (retSlot == NULL) {
|
| - PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
|
| - }
|
| - return retSlot;
|
| -}
|
| -
|
| -SECStatus
|
| -PK11_GetModInfo(SECMODModule *mod,CK_INFO *info)
|
| -{
|
| - CK_RV crv;
|
| -
|
| - if (mod->functionList == NULL) return SECFailure;
|
| - crv = PK11_GETTAB(mod)->C_GetInfo(info);
|
| - if (crv != CKR_OK) {
|
| - PORT_SetError(PK11_MapError(crv));
|
| - }
|
| - return (crv == CKR_OK) ? SECSuccess : SECFailure;
|
| -}
|
| -
|
| -/* Determine if we have the FIP's module loaded as the default
|
| - * module to trigger other bogus FIPS requirements in PKCS #12 and
|
| - * SSL
|
| - */
|
| -PRBool
|
| -PK11_IsFIPS(void)
|
| -{
|
| - SECMODModule *mod = SECMOD_GetInternalModule();
|
| -
|
| - if (mod && mod->internal) {
|
| - return mod->isFIPS;
|
| - }
|
| -
|
| - return PR_FALSE;
|
| -}
|
| -
|
| -/* combines NewModule() & AddModule */
|
| -/* give a string for the module name & the full-path for the dll, */
|
| -/* installs the PKCS11 module & update registry */
|
| -SECStatus
|
| -SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath,
|
| - unsigned long defaultMechanismFlags,
|
| - unsigned long cipherEnableFlags,
|
| - char* modparms, char* nssparms)
|
| -{
|
| - SECMODModule *module;
|
| - SECStatus result = SECFailure;
|
| - int s,i;
|
| - PK11SlotInfo* slot;
|
| -
|
| - PR_SetErrorText(0, NULL);
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return result;
|
| - }
|
| -
|
| - module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms);
|
| -
|
| - if (module == NULL) {
|
| - return result;
|
| - }
|
| -
|
| - if (module->dllName != NULL) {
|
| - if (module->dllName[0] != 0) {
|
| - result = SECMOD_AddModule(module);
|
| - if (result == SECSuccess) {
|
| - /* turn on SSL cipher enable flags */
|
| - module->ssl[0] = cipherEnableFlags;
|
| -
|
| - SECMOD_GetReadLock(moduleLock);
|
| - /* check each slot to turn on appropriate mechanisms */
|
| - for (s = 0; s < module->slotCount; s++) {
|
| - slot = (module->slots)[s];
|
| - /* for each possible mechanism */
|
| - for (i=0; i < num_pk11_default_mechanisms; i++) {
|
| - /* we are told to turn it on by default ? */
|
| - PRBool add =
|
| - (PK11_DefaultArray[i].flag & defaultMechanismFlags) ?
|
| - PR_TRUE: PR_FALSE;
|
| - result = PK11_UpdateSlotAttribute(slot,
|
| - &(PK11_DefaultArray[i]), add);
|
| - } /* for each mechanism */
|
| - /* disable each slot if the defaultFlags say so */
|
| - if (defaultMechanismFlags & PK11_DISABLE_FLAG) {
|
| - PK11_UserDisableSlot(slot);
|
| - }
|
| - } /* for each slot of this module */
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| -
|
| - /* delete and re-add module in order to save changes
|
| - * to the module */
|
| - result = SECMOD_UpdateModule(module);
|
| - }
|
| - }
|
| - }
|
| - SECMOD_DestroyModule(module);
|
| - return result;
|
| -}
|
| -
|
| -SECStatus
|
| -SECMOD_AddNewModule(const char* moduleName, const char* dllPath,
|
| - unsigned long defaultMechanismFlags,
|
| - unsigned long cipherEnableFlags)
|
| -{
|
| - return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags,
|
| - cipherEnableFlags,
|
| - NULL, NULL); /* don't pass module or nss params */
|
| -}
|
| -
|
| -SECStatus
|
| -SECMOD_UpdateModule(SECMODModule *module)
|
| -{
|
| - SECStatus result;
|
| -
|
| - result = SECMOD_DeletePermDB(module);
|
| -
|
| - if (result == SECSuccess) {
|
| - result = SECMOD_AddPermDB(module);
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -/* Public & Internal(Security Library) representation of
|
| - * encryption mechanism flags conversion */
|
| -
|
| -/* Currently, the only difference is that internal representation
|
| - * puts RANDOM_FLAG at bit 31 (Most-significant bit), but
|
| - * public representation puts this bit at bit 28
|
| - */
|
| -unsigned long
|
| -SECMOD_PubMechFlagstoInternal(unsigned long publicFlags)
|
| -{
|
| - unsigned long internalFlags = publicFlags;
|
| -
|
| - if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) {
|
| - internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG;
|
| - internalFlags |= SECMOD_RANDOM_FLAG;
|
| - }
|
| - return internalFlags;
|
| -}
|
| -
|
| -unsigned long
|
| -SECMOD_InternaltoPubMechFlags(unsigned long internalFlags)
|
| -{
|
| - unsigned long publicFlags = internalFlags;
|
| -
|
| - if (internalFlags & SECMOD_RANDOM_FLAG) {
|
| - publicFlags &= ~SECMOD_RANDOM_FLAG;
|
| - publicFlags |= PUBLIC_MECH_RANDOM_FLAG;
|
| - }
|
| - return publicFlags;
|
| -}
|
| -
|
| -
|
| -/* Public & Internal(Security Library) representation of */
|
| -/* cipher flags conversion */
|
| -/* Note: currently they are just stubs */
|
| -unsigned long
|
| -SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags)
|
| -{
|
| - return publicFlags;
|
| -}
|
| -
|
| -unsigned long
|
| -SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags)
|
| -{
|
| - return internalFlags;
|
| -}
|
| -
|
| -/* Funtion reports true if module of modType is installed/configured */
|
| -PRBool
|
| -SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags )
|
| -{
|
| - PRBool result = PR_FALSE;
|
| - SECMODModuleList *mods;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return result;
|
| - }
|
| - SECMOD_GetReadLock(moduleLock);
|
| - mods = SECMOD_GetDefaultModuleList();
|
| - for ( ; mods != NULL; mods = mods->next) {
|
| - if (mods->module->ssl[0] &
|
| - SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) {
|
| - result = PR_TRUE;
|
| - }
|
| - }
|
| -
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| - return result;
|
| -}
|
| -
|
| -/* create a new ModuleListElement */
|
| -SECMODModuleList *SECMOD_NewModuleListElement(void)
|
| -{
|
| - SECMODModuleList *newModList;
|
| -
|
| - newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList));
|
| - if (newModList) {
|
| - newModList->next = NULL;
|
| - newModList->module = NULL;
|
| - }
|
| - return newModList;
|
| -}
|
| -
|
| -/*
|
| - * make a new reference to a module so It doesn't go away on us
|
| - */
|
| -SECMODModule *
|
| -SECMOD_ReferenceModule(SECMODModule *module)
|
| -{
|
| - PZ_Lock(module->refLock);
|
| - PORT_Assert(module->refCount > 0);
|
| -
|
| - module->refCount++;
|
| - PZ_Unlock(module->refLock);
|
| - return module;
|
| -}
|
| -
|
| -
|
| -/* destroy an existing module */
|
| -void
|
| -SECMOD_DestroyModule(SECMODModule *module)
|
| -{
|
| - PRBool willfree = PR_FALSE;
|
| - int slotCount;
|
| - int i;
|
| -
|
| - PZ_Lock(module->refLock);
|
| - if (module->refCount-- == 1) {
|
| - willfree = PR_TRUE;
|
| - }
|
| - PORT_Assert(willfree || (module->refCount > 0));
|
| - PZ_Unlock(module->refLock);
|
| -
|
| - if (!willfree) {
|
| - return;
|
| - }
|
| -
|
| - if (module->parent != NULL) {
|
| - SECMODModule *parent = module->parent;
|
| - /* paranoia, don't loop forever if the modules are looped */
|
| - module->parent = NULL;
|
| - SECMOD_DestroyModule(parent);
|
| - }
|
| -
|
| - /* slots can't really disappear until our module starts freeing them,
|
| - * so this check is safe */
|
| - slotCount = module->slotCount;
|
| - if (slotCount == 0) {
|
| - SECMOD_SlotDestroyModule(module,PR_FALSE);
|
| - return;
|
| - }
|
| -
|
| - /* now free all out slots, when they are done, they will cause the
|
| - * module to disappear altogether */
|
| - for (i=0 ; i < slotCount; i++) {
|
| - if (!module->slots[i]->disabled) {
|
| - PK11_ClearSlotList(module->slots[i]);
|
| - }
|
| - PK11_FreeSlot(module->slots[i]);
|
| - }
|
| - /* WARNING: once the last slot has been freed is it possible (even likely)
|
| - * that module is no more... touching it now is a good way to go south */
|
| -}
|
| -
|
| -
|
| -/* we can only get here if we've destroyed the module, or some one has
|
| - * erroneously freed a slot that wasn't referenced. */
|
| -void
|
| -SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot)
|
| -{
|
| - PRBool willfree = PR_FALSE;
|
| - if (fromSlot) {
|
| - PORT_Assert(module->refCount == 0);
|
| - PZ_Lock(module->refLock);
|
| - if (module->slotCount-- == 1) {
|
| - willfree = PR_TRUE;
|
| - }
|
| - PORT_Assert(willfree || (module->slotCount > 0));
|
| - PZ_Unlock(module->refLock);
|
| - if (!willfree) return;
|
| - }
|
| -
|
| - if (module == pendingModule) {
|
| - pendingModule = NULL;
|
| - }
|
| -
|
| - if (module->loaded) {
|
| - SECMOD_UnloadModule(module);
|
| - }
|
| - PZ_DestroyLock(module->refLock);
|
| - PORT_FreeArena(module->arena,PR_FALSE);
|
| - secmod_PrivateModuleCount--;
|
| -}
|
| -
|
| -/* destroy a list element
|
| - * this destroys a single element, and returns the next element
|
| - * on the chain. It makes it easy to implement for loops to delete
|
| - * the chain. It also make deleting a single element easy */
|
| -SECMODModuleList *
|
| -SECMOD_DestroyModuleListElement(SECMODModuleList *element)
|
| -{
|
| - SECMODModuleList *next = element->next;
|
| -
|
| - if (element->module) {
|
| - SECMOD_DestroyModule(element->module);
|
| - element->module = NULL;
|
| - }
|
| - PORT_Free(element);
|
| - return next;
|
| -}
|
| -
|
| -
|
| -/*
|
| - * Destroy an entire module list
|
| - */
|
| -void
|
| -SECMOD_DestroyModuleList(SECMODModuleList *list)
|
| -{
|
| - SECMODModuleList *lp;
|
| -
|
| - for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ;
|
| -}
|
| -
|
| -PRBool
|
| -SECMOD_CanDeleteInternalModule(void)
|
| -{
|
| - return (PRBool) (pendingModule == NULL);
|
| -}
|
| -
|
| -/*
|
| - * check to see if the module has added new slots. PKCS 11 v2.20 allows for
|
| - * modules to add new slots, but never remove them. Slots cannot be added
|
| - * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent
|
| - * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
|
| - * grow on the caller. It is permissible for the slots to increase between
|
| - * successive calls with NULL to get the size.
|
| - */
|
| -SECStatus
|
| -SECMOD_UpdateSlotList(SECMODModule *mod)
|
| -{
|
| - CK_RV crv;
|
| - CK_ULONG count;
|
| - CK_ULONG i, oldCount;
|
| - PRBool freeRef = PR_FALSE;
|
| - void *mark = NULL;
|
| - CK_ULONG *slotIDs = NULL;
|
| - PK11SlotInfo **newSlots = NULL;
|
| - PK11SlotInfo **oldSlots = NULL;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return SECFailure;
|
| - }
|
| -
|
| - /* C_GetSlotList is not a session function, make sure
|
| - * calls are serialized */
|
| - PZ_Lock(mod->refLock);
|
| - freeRef = PR_TRUE;
|
| - /* see if the number of slots have changed */
|
| - crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count);
|
| - if (crv != CKR_OK) {
|
| - PORT_SetError(PK11_MapError(crv));
|
| - goto loser;
|
| - }
|
| - /* nothing new, blow out early, we want this function to be quick
|
| - * and cheap in the normal case */
|
| - if (count == mod->slotCount) {
|
| - PZ_Unlock(mod->refLock);
|
| - return SECSuccess;
|
| - }
|
| - if (count < (CK_ULONG)mod->slotCount) {
|
| - /* shouldn't happen with a properly functioning PKCS #11 module */
|
| - PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 );
|
| - goto loser;
|
| - }
|
| -
|
| - /* get the new slot list */
|
| - slotIDs = PORT_NewArray(CK_SLOT_ID, count);
|
| - if (slotIDs == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| - crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count);
|
| - if (crv != CKR_OK) {
|
| - PORT_SetError(PK11_MapError(crv));
|
| - goto loser;
|
| - }
|
| - freeRef = PR_FALSE;
|
| - PZ_Unlock(mod->refLock);
|
| - mark = PORT_ArenaMark(mod->arena);
|
| - if (mark == NULL) {
|
| - goto loser;
|
| - }
|
| - newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count);
|
| -
|
| - /* walk down the new slot ID list returned from the module. We keep
|
| - * the old slots which match a returned ID, and we initialize the new
|
| - * slots. */
|
| - for (i=0; i < count; i++) {
|
| - PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]);
|
| -
|
| - if (!slot) {
|
| - /* we have a new slot create a new slot data structure */
|
| - slot = PK11_NewSlotInfo(mod);
|
| - if (!slot) {
|
| - goto loser;
|
| - }
|
| - PK11_InitSlot(mod, slotIDs[i], slot);
|
| - STAN_InitTokenForSlotInfo(NULL, slot);
|
| - }
|
| - newSlots[i] = slot;
|
| - }
|
| - STAN_ResetTokenInterator(NULL);
|
| - PORT_Free(slotIDs);
|
| - slotIDs = NULL;
|
| - PORT_ArenaUnmark(mod->arena, mark);
|
| -
|
| - /* until this point we're still using the old slot list. Now we update
|
| - * module slot list. We update the slots (array) first then the count,
|
| - * since we've already guarrenteed that count has increased (just in case
|
| - * someone is looking at the slots field of module without holding the
|
| - * moduleLock */
|
| - SECMOD_GetWriteLock(moduleLock);
|
| - oldCount =mod->slotCount;
|
| - oldSlots = mod->slots;
|
| - mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is
|
| - * allocated out of the module arena and won't
|
| - * be freed until the module is freed */
|
| - mod->slotCount = count;
|
| - SECMOD_ReleaseWriteLock(moduleLock);
|
| - /* free our old references before forgetting about oldSlot*/
|
| - for (i=0; i < oldCount; i++) {
|
| - PK11_FreeSlot(oldSlots[i]);
|
| - }
|
| - return SECSuccess;
|
| -
|
| -loser:
|
| - if (freeRef) {
|
| - PZ_Unlock(mod->refLock);
|
| - }
|
| - if (slotIDs) {
|
| - PORT_Free(slotIDs);
|
| - }
|
| - /* free all the slots we allocated. newSlots are part of the
|
| - * mod arena. NOTE: the newSlots array contain both new and old
|
| - * slots, but we kept a reference to the old slots when we built the new
|
| - * array, so we need to free all the slots in newSlots array. */
|
| - if (newSlots) {
|
| - for (i=0; i < count; i++) {
|
| - if (newSlots[i] == NULL) {
|
| - break; /* hit the last one */
|
| - }
|
| - PK11_FreeSlot(newSlots[i]);
|
| - }
|
| - }
|
| - /* must come after freeing newSlots */
|
| - if (mark) {
|
| - PORT_ArenaRelease(mod->arena, mark);
|
| - }
|
| - return SECFailure;
|
| -}
|
| -
|
| -/*
|
| - * this handles modules that do not support C_WaitForSlotEvent().
|
| - * The internal flags are stored. Note that C_WaitForSlotEvent() does not
|
| - * have a timeout, so we don't have one for handleWaitForSlotEvent() either.
|
| - */
|
| -PK11SlotInfo *
|
| -secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags,
|
| - PRIntervalTime latency)
|
| -{
|
| - PRBool removableSlotsFound = PR_FALSE;
|
| - int i;
|
| - int error = SEC_ERROR_NO_EVENT;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return NULL;
|
| - }
|
| - PZ_Lock(mod->refLock);
|
| - if (mod->evControlMask & SECMOD_END_WAIT) {
|
| - mod->evControlMask &= ~SECMOD_END_WAIT;
|
| - PZ_Unlock(mod->refLock);
|
| - PORT_SetError(SEC_ERROR_NO_EVENT);
|
| - return NULL;
|
| - }
|
| - mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT;
|
| - while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) {
|
| - PZ_Unlock(mod->refLock);
|
| - /* now is a good time to see if new slots have been added */
|
| - SECMOD_UpdateSlotList(mod);
|
| -
|
| - /* loop through all the slots on a module */
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for (i=0; i < mod->slotCount; i++) {
|
| - PK11SlotInfo *slot = mod->slots[i];
|
| - uint16 series;
|
| - PRBool present;
|
| -
|
| - /* perm modules do not change */
|
| - if (slot->isPerm) {
|
| - continue;
|
| - }
|
| - removableSlotsFound = PR_TRUE;
|
| - /* simulate the PKCS #11 module flags. are the flags different
|
| - * from the last time we called? */
|
| - series = slot->series;
|
| - present = PK11_IsPresent(slot);
|
| - if ((slot->flagSeries != series) || (slot->flagState != present)) {
|
| - slot->flagState = present;
|
| - slot->flagSeries = series;
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| - PZ_Lock(mod->refLock);
|
| - mod->evControlMask &= ~SECMOD_END_WAIT;
|
| - PZ_Unlock(mod->refLock);
|
| - return PK11_ReferenceSlot(slot);
|
| - }
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| - /* if everything was perm modules, don't lock up forever */
|
| - if ((mod->slotCount !=0) && !removableSlotsFound) {
|
| - error =SEC_ERROR_NO_SLOT_SELECTED;
|
| - PZ_Lock(mod->refLock);
|
| - break;
|
| - }
|
| - if (flags & CKF_DONT_BLOCK) {
|
| - PZ_Lock(mod->refLock);
|
| - break;
|
| - }
|
| - PR_Sleep(latency);
|
| - PZ_Lock(mod->refLock);
|
| - }
|
| - mod->evControlMask &= ~SECMOD_END_WAIT;
|
| - PZ_Unlock(mod->refLock);
|
| - PORT_SetError(error);
|
| - return NULL;
|
| -}
|
| -
|
| -/*
|
| - * this function waits for a token event on any slot of a given module
|
| - * This function should not be called from more than one thread of the
|
| - * same process (though other threads can make other library calls
|
| - * on this module while this call is blocked).
|
| - */
|
| -PK11SlotInfo *
|
| -SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags,
|
| - PRIntervalTime latency)
|
| -{
|
| - CK_SLOT_ID id;
|
| - CK_RV crv;
|
| - PK11SlotInfo *slot;
|
| -
|
| - if (!pk11_getFinalizeModulesOption() ||
|
| - ((mod->cryptokiVersion.major == 2) &&
|
| - (mod->cryptokiVersion.minor < 1))) {
|
| - /* if we are sharing the module with other software in our
|
| - * address space, we can't reliably use C_WaitForSlotEvent(),
|
| - * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
|
| - * exist */
|
| - return secmod_HandleWaitForSlotEvent(mod, flags, latency);
|
| - }
|
| - /* first the the PKCS #11 call */
|
| - PZ_Lock(mod->refLock);
|
| - if (mod->evControlMask & SECMOD_END_WAIT) {
|
| - goto end_wait;
|
| - }
|
| - mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT;
|
| - PZ_Unlock(mod->refLock);
|
| - crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL);
|
| - PZ_Lock(mod->refLock);
|
| - mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT;
|
| - /* if we are in end wait, short circuit now, don't even risk
|
| - * going into secmod_HandleWaitForSlotEvent */
|
| - if (mod->evControlMask & SECMOD_END_WAIT) {
|
| - goto end_wait;
|
| - }
|
| - PZ_Unlock(mod->refLock);
|
| - if (crv == CKR_FUNCTION_NOT_SUPPORTED) {
|
| - /* module doesn't support that call, simulate it */
|
| - return secmod_HandleWaitForSlotEvent(mod, flags, latency);
|
| - }
|
| - if (crv != CKR_OK) {
|
| - /* we can get this error if finalize was called while we were
|
| - * still running. This is the only way to force a C_WaitForSlotEvent()
|
| - * to return in PKCS #11. In this case, just return that there
|
| - * was no event. */
|
| - if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) {
|
| - PORT_SetError(SEC_ERROR_NO_EVENT);
|
| - } else {
|
| - PORT_SetError(PK11_MapError(crv));
|
| - }
|
| - return NULL;
|
| - }
|
| - slot = SECMOD_FindSlotByID(mod, id);
|
| - if (slot == NULL) {
|
| - /* possibly a new slot that was added? */
|
| - SECMOD_UpdateSlotList(mod);
|
| - slot = SECMOD_FindSlotByID(mod, id);
|
| - }
|
| - /* if we are in the delay period for the "isPresent" call, reset
|
| - * the delay since we know things have probably changed... */
|
| - if (slot && slot->nssToken && slot->nssToken->slot) {
|
| - nssSlot_ResetDelay(slot->nssToken->slot);
|
| - }
|
| - return slot;
|
| -
|
| - /* must be called with the lock on. */
|
| -end_wait:
|
| - mod->evControlMask &= ~SECMOD_END_WAIT;
|
| - PZ_Unlock(mod->refLock);
|
| - PORT_SetError(SEC_ERROR_NO_EVENT);
|
| - return NULL;
|
| -}
|
| -
|
| -/*
|
| - * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic
|
| - * function, possibly bringing down the pkcs #11 module in question. This
|
| - * should be OK because 1) it does reinitialize, and 2) it should only be
|
| - * called when we are on our way to tear the whole system down anyway.
|
| - */
|
| -SECStatus
|
| -SECMOD_CancelWait(SECMODModule *mod)
|
| -{
|
| - unsigned long controlMask = mod->evControlMask;
|
| - SECStatus rv = SECSuccess;
|
| - CK_RV crv;
|
| -
|
| - PZ_Lock(mod->refLock);
|
| - mod->evControlMask |= SECMOD_END_WAIT;
|
| - controlMask = mod->evControlMask;
|
| - if (controlMask & SECMOD_WAIT_PKCS11_EVENT) {
|
| - if (!pk11_getFinalizeModulesOption()) {
|
| - /* can't get here unless pk11_getFinalizeModulesOption is set */
|
| - PORT_Assert(0);
|
| - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| - rv = SECFailure;
|
| - goto loser;
|
| - }
|
| - /* NOTE: this call will drop all transient keys, in progress
|
| - * operations, and any authentication. This is the only documented
|
| - * way to get WaitForSlotEvent to return. Also note: for non-thread
|
| - * safe tokens, we need to hold the module lock, this is not yet at
|
| - * system shutdown/startup time, so we need to protect these calls */
|
| - crv = PK11_GETTAB(mod)->C_Finalize(NULL);
|
| - /* ok, we slammed the module down, now we need to reinit it in case
|
| - * we intend to use it again */
|
| - if (CKR_OK == crv) {
|
| - PRBool alreadyLoaded;
|
| - secmod_ModuleInit(mod, NULL, &alreadyLoaded);
|
| - } else {
|
| - /* Finalized failed for some reason, notify the application
|
| - * so maybe it has a prayer of recovering... */
|
| - PORT_SetError(PK11_MapError(crv));
|
| - rv = SECFailure;
|
| - }
|
| - } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) {
|
| - mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT;
|
| - /* Simulated events will eventually timeout
|
| - * and wake up in the loop */
|
| - }
|
| -loser:
|
| - PZ_Unlock(mod->refLock);
|
| - return rv;
|
| -}
|
| -
|
| -/*
|
| - * check to see if the module has removable slots that we may need to
|
| - * watch for.
|
| - */
|
| -PRBool
|
| -SECMOD_HasRemovableSlots(SECMODModule *mod)
|
| -{
|
| - int i;
|
| - PRBool ret = PR_FALSE;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return ret;
|
| - }
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for (i=0; i < mod->slotCount; i++) {
|
| - PK11SlotInfo *slot = mod->slots[i];
|
| - /* perm modules are not inserted or removed */
|
| - if (slot->isPerm) {
|
| - continue;
|
| - }
|
| - ret = PR_TRUE;
|
| - break;
|
| - }
|
| - if (mod->slotCount == 0 ) {
|
| - ret = PR_TRUE;
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| - return ret;
|
| -}
|
| -
|
| -/*
|
| - * helper function to actually create and destroy user defined slots
|
| - */
|
| -static SECStatus
|
| -secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass,
|
| - const char *sendSpec)
|
| -{
|
| - CK_OBJECT_HANDLE dummy;
|
| - CK_ATTRIBUTE template[2] ;
|
| - CK_ATTRIBUTE *attrs = template;
|
| - CK_RV crv;
|
| -
|
| - PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
|
| - PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec,
|
| - strlen(sendSpec)+1); attrs++;
|
| -
|
| - PORT_Assert(attrs-template <= 2);
|
| -
|
| -
|
| - PK11_EnterSlotMonitor(slot);
|
| - crv = PK11_CreateNewObject(slot, slot->session,
|
| - template, attrs-template, PR_FALSE, &dummy);
|
| - PK11_ExitSlotMonitor(slot);
|
| -
|
| - if (crv != CKR_OK) {
|
| - PORT_SetError(PK11_MapError(crv));
|
| - return SECFailure;
|
| - }
|
| - return SECMOD_UpdateSlotList(slot->module);
|
| -}
|
| -
|
| -/*
|
| - * return true if the selected slot ID is not present or doesn't exist
|
| - */
|
| -static PRBool
|
| -secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID)
|
| -{
|
| - PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID);
|
| - if (slot) {
|
| - PRBool present = PK11_IsPresent(slot);
|
| - PK11_FreeSlot(slot);
|
| - if (present) {
|
| - return PR_FALSE;
|
| - }
|
| - }
|
| - /* it doesn't exist or isn't present, it's available */
|
| - return PR_TRUE;
|
| -}
|
| -
|
| -/*
|
| - * Find an unused slot id in module.
|
| - */
|
| -static CK_SLOT_ID
|
| -secmod_FindFreeSlot(SECMODModule *mod)
|
| -{
|
| - CK_SLOT_ID i, minSlotID, maxSlotID;
|
| -
|
| - /* look for a free slot id on the internal module */
|
| - if (mod->internal && mod->isFIPS) {
|
| - minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID;
|
| - maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID;
|
| - } else {
|
| - minSlotID = SFTK_MIN_USER_SLOT_ID;
|
| - maxSlotID = SFTK_MAX_USER_SLOT_ID;
|
| - }
|
| - for (i=minSlotID; i < maxSlotID; i++) {
|
| - if (secmod_SlotIsEmpty(mod,i)) {
|
| - return i;
|
| - }
|
| - }
|
| - PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
|
| - return (CK_SLOT_ID) -1;
|
| -}
|
| -
|
| -/*
|
| - * Attempt to open a new slot.
|
| - *
|
| - * This works the same os OpenUserDB except it can be called against
|
| - * any module that understands the softoken protocol for opening new
|
| - * slots, not just the softoken itself. If the selected module does not
|
| - * understand the protocol, C_CreateObject will fail with
|
| - * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set
|
| - * SEC_ERROR_BAD_DATA.
|
| - *
|
| - * NewSlots can be closed with SECMOD_CloseUserDB();
|
| - *
|
| - * Modulespec is module dependent.
|
| - */
|
| -PK11SlotInfo *
|
| -SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec)
|
| -{
|
| - CK_SLOT_ID slotID = 0;
|
| - PK11SlotInfo *slot;
|
| - char *escSpec;
|
| - char *sendSpec;
|
| - SECStatus rv;
|
| -
|
| - slotID = secmod_FindFreeSlot(mod);
|
| - if (slotID == (CK_SLOT_ID) -1) {
|
| - return NULL;
|
| - }
|
| -
|
| - if (mod->slotCount == 0) {
|
| - return NULL;
|
| - }
|
| -
|
| - /* just grab the first slot in the module, any present slot should work */
|
| - slot = PK11_ReferenceSlot(mod->slots[0]);
|
| - if (slot == NULL) {
|
| - return NULL;
|
| - }
|
| -
|
| - /* we've found the slot, now build the moduleSpec */
|
| - escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']');
|
| - if (escSpec == NULL) {
|
| - PK11_FreeSlot(slot);
|
| - return NULL;
|
| - }
|
| - sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec);
|
| - PORT_Free(escSpec);
|
| -
|
| - if (sendSpec == NULL) {
|
| - /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */
|
| - PK11_FreeSlot(slot);
|
| - PORT_SetError(SEC_ERROR_NO_MEMORY);
|
| - return NULL;
|
| - }
|
| - rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec);
|
| - PR_smprintf_free(sendSpec);
|
| - PK11_FreeSlot(slot);
|
| - if (rv != SECSuccess) {
|
| - return NULL;
|
| - }
|
| -
|
| - slot = SECMOD_FindSlotByID(mod, slotID);
|
| - if (slot) {
|
| - /* if we are in the delay period for the "isPresent" call, reset
|
| - * the delay since we know things have probably changed... */
|
| - if (slot->nssToken && slot->nssToken->slot) {
|
| - nssSlot_ResetDelay(slot->nssToken->slot);
|
| - }
|
| - /* force the slot info structures to properly reset */
|
| - (void)PK11_IsPresent(slot);
|
| - }
|
| - return slot;
|
| -}
|
| -
|
| -/*
|
| - * Open a new database using the softoken. The caller is responsible for making
|
| - * sure the module spec is correct and usable. The caller should ask for one
|
| - * new database per call if the caller wants to get meaningful information
|
| - * about the new database.
|
| - *
|
| - * moduleSpec is the same data that you would pass to softoken at
|
| - * initialization time under the 'tokens' options. For example, if you were
|
| - * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
|
| - * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
|
| - * module spec here. The slot ID will be calculated for you by
|
| - * SECMOD_OpenUserDB().
|
| - *
|
| - * Typical parameters here are configdir, tokenDescription and flags.
|
| - *
|
| - * a Full list is below:
|
| - *
|
| - *
|
| - * configDir - The location of the databases for this token. If configDir is
|
| - * not specified, and noCertDB and noKeyDB is not specified, the load
|
| - * will fail.
|
| - * certPrefix - Cert prefix for this token.
|
| - * keyPrefix - Prefix for the key database for this token. (if not specified,
|
| - * certPrefix will be used).
|
| - * tokenDescription - The label value for this token returned in the
|
| - * CK_TOKEN_INFO structure with an internationalize string (UTF8).
|
| - * This value will be truncated at 32 bytes (no NULL, partial UTF8
|
| - * characters dropped). You should specify a user friendly name here
|
| - * as this is the value the token will be referred to in most
|
| - * application UI's. You should make sure tokenDescription is unique.
|
| - * slotDescription - The slotDescription value for this token returned
|
| - * in the CK_SLOT_INFO structure with an internationalize string
|
| - * (UTF8). This value will be truncated at 64 bytes (no NULL, partial
|
| - * UTF8 characters dropped). This name will not change after the
|
| - * database is closed. It should have some number to make this unique.
|
| - * minPWLen - minimum password length for this token.
|
| - * flags - comma separated list of flag values, parsed case-insensitive.
|
| - * Valid flags are:
|
| - * readOnly - Databases should be opened read only.
|
| - * noCertDB - Don't try to open a certificate database.
|
| - * noKeyDB - Don't try to open a key database.
|
| - * forceOpen - Don't fail to initialize the token if the
|
| - * databases could not be opened.
|
| - * passwordRequired - zero length passwords are not acceptable
|
| - * (valid only if there is a keyDB).
|
| - * optimizeSpace - allocate smaller hash tables and lock tables.
|
| - * When this flag is not specified, Softoken will allocate
|
| - * large tables to prevent lock contention.
|
| - */
|
| -PK11SlotInfo *
|
| -SECMOD_OpenUserDB(const char *moduleSpec)
|
| -{
|
| - SECMODModule *mod;
|
| -
|
| - if (moduleSpec == NULL) {
|
| - return NULL;
|
| - }
|
| -
|
| - /* NOTE: unlike most PK11 function, this does not return a reference
|
| - * to the module */
|
| - mod = SECMOD_GetInternalModule();
|
| - if (!mod) {
|
| - /* shouldn't happen */
|
| - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| - return NULL;
|
| - }
|
| - return SECMOD_OpenNewSlot(mod, moduleSpec);
|
| -}
|
| -
|
| -
|
| -/*
|
| - * close an already opened user database. NOTE: the database must be
|
| - * in the internal token, and must be one created with SECMOD_OpenUserDB().
|
| - * Once the database is closed, the slot will remain as an empty slot
|
| - * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot().
|
| - */
|
| -SECStatus
|
| -SECMOD_CloseUserDB(PK11SlotInfo *slot)
|
| -{
|
| - SECStatus rv;
|
| - char *sendSpec;
|
| -
|
| - sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID);
|
| - if (sendSpec == NULL) {
|
| - /* PR_smprintf does not set no memory error */
|
| - PORT_SetError(SEC_ERROR_NO_MEMORY);
|
| - return SECFailure;
|
| - }
|
| - rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec);
|
| - PR_smprintf_free(sendSpec);
|
| - return rv;
|
| -}
|
| -
|
| -/*
|
| - * Restart PKCS #11 modules after a fork(). See secmod.h for more information.
|
| - */
|
| -SECStatus
|
| -SECMOD_RestartModules(PRBool force)
|
| -{
|
| - SECMODModuleList *mlp;
|
| - SECStatus rrv = SECSuccess;
|
| - int lastError = 0;
|
| -
|
| - if (!moduleLock) {
|
| - PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
| - return SECFailure;
|
| - }
|
| -
|
| - /* Only need to restart the PKCS #11 modules that were initialized */
|
| - SECMOD_GetReadLock(moduleLock);
|
| - for (mlp = modules; mlp != NULL; mlp = mlp->next) {
|
| - SECMODModule *mod = mlp->module;
|
| - CK_ULONG count;
|
| - SECStatus rv;
|
| - int i;
|
| -
|
| - /* If the module needs to be reset, do so */
|
| - if (force || (PK11_GETTAB(mod)->
|
| - C_GetSlotList(CK_FALSE, NULL, &count) != CKR_OK)) {
|
| - PRBool alreadyLoaded;
|
| - /* first call Finalize. This is not required by PKCS #11, but some
|
| - * older modules require it, and it doesn't hurt (compliant modules
|
| - * will return CKR_NOT_INITIALIZED */
|
| - (void) PK11_GETTAB(mod)->C_Finalize(NULL);
|
| - /* now initialize the module, this function reinitializes
|
| - * a module in place, preserving existing slots (even if they
|
| - * no longer exist) */
|
| - rv = secmod_ModuleInit(mod, NULL, &alreadyLoaded);
|
| - if (rv != SECSuccess) {
|
| - /* save the last error code */
|
| - lastError = PORT_GetError();
|
| - rrv = rv;
|
| - /* couldn't reinit the module, disable all its slots */
|
| - for (i=0; i < mod->slotCount; i++) {
|
| - mod->slots[i]->disabled = PR_TRUE;
|
| - mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
|
| - }
|
| - continue;
|
| - }
|
| - for (i=0; i < mod->slotCount; i++) {
|
| - /* get new token sessions, bump the series up so that
|
| - * we refresh other old sessions. This will tell much of
|
| - * NSS to flush cached handles it may hold as well */
|
| - rv = PK11_InitToken(mod->slots[i],PR_TRUE);
|
| - /* PK11_InitToken could fail if the slot isn't present.
|
| - * If it is present, though, something is wrong and we should
|
| - * disable the slot and let the caller know. */
|
| - if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) {
|
| - /* save the last error code */
|
| - lastError = PORT_GetError();
|
| - rrv = rv;
|
| - /* disable the token */
|
| - mod->slots[i]->disabled = PR_TRUE;
|
| - mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - SECMOD_ReleaseReadLock(moduleLock);
|
| -
|
| - /*
|
| - * on multiple failures, we are only returning the lastError. The caller
|
| - * can determine which slots are bad by calling PK11_IsDisabled().
|
| - */
|
| - if (rrv != SECSuccess) {
|
| - /* restore the last error code */
|
| - PORT_SetError(lastError);
|
| - }
|
| -
|
| - return rrv;
|
| -}
|
|
|