tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11util.c (52149B)


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