| OLD | NEW |
| (Empty) |
| 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 #ifndef NSS_STATIC | |
| 27 /* | |
| 28 * The following 3 functions duplicate the work done by bl_LoadLibrary. | |
| 29 * We should make bl_LoadLibrary a global and replace the call to | |
| 30 * sftkdb_LoadLibrary(const char *libname) with it. | |
| 31 */ | |
| 32 #ifdef XP_UNIX | |
| 33 #include <unistd.h> | |
| 34 #define LG_MAX_LINKS 20 | |
| 35 static char * | |
| 36 sftkdb_resolvePath(const char *orig) | |
| 37 { | |
| 38 int count = 0; | |
| 39 int len =0; | |
| 40 int ret = -1; | |
| 41 char *resolved = NULL; | |
| 42 char *source = NULL; | |
| 43 | |
| 44 len = 1025; /* MAX PATH +1*/ | |
| 45 if (strlen(orig)+1 > len) { | |
| 46 /* PATH TOO LONG */ | |
| 47 return NULL; | |
| 48 } | |
| 49 resolved = PORT_Alloc(len); | |
| 50 if (!resolved) { | |
| 51 return NULL; | |
| 52 } | |
| 53 source = PORT_Alloc(len); | |
| 54 if (!source) { | |
| 55 goto loser; | |
| 56 } | |
| 57 PORT_Strcpy(source, orig); | |
| 58 /* Walk down all the links */ | |
| 59 while ( count++ < LG_MAX_LINKS) { | |
| 60 char *tmp; | |
| 61 /* swap our previous sorce out with resolved */ | |
| 62 /* read it */ | |
| 63 ret = readlink(source, resolved, len-1); | |
| 64 if (ret < 0) { | |
| 65 break; | |
| 66 } | |
| 67 resolved[ret] = 0; | |
| 68 tmp = source; source = resolved; resolved = tmp; | |
| 69 } | |
| 70 if (count > 1) { | |
| 71 ret = 0; | |
| 72 } | |
| 73 loser: | |
| 74 if (resolved) { | |
| 75 PORT_Free(resolved); | |
| 76 } | |
| 77 if (ret < 0) { | |
| 78 if (source) { | |
| 79 PORT_Free(source); | |
| 80 source = NULL; | |
| 81 } | |
| 82 } | |
| 83 return source; | |
| 84 } | |
| 85 | |
| 86 #endif | |
| 87 | |
| 88 static PRLibrary * | |
| 89 sftkdb_LoadFromPath(const char *path, const char *libname) | |
| 90 { | |
| 91 char *c; | |
| 92 int pathLen, nameLen, fullPathLen; | |
| 93 char *fullPathName = NULL; | |
| 94 PRLibSpec libSpec; | |
| 95 PRLibrary *lib = NULL; | |
| 96 | |
| 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 | |
| 122 static PRLibrary * | |
| 123 sftkdb_LoadLibrary(const char *libname) | |
| 124 { | |
| 125 PRLibrary *lib = NULL; | |
| 126 PRFuncPtr fn_addr; | |
| 127 char *parentLibPath = NULL; | |
| 128 | |
| 129 fn_addr = (PRFuncPtr) &sftkdb_LoadLibrary; | |
| 130 parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr); | |
| 131 | |
| 132 if (!parentLibPath) { | |
| 133 goto done; | |
| 134 } | |
| 135 | |
| 136 lib = sftkdb_LoadFromPath(parentLibPath, libname); | |
| 137 #ifdef XP_UNIX | |
| 138 /* handle symbolic link case */ | |
| 139 if (!lib) { | |
| 140 char *trueParentLibPath = sftkdb_resolvePath(parentLibPath); | |
| 141 if (!trueParentLibPath) { | |
| 142 goto done; | |
| 143 } | |
| 144 lib = sftkdb_LoadFromPath(trueParentLibPath, libname); | |
| 145 PORT_Free(trueParentLibPath); | |
| 146 } | |
| 147 #endif | |
| 148 | |
| 149 done: | |
| 150 if (parentLibPath) { | |
| 151 PORT_Free(parentLibPath); | |
| 152 } | |
| 153 | |
| 154 /* still couldn't load it, try the generic path */ | |
| 155 if (!lib) { | |
| 156 PRLibSpec libSpec; | |
| 157 libSpec.type = PR_LibSpec_Pathname; | |
| 158 libSpec.value.pathname = libname; | |
| 159 lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); | |
| 160 } | |
| 161 | |
| 162 return lib; | |
| 163 } | |
| 164 #endif /* STATIC LIBRARIES */ | |
| 165 | |
| 166 /* | |
| 167 * stub files for legacy db's to be able to encrypt and decrypt | |
| 168 * various keys and attributes. | |
| 169 */ | |
| 170 static SECStatus | |
| 171 sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText, | |
| 172 SECItem **cipherText) | |
| 173 { | |
| 174 SFTKDBHandle *handle = sdb->app_private; | |
| 175 SECStatus rv; | |
| 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 | |
| 198 rv = sftkdb_EncryptAttribute(arena, | |
| 199 handle->newKey?handle->newKey:&handle->passwordKey, | |
| 200 plainText, cipherText); | |
| 201 PZ_Unlock(handle->passwordLock); | |
| 202 | |
| 203 return rv; | |
| 204 } | |
| 205 | |
| 206 /* | |
| 207 * stub files for legacy db's to be able to encrypt and decrypt | |
| 208 * various keys and attributes. | |
| 209 */ | |
| 210 static SECStatus | |
| 211 sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) | |
| 212 { | |
| 213 SFTKDBHandle *handle = sdb->app_private; | |
| 214 SECStatus rv; | |
| 215 SECItem *oldKey = NULL; | |
| 216 | |
| 217 if (handle == NULL) { | |
| 218 return SECFailure; | |
| 219 } | |
| 220 | |
| 221 /* if we aren't th handle, try the other handle */ | |
| 222 oldKey = handle->oldKey; | |
| 223 if (handle->type != SFTK_KEYDB_TYPE) { | |
| 224 handle = handle->peerDB; | |
| 225 } | |
| 226 | |
| 227 /* not a key handle */ | |
| 228 if (handle == NULL || handle->passwordLock == NULL) { | |
| 229 return SECFailure; | |
| 230 } | |
| 231 | |
| 232 PZ_Lock(handle->passwordLock); | |
| 233 if (handle->passwordKey.data == NULL) { | |
| 234 PZ_Unlock(handle->passwordLock); | |
| 235 /* PORT_SetError */ | |
| 236 return SECFailure; | |
| 237 } | |
| 238 rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey, | |
| 239 cipherText, plainText); | |
| 240 PZ_Unlock(handle->passwordLock); | |
| 241 | |
| 242 return rv; | |
| 243 } | |
| 244 | |
| 245 static const char *LEGACY_LIB_NAME = | |
| 246 SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX; | |
| 247 /* | |
| 248 * 2 bools to tell us if we've check the legacy library successfully or | |
| 249 * not. Initialize on startup to false by the C BSS segment; | |
| 250 */ | |
| 251 static PRBool legacy_glue_libCheckFailed; /* set if we failed the check */ | |
| 252 static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */ | |
| 253 static PRLibrary *legacy_glue_lib = NULL; | |
| 254 static SECStatus | |
| 255 sftkdbLoad_Legacy(PRBool isFIPS) | |
| 256 { | |
| 257 PRLibrary *lib = NULL; | |
| 258 LGSetCryptFunc setCryptFunction = NULL; | |
| 259 | |
| 260 if (legacy_glue_lib) { | |
| 261 /* this check is necessary because it's possible we loaded the | |
| 262 * legacydb to read secmod.db, which told us whether we were in | |
| 263 * FIPS mode or not. */ | |
| 264 if (isFIPS && !legacy_glue_libCheckSucceeded) { | |
| 265 if (legacy_glue_libCheckFailed || | |
| 266 !BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) { | |
| 267 legacy_glue_libCheckFailed = PR_TRUE; | |
| 268 /* don't clobber legacy glue to avoid race. just let it | |
| 269 * get cleared in shutdown */ | |
| 270 return SECFailure; | |
| 271 } | |
| 272 legacy_glue_libCheckSucceeded = PR_TRUE; | |
| 273 } | |
| 274 return SECSuccess; | |
| 275 } | |
| 276 | |
| 277 #ifdef NSS_STATIC | |
| 278 #ifdef NSS_DISABLE_DBM | |
| 279 return SECFailure; | |
| 280 #else | |
| 281 lib = (PRLibrary *) 0x8; | |
| 282 | |
| 283 legacy_glue_open = legacy_Open; | |
| 284 legacy_glue_readSecmod = legacy_ReadSecmodDB; | |
| 285 legacy_glue_releaseSecmod = legacy_ReleaseSecmodDBData; | |
| 286 legacy_glue_deleteSecmod = legacy_DeleteSecmodDB; | |
| 287 legacy_glue_addSecmod = legacy_AddSecmodDB; | |
| 288 legacy_glue_shutdown = legacy_Shutdown; | |
| 289 setCryptFunction = legacy_SetCryptFunctions; | |
| 290 #endif | |
| 291 #else | |
| 292 lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME); | |
| 293 if (lib == NULL) { | |
| 294 return SECFailure; | |
| 295 } | |
| 296 | |
| 297 legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open"); | |
| 298 legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib, | |
| 299 "legacy_ReadSecmodDB"); | |
| 300 legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib, | |
| 301 "legacy_ReleaseSecmodDBData"); | |
| 302 legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib, | |
| 303 "legacy_DeleteSecmodDB"); | |
| 304 legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, | |
| 305 "legacy_AddSecmodDB"); | |
| 306 legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, | |
| 307 "legacy_Shutdown"); | |
| 308 setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, | |
| 309 "legacy_SetCryptFunctions"); | |
| 310 | |
| 311 if (!legacy_glue_open || !legacy_glue_readSecmod || | |
| 312 !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || | |
| 313 !legacy_glue_addSecmod || !setCryptFunction) { | |
| 314 PR_UnloadLibrary(lib); | |
| 315 return SECFailure; | |
| 316 } | |
| 317 #endif /* NSS_STATIC */ | |
| 318 | |
| 319 /* verify the loaded library if we are in FIPS mode */ | |
| 320 if (isFIPS) { | |
| 321 if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) { | |
| 322 #ifndef NSS_STATIC | |
| 323 PR_UnloadLibrary(lib); | |
| 324 #endif | |
| 325 return SECFailure; | |
| 326 } | |
| 327 legacy_glue_libCheckSucceeded = PR_TRUE; | |
| 328 } | |
| 329 | |
| 330 setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub); | |
| 331 legacy_glue_lib = lib; | |
| 332 return SECSuccess; | |
| 333 } | |
| 334 | |
| 335 CK_RV | |
| 336 sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, | |
| 337 int certVersion, int keyVersion, int flags, PRBool isFIPS, | |
| 338 SDB **certDB, SDB **keyDB) | |
| 339 { | |
| 340 SECStatus rv; | |
| 341 | |
| 342 rv = sftkdbLoad_Legacy(isFIPS); | |
| 343 if (rv != SECSuccess) { | |
| 344 return CKR_GENERAL_ERROR; | |
| 345 } | |
| 346 if (!legacy_glue_open) { | |
| 347 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 348 return SECFailure; | |
| 349 } | |
| 350 return (*legacy_glue_open)(dir, certPrefix, keyPrefix, | |
| 351 certVersion, keyVersion, | |
| 352 flags, certDB, keyDB); | |
| 353 } | |
| 354 | |
| 355 char ** | |
| 356 sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, | |
| 357 const char *dbname, char *params, PRBool rw) | |
| 358 { | |
| 359 SECStatus rv; | |
| 360 | |
| 361 rv = sftkdbLoad_Legacy(PR_FALSE); | |
| 362 if (rv != SECSuccess) { | |
| 363 return NULL; | |
| 364 } | |
| 365 if (!legacy_glue_readSecmod) { | |
| 366 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 367 return NULL; | |
| 368 } | |
| 369 return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw); | |
| 370 } | |
| 371 | |
| 372 SECStatus | |
| 373 sftkdbCall_ReleaseSecmodDBData(const char *appName, | |
| 374 const char *filename, const char *dbname, | |
| 375 char **moduleSpecList, PRBool rw) | |
| 376 { | |
| 377 SECStatus rv; | |
| 378 | |
| 379 rv = sftkdbLoad_Legacy(PR_FALSE); | |
| 380 if (rv != SECSuccess) { | |
| 381 return rv; | |
| 382 } | |
| 383 if (!legacy_glue_releaseSecmod) { | |
| 384 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 385 return SECFailure; | |
| 386 } | |
| 387 return (*legacy_glue_releaseSecmod)(appName, filename, dbname, | |
| 388 moduleSpecList, rw); | |
| 389 } | |
| 390 | |
| 391 SECStatus | |
| 392 sftkdbCall_DeleteSecmodDB(const char *appName, | |
| 393 const char *filename, const char *dbname, | |
| 394 char *args, PRBool rw) | |
| 395 { | |
| 396 SECStatus rv; | |
| 397 | |
| 398 rv = sftkdbLoad_Legacy(PR_FALSE); | |
| 399 if (rv != SECSuccess) { | |
| 400 return rv; | |
| 401 } | |
| 402 if (!legacy_glue_deleteSecmod) { | |
| 403 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 404 return SECFailure; | |
| 405 } | |
| 406 return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw); | |
| 407 } | |
| 408 | |
| 409 SECStatus | |
| 410 sftkdbCall_AddSecmodDB(const char *appName, | |
| 411 const char *filename, const char *dbname, | |
| 412 char *module, PRBool rw) | |
| 413 { | |
| 414 SECStatus rv; | |
| 415 | |
| 416 rv = sftkdbLoad_Legacy(PR_FALSE); | |
| 417 if (rv != SECSuccess) { | |
| 418 return rv; | |
| 419 } | |
| 420 if (!legacy_glue_addSecmod) { | |
| 421 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
| 422 return SECFailure; | |
| 423 } | |
| 424 return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw); | |
| 425 } | |
| 426 | |
| 427 CK_RV | |
| 428 sftkdbCall_Shutdown(void) | |
| 429 { | |
| 430 CK_RV crv = CKR_OK; | |
| 431 char *disableUnload = NULL; | |
| 432 if (!legacy_glue_lib) { | |
| 433 return CKR_OK; | |
| 434 } | |
| 435 if (legacy_glue_shutdown) { | |
| 436 #ifdef NO_FORK_CHECK | |
| 437 PRBool parentForkedAfterC_Initialize = PR_FALSE; | |
| 438 #endif | |
| 439 crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize); | |
| 440 } | |
| 441 #ifndef NSS_STATIC | |
| 442 disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD"); | |
| 443 if (!disableUnload) { | |
| 444 PR_UnloadLibrary(legacy_glue_lib); | |
| 445 } | |
| 446 #endif | |
| 447 legacy_glue_lib = NULL; | |
| 448 legacy_glue_open = NULL; | |
| 449 legacy_glue_readSecmod = NULL; | |
| 450 legacy_glue_releaseSecmod = NULL; | |
| 451 legacy_glue_deleteSecmod = NULL; | |
| 452 legacy_glue_addSecmod = NULL; | |
| 453 legacy_glue_libCheckFailed = PR_FALSE; | |
| 454 legacy_glue_libCheckSucceeded = PR_FALSE; | |
| 455 return crv; | |
| 456 } | |
| 457 | |
| 458 | |
| OLD | NEW |