Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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"
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;
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;
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; source = resolved; resolved = tmp;
68 }
69 if (count > 1) {
70 ret = 0;
71 }
72 loser:
73 if (resolved) {
74 PORT_Free(resolved);
75 }
76 if (ret < 0) {
77 if (source) {
78 PORT_Free(source);
79 source = NULL;
80 }
81 }
82 return source;
83 }
85 #endif
87 static PRLibrary *
88 sftkdb_LoadFromPath(const char *path, const char *libname)
89 {
90 char *c;
91 int pathLen, nameLen, fullPathLen;
92 char *fullPathName = NULL;
93 PRLibSpec libSpec;
94 PRLibrary *lib = NULL;
97 /* strip of our parent's library name */
98 c = strrchr(path, PR_GetDirectorySeparator());
99 if (!c) {
100 return NULL; /* invalid path */
101 }
102 pathLen = (c-path)+1;
103 nameLen = strlen(libname);
104 fullPathLen = pathLen + nameLen +1;
105 fullPathName = (char *)PORT_Alloc(fullPathLen);
106 if (fullPathName == NULL) {
107 return NULL; /* memory allocation error */
108 }
109 PORT_Memcpy(fullPathName, path, pathLen);
110 PORT_Memcpy(fullPathName+pathLen, libname, nameLen);
111 fullPathName[fullPathLen-1] = 0;
113 libSpec.type = PR_LibSpec_Pathname;
114 libSpec.value.pathname = fullPathName;
115 lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
116 PORT_Free(fullPathName);
117 return lib;
118 }
121 static PRLibrary *
122 sftkdb_LoadLibrary(const char *libname)
123 {
124 PRLibrary *lib = NULL;
125 PRFuncPtr fn_addr;
126 char *parentLibPath = NULL;
128 fn_addr = (PRFuncPtr) &sftkdb_LoadLibrary;
129 parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr);
131 if (!parentLibPath) {
132 goto done;
133 }
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
148 done:
149 if (parentLibPath) {
150 PORT_Free(parentLibPath);
151 }
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 }
161 return lib;
162 }
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;
175 if (handle == NULL) {
176 return SECFailure;
177 }
179 /* if we aren't the key handle, try the other handle */
180 if (handle->type != SFTK_KEYDB_TYPE) {
181 handle = handle->peerDB;
182 }
184 /* not a key handle */
185 if (handle == NULL || handle->passwordLock == NULL) {
186 return SECFailure;
187 }
189 PZ_Lock(handle->passwordLock);
190 if (handle->passwordKey.data == NULL) {
191 PZ_Unlock(handle->passwordLock);
192 /* PORT_SetError */
193 return SECFailure;
194 }
196 rv = sftkdb_EncryptAttribute(arena,
197 handle->newKey?handle->newKey:&handle->passwordKey,
198 plainText, cipherText);
199 PZ_Unlock(handle->passwordLock);
201 return rv;
202 }
204 /*
205 * stub files for legacy db's to be able to encrypt and decrypt
206 * various keys and attributes.
207 */
208 static SECStatus
209 sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText)
210 {
211 SFTKDBHandle *handle = sdb->app_private;
212 SECStatus rv;
213 SECItem *oldKey = NULL;
215 if (handle == NULL) {
216 return SECFailure;
217 }
219 /* if we aren't th handle, try the other handle */
220 oldKey = handle->oldKey;
221 if (handle->type != SFTK_KEYDB_TYPE) {
222 handle = handle->peerDB;
223 }
225 /* not a key handle */
226 if (handle == NULL || handle->passwordLock == NULL) {
227 return SECFailure;
228 }
230 PZ_Lock(handle->passwordLock);
231 if (handle->passwordKey.data == NULL) {
232 PZ_Unlock(handle->passwordLock);
233 /* PORT_SetError */
234 return SECFailure;
235 }
236 rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey,
237 cipherText, plainText);
238 PZ_Unlock(handle->passwordLock);
240 return rv;
241 }
243 static const char *LEGACY_LIB_NAME =
244 SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX;
245 /*
246 * 2 bools to tell us if we've check the legacy library successfully or
247 * not. Initialize on startup to false by the C BSS segment;
248 */
249 static PRBool legacy_glue_libCheckFailed; /* set if we failed the check */
250 static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */
251 static PRLibrary *legacy_glue_lib = NULL;
252 static SECStatus
253 sftkdbLoad_Legacy(PRBool isFIPS)
254 {
255 PRLibrary *lib = NULL;
256 LGSetCryptFunc setCryptFunction = NULL;
258 if (legacy_glue_lib) {
259 /* this check is necessary because it's possible we loaded the
260 * legacydb to read secmod.db, which told us whether we were in
261 * FIPS mode or not. */
262 if (isFIPS && !legacy_glue_libCheckSucceeded) {
263 if (legacy_glue_libCheckFailed ||
264 !BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
265 legacy_glue_libCheckFailed = PR_TRUE;
266 /* don't clobber legacy glue to avoid race. just let it
267 * get cleared in shutdown */
268 return SECFailure;
269 }
270 legacy_glue_libCheckSucceeded = PR_TRUE;
271 }
272 return SECSuccess;
273 }
275 lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME);
276 if (lib == NULL) {
277 return SECFailure;
278 }
280 legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open");
281 legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib,
282 "legacy_ReadSecmodDB");
283 legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib,
284 "legacy_ReleaseSecmodDBData");
285 legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib,
286 "legacy_DeleteSecmodDB");
287 legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib,
288 "legacy_AddSecmodDB");
289 legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib,
290 "legacy_Shutdown");
291 setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib,
292 "legacy_SetCryptFunctions");
294 if (!legacy_glue_open || !legacy_glue_readSecmod ||
295 !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod ||
296 !legacy_glue_addSecmod || !setCryptFunction) {
297 PR_UnloadLibrary(lib);
298 return SECFailure;
299 }
301 /* verify the loaded library if we are in FIPS mode */
302 if (isFIPS) {
303 if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
304 PR_UnloadLibrary(lib);
305 return SECFailure;
306 }
307 legacy_glue_libCheckSucceeded = PR_TRUE;
308 }
310 setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub);
311 legacy_glue_lib = lib;
312 return SECSuccess;
313 }
315 CK_RV
316 sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix,
317 int certVersion, int keyVersion, int flags, PRBool isFIPS,
318 SDB **certDB, SDB **keyDB)
319 {
320 SECStatus rv;
322 rv = sftkdbLoad_Legacy(isFIPS);
323 if (rv != SECSuccess) {
324 return CKR_GENERAL_ERROR;
325 }
326 if (!legacy_glue_open) {
327 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
328 return SECFailure;
329 }
330 return (*legacy_glue_open)(dir, certPrefix, keyPrefix,
331 certVersion, keyVersion,
332 flags, certDB, keyDB);
333 }
335 char **
336 sftkdbCall_ReadSecmodDB(const char *appName, const char *filename,
337 const char *dbname, char *params, PRBool rw)
338 {
339 SECStatus rv;
341 rv = sftkdbLoad_Legacy(PR_FALSE);
342 if (rv != SECSuccess) {
343 return NULL;
344 }
345 if (!legacy_glue_readSecmod) {
346 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
347 return NULL;
348 }
349 return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw);
350 }
352 SECStatus
353 sftkdbCall_ReleaseSecmodDBData(const char *appName,
354 const char *filename, const char *dbname,
355 char **moduleSpecList, PRBool rw)
356 {
357 SECStatus rv;
359 rv = sftkdbLoad_Legacy(PR_FALSE);
360 if (rv != SECSuccess) {
361 return rv;
362 }
363 if (!legacy_glue_releaseSecmod) {
364 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
365 return SECFailure;
366 }
367 return (*legacy_glue_releaseSecmod)(appName, filename, dbname,
368 moduleSpecList, rw);
369 }
371 SECStatus
372 sftkdbCall_DeleteSecmodDB(const char *appName,
373 const char *filename, const char *dbname,
374 char *args, PRBool rw)
375 {
376 SECStatus rv;
378 rv = sftkdbLoad_Legacy(PR_FALSE);
379 if (rv != SECSuccess) {
380 return rv;
381 }
382 if (!legacy_glue_deleteSecmod) {
383 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
384 return SECFailure;
385 }
386 return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw);
387 }
389 SECStatus
390 sftkdbCall_AddSecmodDB(const char *appName,
391 const char *filename, const char *dbname,
392 char *module, PRBool rw)
393 {
394 SECStatus rv;
396 rv = sftkdbLoad_Legacy(PR_FALSE);
397 if (rv != SECSuccess) {
398 return rv;
399 }
400 if (!legacy_glue_addSecmod) {
401 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
402 return SECFailure;
403 }
404 return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw);
405 }
407 CK_RV
408 sftkdbCall_Shutdown(void)
409 {
410 CK_RV crv = CKR_OK;
411 char *disableUnload = NULL;
412 if (!legacy_glue_lib) {
413 return CKR_OK;
414 }
415 if (legacy_glue_shutdown) {
416 #ifdef NO_FORK_CHECK
417 PRBool parentForkedAfterC_Initialize = PR_FALSE;
418 #endif
419 crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize);
420 }
421 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
422 if (!disableUnload) {
423 PR_UnloadLibrary(legacy_glue_lib);
424 }
425 legacy_glue_lib = NULL;
426 legacy_glue_open = NULL;
427 legacy_glue_readSecmod = NULL;
428 legacy_glue_releaseSecmod = NULL;
429 legacy_glue_deleteSecmod = NULL;
430 legacy_glue_addSecmod = NULL;
431 legacy_glue_libCheckFailed = PR_FALSE;
432 legacy_glue_libCheckSucceeded = PR_FALSE;
433 return crv;
434 }