andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * The following code handles the storage of PKCS 11 modules used by the andre@0: * NSS. This file is written to abstract away how the modules are andre@0: * stored so we can deside that later. andre@0: */ andre@0: #include "sftkdb.h" andre@0: #include "sftkdbti.h" andre@0: #include "sdb.h" andre@0: #include "prsystem.h" andre@0: #include "prprf.h" andre@0: #include "prenv.h" andre@0: #include "lgglue.h" andre@0: #include "secerr.h" andre@0: #include "softoken.h" andre@0: andre@0: static LGOpenFunc legacy_glue_open = NULL; andre@0: static LGReadSecmodFunc legacy_glue_readSecmod = NULL; andre@0: static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL; andre@0: static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL; andre@0: static LGAddSecmodFunc legacy_glue_addSecmod = NULL; andre@0: static LGShutdownFunc legacy_glue_shutdown = NULL; andre@0: andre@0: #ifndef NSS_STATIC andre@0: /* andre@0: * The following 3 functions duplicate the work done by bl_LoadLibrary. andre@0: * We should make bl_LoadLibrary a global and replace the call to andre@0: * sftkdb_LoadLibrary(const char *libname) with it. andre@0: */ andre@0: #ifdef XP_UNIX andre@0: #include andre@0: #define LG_MAX_LINKS 20 andre@0: static char * andre@0: sftkdb_resolvePath(const char *orig) andre@0: { andre@0: int count = 0; andre@0: int len =0; andre@0: int ret = -1; andre@0: char *resolved = NULL; andre@0: char *source = NULL; andre@0: andre@0: len = 1025; /* MAX PATH +1*/ andre@0: if (strlen(orig)+1 > len) { andre@0: /* PATH TOO LONG */ andre@0: return NULL; andre@0: } andre@0: resolved = PORT_Alloc(len); andre@0: if (!resolved) { andre@0: return NULL; andre@0: } andre@0: source = PORT_Alloc(len); andre@0: if (!source) { andre@0: goto loser; andre@0: } andre@0: PORT_Strcpy(source, orig); andre@0: /* Walk down all the links */ andre@0: while ( count++ < LG_MAX_LINKS) { andre@0: char *tmp; andre@0: /* swap our previous sorce out with resolved */ andre@0: /* read it */ andre@0: ret = readlink(source, resolved, len-1); andre@0: if (ret < 0) { andre@0: break; andre@0: } andre@0: resolved[ret] = 0; andre@0: tmp = source; source = resolved; resolved = tmp; andre@0: } andre@0: if (count > 1) { andre@0: ret = 0; andre@0: } andre@0: loser: andre@0: if (resolved) { andre@0: PORT_Free(resolved); andre@0: } andre@0: if (ret < 0) { andre@0: if (source) { andre@0: PORT_Free(source); andre@0: source = NULL; andre@0: } andre@0: } andre@0: return source; andre@0: } andre@0: andre@0: #endif andre@0: andre@0: static PRLibrary * andre@0: sftkdb_LoadFromPath(const char *path, const char *libname) andre@0: { andre@0: char *c; andre@0: int pathLen, nameLen, fullPathLen; andre@0: char *fullPathName = NULL; andre@0: PRLibSpec libSpec; andre@0: PRLibrary *lib = NULL; andre@0: andre@0: andre@0: /* strip of our parent's library name */ andre@0: c = strrchr(path, PR_GetDirectorySeparator()); andre@0: if (!c) { andre@0: return NULL; /* invalid path */ andre@0: } andre@0: pathLen = (c-path)+1; andre@0: nameLen = strlen(libname); andre@0: fullPathLen = pathLen + nameLen +1; andre@0: fullPathName = (char *)PORT_Alloc(fullPathLen); andre@0: if (fullPathName == NULL) { andre@0: return NULL; /* memory allocation error */ andre@0: } andre@0: PORT_Memcpy(fullPathName, path, pathLen); andre@0: PORT_Memcpy(fullPathName+pathLen, libname, nameLen); andre@0: fullPathName[fullPathLen-1] = 0; andre@0: andre@0: libSpec.type = PR_LibSpec_Pathname; andre@0: libSpec.value.pathname = fullPathName; andre@0: lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); andre@0: PORT_Free(fullPathName); andre@0: return lib; andre@0: } andre@0: andre@0: andre@0: static PRLibrary * andre@0: sftkdb_LoadLibrary(const char *libname) andre@0: { andre@0: PRLibrary *lib = NULL; andre@0: PRFuncPtr fn_addr; andre@0: char *parentLibPath = NULL; andre@0: andre@0: fn_addr = (PRFuncPtr) &sftkdb_LoadLibrary; andre@0: parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr); andre@0: andre@0: if (!parentLibPath) { andre@0: goto done; andre@0: } andre@0: andre@0: lib = sftkdb_LoadFromPath(parentLibPath, libname); andre@0: #ifdef XP_UNIX andre@0: /* handle symbolic link case */ andre@0: if (!lib) { andre@0: char *trueParentLibPath = sftkdb_resolvePath(parentLibPath); andre@0: if (!trueParentLibPath) { andre@0: goto done; andre@0: } andre@0: lib = sftkdb_LoadFromPath(trueParentLibPath, libname); andre@0: PORT_Free(trueParentLibPath); andre@0: } andre@0: #endif andre@0: andre@0: done: andre@0: if (parentLibPath) { andre@0: PORT_Free(parentLibPath); andre@0: } andre@0: andre@0: /* still couldn't load it, try the generic path */ andre@0: if (!lib) { andre@0: PRLibSpec libSpec; andre@0: libSpec.type = PR_LibSpec_Pathname; andre@0: libSpec.value.pathname = libname; andre@0: lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); andre@0: } andre@0: andre@0: return lib; andre@0: } andre@0: #endif /* STATIC LIBRARIES */ andre@0: andre@0: /* andre@0: * stub files for legacy db's to be able to encrypt and decrypt andre@0: * various keys and attributes. andre@0: */ andre@0: static SECStatus andre@0: sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText, andre@0: SECItem **cipherText) andre@0: { andre@0: SFTKDBHandle *handle = sdb->app_private; andre@0: SECStatus rv; andre@0: andre@0: if (handle == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* if we aren't the key handle, try the other handle */ andre@0: if (handle->type != SFTK_KEYDB_TYPE) { andre@0: handle = handle->peerDB; andre@0: } andre@0: andre@0: /* not a key handle */ andre@0: if (handle == NULL || handle->passwordLock == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: PZ_Lock(handle->passwordLock); andre@0: if (handle->passwordKey.data == NULL) { andre@0: PZ_Unlock(handle->passwordLock); andre@0: /* PORT_SetError */ andre@0: return SECFailure; andre@0: } andre@0: andre@0: rv = sftkdb_EncryptAttribute(arena, andre@0: handle->newKey?handle->newKey:&handle->passwordKey, andre@0: plainText, cipherText); andre@0: PZ_Unlock(handle->passwordLock); andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: * stub files for legacy db's to be able to encrypt and decrypt andre@0: * various keys and attributes. andre@0: */ andre@0: static SECStatus andre@0: sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) andre@0: { andre@0: SFTKDBHandle *handle = sdb->app_private; andre@0: SECStatus rv; andre@0: SECItem *oldKey = NULL; andre@0: andre@0: if (handle == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* if we aren't th handle, try the other handle */ andre@0: oldKey = handle->oldKey; andre@0: if (handle->type != SFTK_KEYDB_TYPE) { andre@0: handle = handle->peerDB; andre@0: } andre@0: andre@0: /* not a key handle */ andre@0: if (handle == NULL || handle->passwordLock == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: PZ_Lock(handle->passwordLock); andre@0: if (handle->passwordKey.data == NULL) { andre@0: PZ_Unlock(handle->passwordLock); andre@0: /* PORT_SetError */ andre@0: return SECFailure; andre@0: } andre@0: rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey, andre@0: cipherText, plainText); andre@0: PZ_Unlock(handle->passwordLock); andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: static const char *LEGACY_LIB_NAME = andre@0: SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX; andre@0: /* andre@0: * 2 bools to tell us if we've check the legacy library successfully or andre@0: * not. Initialize on startup to false by the C BSS segment; andre@0: */ andre@0: static PRBool legacy_glue_libCheckFailed; /* set if we failed the check */ andre@0: static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */ andre@0: static PRLibrary *legacy_glue_lib = NULL; andre@0: static SECStatus andre@0: sftkdbLoad_Legacy(PRBool isFIPS) andre@0: { andre@0: PRLibrary *lib = NULL; andre@0: LGSetCryptFunc setCryptFunction = NULL; andre@0: andre@0: if (legacy_glue_lib) { andre@0: /* this check is necessary because it's possible we loaded the andre@0: * legacydb to read secmod.db, which told us whether we were in andre@0: * FIPS mode or not. */ andre@0: if (isFIPS && !legacy_glue_libCheckSucceeded) { andre@0: if (legacy_glue_libCheckFailed || andre@0: !BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) { andre@0: legacy_glue_libCheckFailed = PR_TRUE; andre@0: /* don't clobber legacy glue to avoid race. just let it andre@0: * get cleared in shutdown */ andre@0: return SECFailure; andre@0: } andre@0: legacy_glue_libCheckSucceeded = PR_TRUE; andre@0: } andre@0: return SECSuccess; andre@0: } andre@0: andre@0: #ifdef NSS_STATIC andre@0: #ifdef NSS_DISABLE_DBM andre@0: return SECFailure; andre@0: #else andre@0: lib = (PRLibrary *) 0x8; andre@0: andre@0: legacy_glue_open = legacy_Open; andre@0: legacy_glue_readSecmod = legacy_ReadSecmodDB; andre@0: legacy_glue_releaseSecmod = legacy_ReleaseSecmodDBData; andre@0: legacy_glue_deleteSecmod = legacy_DeleteSecmodDB; andre@0: legacy_glue_addSecmod = legacy_AddSecmodDB; andre@0: legacy_glue_shutdown = legacy_Shutdown; andre@0: setCryptFunction = legacy_SetCryptFunctions; andre@0: #endif andre@0: #else andre@0: lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME); andre@0: if (lib == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open"); andre@0: legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib, andre@0: "legacy_ReadSecmodDB"); andre@0: legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib, andre@0: "legacy_ReleaseSecmodDBData"); andre@0: legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib, andre@0: "legacy_DeleteSecmodDB"); andre@0: legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, andre@0: "legacy_AddSecmodDB"); andre@0: legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, andre@0: "legacy_Shutdown"); andre@0: setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, andre@0: "legacy_SetCryptFunctions"); andre@0: andre@0: if (!legacy_glue_open || !legacy_glue_readSecmod || andre@0: !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || andre@0: !legacy_glue_addSecmod || !setCryptFunction) { andre@0: PR_UnloadLibrary(lib); andre@0: return SECFailure; andre@0: } andre@0: #endif /* NSS_STATIC */ andre@0: andre@0: /* verify the loaded library if we are in FIPS mode */ andre@0: if (isFIPS) { andre@0: if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) { andre@0: #ifndef NSS_STATIC andre@0: PR_UnloadLibrary(lib); andre@0: #endif andre@0: return SECFailure; andre@0: } andre@0: legacy_glue_libCheckSucceeded = PR_TRUE; andre@0: } andre@0: andre@0: setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub); andre@0: legacy_glue_lib = lib; andre@0: return SECSuccess; andre@0: } andre@0: andre@0: CK_RV andre@0: sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, andre@0: int certVersion, int keyVersion, int flags, PRBool isFIPS, andre@0: SDB **certDB, SDB **keyDB) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: rv = sftkdbLoad_Legacy(isFIPS); andre@0: if (rv != SECSuccess) { andre@0: return CKR_GENERAL_ERROR; andre@0: } andre@0: if (!legacy_glue_open) { andre@0: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); andre@0: return SECFailure; andre@0: } andre@0: return (*legacy_glue_open)(dir, certPrefix, keyPrefix, andre@0: certVersion, keyVersion, andre@0: flags, certDB, keyDB); andre@0: } andre@0: andre@0: char ** andre@0: sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, andre@0: const char *dbname, char *params, PRBool rw) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: rv = sftkdbLoad_Legacy(PR_FALSE); andre@0: if (rv != SECSuccess) { andre@0: return NULL; andre@0: } andre@0: if (!legacy_glue_readSecmod) { andre@0: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); andre@0: return NULL; andre@0: } andre@0: return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw); andre@0: } andre@0: andre@0: SECStatus andre@0: sftkdbCall_ReleaseSecmodDBData(const char *appName, andre@0: const char *filename, const char *dbname, andre@0: char **moduleSpecList, PRBool rw) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: rv = sftkdbLoad_Legacy(PR_FALSE); andre@0: if (rv != SECSuccess) { andre@0: return rv; andre@0: } andre@0: if (!legacy_glue_releaseSecmod) { andre@0: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); andre@0: return SECFailure; andre@0: } andre@0: return (*legacy_glue_releaseSecmod)(appName, filename, dbname, andre@0: moduleSpecList, rw); andre@0: } andre@0: andre@0: SECStatus andre@0: sftkdbCall_DeleteSecmodDB(const char *appName, andre@0: const char *filename, const char *dbname, andre@0: char *args, PRBool rw) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: rv = sftkdbLoad_Legacy(PR_FALSE); andre@0: if (rv != SECSuccess) { andre@0: return rv; andre@0: } andre@0: if (!legacy_glue_deleteSecmod) { andre@0: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); andre@0: return SECFailure; andre@0: } andre@0: return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw); andre@0: } andre@0: andre@0: SECStatus andre@0: sftkdbCall_AddSecmodDB(const char *appName, andre@0: const char *filename, const char *dbname, andre@0: char *module, PRBool rw) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: rv = sftkdbLoad_Legacy(PR_FALSE); andre@0: if (rv != SECSuccess) { andre@0: return rv; andre@0: } andre@0: if (!legacy_glue_addSecmod) { andre@0: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); andre@0: return SECFailure; andre@0: } andre@0: return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw); andre@0: } andre@0: andre@0: CK_RV andre@0: sftkdbCall_Shutdown(void) andre@0: { andre@0: CK_RV crv = CKR_OK; andre@0: char *disableUnload = NULL; andre@0: if (!legacy_glue_lib) { andre@0: return CKR_OK; andre@0: } andre@0: if (legacy_glue_shutdown) { andre@0: #ifdef NO_FORK_CHECK andre@0: PRBool parentForkedAfterC_Initialize = PR_FALSE; andre@0: #endif andre@0: crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize); andre@0: } andre@0: #ifndef NSS_STATIC andre@0: disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); andre@0: if (!disableUnload) { andre@0: PR_UnloadLibrary(legacy_glue_lib); andre@0: } andre@0: #endif andre@0: legacy_glue_lib = NULL; andre@0: legacy_glue_open = NULL; andre@0: legacy_glue_readSecmod = NULL; andre@0: legacy_glue_releaseSecmod = NULL; andre@0: legacy_glue_deleteSecmod = NULL; andre@0: legacy_glue_addSecmod = NULL; andre@0: legacy_glue_libCheckFailed = PR_FALSE; andre@0: legacy_glue_libCheckSucceeded = PR_FALSE; andre@0: return crv; andre@0: } andre@0: andre@0: