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

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

mercurial