PageRenderTime 112ms CodeModel.GetById 18ms app.highlight 82ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/pk11wrap/pk11util.c

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