Back to index

lightning-sunbird  0.9+nobinonly
pk11util.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 /*
00037  * Initialize the PCKS 11 subsystem
00038  */
00039 #include "seccomon.h"
00040 #include "secmod.h"
00041 #include "nssilock.h"
00042 #include "secmodi.h"
00043 #include "secmodti.h"
00044 #include "pk11func.h"
00045 #include "pki3hack.h"
00046 #include "secerr.h"
00047 #include "dev.h"
00048 #include "pkcs11ni.h"
00049 
00050 /* these are for displaying error messages */
00051 
00052 static  SECMODModuleList *modules = NULL;
00053 static  SECMODModuleList *modulesDB = NULL;
00054 static  SECMODModuleList *modulesUnload = NULL;
00055 static  SECMODModule *internalModule = NULL;
00056 static  SECMODModule *defaultDBModule = NULL;
00057 static  SECMODModule *pendingModule = NULL;
00058 static SECMODListLock *moduleLock = NULL;
00059 
00060 int secmod_PrivateModuleCount = 0;
00061 
00062 extern PK11DefaultArrayEntry PK11_DefaultArray[];
00063 extern int num_pk11_default_mechanisms;
00064 
00065 
00066 void
00067 SECMOD_Init() 
00068 {
00069     /* don't initialize twice */
00070     if (moduleLock) return;
00071 
00072     moduleLock = SECMOD_NewListLock();
00073     PK11_InitSlotLists();
00074 }
00075 
00076 
00077 SECStatus
00078 SECMOD_Shutdown() 
00079 {
00080     /* destroy the lock */
00081     if (moduleLock) {
00082        SECMOD_DestroyListLock(moduleLock);
00083        moduleLock = NULL;
00084     }
00085     /* free the internal module */
00086     if (internalModule) {
00087        SECMOD_DestroyModule(internalModule);
00088        internalModule = NULL;
00089     }
00090 
00091     /* free the default database module */
00092     if (defaultDBModule) {
00093        SECMOD_DestroyModule(defaultDBModule);
00094        defaultDBModule = NULL;
00095     }
00096        
00097     /* destroy the list */
00098     if (modules) {
00099        SECMOD_DestroyModuleList(modules);
00100        modules = NULL;
00101     }
00102    
00103     if (modulesDB) {
00104        SECMOD_DestroyModuleList(modulesDB);
00105        modulesDB = NULL;
00106     }
00107 
00108     if (modulesUnload) {
00109        SECMOD_DestroyModuleList(modulesUnload);
00110        modulesUnload = NULL;
00111     }
00112 
00113     /* make all the slots and the lists go away */
00114     PK11_DestroySlotLists();
00115 
00116     nss_DumpModuleLog();
00117 
00118 #ifdef DEBUG
00119     if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) {
00120        PORT_Assert(secmod_PrivateModuleCount == 0);
00121     }
00122 #endif
00123     if (secmod_PrivateModuleCount) {
00124        PORT_SetError(SEC_ERROR_BUSY);
00125        return SECFailure;
00126     }
00127     return SECSuccess;
00128 }
00129 
00130 
00131 /*
00132  * retrieve the internal module
00133  */
00134 SECMODModule *
00135 SECMOD_GetInternalModule(void)
00136 {
00137    return internalModule;
00138 }
00139 
00140 
00141 SECStatus
00142 secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule)
00143 {
00144     SECMODModuleList *mlp, *newListElement, *last = NULL;
00145 
00146     newListElement = SECMOD_NewModuleListElement();
00147     if (newListElement == NULL) {
00148        return SECFailure;
00149     }
00150 
00151     newListElement->module = SECMOD_ReferenceModule(newModule);
00152 
00153     SECMOD_GetWriteLock(moduleLock);
00154     /* Added it to the end (This is very inefficient, but Adding a module
00155      * on the fly should happen maybe 2-3 times through the life this program
00156      * on a given computer, and this list should be *SHORT*. */
00157     for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) {
00158        last = mlp;
00159     }
00160 
00161     if (last == NULL) {
00162        *moduleList = newListElement;
00163     } else {
00164        SECMOD_AddList(last,newListElement,NULL);
00165     }
00166     SECMOD_ReleaseWriteLock(moduleLock);
00167     return SECSuccess;
00168 }
00169 
00170 SECStatus
00171 SECMOD_AddModuleToList(SECMODModule *newModule)
00172 {
00173     if (newModule->internal && !internalModule) {
00174        internalModule = SECMOD_ReferenceModule(newModule);
00175     }
00176     return secmod_AddModuleToList(&modules,newModule);
00177 }
00178 
00179 SECStatus
00180 SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule)
00181 {
00182     if (defaultDBModule == NULL) {
00183        defaultDBModule = SECMOD_ReferenceModule(newModule);
00184     }
00185     return secmod_AddModuleToList(&modulesDB,newModule);
00186 }
00187 
00188 SECStatus
00189 SECMOD_AddModuleToUnloadList(SECMODModule *newModule)
00190 {
00191     return secmod_AddModuleToList(&modulesUnload,newModule);
00192 }
00193 
00194 /*
00195  * get the list of PKCS11 modules that are available.
00196  */
00197 SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; }
00198 SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; }
00199 SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; }
00200 
00201 /*
00202  * This lock protects the global module lists.
00203  * it also protects changes to the slot array (module->slots[]) and slot count 
00204  * (module->slotCount) in each module. It is a read/write lock with multiple 
00205  * readers or one writer. Writes are uncommon. 
00206  * Because of legacy considerations protection of the slot array and count is 
00207  * only necessary in applications if the application calls 
00208  * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new
00209  * applications are encouraged to acquire this lock when reading the
00210  * slot array information directly.
00211  */
00212 SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; }
00213 
00214 
00215 
00216 /*
00217  * find a module by name, and add a reference to it.
00218  * return that module.
00219  */
00220 SECMODModule *
00221 SECMOD_FindModule(const char *name)
00222 {
00223     SECMODModuleList *mlp;
00224     SECMODModule *module = NULL;
00225 
00226     SECMOD_GetReadLock(moduleLock);
00227     for(mlp = modules; mlp != NULL; mlp = mlp->next) {
00228        if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
00229            module = mlp->module;
00230            SECMOD_ReferenceModule(module);
00231            break;
00232        }
00233     }
00234     if (module) {
00235        goto found;
00236     }
00237     for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) {
00238        if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
00239            module = mlp->module;
00240            SECMOD_ReferenceModule(module);
00241            break;
00242        }
00243     }
00244 
00245 found:
00246     SECMOD_ReleaseReadLock(moduleLock);
00247 
00248     return module;
00249 }
00250 
00251 /*
00252  * find a module by ID, and add a reference to it.
00253  * return that module.
00254  */
00255 SECMODModule *
00256 SECMOD_FindModuleByID(SECMODModuleID id) 
00257 {
00258     SECMODModuleList *mlp;
00259     SECMODModule *module = NULL;
00260 
00261     SECMOD_GetReadLock(moduleLock);
00262     for(mlp = modules; mlp != NULL; mlp = mlp->next) {
00263        if (id == mlp->module->moduleID) {
00264            module = mlp->module;
00265            SECMOD_ReferenceModule(module);
00266            break;
00267        }
00268     }
00269     SECMOD_ReleaseReadLock(moduleLock);
00270     if (module == NULL) {
00271        PORT_SetError(SEC_ERROR_NO_MODULE);
00272     }
00273     return module;
00274 }
00275 
00276 /*
00277  * Find the Slot based on ID and the module.
00278  */
00279 PK11SlotInfo *
00280 SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID)
00281 {
00282     int i;
00283     PK11SlotInfo *slot = NULL;
00284 
00285     SECMOD_GetReadLock(moduleLock);
00286     for (i=0; i < module->slotCount; i++) {
00287        PK11SlotInfo *cSlot = module->slots[i];
00288 
00289        if (cSlot->slotID == slotID) {
00290            slot = PK11_ReferenceSlot(cSlot);
00291            break;
00292        }
00293     }
00294     SECMOD_ReleaseReadLock(moduleLock);
00295 
00296     if (slot == NULL) {
00297        PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
00298     }
00299     return slot;
00300 }
00301 
00302 /*
00303  * lookup the Slot module based on it's module ID and slot ID.
00304  */
00305 PK11SlotInfo *
00306 SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) 
00307 {
00308     SECMODModule *module;
00309     PK11SlotInfo *slot;
00310 
00311     module = SECMOD_FindModuleByID(moduleID);
00312     if (module == NULL) return NULL;
00313 
00314     slot = SECMOD_FindSlotByID(module, slotID);
00315     SECMOD_DestroyModule(module);
00316     return slot;
00317 }
00318 
00319 
00320 /*
00321  * find a module by name or module pointer and delete it off the module list.
00322  * optionally remove it from secmod.db.
00323  */
00324 SECStatus
00325 SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod, 
00326                                           int *type, PRBool permdb) 
00327 {
00328     SECMODModuleList *mlp;
00329     SECMODModuleList **mlpp;
00330     SECStatus rv = SECFailure;
00331 
00332     *type = SECMOD_EXTERNAL;
00333 
00334     SECMOD_GetWriteLock(moduleLock);
00335     for (mlpp = &modules,mlp = modules; 
00336                             mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
00337        if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
00338                                                  mod == mlp->module) {
00339            /* don't delete the internal module */
00340            if (!mlp->module->internal) {
00341               SECMOD_RemoveList(mlpp,mlp);
00342               /* delete it after we release the lock */
00343               rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
00344            } else if (mlp->module->isFIPS) {
00345               *type = SECMOD_FIPS;
00346            } else {
00347               *type = SECMOD_INTERNAL;
00348            }
00349            break;
00350        }
00351     }
00352     if (mlp) {
00353        goto found;
00354     }
00355     /* not on the internal list, check the unload list */
00356     for (mlpp = &modulesUnload,mlp = modulesUnload; 
00357                             mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
00358        if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) ||
00359                                                  mod == mlp->module) {
00360            /* don't delete the internal module */
00361            if (!mlp->module->internal) {
00362               SECMOD_RemoveList(mlpp,mlp);
00363               rv = SECSuccess;
00364            } else if (mlp->module->isFIPS) {
00365               *type = SECMOD_FIPS;
00366            } else {
00367               *type = SECMOD_INTERNAL;
00368            }
00369            break;
00370        }
00371     }
00372 found:
00373     SECMOD_ReleaseWriteLock(moduleLock);
00374 
00375 
00376     if (rv == SECSuccess) {
00377        if (permdb) {
00378            SECMOD_DeletePermDB(mlp->module);
00379        }
00380        SECMOD_DestroyModuleListElement(mlp);
00381     }
00382     return rv;
00383 }
00384 
00385 /*
00386  * find a module by name and delete it off the module list
00387  */
00388 SECStatus
00389 SECMOD_DeleteModule(const char *name, int *type) 
00390 {
00391     return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE);
00392 }
00393 
00394 /*
00395  * find a module by name and delete it off the module list
00396  */
00397 SECStatus
00398 SECMOD_DeleteInternalModule(const char *name) 
00399 {
00400     SECMODModuleList *mlp;
00401     SECMODModuleList **mlpp;
00402     SECStatus rv = SECFailure;
00403 
00404     if (pendingModule) {
00405        PORT_SetError(SEC_ERROR_MODULE_STUCK);
00406        return rv;
00407     }
00408 
00409     SECMOD_GetWriteLock(moduleLock);
00410     for(mlpp = &modules,mlp = modules; 
00411                             mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
00412        if (PORT_Strcmp(name,mlp->module->commonName) == 0) {
00413            /* don't delete the internal module */
00414            if (mlp->module->internal) {
00415               SECMOD_RemoveList(mlpp,mlp);
00416               rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
00417            } 
00418            break;
00419        }
00420     }
00421     SECMOD_ReleaseWriteLock(moduleLock);
00422 
00423     if (rv == SECSuccess) {
00424        SECMODModule *newModule,*oldModule;
00425 
00426        if (mlp->module->isFIPS) {
00427            newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME,
00428                             NULL, SECMOD_INT_FLAGS);
00429        } else {
00430            newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME,
00431                             NULL, SECMOD_FIPS_FLAGS);
00432        }
00433        if (newModule) {
00434            newModule->libraryParams = 
00435             PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams);
00436            rv = SECMOD_AddModule(newModule);
00437            if (rv != SECSuccess) {
00438               SECMOD_DestroyModule(newModule);
00439               newModule = NULL;
00440            }
00441        }
00442        if (newModule == NULL) {
00443            SECMODModuleList *last = NULL,*mlp2;
00444           /* we're in pretty deep trouble if this happens...Security
00445            * not going to work well... try to put the old module back on
00446            * the list */
00447           SECMOD_GetWriteLock(moduleLock);
00448           for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) {
00449               last = mlp2;
00450           }
00451 
00452           if (last == NULL) {
00453               modules = mlp;
00454           } else {
00455               SECMOD_AddList(last,mlp,NULL);
00456           }
00457           SECMOD_ReleaseWriteLock(moduleLock);
00458           return SECFailure; 
00459        }
00460        pendingModule = oldModule = internalModule;
00461        internalModule = NULL;
00462        SECMOD_DestroyModule(oldModule);
00463        SECMOD_DeletePermDB(mlp->module);
00464        SECMOD_DestroyModuleListElement(mlp);
00465        internalModule = newModule; /* adopt the module */
00466     }
00467     return rv;
00468 }
00469 
00470 SECStatus
00471 SECMOD_AddModule(SECMODModule *newModule) 
00472 {
00473     SECStatus rv;
00474     SECMODModule *oldModule;
00475 
00476     /* Test if a module w/ the same name already exists */
00477     /* and return SECWouldBlock if so. */
00478     /* We should probably add a new return value such as */
00479     /* SECDublicateModule, but to minimize ripples, I'll */
00480     /* give SECWouldBlock a new meaning */
00481     if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) {
00482        SECMOD_DestroyModule(oldModule);
00483         return SECWouldBlock;
00484         /* module already exists. */
00485     }
00486 
00487     rv = SECMOD_LoadPKCS11Module(newModule);
00488     if (rv != SECSuccess) {
00489        return rv;
00490     }
00491 
00492     if (newModule->parent == NULL) {
00493        newModule->parent = SECMOD_ReferenceModule(defaultDBModule);
00494     }
00495 
00496     SECMOD_AddPermDB(newModule);
00497     SECMOD_AddModuleToList(newModule);
00498 
00499     rv = STAN_AddModuleToDefaultTrustDomain(newModule);
00500 
00501     return rv;
00502 }
00503 
00504 PK11SlotInfo *
00505 SECMOD_FindSlot(SECMODModule *module,const char *name) 
00506 {
00507     int i;
00508     char *string;
00509     PK11SlotInfo *retSlot = NULL;
00510 
00511     SECMOD_GetReadLock(moduleLock);
00512     for (i=0; i < module->slotCount; i++) {
00513        PK11SlotInfo *slot = module->slots[i];
00514 
00515        if (PK11_IsPresent(slot)) {
00516            string = PK11_GetTokenName(slot);
00517        } else {
00518            string = PK11_GetSlotName(slot);
00519        }
00520        if (PORT_Strcmp(name,string) == 0) {
00521            retSlot = PK11_ReferenceSlot(slot);
00522            break;
00523        }
00524     }
00525     SECMOD_ReleaseReadLock(moduleLock);
00526 
00527     if (retSlot == NULL) {
00528        PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
00529     }
00530     return retSlot;
00531 }
00532 
00533 SECStatus
00534 PK11_GetModInfo(SECMODModule *mod,CK_INFO *info)
00535 {
00536     CK_RV crv;
00537 
00538     if (mod->functionList == NULL) return SECFailure;
00539     crv = PK11_GETTAB(mod)->C_GetInfo(info);
00540     if (crv != CKR_OK) {
00541        PORT_SetError(PK11_MapError(crv));
00542     }  
00543     return (crv == CKR_OK) ? SECSuccess : SECFailure;
00544 }
00545 
00546 /* Determine if we have the FIP's module loaded as the default
00547  * module to trigger other bogus FIPS requirements in PKCS #12 and
00548  * SSL
00549  */
00550 PRBool
00551 PK11_IsFIPS(void)
00552 {
00553     SECMODModule *mod = SECMOD_GetInternalModule();
00554 
00555     if (mod && mod->internal) {
00556        return mod->isFIPS;
00557     }
00558 
00559     return PR_FALSE;
00560 }
00561 
00562 /* combines NewModule() & AddModule */
00563 /* give a string for the module name & the full-path for the dll, */
00564 /* installs the PKCS11 module & update registry */
00565 SECStatus 
00566 SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath,
00567                               unsigned long defaultMechanismFlags,
00568                               unsigned long cipherEnableFlags,
00569                               char* modparms, char* nssparms)
00570 {
00571     SECMODModule *module;
00572     SECStatus result = SECFailure;
00573     int s,i;
00574     PK11SlotInfo* slot;
00575 
00576     PR_SetErrorText(0, NULL);
00577 
00578     module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms);
00579 
00580     if (module == NULL) {
00581        return result;
00582     }
00583 
00584     if (module->dllName != NULL) {
00585         if (module->dllName[0] != 0) {
00586             result = SECMOD_AddModule(module);
00587             if (result == SECSuccess) {
00588                 /* turn on SSL cipher enable flags */
00589                 module->ssl[0] = cipherEnableFlags;
00590 
00591               SECMOD_GetReadLock(moduleLock);
00592                 /* check each slot to turn on appropriate mechanisms */
00593                 for (s = 0; s < module->slotCount; s++) {
00594                     slot = (module->slots)[s];
00595                     /* for each possible mechanism */
00596                     for (i=0; i < num_pk11_default_mechanisms; i++) {
00597                         /* we are told to turn it on by default ? */
00598                      PRBool add = 
00599                       (PK11_DefaultArray[i].flag & defaultMechanismFlags) ?
00600                                           PR_TRUE: PR_FALSE;
00601                         result = PK11_UpdateSlotAttribute(slot, 
00602                                    &(PK11_DefaultArray[i]),  add);
00603                     } /* for each mechanism */
00604                     /* disable each slot if the defaultFlags say so */
00605                     if (defaultMechanismFlags & PK11_DISABLE_FLAG) {
00606                         PK11_UserDisableSlot(slot);
00607                     }
00608                 } /* for each slot of this module */
00609               SECMOD_ReleaseReadLock(moduleLock);
00610 
00611                 /* delete and re-add module in order to save changes 
00612                * to the module */
00613               result = SECMOD_UpdateModule(module);
00614             }
00615         }
00616     }
00617     SECMOD_DestroyModule(module);
00618     return result;
00619 }
00620 
00621 SECStatus 
00622 SECMOD_AddNewModule(const char* moduleName, const char* dllPath,
00623                               unsigned long defaultMechanismFlags,
00624                               unsigned long cipherEnableFlags)
00625 {
00626     return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags,
00627                   cipherEnableFlags, 
00628                   NULL, NULL); /* don't pass module or nss params */
00629 }
00630 
00631 SECStatus 
00632 SECMOD_UpdateModule(SECMODModule *module)
00633 {
00634     SECStatus result;
00635 
00636     result = SECMOD_DeletePermDB(module);
00637                 
00638     if (result == SECSuccess) {          
00639        result = SECMOD_AddPermDB(module);
00640     }
00641     return result;
00642 }
00643 
00644 /* Public & Internal(Security Library)  representation of
00645  * encryption mechanism flags conversion */
00646 
00647 /* Currently, the only difference is that internal representation 
00648  * puts RANDOM_FLAG at bit 31 (Most-significant bit), but
00649  * public representation puts this bit at bit 28
00650  */
00651 unsigned long 
00652 SECMOD_PubMechFlagstoInternal(unsigned long publicFlags)
00653 {
00654     unsigned long internalFlags = publicFlags;
00655 
00656     if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) {
00657         internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG;
00658         internalFlags |= SECMOD_RANDOM_FLAG;
00659     }
00660     return internalFlags;
00661 }
00662 
00663 unsigned long 
00664 SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) 
00665 {
00666     unsigned long publicFlags = internalFlags;
00667 
00668     if (internalFlags & SECMOD_RANDOM_FLAG) {
00669         publicFlags &= ~SECMOD_RANDOM_FLAG;
00670         publicFlags |= PUBLIC_MECH_RANDOM_FLAG;
00671     }
00672     return publicFlags;
00673 }
00674 
00675 
00676 /* Public & Internal(Security Library)  representation of */
00677 /* cipher flags conversion */
00678 /* Note: currently they are just stubs */
00679 unsigned long 
00680 SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) 
00681 {
00682     return publicFlags;
00683 }
00684 
00685 unsigned long 
00686 SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) 
00687 {
00688     return internalFlags;
00689 }
00690 
00691 /* Funtion reports true if module of modType is installed/configured */
00692 PRBool 
00693 SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags )
00694 {
00695     PRBool result = PR_FALSE;
00696     SECMODModuleList *mods = SECMOD_GetDefaultModuleList();
00697     SECMOD_GetReadLock(moduleLock);
00698 
00699 
00700     for ( ; mods != NULL; mods = mods->next) {
00701         if (mods->module->ssl[0] & 
00702               SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) {
00703             result = PR_TRUE;
00704         }
00705     }
00706 
00707     SECMOD_ReleaseReadLock(moduleLock);
00708     return result;
00709 }
00710 
00711 /* create a new ModuleListElement */
00712 SECMODModuleList *SECMOD_NewModuleListElement(void) 
00713 {
00714     SECMODModuleList *newModList;
00715 
00716     newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList));
00717     if (newModList) {
00718        newModList->next = NULL;
00719        newModList->module = NULL;
00720     }
00721     return newModList;
00722 }
00723 
00724 /*
00725  * make a new reference to a module so It doesn't go away on us
00726  */
00727 SECMODModule *
00728 SECMOD_ReferenceModule(SECMODModule *module) 
00729 {
00730     PZ_Lock(module->refLock);
00731     PORT_Assert(module->refCount > 0);
00732 
00733     module->refCount++;
00734     PZ_Unlock(module->refLock);
00735     return module;
00736 }
00737 
00738 
00739 /* destroy an existing module */
00740 void
00741 SECMOD_DestroyModule(SECMODModule *module) 
00742 {
00743     PRBool willfree = PR_FALSE;
00744     int slotCount;
00745     int i;
00746 
00747     PZ_Lock(module->refLock);
00748     if (module->refCount-- == 1) {
00749        willfree = PR_TRUE;
00750     }
00751     PORT_Assert(willfree || (module->refCount > 0));
00752     PZ_Unlock(module->refLock);
00753 
00754     if (!willfree) {
00755        return;
00756     }
00757    
00758     if (module->parent != NULL) {
00759        SECMODModule *parent = module->parent;
00760        /* paranoia, don't loop forever if the modules are looped */
00761        module->parent = NULL;
00762        SECMOD_DestroyModule(parent);
00763     }
00764 
00765     /* slots can't really disappear until our module starts freeing them,
00766      * so this check is safe */
00767     slotCount = module->slotCount;
00768     if (slotCount == 0) {
00769        SECMOD_SlotDestroyModule(module,PR_FALSE);
00770        return;
00771     }
00772 
00773     /* now free all out slots, when they are done, they will cause the
00774      * module to disappear altogether */
00775     for (i=0 ; i < slotCount; i++) {
00776        if (!module->slots[i]->disabled) {
00777               PK11_ClearSlotList(module->slots[i]);
00778        }
00779        PK11_FreeSlot(module->slots[i]);
00780     }
00781     /* WARNING: once the last slot has been freed is it possible (even likely)
00782      * that module is no more... touching it now is a good way to go south */
00783 }
00784 
00785 
00786 /* we can only get here if we've destroyed the module, or some one has
00787  * erroneously freed a slot that wasn't referenced. */
00788 void
00789 SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) 
00790 {
00791     PRBool willfree = PR_FALSE;
00792     if (fromSlot) {
00793         PORT_Assert(module->refCount == 0);
00794        PZ_Lock(module->refLock);
00795        if (module->slotCount-- == 1) {
00796            willfree = PR_TRUE;
00797        }
00798        PORT_Assert(willfree || (module->slotCount > 0));
00799        PZ_Unlock(module->refLock);
00800         if (!willfree) return;
00801     }
00802 
00803     if (module == pendingModule) {
00804        pendingModule = NULL;
00805     }
00806 
00807     if (module->loaded) {
00808        SECMOD_UnloadModule(module);
00809     }
00810     PZ_DestroyLock(module->refLock);
00811     PORT_FreeArena(module->arena,PR_FALSE);
00812     secmod_PrivateModuleCount--;
00813 }
00814 
00815 /* destroy a list element
00816  * this destroys a single element, and returns the next element
00817  * on the chain. It makes it easy to implement for loops to delete
00818  * the chain. It also make deleting a single element easy */
00819 SECMODModuleList *
00820 SECMOD_DestroyModuleListElement(SECMODModuleList *element) 
00821 {
00822     SECMODModuleList *next = element->next;
00823 
00824     if (element->module) {
00825        SECMOD_DestroyModule(element->module);
00826        element->module = NULL;
00827     }
00828     PORT_Free(element);
00829     return next;
00830 }
00831 
00832 
00833 /*
00834  * Destroy an entire module list
00835  */
00836 void
00837 SECMOD_DestroyModuleList(SECMODModuleList *list) 
00838 {
00839     SECMODModuleList *lp;
00840 
00841     for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ;
00842 }
00843 
00844 PRBool
00845 SECMOD_CanDeleteInternalModule(void)
00846 {
00847     return (PRBool) (pendingModule == NULL);
00848 }
00849 
00850 /*
00851  * check to see if the module has added new slots. PKCS 11 v2.20 allows for
00852  * modules to add new slots, but never remove them. Slots cannot be added 
00853  * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent
00854  * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
00855  * grow on the caller. It is permissible for the slots to increase between
00856  * successive calls with NULL to get the size.
00857  */
00858 SECStatus
00859 SECMOD_UpdateSlotList(SECMODModule *mod)
00860 {
00861     CK_RV crv;
00862     CK_ULONG count;
00863     CK_ULONG i, oldCount;
00864     PRBool freeRef = PR_FALSE;
00865     void *mark = NULL;
00866     CK_ULONG *slotIDs = NULL;
00867     PK11SlotInfo **newSlots = NULL;
00868     PK11SlotInfo **oldSlots = NULL;
00869 
00870     /* C_GetSlotList is not a session function, make sure 
00871      * calls are serialized */
00872     PZ_Lock(mod->refLock);
00873     freeRef = PR_TRUE;
00874     /* see if the number of slots have changed */
00875     crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count);
00876     if (crv != CKR_OK) {
00877        PORT_SetError(PK11_MapError(crv));
00878        goto loser;
00879     }
00880     /* nothing new, blow out early, we want this function to be quick
00881      * and cheap in the normal case  */
00882     if (count == mod->slotCount) {
00883        PZ_Unlock(mod->refLock);
00884        return SECSuccess;
00885     }
00886     if (count < (CK_ULONG)mod->slotCount) {
00887        /* shouldn't happen with a properly functioning PKCS #11 module */
00888        PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 );
00889        goto loser;
00890     }
00891 
00892     /* get the new slot list */
00893     slotIDs = PORT_NewArray(CK_SLOT_ID, count);
00894     if (slotIDs == NULL) {
00895        goto loser;
00896     }
00897 
00898     crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count);
00899     if (crv != CKR_OK) {
00900        PORT_SetError(PK11_MapError(crv));
00901        goto loser;
00902     }
00903     freeRef = PR_FALSE;
00904     PZ_Unlock(mod->refLock);
00905     mark = PORT_ArenaMark(mod->arena);
00906     if (mark == NULL) {
00907        goto loser;
00908     }
00909     newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count);
00910 
00911     /* walk down the new slot ID list returned from the module. We keep
00912      * the old slots which match a returned ID, and we initialize the new 
00913      * slots. */
00914     for (i=0; i < count; i++) {
00915        PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]);
00916 
00917        if (!slot) {
00918            /* we have a new slot create a new slot data structure */
00919            slot = PK11_NewSlotInfo(mod);
00920            if (!slot) {
00921               goto loser;
00922            }
00923            PK11_InitSlot(mod, slotIDs[i], slot);
00924            STAN_InitTokenForSlotInfo(NULL, slot);
00925        }
00926        newSlots[i] = slot;
00927     }
00928     STAN_ResetTokenInterator(NULL);
00929     PORT_Free(slotIDs);
00930     slotIDs = NULL;
00931     PORT_ArenaUnmark(mod->arena, mark);
00932 
00933     /* until this point we're still using the old slot list. Now we update
00934      * module slot list. We update the slots (array) first then the count, 
00935      * since we've already guarrenteed that count has increased (just in case 
00936      * someone is looking at the slots field of  module without holding the 
00937      * moduleLock */
00938     SECMOD_GetWriteLock(moduleLock);
00939     oldCount =mod->slotCount;
00940     oldSlots = mod->slots;
00941     mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is
00942                          * allocated out of the module arena and won't
00943                          * be freed until the module is freed */
00944     mod->slotCount = count;
00945     SECMOD_ReleaseWriteLock(moduleLock);
00946     /* free our old references before forgetting about oldSlot*/
00947     for (i=0; i < oldCount; i++) {
00948        PK11_FreeSlot(oldSlots[i]);
00949     }
00950     return SECSuccess;
00951 
00952 loser:
00953     if (freeRef) {
00954        PZ_Unlock(mod->refLock);
00955     }
00956     if (slotIDs) {
00957        PORT_Free(slotIDs);
00958     }
00959     /* free all the slots we allocated. newSlots are part of the
00960      * mod arena. NOTE: the newSlots array contain both new and old
00961      * slots, but we kept a reference to the old slots when we built the new
00962      * array, so we need to free all the slots in newSlots array. */
00963     if (newSlots) {
00964        for (i=0; i < count; i++) {
00965            if (newSlots[i] == NULL) {
00966               break; /* hit the last one */
00967            }
00968            PK11_FreeSlot(newSlots[i]);
00969        }
00970     }
00971     /* must come after freeing newSlots */
00972     if (mark) {
00973        PORT_ArenaRelease(mod->arena, mark);
00974     }
00975     return SECFailure;
00976 }
00977 
00978 /*
00979  * this handles modules that do not support C_WaitForSlotEvent().
00980  * The internal flags are stored. Note that C_WaitForSlotEvent() does not
00981  * have a timeout, so we don't have one for handleWaitForSlotEvent() either.
00982  */
00983 PK11SlotInfo *
00984 secmod_HandleWaitForSlotEvent(SECMODModule *mod,  unsigned long flags,
00985                                           PRIntervalTime latency)
00986 {
00987     PRBool removableSlotsFound = PR_FALSE;
00988     int i;
00989     int error = SEC_ERROR_NO_EVENT;
00990 
00991     PZ_Lock(mod->refLock);
00992     if (mod->evControlMask & SECMOD_END_WAIT) {
00993        mod->evControlMask &= ~SECMOD_END_WAIT;
00994        PZ_Unlock(mod->refLock);
00995        PORT_SetError(SEC_ERROR_NO_EVENT);
00996        return NULL;
00997     }
00998     mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT;
00999     while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) {
01000        PZ_Unlock(mod->refLock);
01001        /* now is a good time to see if new slots have been added */
01002        SECMOD_UpdateSlotList(mod);
01003 
01004        /* loop through all the slots on a module */
01005        SECMOD_GetReadLock(moduleLock);
01006        for (i=0; i < mod->slotCount; i++) {
01007            PK11SlotInfo *slot = mod->slots[i];
01008            uint16 series;
01009            PRBool present;
01010 
01011            /* perm modules do not change */
01012            if (slot->isPerm) {
01013               continue;
01014            }
01015            removableSlotsFound = PR_TRUE;
01016            /* simulate the PKCS #11 module flags. are the flags different
01017             * from the last time we called? */
01018            series = slot->series;
01019            present = PK11_IsPresent(slot);
01020            if ((slot->flagSeries != series) || (slot->flagState != present)) {
01021               slot->flagState = present;
01022               slot->flagSeries = series;
01023               SECMOD_ReleaseReadLock(moduleLock);
01024               PZ_Lock(mod->refLock);
01025               mod->evControlMask &= ~SECMOD_END_WAIT;
01026               PZ_Unlock(mod->refLock);
01027               return PK11_ReferenceSlot(slot);
01028            }
01029        }
01030        SECMOD_ReleaseReadLock(moduleLock);
01031        /* if everything was perm modules, don't lock up forever */
01032        if (!removableSlotsFound) {
01033            error =SEC_ERROR_NO_SLOT_SELECTED;
01034            PZ_Lock(mod->refLock);
01035            break;
01036        }
01037        if (flags & CKF_DONT_BLOCK) {
01038            PZ_Lock(mod->refLock);
01039            break;
01040        }
01041        PR_Sleep(latency);
01042        PZ_Lock(mod->refLock);
01043     }
01044     mod->evControlMask &= ~SECMOD_END_WAIT;
01045     PZ_Unlock(mod->refLock);
01046     PORT_SetError(error);
01047     return NULL;
01048 }
01049 
01050 /*
01051  * this function waits for a token event on any slot of a given module
01052  * This function should not be called from more than one thread of the
01053  * same process (though other threads can make other library calls
01054  * on this module while this call is blocked).
01055  */
01056 PK11SlotInfo *
01057 SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags,
01058                                            PRIntervalTime latency)
01059 {
01060     CK_SLOT_ID id;
01061     CK_RV crv;
01062     PK11SlotInfo *slot;
01063 
01064     if (!pk11_getFinalizeModulesOption() ||
01065         ((mod->cryptokiVersion.major == 2) &&
01066          (mod->cryptokiVersion.minor < 1))) { 
01067         /* if we are sharing the module with other software in our
01068          * address space, we can't reliably use C_WaitForSlotEvent(),
01069          * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
01070          * exist */
01071        return secmod_HandleWaitForSlotEvent(mod, flags, latency);
01072     }
01073     /* first the the PKCS #11 call */
01074     PZ_Lock(mod->refLock);
01075     if (mod->evControlMask & SECMOD_END_WAIT) {
01076        goto end_wait;
01077     }
01078     mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT;
01079     PZ_Unlock(mod->refLock);
01080     crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL);
01081     PZ_Lock(mod->refLock);
01082     mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT;
01083     /* if we are in end wait, short circuit now, don't even risk
01084      * going into secmod_HandleWaitForSlotEvent */
01085     if (mod->evControlMask & SECMOD_END_WAIT) {
01086        goto end_wait;
01087     }
01088     PZ_Unlock(mod->refLock);
01089     if (crv == CKR_FUNCTION_NOT_SUPPORTED) {
01090        /* module doesn't support that call, simulate it */
01091        return secmod_HandleWaitForSlotEvent(mod, flags, latency);
01092     }
01093     if (crv != CKR_OK) {
01094        /* we can get this error if finalize was called while we were
01095         * still running. This is the only way to force a C_WaitForSlotEvent()
01096         * to return in PKCS #11. In this case, just return that there
01097         * was no event. */
01098        if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) {
01099            PORT_SetError(SEC_ERROR_NO_EVENT);
01100        } else {
01101            PORT_SetError(PK11_MapError(crv));
01102        }
01103        return NULL;
01104     }
01105     slot = SECMOD_FindSlotByID(mod, id);
01106     if (slot == NULL) {
01107        /* possibly a new slot that was added? */
01108        SECMOD_UpdateSlotList(mod);
01109        slot = SECMOD_FindSlotByID(mod, id);
01110     }
01111     /* if we are in the delay period for the "isPresent" call, reset
01112      * the delay since we know things have probably changed... */
01113     if (slot && slot->nssToken && slot->nssToken->slot) {
01114        nssSlot_ResetDelay(slot->nssToken->slot);
01115     }
01116     return slot;
01117 
01118     /* must be called with the lock on. */
01119 end_wait:
01120     mod->evControlMask &= ~SECMOD_END_WAIT;
01121     PZ_Unlock(mod->refLock);
01122     PORT_SetError(SEC_ERROR_NO_EVENT);
01123     return NULL;
01124 }
01125 
01126 /*
01127  * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic
01128  * function, possibly bringing down the pkcs #11 module in question. This
01129  * should be OK because 1) it does reinitialize, and 2) it should only be
01130  * called when we are on our way to tear the whole system down anyway.
01131  */
01132 SECStatus
01133 SECMOD_CancelWait(SECMODModule *mod)
01134 {
01135     unsigned long controlMask = mod->evControlMask;
01136     SECStatus rv = SECSuccess;
01137     CK_RV crv;
01138 
01139     PZ_Lock(mod->refLock);
01140     mod->evControlMask |= SECMOD_END_WAIT;
01141     controlMask = mod->evControlMask;
01142     if (controlMask & SECMOD_WAIT_PKCS11_EVENT) {
01143         if (!pk11_getFinalizeModulesOption()) {
01144             /* can't get here unless pk11_getFinalizeModulesOption is set */
01145             PORT_Assert(0);
01146             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01147             rv = SECFailure;
01148             goto loser;
01149         }
01150        /* NOTE: this call will drop all transient keys, in progress
01151         * operations, and any authentication. This is the only documented
01152         * way to get WaitForSlotEvent to return. Also note: for non-thread
01153         * safe tokens, we need to hold the module lock, this is not yet at
01154         * system shutdown/startup time, so we need to protect these calls */
01155        crv = PK11_GETTAB(mod)->C_Finalize(NULL);
01156        /* ok, we slammed the module down, now we need to reinit it in case
01157         * we intend to use it again */
01158        if (CKR_OK == crv) {
01159             PRBool alreadyLoaded;
01160            secmod_ModuleInit(mod, &alreadyLoaded);
01161        } else {
01162            /* Finalized failed for some reason,  notify the application
01163             * so maybe it has a prayer of recovering... */
01164            PORT_SetError(PK11_MapError(crv));
01165            rv = SECFailure;
01166        }
01167     } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) {
01168        mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; 
01169                             /* Simulated events will eventually timeout
01170                              * and wake up in the loop */
01171     }
01172 loser:
01173     PZ_Unlock(mod->refLock);
01174     return rv;
01175 }
01176 
01177 /*
01178  * check to see if the module has removable slots that we may need to
01179  * watch for.
01180  */
01181 PRBool
01182 SECMOD_HasRemovableSlots(SECMODModule *mod)
01183 {
01184     int i;
01185     PRBool ret = PR_FALSE;
01186 
01187     SECMOD_GetReadLock(moduleLock);
01188     for (i=0; i < mod->slotCount; i++) {
01189        PK11SlotInfo *slot = mod->slots[i];
01190        /* perm modules are not inserted or removed */
01191        if (slot->isPerm) {
01192            continue;
01193        }
01194        ret = PR_TRUE;
01195        break;
01196     }
01197     SECMOD_ReleaseReadLock(moduleLock);
01198     return ret;
01199 }
01200 
01201 /*
01202  * helper function to actually create and destroy user defined slots
01203  */
01204 static SECStatus
01205 secmod_UserDBOp(CK_OBJECT_CLASS objClass, const char *sendSpec)
01206 {
01207     PK11SlotInfo *slot = PK11_GetInternalSlot();
01208     CK_OBJECT_HANDLE dummy;
01209     CK_ATTRIBUTE template[2] ;
01210     CK_ATTRIBUTE *attrs = template;
01211     SECStatus rv;
01212     CK_RV crv;
01213 
01214     PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
01215     PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec,
01216                                     strlen(sendSpec)+1); attrs++;
01217 
01218     PORT_Assert(attrs-template <= 2);
01219 
01220 
01221     PK11_EnterSlotMonitor(slot);
01222     crv = PK11_CreateNewObject(slot, slot->session,
01223        template, attrs-template, PR_FALSE, &dummy);
01224     PK11_ExitSlotMonitor(slot);
01225 
01226     if (crv != CKR_OK) {
01227        PK11_FreeSlot(slot);
01228        PORT_SetError(PK11_MapError(crv));
01229        return SECFailure;
01230     }
01231     rv = SECMOD_UpdateSlotList(slot->module);
01232     PK11_FreeSlot(slot);
01233     return rv;
01234 }
01235 
01236 /*
01237  * add escapes to protect quote characters...
01238  */
01239 static char *
01240 nss_addEscape(const char *string, char quote)
01241 {
01242     char *newString = 0;
01243     int escapes = 0, size = 0;
01244     const char *src;
01245     char *dest;
01246 
01247     for (src=string; *src ; src++) {
01248         if ((*src == quote) || (*src == '\\')) escapes++;
01249         size++;
01250     }
01251 
01252     newString = PORT_ZAlloc(escapes+size+1);
01253     if (newString == NULL) {
01254         return NULL;
01255     }
01256 
01257     for (src=string, dest=newString; *src; src++,dest++) {
01258         if ((*src == '\\') || (*src == quote)) {
01259             *dest++ = '\\';
01260         }
01261         *dest = *src;
01262     }
01263 
01264     return newString;
01265 }
01266 
01267 static char *
01268 nss_doubleEscape(const char *string)
01269 {
01270     char *round1 = NULL;
01271     char *retValue = NULL;
01272     if (string == NULL) {
01273         goto done;
01274     }
01275     round1 = nss_addEscape(string,'>');
01276     if (round1) {
01277         retValue = nss_addEscape(round1,']');
01278         PORT_Free(round1);
01279     }
01280 
01281 done:
01282     if (retValue == NULL) {
01283         retValue = PORT_Strdup("");
01284     }
01285     return retValue;
01286 }
01287 
01288 /*
01289  * Open a new database using the softoken. The caller is responsible for making
01290  * sure the module spec is correct and usable. The caller should ask for one
01291  * new database per call if the caller wants to get meaningful information 
01292  * about the new database.
01293  *
01294  * moduleSpec is the same data that you would pass to softoken at 
01295  * initialization time under the 'tokens' options. For example, if you were
01296  * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
01297  * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
01298  * module spec here. The slot ID will be calculated for you by 
01299  * SECMOD_OpenUserDB().
01300  *
01301  * Typical parameters here are configdir, tokenDescription and flags.
01302  *
01303  * a Full list is below:
01304  *
01305  *
01306  *  configDir - The location of the databases for this token. If configDir is 
01307  *         not specified, and noCertDB and noKeyDB is not specified, the load
01308  *         will fail.
01309  *   certPrefix - Cert prefix for this token.
01310  *   keyPrefix - Prefix for the key database for this token. (if not specified,
01311  *         certPrefix will be used).
01312  *   tokenDescription - The label value for this token returned in the 
01313  *         CK_TOKEN_INFO structure with an internationalize string (UTF8). 
01314  *         This value will be truncated at 32 bytes (no NULL, partial UTF8 
01315  *         characters dropped). You should specify a user friendly name here
01316  *         as this is the value the token will be refered to in most 
01317  *         application UI's. You should make sure tokenDescription is unique.
01318  *   slotDescription - The slotDescription value for this token returned 
01319  *         in the CK_SLOT_INFO structure with an internationalize string 
01320  *         (UTF8). This value will be truncated at 64 bytes (no NULL, partial 
01321  *         UTF8 characters dropped). This name will not change after the 
01322  *         database is closed. It should have some number to make this unique.
01323  *   minPWLen - minimum password length for this token.
01324  *   flags - comma separated list of flag values, parsed case-insensitive.
01325  *         Valid flags are:
01326  *              readOnly - Databases should be opened read only.
01327  *              noCertDB - Don't try to open a certificate database.
01328  *              noKeyDB - Don't try to open a key database.
01329  *              forceOpen - Don't fail to initialize the token if the 
01330  *                databases could not be opened.
01331  *              passwordRequired - zero length passwords are not acceptable 
01332  *                (valid only if there is a keyDB).
01333  *              optimizeSpace - allocate smaller hash tables and lock tables.
01334  *                When this flag is not specified, Softoken will allocate 
01335  *                large tables to prevent lock contention. 
01336  */
01337 PK11SlotInfo *
01338 SECMOD_OpenUserDB(const char *moduleSpec)
01339 {
01340     CK_SLOT_ID slotID = 0;
01341     char *escSpec;
01342     char *sendSpec;
01343     SECStatus rv;
01344     SECMODModule *mod;
01345     CK_SLOT_ID i, minSlotID, maxSlotID;
01346     PRBool found = PR_FALSE;
01347 
01348     if (moduleSpec == NULL) {
01349        return NULL;
01350     }
01351 
01352     /* NOTE: unlike most PK11 function, this does not return a reference
01353      * to the module */
01354     mod = SECMOD_GetInternalModule();
01355     if (!mod) {
01356        /* shouldn't happen */
01357        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01358        return NULL;
01359     }
01360 
01361     /* look for a free slot id on the internal module */
01362     if (mod->isFIPS) {
01363        minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID;
01364        maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID;
01365     } else {
01366        minSlotID = SFTK_MIN_USER_SLOT_ID;
01367        maxSlotID = SFTK_MAX_USER_SLOT_ID;
01368     }
01369     for (i=minSlotID; i < maxSlotID; i++) {
01370        PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, i);
01371        if (slot) {
01372            PRBool present = PK11_IsPresent(slot);
01373            PK11_FreeSlot(slot);
01374            if (present) {
01375               continue;
01376            }
01377            /* not present means it's available */
01378        }
01379        /* it doesn't exist or isn't present, it's available */
01380        slotID = i;
01381        found = PR_TRUE;
01382        break;
01383     }
01384 
01385     if (!found) {
01386        /* this could happen if we try to open too many slots */
01387        PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
01388        return NULL;
01389     }
01390 
01391     /* we've found the slot, now build the moduleSpec */
01392 
01393     escSpec = nss_doubleEscape(moduleSpec);
01394     if (escSpec == NULL) {
01395        return NULL;
01396     }
01397     sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec);
01398     PORT_Free(escSpec);
01399 
01400     if (sendSpec == NULL) {
01401        /* PR_smprintf does not set no memory error */
01402        PORT_SetError(SEC_ERROR_NO_MEMORY);
01403        return NULL;
01404     }
01405     rv = secmod_UserDBOp(CKO_NETSCAPE_NEWSLOT, sendSpec);
01406     PR_smprintf_free(sendSpec);
01407     if (rv != SECSuccess) {
01408        return NULL;
01409     }
01410 
01411     return SECMOD_FindSlotByID(mod, slotID);
01412 }
01413 
01414 /*
01415  * close an already opened user database. NOTE: the database must be
01416  * in the internal token, and must be one created with SECMOD_OpenUserDB().
01417  * Once the database is closed, the slot will remain as an empty slot
01418  * until it's used again with SECMOD_OpenUserDB().
01419  */
01420 SECStatus
01421 SECMOD_CloseUserDB(PK11SlotInfo *slot)
01422 {
01423     SECStatus rv;
01424     char *sendSpec;
01425 
01426     if (!slot->isInternal) {
01427        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01428        return SECFailure;
01429     }
01430     
01431     sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID);
01432     if (sendSpec == NULL) {
01433        /* PR_smprintf does not set no memory error */
01434        PORT_SetError(SEC_ERROR_NO_MEMORY);
01435        return SECFailure;
01436     }
01437     rv = secmod_UserDBOp(CKO_NETSCAPE_DELSLOT, sendSpec);
01438     PR_smprintf_free(sendSpec);
01439     return rv;
01440 }