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 }