1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/lgglue.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,436 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * The following code handles the storage of PKCS 11 modules used by the 1.9 + * NSS. This file is written to abstract away how the modules are 1.10 + * stored so we can deside that later. 1.11 + */ 1.12 +#include "sftkdb.h" 1.13 +#include "sftkdbti.h" 1.14 +#include "sdb.h" 1.15 +#include "prsystem.h" 1.16 +#include "prprf.h" 1.17 +#include "prenv.h" 1.18 +#include "lgglue.h" 1.19 +#include "secerr.h" 1.20 +#include "softoken.h" 1.21 + 1.22 +static LGOpenFunc legacy_glue_open = NULL; 1.23 +static LGReadSecmodFunc legacy_glue_readSecmod = NULL; 1.24 +static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL; 1.25 +static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL; 1.26 +static LGAddSecmodFunc legacy_glue_addSecmod = NULL; 1.27 +static LGShutdownFunc legacy_glue_shutdown = NULL; 1.28 + 1.29 +/* 1.30 + * The following 3 functions duplicate the work done by bl_LoadLibrary. 1.31 + * We should make bl_LoadLibrary a global and replace the call to 1.32 + * sftkdb_LoadLibrary(const char *libname) with it. 1.33 + */ 1.34 +#ifdef XP_UNIX 1.35 +#include <unistd.h> 1.36 +#define LG_MAX_LINKS 20 1.37 +static char * 1.38 +sftkdb_resolvePath(const char *orig) 1.39 +{ 1.40 + int count = 0; 1.41 + int len =0; 1.42 + int ret = -1; 1.43 + char *resolved = NULL; 1.44 + char *source = NULL; 1.45 + 1.46 + len = 1025; /* MAX PATH +1*/ 1.47 + if (strlen(orig)+1 > len) { 1.48 + /* PATH TOO LONG */ 1.49 + return NULL; 1.50 + } 1.51 + resolved = PORT_Alloc(len); 1.52 + if (!resolved) { 1.53 + return NULL; 1.54 + } 1.55 + source = PORT_Alloc(len); 1.56 + if (!source) { 1.57 + goto loser; 1.58 + } 1.59 + PORT_Strcpy(source, orig); 1.60 + /* Walk down all the links */ 1.61 + while ( count++ < LG_MAX_LINKS) { 1.62 + char *tmp; 1.63 + /* swap our previous sorce out with resolved */ 1.64 + /* read it */ 1.65 + ret = readlink(source, resolved, len-1); 1.66 + if (ret < 0) { 1.67 + break; 1.68 + } 1.69 + resolved[ret] = 0; 1.70 + tmp = source; source = resolved; resolved = tmp; 1.71 + } 1.72 + if (count > 1) { 1.73 + ret = 0; 1.74 + } 1.75 +loser: 1.76 + if (resolved) { 1.77 + PORT_Free(resolved); 1.78 + } 1.79 + if (ret < 0) { 1.80 + if (source) { 1.81 + PORT_Free(source); 1.82 + source = NULL; 1.83 + } 1.84 + } 1.85 + return source; 1.86 +} 1.87 + 1.88 +#endif 1.89 + 1.90 +static PRLibrary * 1.91 +sftkdb_LoadFromPath(const char *path, const char *libname) 1.92 +{ 1.93 + char *c; 1.94 + int pathLen, nameLen, fullPathLen; 1.95 + char *fullPathName = NULL; 1.96 + PRLibSpec libSpec; 1.97 + PRLibrary *lib = NULL; 1.98 + 1.99 + 1.100 + /* strip of our parent's library name */ 1.101 + c = strrchr(path, PR_GetDirectorySeparator()); 1.102 + if (!c) { 1.103 + return NULL; /* invalid path */ 1.104 + } 1.105 + pathLen = (c-path)+1; 1.106 + nameLen = strlen(libname); 1.107 + fullPathLen = pathLen + nameLen +1; 1.108 + fullPathName = (char *)PORT_Alloc(fullPathLen); 1.109 + if (fullPathName == NULL) { 1.110 + return NULL; /* memory allocation error */ 1.111 + } 1.112 + PORT_Memcpy(fullPathName, path, pathLen); 1.113 + PORT_Memcpy(fullPathName+pathLen, libname, nameLen); 1.114 + fullPathName[fullPathLen-1] = 0; 1.115 + 1.116 + libSpec.type = PR_LibSpec_Pathname; 1.117 + libSpec.value.pathname = fullPathName; 1.118 + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); 1.119 + PORT_Free(fullPathName); 1.120 + return lib; 1.121 +} 1.122 + 1.123 + 1.124 +static PRLibrary * 1.125 +sftkdb_LoadLibrary(const char *libname) 1.126 +{ 1.127 + PRLibrary *lib = NULL; 1.128 + PRFuncPtr fn_addr; 1.129 + char *parentLibPath = NULL; 1.130 + 1.131 + fn_addr = (PRFuncPtr) &sftkdb_LoadLibrary; 1.132 + parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr); 1.133 + 1.134 + if (!parentLibPath) { 1.135 + goto done; 1.136 + } 1.137 + 1.138 + lib = sftkdb_LoadFromPath(parentLibPath, libname); 1.139 +#ifdef XP_UNIX 1.140 + /* handle symbolic link case */ 1.141 + if (!lib) { 1.142 + char *trueParentLibPath = sftkdb_resolvePath(parentLibPath); 1.143 + if (!trueParentLibPath) { 1.144 + goto done; 1.145 + } 1.146 + lib = sftkdb_LoadFromPath(trueParentLibPath, libname); 1.147 + PORT_Free(trueParentLibPath); 1.148 + } 1.149 +#endif 1.150 + 1.151 +done: 1.152 + if (parentLibPath) { 1.153 + PORT_Free(parentLibPath); 1.154 + } 1.155 + 1.156 + /* still couldn't load it, try the generic path */ 1.157 + if (!lib) { 1.158 + PRLibSpec libSpec; 1.159 + libSpec.type = PR_LibSpec_Pathname; 1.160 + libSpec.value.pathname = libname; 1.161 + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); 1.162 + } 1.163 + 1.164 + return lib; 1.165 +} 1.166 + 1.167 +/* 1.168 + * stub files for legacy db's to be able to encrypt and decrypt 1.169 + * various keys and attributes. 1.170 + */ 1.171 +static SECStatus 1.172 +sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText, 1.173 + SECItem **cipherText) 1.174 +{ 1.175 + SFTKDBHandle *handle = sdb->app_private; 1.176 + SECStatus rv; 1.177 + 1.178 + if (handle == NULL) { 1.179 + return SECFailure; 1.180 + } 1.181 + 1.182 + /* if we aren't the key handle, try the other handle */ 1.183 + if (handle->type != SFTK_KEYDB_TYPE) { 1.184 + handle = handle->peerDB; 1.185 + } 1.186 + 1.187 + /* not a key handle */ 1.188 + if (handle == NULL || handle->passwordLock == NULL) { 1.189 + return SECFailure; 1.190 + } 1.191 + 1.192 + PZ_Lock(handle->passwordLock); 1.193 + if (handle->passwordKey.data == NULL) { 1.194 + PZ_Unlock(handle->passwordLock); 1.195 + /* PORT_SetError */ 1.196 + return SECFailure; 1.197 + } 1.198 + 1.199 + rv = sftkdb_EncryptAttribute(arena, 1.200 + handle->newKey?handle->newKey:&handle->passwordKey, 1.201 + plainText, cipherText); 1.202 + PZ_Unlock(handle->passwordLock); 1.203 + 1.204 + return rv; 1.205 +} 1.206 + 1.207 +/* 1.208 + * stub files for legacy db's to be able to encrypt and decrypt 1.209 + * various keys and attributes. 1.210 + */ 1.211 +static SECStatus 1.212 +sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) 1.213 +{ 1.214 + SFTKDBHandle *handle = sdb->app_private; 1.215 + SECStatus rv; 1.216 + SECItem *oldKey = NULL; 1.217 + 1.218 + if (handle == NULL) { 1.219 + return SECFailure; 1.220 + } 1.221 + 1.222 + /* if we aren't th handle, try the other handle */ 1.223 + oldKey = handle->oldKey; 1.224 + if (handle->type != SFTK_KEYDB_TYPE) { 1.225 + handle = handle->peerDB; 1.226 + } 1.227 + 1.228 + /* not a key handle */ 1.229 + if (handle == NULL || handle->passwordLock == NULL) { 1.230 + return SECFailure; 1.231 + } 1.232 + 1.233 + PZ_Lock(handle->passwordLock); 1.234 + if (handle->passwordKey.data == NULL) { 1.235 + PZ_Unlock(handle->passwordLock); 1.236 + /* PORT_SetError */ 1.237 + return SECFailure; 1.238 + } 1.239 + rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey, 1.240 + cipherText, plainText); 1.241 + PZ_Unlock(handle->passwordLock); 1.242 + 1.243 + return rv; 1.244 +} 1.245 + 1.246 +static const char *LEGACY_LIB_NAME = 1.247 + SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX; 1.248 +/* 1.249 + * 2 bools to tell us if we've check the legacy library successfully or 1.250 + * not. Initialize on startup to false by the C BSS segment; 1.251 + */ 1.252 +static PRBool legacy_glue_libCheckFailed; /* set if we failed the check */ 1.253 +static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */ 1.254 +static PRLibrary *legacy_glue_lib = NULL; 1.255 +static SECStatus 1.256 +sftkdbLoad_Legacy(PRBool isFIPS) 1.257 +{ 1.258 + PRLibrary *lib = NULL; 1.259 + LGSetCryptFunc setCryptFunction = NULL; 1.260 + 1.261 + if (legacy_glue_lib) { 1.262 + /* this check is necessary because it's possible we loaded the 1.263 + * legacydb to read secmod.db, which told us whether we were in 1.264 + * FIPS mode or not. */ 1.265 + if (isFIPS && !legacy_glue_libCheckSucceeded) { 1.266 + if (legacy_glue_libCheckFailed || 1.267 + !BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) { 1.268 + legacy_glue_libCheckFailed = PR_TRUE; 1.269 + /* don't clobber legacy glue to avoid race. just let it 1.270 + * get cleared in shutdown */ 1.271 + return SECFailure; 1.272 + } 1.273 + legacy_glue_libCheckSucceeded = PR_TRUE; 1.274 + } 1.275 + return SECSuccess; 1.276 + } 1.277 + 1.278 + lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME); 1.279 + if (lib == NULL) { 1.280 + return SECFailure; 1.281 + } 1.282 + 1.283 + legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open"); 1.284 + legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib, 1.285 + "legacy_ReadSecmodDB"); 1.286 + legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib, 1.287 + "legacy_ReleaseSecmodDBData"); 1.288 + legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib, 1.289 + "legacy_DeleteSecmodDB"); 1.290 + legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, 1.291 + "legacy_AddSecmodDB"); 1.292 + legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, 1.293 + "legacy_Shutdown"); 1.294 + setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, 1.295 + "legacy_SetCryptFunctions"); 1.296 + 1.297 + if (!legacy_glue_open || !legacy_glue_readSecmod || 1.298 + !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || 1.299 + !legacy_glue_addSecmod || !setCryptFunction) { 1.300 + PR_UnloadLibrary(lib); 1.301 + return SECFailure; 1.302 + } 1.303 + 1.304 + /* verify the loaded library if we are in FIPS mode */ 1.305 + if (isFIPS) { 1.306 + if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) { 1.307 + PR_UnloadLibrary(lib); 1.308 + return SECFailure; 1.309 + } 1.310 + legacy_glue_libCheckSucceeded = PR_TRUE; 1.311 + } 1.312 + 1.313 + setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub); 1.314 + legacy_glue_lib = lib; 1.315 + return SECSuccess; 1.316 +} 1.317 + 1.318 +CK_RV 1.319 +sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, 1.320 + int certVersion, int keyVersion, int flags, PRBool isFIPS, 1.321 + SDB **certDB, SDB **keyDB) 1.322 +{ 1.323 + SECStatus rv; 1.324 + 1.325 + rv = sftkdbLoad_Legacy(isFIPS); 1.326 + if (rv != SECSuccess) { 1.327 + return CKR_GENERAL_ERROR; 1.328 + } 1.329 + if (!legacy_glue_open) { 1.330 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.331 + return SECFailure; 1.332 + } 1.333 + return (*legacy_glue_open)(dir, certPrefix, keyPrefix, 1.334 + certVersion, keyVersion, 1.335 + flags, certDB, keyDB); 1.336 +} 1.337 + 1.338 +char ** 1.339 +sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, 1.340 + const char *dbname, char *params, PRBool rw) 1.341 +{ 1.342 + SECStatus rv; 1.343 + 1.344 + rv = sftkdbLoad_Legacy(PR_FALSE); 1.345 + if (rv != SECSuccess) { 1.346 + return NULL; 1.347 + } 1.348 + if (!legacy_glue_readSecmod) { 1.349 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.350 + return NULL; 1.351 + } 1.352 + return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw); 1.353 +} 1.354 + 1.355 +SECStatus 1.356 +sftkdbCall_ReleaseSecmodDBData(const char *appName, 1.357 + const char *filename, const char *dbname, 1.358 + char **moduleSpecList, PRBool rw) 1.359 +{ 1.360 + SECStatus rv; 1.361 + 1.362 + rv = sftkdbLoad_Legacy(PR_FALSE); 1.363 + if (rv != SECSuccess) { 1.364 + return rv; 1.365 + } 1.366 + if (!legacy_glue_releaseSecmod) { 1.367 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.368 + return SECFailure; 1.369 + } 1.370 + return (*legacy_glue_releaseSecmod)(appName, filename, dbname, 1.371 + moduleSpecList, rw); 1.372 +} 1.373 + 1.374 +SECStatus 1.375 +sftkdbCall_DeleteSecmodDB(const char *appName, 1.376 + const char *filename, const char *dbname, 1.377 + char *args, PRBool rw) 1.378 +{ 1.379 + SECStatus rv; 1.380 + 1.381 + rv = sftkdbLoad_Legacy(PR_FALSE); 1.382 + if (rv != SECSuccess) { 1.383 + return rv; 1.384 + } 1.385 + if (!legacy_glue_deleteSecmod) { 1.386 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.387 + return SECFailure; 1.388 + } 1.389 + return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw); 1.390 +} 1.391 + 1.392 +SECStatus 1.393 +sftkdbCall_AddSecmodDB(const char *appName, 1.394 + const char *filename, const char *dbname, 1.395 + char *module, PRBool rw) 1.396 +{ 1.397 + SECStatus rv; 1.398 + 1.399 + rv = sftkdbLoad_Legacy(PR_FALSE); 1.400 + if (rv != SECSuccess) { 1.401 + return rv; 1.402 + } 1.403 + if (!legacy_glue_addSecmod) { 1.404 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.405 + return SECFailure; 1.406 + } 1.407 + return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw); 1.408 +} 1.409 + 1.410 +CK_RV 1.411 +sftkdbCall_Shutdown(void) 1.412 +{ 1.413 + CK_RV crv = CKR_OK; 1.414 + char *disableUnload = NULL; 1.415 + if (!legacy_glue_lib) { 1.416 + return CKR_OK; 1.417 + } 1.418 + if (legacy_glue_shutdown) { 1.419 +#ifdef NO_FORK_CHECK 1.420 + PRBool parentForkedAfterC_Initialize = PR_FALSE; 1.421 +#endif 1.422 + crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize); 1.423 + } 1.424 + disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); 1.425 + if (!disableUnload) { 1.426 + PR_UnloadLibrary(legacy_glue_lib); 1.427 + } 1.428 + legacy_glue_lib = NULL; 1.429 + legacy_glue_open = NULL; 1.430 + legacy_glue_readSecmod = NULL; 1.431 + legacy_glue_releaseSecmod = NULL; 1.432 + legacy_glue_deleteSecmod = NULL; 1.433 + legacy_glue_addSecmod = NULL; 1.434 + legacy_glue_libCheckFailed = PR_FALSE; 1.435 + legacy_glue_libCheckSucceeded = PR_FALSE; 1.436 + return crv; 1.437 +} 1.438 + 1.439 +