|
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; 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 } |
|
84 |
|
85 #endif |
|
86 |
|
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; |
|
95 |
|
96 |
|
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; |
|
112 |
|
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 } |
|
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 |
|
175 if (handle == NULL) { |
|
176 return SECFailure; |
|
177 } |
|
178 |
|
179 /* if we aren't the key handle, try the other handle */ |
|
180 if (handle->type != SFTK_KEYDB_TYPE) { |
|
181 handle = handle->peerDB; |
|
182 } |
|
183 |
|
184 /* not a key handle */ |
|
185 if (handle == NULL || handle->passwordLock == NULL) { |
|
186 return SECFailure; |
|
187 } |
|
188 |
|
189 PZ_Lock(handle->passwordLock); |
|
190 if (handle->passwordKey.data == NULL) { |
|
191 PZ_Unlock(handle->passwordLock); |
|
192 /* PORT_SetError */ |
|
193 return SECFailure; |
|
194 } |
|
195 |
|
196 rv = sftkdb_EncryptAttribute(arena, |
|
197 handle->newKey?handle->newKey:&handle->passwordKey, |
|
198 plainText, cipherText); |
|
199 PZ_Unlock(handle->passwordLock); |
|
200 |
|
201 return rv; |
|
202 } |
|
203 |
|
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; |
|
214 |
|
215 if (handle == NULL) { |
|
216 return SECFailure; |
|
217 } |
|
218 |
|
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 } |
|
224 |
|
225 /* not a key handle */ |
|
226 if (handle == NULL || handle->passwordLock == NULL) { |
|
227 return SECFailure; |
|
228 } |
|
229 |
|
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); |
|
239 |
|
240 return rv; |
|
241 } |
|
242 |
|
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; |
|
257 |
|
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 } |
|
274 |
|
275 lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME); |
|
276 if (lib == NULL) { |
|
277 return SECFailure; |
|
278 } |
|
279 |
|
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"); |
|
293 |
|
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 } |
|
300 |
|
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 } |
|
309 |
|
310 setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub); |
|
311 legacy_glue_lib = lib; |
|
312 return SECSuccess; |
|
313 } |
|
314 |
|
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; |
|
321 |
|
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 } |
|
334 |
|
335 char ** |
|
336 sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, |
|
337 const char *dbname, char *params, PRBool rw) |
|
338 { |
|
339 SECStatus rv; |
|
340 |
|
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 } |
|
351 |
|
352 SECStatus |
|
353 sftkdbCall_ReleaseSecmodDBData(const char *appName, |
|
354 const char *filename, const char *dbname, |
|
355 char **moduleSpecList, PRBool rw) |
|
356 { |
|
357 SECStatus rv; |
|
358 |
|
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 } |
|
370 |
|
371 SECStatus |
|
372 sftkdbCall_DeleteSecmodDB(const char *appName, |
|
373 const char *filename, const char *dbname, |
|
374 char *args, PRBool rw) |
|
375 { |
|
376 SECStatus rv; |
|
377 |
|
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 } |
|
388 |
|
389 SECStatus |
|
390 sftkdbCall_AddSecmodDB(const char *appName, |
|
391 const char *filename, const char *dbname, |
|
392 char *module, PRBool rw) |
|
393 { |
|
394 SECStatus rv; |
|
395 |
|
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 } |
|
406 |
|
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 } |
|
435 |
|
436 |