tor-browser

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

lgglue.c (11668B)


      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 *  The following code handles the storage of PKCS 11 modules used by the
      6 * NSS. This file is written to abstract away how the modules are
      7 * stored so we can deside that later.
      8 */
      9 #include "sftkdb.h"
     10 #include "sftkdbti.h"
     11 #include "sdb.h"
     12 #include "prsystem.h"
     13 #include "prprf.h"
     14 #include "prenv.h"
     15 #include "lgglue.h"
     16 #include "secerr.h"
     17 #include "softoken.h"
     18 
     19 static LGOpenFunc legacy_glue_open = NULL;
     20 static LGReadSecmodFunc legacy_glue_readSecmod = NULL;
     21 static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL;
     22 static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL;
     23 static LGAddSecmodFunc legacy_glue_addSecmod = NULL;
     24 static LGShutdownFunc legacy_glue_shutdown = NULL;
     25 
     26 /*
     27 * The following 3 functions duplicate the work done by bl_LoadLibrary.
     28 * We should make bl_LoadLibrary a global and replace the call to
     29 * sftkdb_LoadLibrary(const char *libname) with it.
     30 */
     31 #ifdef XP_UNIX
     32 #include <unistd.h>
     33 #define LG_MAX_LINKS 20
     34 static char *
     35 sftkdb_resolvePath(const char *orig)
     36 {
     37    int count = 0;
     38    int len = 0;
     39    int ret = -1;
     40    char *resolved = NULL;
     41    char *source = NULL;
     42 
     43    len = 1025; /* MAX PATH +1*/
     44    if (strlen(orig) + 1 > len) {
     45        /* PATH TOO LONG */
     46        return NULL;
     47    }
     48    resolved = PORT_Alloc(len);
     49    if (!resolved) {
     50        return NULL;
     51    }
     52    source = PORT_Alloc(len);
     53    if (!source) {
     54        goto loser;
     55    }
     56    PORT_Strcpy(source, orig);
     57    /* Walk down all the links */
     58    while (count++ < LG_MAX_LINKS) {
     59        char *tmp;
     60        /* swap our previous sorce out with resolved */
     61        /* read it */
     62        ret = readlink(source, resolved, len - 1);
     63        if (ret < 0) {
     64            break;
     65        }
     66        resolved[ret] = 0;
     67        tmp = source;
     68        source = resolved;
     69        resolved = tmp;
     70    }
     71    if (count > 1) {
     72        ret = 0;
     73    }
     74 loser:
     75    if (resolved) {
     76        PORT_Free(resolved);
     77    }
     78    if (ret < 0) {
     79        if (source) {
     80            PORT_Free(source);
     81            source = NULL;
     82        }
     83    }
     84    return source;
     85 }
     86 
     87 #endif
     88 
     89 static PRLibrary *
     90 sftkdb_LoadFromPath(const char *path, const char *libname)
     91 {
     92    char *c;
     93    int pathLen, nameLen, fullPathLen;
     94    char *fullPathName = NULL;
     95    PRLibSpec libSpec;
     96    PRLibrary *lib = NULL;
     97 
     98    /* strip of our parent's library name */
     99    c = strrchr(path, PR_GetDirectorySeparator());
    100    if (!c) {
    101        return NULL; /* invalid path */
    102    }
    103    pathLen = (c - path) + 1;
    104    nameLen = strlen(libname);
    105    fullPathLen = pathLen + nameLen + 1;
    106    fullPathName = (char *)PORT_Alloc(fullPathLen);
    107    if (fullPathName == NULL) {
    108        return NULL; /* memory allocation error */
    109    }
    110    PORT_Memcpy(fullPathName, path, pathLen);
    111    PORT_Memcpy(fullPathName + pathLen, libname, nameLen);
    112    fullPathName[fullPathLen - 1] = 0;
    113 
    114    libSpec.type = PR_LibSpec_Pathname;
    115    libSpec.value.pathname = fullPathName;
    116    lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
    117    PORT_Free(fullPathName);
    118    return lib;
    119 }
    120 
    121 static PRLibrary *
    122 sftkdb_LoadLibrary(const char *libname)
    123 {
    124    PRLibrary *lib = NULL;
    125    PRFuncPtr fn_addr;
    126    char *parentLibPath = NULL;
    127 
    128    fn_addr = (PRFuncPtr)&sftkdb_LoadLibrary;
    129    parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr);
    130 
    131    if (!parentLibPath) {
    132        goto done;
    133    }
    134 
    135    lib = sftkdb_LoadFromPath(parentLibPath, libname);
    136 #ifdef XP_UNIX
    137    /* handle symbolic link case */
    138    if (!lib) {
    139        char *trueParentLibPath = sftkdb_resolvePath(parentLibPath);
    140        if (!trueParentLibPath) {
    141            goto done;
    142        }
    143        lib = sftkdb_LoadFromPath(trueParentLibPath, libname);
    144        PORT_Free(trueParentLibPath);
    145    }
    146 #endif
    147 
    148 done:
    149    if (parentLibPath) {
    150        PORT_Free(parentLibPath);
    151    }
    152 
    153    /* still couldn't load it, try the generic path */
    154    if (!lib) {
    155        PRLibSpec libSpec;
    156        libSpec.type = PR_LibSpec_Pathname;
    157        libSpec.value.pathname = libname;
    158        lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
    159    }
    160 
    161    return lib;
    162 }
    163 
    164 /*
    165 * stub files for legacy db's to be able to encrypt and decrypt
    166 * various keys and attributes.
    167 */
    168 static SECStatus
    169 sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText,
    170                    SECItem **cipherText)
    171 {
    172    SFTKDBHandle *handle = sdb->app_private;
    173    SECStatus rv;
    174    SECItem *key;
    175    int iterationCount;
    176 
    177    if (handle == NULL) {
    178        return SECFailure;
    179    }
    180 
    181    /* if we aren't the key handle, try the other handle */
    182    if (handle->type != SFTK_KEYDB_TYPE) {
    183        handle = handle->peerDB;
    184    }
    185 
    186    /* not a key handle */
    187    if (handle == NULL || handle->passwordLock == NULL) {
    188        return SECFailure;
    189    }
    190 
    191    PZ_Lock(handle->passwordLock);
    192    if (handle->passwordKey.data == NULL) {
    193        PZ_Unlock(handle->passwordLock);
    194        /* PORT_SetError */
    195        return SECFailure;
    196    }
    197    key = handle->newKey ? handle->newKey : &handle->passwordKey;
    198    if (sftk_isLegacyIterationCountAllowed()) {
    199        if (handle->newKey) {
    200            iterationCount = handle->newDefaultIterationCount;
    201        } else {
    202            iterationCount = handle->defaultIterationCount;
    203        }
    204    } else {
    205        iterationCount = 1;
    206    }
    207 
    208    rv = sftkdb_EncryptAttribute(arena, handle, sdb, key, iterationCount,
    209                                 CK_INVALID_HANDLE, CKT_INVALID_TYPE,
    210                                 plainText, cipherText);
    211    PZ_Unlock(handle->passwordLock);
    212 
    213    return rv;
    214 }
    215 
    216 /*
    217 * stub files for legacy db's to be able to encrypt and decrypt
    218 * various keys and attributes.
    219 */
    220 static SECStatus
    221 sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText)
    222 {
    223    SFTKDBHandle *handle = sdb->app_private;
    224    SECStatus rv;
    225    SECItem *oldKey = NULL;
    226 
    227    if (handle == NULL) {
    228        return SECFailure;
    229    }
    230 
    231    /* if we aren't the key handle, try the other handle */
    232    oldKey = handle->oldKey;
    233    if (handle->type != SFTK_KEYDB_TYPE) {
    234        handle = handle->peerDB;
    235    }
    236 
    237    /* not a key handle */
    238    if (handle == NULL || handle->passwordLock == NULL) {
    239        return SECFailure;
    240    }
    241 
    242    PZ_Lock(handle->passwordLock);
    243    if (handle->passwordKey.data == NULL) {
    244        PZ_Unlock(handle->passwordLock);
    245        /* PORT_SetError */
    246        return SECFailure;
    247    }
    248    rv = sftkdb_DecryptAttribute(NULL, oldKey ? oldKey : &handle->passwordKey,
    249                                 CK_INVALID_HANDLE,
    250                                 CKT_INVALID_TYPE,
    251                                 cipherText, plainText);
    252    PZ_Unlock(handle->passwordLock);
    253 
    254    return rv;
    255 }
    256 
    257 static const char *LEGACY_LIB_NAME =
    258    SHLIB_PREFIX "nssdbm" SHLIB_VERSION "." SHLIB_SUFFIX;
    259 /*
    260 * 2 bools to tell us if we've check the legacy library successfully or
    261 * not. Initialize on startup to false by the C BSS segment;
    262 */
    263 static PRLibrary *legacy_glue_lib = NULL;
    264 static SECStatus
    265 sftkdbLoad_Legacy()
    266 {
    267    PRLibrary *lib = NULL;
    268    LGSetCryptFunc setCryptFunction = NULL;
    269 
    270    if (legacy_glue_lib) {
    271        return SECSuccess;
    272    }
    273 
    274    lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME);
    275    if (lib == NULL) {
    276        return SECFailure;
    277    }
    278 
    279    legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open");
    280    legacy_glue_readSecmod =
    281        (LGReadSecmodFunc)PR_FindFunctionSymbol(lib, "legacy_ReadSecmodDB");
    282    legacy_glue_releaseSecmod =
    283        (LGReleaseSecmodFunc)PR_FindFunctionSymbol(lib, "legacy_ReleaseSecmodDBData");
    284    legacy_glue_deleteSecmod =
    285        (LGDeleteSecmodFunc)PR_FindFunctionSymbol(lib, "legacy_DeleteSecmodDB");
    286    legacy_glue_addSecmod =
    287        (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, "legacy_AddSecmodDB");
    288    legacy_glue_shutdown =
    289        (LGShutdownFunc)PR_FindFunctionSymbol(lib, "legacy_Shutdown");
    290    setCryptFunction =
    291        (LGSetCryptFunc)PR_FindFunctionSymbol(lib, "legacy_SetCryptFunctions");
    292 
    293    if (!legacy_glue_open || !legacy_glue_readSecmod ||
    294        !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod ||
    295        !legacy_glue_addSecmod || !setCryptFunction) {
    296        PR_UnloadLibrary(lib);
    297        return SECFailure;
    298    }
    299 
    300    setCryptFunction(sftkdb_encrypt_stub, sftkdb_decrypt_stub);
    301    legacy_glue_lib = lib;
    302    return SECSuccess;
    303 }
    304 
    305 CK_RV
    306 sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix,
    307                int certVersion, int keyVersion, int flags,
    308                SDB **certDB, SDB **keyDB)
    309 {
    310    SECStatus rv;
    311 
    312    rv = sftkdbLoad_Legacy();
    313    if (rv != SECSuccess) {
    314        return CKR_GENERAL_ERROR;
    315    }
    316    if (!legacy_glue_open) {
    317        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    318        return SECFailure;
    319    }
    320    return (*legacy_glue_open)(dir, certPrefix, keyPrefix,
    321                               certVersion, keyVersion,
    322                               flags, certDB, keyDB);
    323 }
    324 
    325 char **
    326 sftkdbCall_ReadSecmodDB(const char *appName, const char *filename,
    327                        const char *dbname, char *params, PRBool rw)
    328 {
    329    SECStatus rv;
    330 
    331    rv = sftkdbLoad_Legacy();
    332    if (rv != SECSuccess) {
    333        return NULL;
    334    }
    335    if (!legacy_glue_readSecmod) {
    336        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    337        return NULL;
    338    }
    339    return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw);
    340 }
    341 
    342 SECStatus
    343 sftkdbCall_ReleaseSecmodDBData(const char *appName,
    344                               const char *filename, const char *dbname,
    345                               char **moduleSpecList, PRBool rw)
    346 {
    347    SECStatus rv;
    348 
    349    rv = sftkdbLoad_Legacy();
    350    if (rv != SECSuccess) {
    351        return rv;
    352    }
    353    if (!legacy_glue_releaseSecmod) {
    354        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    355        return SECFailure;
    356    }
    357    return (*legacy_glue_releaseSecmod)(appName, filename, dbname,
    358                                        moduleSpecList, rw);
    359 }
    360 
    361 SECStatus
    362 sftkdbCall_DeleteSecmodDB(const char *appName,
    363                          const char *filename, const char *dbname,
    364                          char *args, PRBool rw)
    365 {
    366    SECStatus rv;
    367 
    368    rv = sftkdbLoad_Legacy();
    369    if (rv != SECSuccess) {
    370        return rv;
    371    }
    372    if (!legacy_glue_deleteSecmod) {
    373        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    374        return SECFailure;
    375    }
    376    return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw);
    377 }
    378 
    379 SECStatus
    380 sftkdbCall_AddSecmodDB(const char *appName,
    381                       const char *filename, const char *dbname,
    382                       char *module, PRBool rw)
    383 {
    384    SECStatus rv;
    385 
    386    rv = sftkdbLoad_Legacy();
    387    if (rv != SECSuccess) {
    388        return rv;
    389    }
    390    if (!legacy_glue_addSecmod) {
    391        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    392        return SECFailure;
    393    }
    394    return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw);
    395 }
    396 
    397 CK_RV
    398 sftkdbCall_Shutdown(void)
    399 {
    400    CK_RV crv = CKR_OK;
    401    char *disableUnload = NULL;
    402    if (!legacy_glue_lib) {
    403        return CKR_OK;
    404    }
    405    if (legacy_glue_shutdown) {
    406 #ifdef NO_FORK_CHECK
    407        PRBool parentForkedAfterC_Initialize = PR_FALSE;
    408 #endif
    409        crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize);
    410    }
    411    disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
    412    if (!disableUnload) {
    413        PR_UnloadLibrary(legacy_glue_lib);
    414    }
    415    legacy_glue_lib = NULL;
    416    legacy_glue_open = NULL;
    417    legacy_glue_readSecmod = NULL;
    418    legacy_glue_releaseSecmod = NULL;
    419    legacy_glue_deleteSecmod = NULL;
    420    legacy_glue_addSecmod = NULL;
    421    return crv;
    422 }