tor-browser

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

lginit.c (15504B)


      1 /*
      2 * NSS utility functions
      3 *
      4 * This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "lowkeyi.h"
      9 #include "pcert.h"
     10 #include "keydbi.h"
     11 #include "lgdb.h"
     12 #include "secoid.h"
     13 #include "prenv.h"
     14 #include "softkver.h"
     15 
     16 /* Library identity and versioning */
     17 
     18 #if defined(DEBUG)
     19 #define _DEBUG_STRING " (debug)"
     20 #else
     21 #define _DEBUG_STRING ""
     22 #endif
     23 
     24 /*
     25 * Version information
     26 */
     27 const char __nss_dbm_version[] = "Version: NSS " SOFTOKEN_VERSION _DEBUG_STRING;
     28 
     29 typedef struct LGPrivateStr {
     30    NSSLOWCERTCertDBHandle *certDB;
     31    NSSLOWKEYDBHandle *keyDB;
     32    PRLock *dbLock;
     33    PLHashTable *hashTable;
     34 } LGPrivate;
     35 
     36 static char *
     37 lg_certdb_name_cb(void *arg, int dbVersion)
     38 {
     39    const char *configdir = (const char *)arg;
     40    const char *dbver;
     41    char *smpname = NULL;
     42    char *dbname = NULL;
     43 
     44    switch (dbVersion) {
     45        case 8:
     46            dbver = "8";
     47            break;
     48        case 7:
     49            dbver = "7";
     50            break;
     51        case 6:
     52            dbver = "6";
     53            break;
     54        case 5:
     55            dbver = "5";
     56            break;
     57        case 4:
     58        default:
     59            dbver = "";
     60            break;
     61    }
     62 
     63    /* make sure we return something allocated with PORT_ so we have properly
     64     * matched frees at the end */
     65    smpname = PR_smprintf(CERT_DB_FMT, configdir, dbver);
     66    if (smpname) {
     67        dbname = PORT_Strdup(smpname);
     68        PR_smprintf_free(smpname);
     69    }
     70    return dbname;
     71 }
     72 
     73 static char *
     74 lg_keydb_name_cb(void *arg, int dbVersion)
     75 {
     76    const char *configdir = (const char *)arg;
     77    const char *dbver;
     78    char *smpname = NULL;
     79    char *dbname = NULL;
     80 
     81    switch (dbVersion) {
     82        case 4:
     83            dbver = "4";
     84            break;
     85        case 3:
     86            dbver = "3";
     87            break;
     88        case 1:
     89            dbver = "1";
     90            break;
     91        case 2:
     92        default:
     93            dbver = "";
     94            break;
     95    }
     96 
     97    smpname = PR_smprintf(KEY_DB_FMT, configdir, dbver);
     98    if (smpname) {
     99        dbname = PORT_Strdup(smpname);
    100        PR_smprintf_free(smpname);
    101    }
    102    return dbname;
    103 }
    104 
    105 const char *
    106 lg_EvaluateConfigDir(const char *configdir, char **appName)
    107 {
    108    if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS) - 1) == 0) {
    109        char *cdir;
    110 
    111        *appName = PORT_Strdup(configdir + sizeof(MULTIACCESS) - 1);
    112        if (*appName == NULL) {
    113            return configdir;
    114        }
    115        cdir = *appName;
    116        while (*cdir && *cdir != ':') {
    117            cdir++;
    118        }
    119        if (*cdir == ':') {
    120            *cdir = 0;
    121            cdir++;
    122        }
    123        configdir = cdir;
    124    }
    125    return configdir;
    126 }
    127 
    128 static int rdbmapflags(int flags);
    129 static rdbfunc lg_rdbfunc = NULL;
    130 static rdbstatusfunc lg_rdbstatusfunc = NULL;
    131 
    132 /* NOTE: SHLIB_SUFFIX is defined on the command line */
    133 #define RDBLIB SHLIB_PREFIX "rdb." SHLIB_SUFFIX
    134 
    135 DB *
    136 rdbopen(const char *appName, const char *prefix,
    137        const char *type, int flags, int *status)
    138 {
    139    PRLibrary *lib;
    140    DB *db;
    141    char *disableUnload = NULL;
    142 
    143    if (lg_rdbfunc) {
    144        db = (*lg_rdbfunc)(appName, prefix, type, rdbmapflags(flags));
    145        if (!db && status && lg_rdbstatusfunc) {
    146            *status = (*lg_rdbstatusfunc)();
    147        }
    148        return db;
    149    }
    150 
    151    /*
    152     * try to open the library.
    153     */
    154    lib = PR_LoadLibrary(RDBLIB);
    155 
    156    if (!lib) {
    157        return NULL;
    158    }
    159 
    160    /* get the entry points */
    161    lg_rdbstatusfunc = (rdbstatusfunc)PR_FindSymbol(lib, "rdbstatus");
    162    lg_rdbfunc = (rdbfunc)PR_FindSymbol(lib, "rdbopen");
    163    if (lg_rdbfunc) {
    164        db = (*lg_rdbfunc)(appName, prefix, type, rdbmapflags(flags));
    165        if (!db && status && lg_rdbstatusfunc) {
    166            *status = (*lg_rdbstatusfunc)();
    167        }
    168        return db;
    169    }
    170 
    171    /* couldn't find the entry point, unload the library and fail */
    172    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
    173    if (!disableUnload) {
    174        PR_UnloadLibrary(lib);
    175    }
    176    return NULL;
    177 }
    178 
    179 /*
    180 * the following data structures are from rdb.h.
    181 */
    182 struct RDBStr {
    183    DB db;
    184    int (*xactstart)(DB *db);
    185    int (*xactdone)(DB *db, PRBool abort);
    186    int version;
    187    int (*dbinitcomplete)(DB *db);
    188 };
    189 
    190 #define DB_RDB ((DBTYPE)0xff)
    191 #define RDB_RDONLY 1
    192 #define RDB_RDWR 2
    193 #define RDB_CREATE 4
    194 
    195 static int
    196 rdbmapflags(int flags)
    197 {
    198    switch (flags) {
    199        case NO_RDONLY:
    200            return RDB_RDONLY;
    201        case NO_RDWR:
    202            return RDB_RDWR;
    203        case NO_CREATE:
    204            return RDB_CREATE;
    205        default:
    206            break;
    207    }
    208    return 0;
    209 }
    210 
    211 PRBool
    212 db_IsRDB(DB *db)
    213 {
    214    return (PRBool)db->type == DB_RDB;
    215 }
    216 
    217 int
    218 db_BeginTransaction(DB *db)
    219 {
    220    struct RDBStr *rdb = (struct RDBStr *)db;
    221    if (db->type != DB_RDB) {
    222        return 0;
    223    }
    224 
    225    return rdb->xactstart(db);
    226 }
    227 
    228 int
    229 db_FinishTransaction(DB *db, PRBool abort)
    230 {
    231    struct RDBStr *rdb = (struct RDBStr *)db;
    232    if (db->type != DB_RDB) {
    233        return 0;
    234    }
    235 
    236    return rdb->xactdone(db, abort);
    237 }
    238 
    239 static DB *
    240 lg_getRawDB(SDB *sdb)
    241 {
    242    NSSLOWCERTCertDBHandle *certDB;
    243    NSSLOWKEYDBHandle *keyDB;
    244 
    245    certDB = lg_getCertDB(sdb);
    246    if (certDB) {
    247        return certDB->permCertDB;
    248    }
    249    keyDB = lg_getKeyDB(sdb);
    250    if (keyDB) {
    251        return keyDB->db;
    252    }
    253    return NULL;
    254 }
    255 
    256 CK_RV
    257 lg_Begin(SDB *sdb)
    258 {
    259    DB *db = lg_getRawDB(sdb);
    260    int ret;
    261 
    262    if (db == NULL) {
    263        return CKR_GENERAL_ERROR; /* shouldn't happen */
    264    }
    265    ret = db_BeginTransaction(db);
    266    if (ret != 0) {
    267        return CKR_GENERAL_ERROR; /* could happen */
    268    }
    269    return CKR_OK;
    270 }
    271 
    272 CK_RV
    273 lg_Commit(SDB *sdb)
    274 {
    275    DB *db = lg_getRawDB(sdb);
    276    int ret;
    277 
    278    if (db == NULL) {
    279        return CKR_GENERAL_ERROR; /* shouldn't happen */
    280    }
    281    ret = db_FinishTransaction(db, PR_FALSE);
    282    if (ret != 0) {
    283        return CKR_GENERAL_ERROR; /* could happen */
    284    }
    285    return CKR_OK;
    286 }
    287 
    288 CK_RV
    289 lg_Abort(SDB *sdb)
    290 {
    291    DB *db = lg_getRawDB(sdb);
    292    int ret;
    293 
    294    if (db == NULL) {
    295        return CKR_GENERAL_ERROR; /* shouldn't happen */
    296    }
    297    ret = db_FinishTransaction(db, PR_TRUE);
    298    if (ret != 0) {
    299        return CKR_GENERAL_ERROR; /* could happen */
    300    }
    301    return CKR_OK;
    302 }
    303 
    304 int
    305 db_InitComplete(DB *db)
    306 {
    307    struct RDBStr *rdb = (struct RDBStr *)db;
    308    if (db->type != DB_RDB) {
    309        return 0;
    310    }
    311    /* we should have added a version number to the RDBS structure. Since we
    312     * didn't, we detect that we have and 'extended' structure if the rdbstatus
    313     * func exists */
    314    if (!lg_rdbstatusfunc) {
    315        return 0;
    316    }
    317 
    318    return rdb->dbinitcomplete(db);
    319 }
    320 
    321 SECStatus
    322 db_Copy(DB *dest, DB *src)
    323 {
    324    int ret;
    325    DBT key, data;
    326    ret = (*src->seq)(src, &key, &data, R_FIRST);
    327    if (ret) {
    328        return SECSuccess;
    329    }
    330 
    331    do {
    332        (void)(*dest->put)(dest, &key, &data, R_NOOVERWRITE);
    333    } while ((*src->seq)(src, &key, &data, R_NEXT) == 0);
    334    (void)(*dest->sync)(dest, 0);
    335 
    336    return SECSuccess;
    337 }
    338 
    339 static CK_RV
    340 lg_OpenCertDB(const char *configdir, const char *prefix, PRBool readOnly,
    341              NSSLOWCERTCertDBHandle **certdbPtr)
    342 {
    343    NSSLOWCERTCertDBHandle *certdb = NULL;
    344    CK_RV crv = CKR_NSS_CERTDB_FAILED;
    345    SECStatus rv;
    346    char *name = NULL;
    347    char *appName = NULL;
    348 
    349    if (prefix == NULL) {
    350        prefix = "";
    351    }
    352 
    353    configdir = lg_EvaluateConfigDir(configdir, &appName);
    354 
    355    name = PR_smprintf("%s" PATH_SEPARATOR "%s", configdir, prefix);
    356    if (name == NULL)
    357        goto loser;
    358 
    359    certdb = (NSSLOWCERTCertDBHandle *)PORT_ZAlloc(sizeof(NSSLOWCERTCertDBHandle));
    360    if (certdb == NULL)
    361        goto loser;
    362 
    363    certdb->ref = 1;
    364    /* fix when we get the DB in */
    365    rv = nsslowcert_OpenCertDB(certdb, readOnly, appName, prefix,
    366                               lg_certdb_name_cb, (void *)name, PR_FALSE);
    367    if (rv == SECSuccess) {
    368        crv = CKR_OK;
    369        *certdbPtr = certdb;
    370        certdb = NULL;
    371    }
    372 loser:
    373    if (certdb)
    374        PR_Free(certdb);
    375    if (name)
    376        PR_smprintf_free(name);
    377    if (appName)
    378        PORT_Free(appName);
    379    return crv;
    380 }
    381 
    382 static CK_RV
    383 lg_OpenKeyDB(const char *configdir, const char *prefix, PRBool readOnly,
    384             NSSLOWKEYDBHandle **keydbPtr)
    385 {
    386    NSSLOWKEYDBHandle *keydb;
    387    char *name = NULL;
    388    char *appName = NULL;
    389 
    390    if (prefix == NULL) {
    391        prefix = "";
    392    }
    393    configdir = lg_EvaluateConfigDir(configdir, &appName);
    394 
    395    name = PR_smprintf("%s" PATH_SEPARATOR "%s", configdir, prefix);
    396    if (name == NULL)
    397        return CKR_HOST_MEMORY;
    398    keydb = nsslowkey_OpenKeyDB(readOnly, appName, prefix,
    399                                lg_keydb_name_cb, (void *)name);
    400    PR_smprintf_free(name);
    401    if (appName)
    402        PORT_Free(appName);
    403    if (keydb == NULL)
    404        return CKR_NSS_KEYDB_FAILED;
    405    *keydbPtr = keydb;
    406 
    407    return CKR_OK;
    408 }
    409 
    410 /*
    411 * Accessors for the private parts of the sdb structure.
    412 */
    413 void
    414 lg_DBLock(SDB *sdb)
    415 {
    416    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
    417    SKIP_AFTER_FORK(PR_Lock(lgdb_p->dbLock));
    418 }
    419 
    420 void
    421 lg_DBUnlock(SDB *sdb)
    422 {
    423    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
    424    SKIP_AFTER_FORK(PR_Unlock(lgdb_p->dbLock));
    425 }
    426 
    427 PLHashTable *
    428 lg_GetHashTable(SDB *sdb)
    429 {
    430    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
    431    return lgdb_p->hashTable;
    432 }
    433 
    434 NSSLOWCERTCertDBHandle *
    435 lg_getCertDB(SDB *sdb)
    436 {
    437    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
    438 
    439    return lgdb_p->certDB;
    440 }
    441 
    442 NSSLOWKEYDBHandle *
    443 lg_getKeyDB(SDB *sdb)
    444 {
    445    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
    446 
    447    return lgdb_p->keyDB;
    448 }
    449 
    450 PRBool lg_parentForkedAfterC_Initialize;
    451 
    452 void
    453 lg_SetForkState(PRBool forked)
    454 {
    455    lg_parentForkedAfterC_Initialize = forked;
    456 }
    457 
    458 CK_RV
    459 lg_Close(SDB *sdb)
    460 {
    461    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
    462    lg_ClearTokenKeyHashTable(sdb);
    463    if (lgdb_p) {
    464        if (lgdb_p->certDB) {
    465            nsslowcert_ClosePermCertDB(lgdb_p->certDB);
    466        } else if (lgdb_p->keyDB) {
    467            nsslowkey_CloseKeyDB(lgdb_p->keyDB);
    468        }
    469        if (lgdb_p->dbLock) {
    470            SKIP_AFTER_FORK(PR_DestroyLock(lgdb_p->dbLock));
    471        }
    472        if (lgdb_p->hashTable) {
    473            PL_HashTableDestroy(lgdb_p->hashTable);
    474        }
    475        PORT_Free(lgdb_p);
    476    }
    477    PORT_Free(sdb);
    478    return CKR_OK;
    479 }
    480 
    481 static PLHashNumber
    482 lg_HashNumber(const void *key)
    483 {
    484    return (PLHashNumber)((char *)key - (char *)NULL);
    485 }
    486 
    487 /*
    488 * helper function to wrap a NSSLOWCERTCertDBHandle or a NSSLOWKEYDBHandle
    489 * with and sdb structure.
    490 */
    491 CK_RV
    492 lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr,
    493        NSSLOWKEYDBHandle *keydbPtr)
    494 {
    495    SDB *sdb = NULL;
    496    LGPrivate *lgdb_p = NULL;
    497    CK_RV error = CKR_HOST_MEMORY;
    498 
    499    *pSdb = NULL;
    500    sdb = (SDB *)PORT_Alloc(sizeof(SDB));
    501    if (sdb == NULL) {
    502        goto loser;
    503    }
    504    lgdb_p = (LGPrivate *)PORT_Alloc(sizeof(LGPrivate));
    505    if (lgdb_p == NULL) {
    506        goto loser;
    507    }
    508    /* invariant fields */
    509    lgdb_p->certDB = certdbPtr;
    510    lgdb_p->keyDB = keydbPtr;
    511    lgdb_p->dbLock = PR_NewLock();
    512    if (lgdb_p->dbLock == NULL) {
    513        goto loser;
    514    }
    515    lgdb_p->hashTable = PL_NewHashTable(64, lg_HashNumber, PL_CompareValues,
    516                                        SECITEM_HashCompare, NULL, 0);
    517    if (lgdb_p->hashTable == NULL) {
    518        PR_DestroyLock(lgdb_p->dbLock);
    519        goto loser;
    520    }
    521 
    522    sdb->private = lgdb_p;
    523    sdb->version = 1;
    524    sdb->sdb_flags = flags;
    525    sdb->app_private = NULL;
    526    sdb->sdb_FindObjectsInit = lg_FindObjectsInit;
    527    sdb->sdb_FindObjects = lg_FindObjects;
    528    sdb->sdb_FindObjectsFinal = lg_FindObjectsFinal;
    529    sdb->sdb_GetAttributeValue = lg_GetAttributeValue;
    530    sdb->sdb_SetAttributeValue = lg_SetAttributeValue;
    531    sdb->sdb_CreateObject = lg_CreateObject;
    532    sdb->sdb_DestroyObject = lg_DestroyObject;
    533    sdb->sdb_GetMetaData = lg_GetMetaData;
    534    sdb->sdb_PutMetaData = lg_PutMetaData;
    535    sdb->sdb_DestroyMetaData = lg_DestroyMetaData;
    536    sdb->sdb_Begin = lg_Begin;
    537    sdb->sdb_Commit = lg_Commit;
    538    sdb->sdb_Abort = lg_Abort;
    539    sdb->sdb_Reset = lg_Reset;
    540    sdb->sdb_Close = lg_Close;
    541    sdb->sdb_SetForkState = lg_SetForkState;
    542    sdb->sdb_GetNewObjectID = lg_GetNewObjectID;
    543 
    544    *pSdb = sdb;
    545    return CKR_OK;
    546 
    547 loser:
    548    if (sdb) {
    549        PORT_Free(sdb);
    550    }
    551    if (lgdb_p) {
    552        PORT_Free(lgdb_p);
    553    }
    554    return error;
    555 }
    556 
    557 /*
    558 * OK there are now lots of options here, lets go through them all:
    559 *
    560 * configdir - base directory where all the cert, key, and module datbases live.
    561 * certPrefix - prefix added to the beginning of the cert database example: "
    562 *              "https-server1-"
    563 * keyPrefix - prefix added to the beginning of the key database example: "
    564 *             "https-server1-"
    565 * secmodName - name of the security module database (usually "secmod.db").
    566 * readOnly - Boolean: true if the databases are to be openned read only.
    567 * nocertdb - Don't open the cert DB and key DB's, just initialize the
    568 *            Volatile certdb.
    569 * nomoddb - Don't open the security module DB, just initialize the
    570 *           PKCS #11 module.
    571 * forceOpen - Continue to force initializations even if the databases cannot
    572 *             be opened.
    573 */
    574 CK_RV
    575 legacy_Open(const char *configdir, const char *certPrefix,
    576            const char *keyPrefix, int certVersion, int keyVersion,
    577            int flags, SDB **certDB, SDB **keyDB)
    578 {
    579    CK_RV crv = CKR_OK;
    580    SECStatus rv;
    581    PRBool readOnly = ((flags & 0x7) == SDB_RDONLY) ? PR_TRUE : PR_FALSE;
    582 
    583 #define NSS_VERSION_VARIABLE __nss_dbm_version
    584 #include "verref.h"
    585 
    586 #ifndef NSS_FIPS_DISABLED
    587    if (flags & SDB_FIPS) {
    588        /* We shouldn't get here when FIPS is not enabled on the database. But
    589         * we also don't care when this NSS build doesn't support FIPS. */
    590        if (!lg_FIPSEntryOK()) {
    591            return CKR_DEVICE_ERROR;
    592        }
    593    }
    594 #endif
    595 
    596    rv = SECOID_Init();
    597    if (SECSuccess != rv) {
    598        return CKR_DEVICE_ERROR;
    599    }
    600    nsslowcert_InitLocks();
    601 
    602    if (keyDB)
    603        *keyDB = NULL;
    604    if (certDB)
    605        *certDB = NULL;
    606 
    607    if (certDB) {
    608        NSSLOWCERTCertDBHandle *certdbPtr = NULL;
    609 
    610        crv = lg_OpenCertDB(configdir, certPrefix, readOnly, &certdbPtr);
    611        if (crv != CKR_OK) {
    612            goto loser;
    613        }
    614        crv = lg_init(certDB, flags, certdbPtr, NULL);
    615        if (crv != CKR_OK) {
    616            nsslowcert_ClosePermCertDB(certdbPtr);
    617            goto loser;
    618        }
    619    }
    620    if (keyDB) {
    621        NSSLOWKEYDBHandle *keydbPtr;
    622 
    623        crv = lg_OpenKeyDB(configdir, keyPrefix, readOnly, &keydbPtr);
    624        if (crv != CKR_OK) {
    625            goto loser;
    626        }
    627        crv = lg_init(keyDB, flags, NULL, keydbPtr);
    628        if (crv != CKR_OK) {
    629            nsslowkey_CloseKeyDB(keydbPtr);
    630            goto loser;
    631        }
    632        if (certDB && *certDB) {
    633            LGPrivate *lgdb_p = (LGPrivate *)(*certDB)->private;
    634            lgdb_p->keyDB = keydbPtr;
    635        }
    636    }
    637 
    638 loser:
    639    if (crv != CKR_OK) {
    640        if (keyDB && *keyDB) {
    641            lg_Close(*keyDB);
    642            *keyDB = NULL;
    643        }
    644        if (certDB && *certDB) {
    645            lg_Close(*certDB);
    646            *certDB = NULL;
    647        }
    648    }
    649    return crv;
    650 }
    651 
    652 CK_RV
    653 legacy_Shutdown(PRBool forked)
    654 {
    655    lg_SetForkState(forked);
    656    nsslowcert_DestroyFreeLists();
    657    nsslowcert_DestroyGlobalLocks();
    658    SECOID_Shutdown();
    659    lg_SetForkState(PR_FALSE);
    660    return CKR_OK;
    661 }