Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / softoken / lgglue.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is the Netscape security libraries.
15  *
16  * The Initial Developer of the Original Code is
17  * Netscape Communications Corporation.
18  * Portions created by the Initial Developer are Copyright (C) 1994-2000
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */
36 /* 
37  *  The following code handles the storage of PKCS 11 modules used by the
38  * NSS. This file is written to abstract away how the modules are
39  * stored so we can deside that later.
40  */
41 #include "sftkdb.h"
42 #include "sftkdbti.h"
43 #include "sdb.h"
44 #include "prsystem.h"
45 #include "prprf.h"
46 #include "prenv.h"
47 #include "lgglue.h"
48 #include "secerr.h"
49 #include "softoken.h"
50
51 static LGOpenFunc legacy_glue_open = NULL;
52 static LGReadSecmodFunc legacy_glue_readSecmod = NULL;
53 static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL;
54 static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL;
55 static LGAddSecmodFunc legacy_glue_addSecmod = NULL;
56 static LGShutdownFunc legacy_glue_shutdown = NULL;
57
58 /*
59  * The following 3 functions duplicate the work done by bl_LoadLibrary.
60  * We should make bl_LoadLibrary a global and replace the call to
61  * sftkdb_LoadLibrary(const char *libname) with it.
62  */
63 #ifdef XP_UNIX
64 #include <unistd.h>
65 #define LG_MAX_LINKS 20
66 static char *
67 sftkdb_resolvePath(const char *orig)
68 {
69     int count = 0;
70     int len =0;
71     int ret = -1;
72     char *resolved = NULL;
73     char *source = NULL;
74
75     len = 1025; /* MAX PATH +1*/
76     if (strlen(orig)+1 > len) {
77         /* PATH TOO LONG */
78         return NULL;
79     }
80     resolved = PORT_Alloc(len);
81     if (!resolved) {
82         return NULL;
83     }
84     source = PORT_Alloc(len);
85     if (!source) {
86         goto loser;
87     }
88     PORT_Strcpy(source, orig);
89     /* Walk down all the links */
90     while ( count++ < LG_MAX_LINKS) {
91         char *tmp;
92         /* swap our previous sorce out with resolved */
93         /* read it */
94         ret = readlink(source, resolved, len-1);
95         if (ret  < 0) {
96             break;
97         }
98         resolved[ret] = 0;
99         tmp = source; source = resolved; resolved = tmp;
100     }
101     if (count > 1) {
102         ret = 0;
103     }
104 loser:
105     if (resolved) {
106         PORT_Free(resolved);
107     }
108     if (ret < 0) {
109         if (source) {
110             PORT_Free(source);
111             source = NULL;
112         }
113     }
114     return source;
115 }
116
117 #endif
118
119 static PRLibrary *
120 sftkdb_LoadFromPath(const char *path, const char *libname)
121 {
122     char *c;
123     int pathLen, nameLen, fullPathLen;
124     char *fullPathName = NULL;
125     PRLibSpec libSpec;
126     PRLibrary *lib = NULL;
127
128
129     /* strip of our parent's library name */ 
130     c = strrchr(path, PR_GetDirectorySeparator());
131     if (!c) {
132         return NULL; /* invalid path */
133     }
134     pathLen = (c-path)+1;
135     nameLen = strlen(libname);
136     fullPathLen = pathLen + nameLen +1;
137     fullPathName = (char *)PORT_Alloc(fullPathLen);
138     if (fullPathName == NULL) {
139         return NULL; /* memory allocation error */
140     }
141     PORT_Memcpy(fullPathName, path, pathLen);
142     PORT_Memcpy(fullPathName+pathLen, libname, nameLen);
143     fullPathName[fullPathLen-1] = 0;
144
145     libSpec.type = PR_LibSpec_Pathname;
146     libSpec.value.pathname = fullPathName;
147     lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
148     PORT_Free(fullPathName);
149     return lib;
150 }
151
152
153 static PRLibrary *
154 sftkdb_LoadLibrary(const char *libname)
155 {
156     PRLibrary *lib = NULL;
157     PRFuncPtr fn_addr;
158     char *parentLibPath = NULL;
159
160     fn_addr  = (PRFuncPtr) &sftkdb_LoadLibrary;
161     parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr);
162
163     if (!parentLibPath) {
164         goto done;
165     }
166
167     lib = sftkdb_LoadFromPath(parentLibPath, libname);
168 #ifdef XP_UNIX
169     /* handle symbolic link case */
170     if (!lib) {
171         char *trueParentLibPath = sftkdb_resolvePath(parentLibPath);
172         if (!trueParentLibPath) {
173             goto done;
174         }
175         lib = sftkdb_LoadFromPath(trueParentLibPath, libname);
176         PORT_Free(trueParentLibPath);
177     }
178 #endif
179
180 done:
181     if (parentLibPath) {
182         PORT_Free(parentLibPath);
183     }
184
185     /* still couldn't load it, try the generic path */
186     if (!lib) {
187         PRLibSpec libSpec;
188         libSpec.type = PR_LibSpec_Pathname;
189         libSpec.value.pathname = libname;
190         lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
191     }
192
193     return lib;
194 }
195
196 /*
197  * stub files for legacy db's to be able to encrypt and decrypt
198  * various keys and attributes.
199  */
200 static SECStatus
201 sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText,
202                     SECItem **cipherText)
203 {
204     SFTKDBHandle *handle = sdb->app_private;
205     SECStatus rv;
206
207     if (handle == NULL) {
208         return SECFailure;
209     }
210
211     /* if we aren't the key handle, try the other handle */
212     if (handle->type != SFTK_KEYDB_TYPE) {
213         handle = handle->peerDB;
214     }
215
216     /* not a key handle */
217     if (handle == NULL || handle->passwordLock == NULL) {
218         return SECFailure;
219     }
220
221     PZ_Lock(handle->passwordLock);
222     if (handle->passwordKey.data == NULL) {
223         PZ_Unlock(handle->passwordLock);
224         /* PORT_SetError */
225         return SECFailure;
226     }
227
228     rv = sftkdb_EncryptAttribute(arena, 
229         handle->newKey?handle->newKey:&handle->passwordKey, 
230         plainText, cipherText);
231     PZ_Unlock(handle->passwordLock);
232
233     return rv;
234 }
235
236 /*
237  * stub files for legacy db's to be able to encrypt and decrypt
238  * various keys and attributes.
239  */
240 static SECStatus
241 sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) 
242 {
243     SFTKDBHandle *handle = sdb->app_private;
244     SECStatus rv;
245     SECItem *oldKey = NULL;
246
247     if (handle == NULL) {
248         return SECFailure;
249     }
250
251     /* if we aren't th handle, try the other handle */
252     oldKey = handle->oldKey;
253     if (handle->type != SFTK_KEYDB_TYPE) {
254         handle = handle->peerDB;
255     }
256
257     /* not a key handle */
258     if (handle == NULL || handle->passwordLock == NULL) {
259         return SECFailure;
260     }
261
262     PZ_Lock(handle->passwordLock);
263     if (handle->passwordKey.data == NULL) {
264         PZ_Unlock(handle->passwordLock);
265         /* PORT_SetError */
266         return SECFailure;
267     }
268     rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey,
269                 cipherText, plainText);
270     PZ_Unlock(handle->passwordLock);
271
272     return rv;
273 }
274
275 static const char *LEGACY_LIB_NAME = 
276         SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX;
277 /*
278  * 2 bools to tell us if we've check the legacy library successfully or
279  * not. Initialize on startup to false by the C BSS segment;
280  */
281 static PRBool legacy_glue_libCheckFailed;    /* set if we failed the check */
282 static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */
283 static PRLibrary *legacy_glue_lib = NULL;
284 static SECStatus 
285 sftkdbLoad_Legacy(PRBool isFIPS)
286 {
287     PRLibrary *lib = NULL;
288     LGSetCryptFunc setCryptFunction = NULL;
289
290     if (legacy_glue_lib) {
291         /* this check is necessary because it's possible we loaded the
292          * legacydb to read secmod.db, which told us whether we were in
293          * FIPS mode or not. */
294         if (isFIPS && !legacy_glue_libCheckSucceeded) {
295             if (legacy_glue_libCheckFailed || 
296                 !BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
297                 legacy_glue_libCheckFailed = PR_TRUE;
298                 /* don't clobber legacy glue to avoid race. just let it
299                  * get cleared in shutdown */
300                 return SECFailure;
301             }
302             legacy_glue_libCheckSucceeded = PR_TRUE;
303         } 
304         return SECSuccess;
305     }
306
307     lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME);
308     if (lib == NULL) {
309         return SECFailure;
310     }
311     
312     legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open");
313     legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib,
314                                                  "legacy_ReadSecmodDB");
315     legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib,
316                                                  "legacy_ReleaseSecmodDBData");
317     legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib,
318                                                  "legacy_DeleteSecmodDB");
319     legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, 
320                                                  "legacy_AddSecmodDB");
321     legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, 
322                                                 "legacy_Shutdown");
323     setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, 
324                                                 "legacy_SetCryptFunctions");
325
326     if (!legacy_glue_open || !legacy_glue_readSecmod || 
327             !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || 
328             !legacy_glue_addSecmod || !setCryptFunction) {
329         PR_UnloadLibrary(lib);
330         return SECFailure;
331     }
332
333     /* verify the loaded library if we are in FIPS mode */
334     if (isFIPS) {
335         if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
336             PR_UnloadLibrary(lib);
337             return SECFailure;
338         }
339         legacy_glue_libCheckSucceeded = PR_TRUE;
340     } 
341
342     setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub);
343     legacy_glue_lib = lib;
344     return SECSuccess;
345 }
346
347 CK_RV
348 sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, 
349                 int certVersion, int keyVersion, int flags, PRBool isFIPS,
350                 SDB **certDB, SDB **keyDB)
351 {
352     SECStatus rv;
353
354     rv = sftkdbLoad_Legacy(isFIPS);
355     if (rv != SECSuccess) {
356         return CKR_GENERAL_ERROR;
357     }
358     if (!legacy_glue_open) {
359         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
360         return SECFailure;
361     }
362     return (*legacy_glue_open)(dir, certPrefix, keyPrefix, 
363                                 certVersion, keyVersion,
364                                 flags, certDB, keyDB);
365 }
366
367 char **
368 sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, 
369                         const char *dbname, char *params, PRBool rw)
370 {
371     SECStatus rv;
372
373     rv = sftkdbLoad_Legacy(PR_FALSE);
374     if (rv != SECSuccess) {
375         return NULL;
376     }
377     if (!legacy_glue_readSecmod) {
378         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
379         return NULL;
380     }
381     return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw);
382 }
383
384 SECStatus
385 sftkdbCall_ReleaseSecmodDBData(const char *appName, 
386                         const char *filename, const char *dbname, 
387                         char **moduleSpecList, PRBool rw)
388 {
389     SECStatus rv;
390
391     rv = sftkdbLoad_Legacy(PR_FALSE);
392     if (rv != SECSuccess) {
393         return rv;
394     }
395     if (!legacy_glue_releaseSecmod) {
396         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
397         return SECFailure;
398     }
399     return (*legacy_glue_releaseSecmod)(appName, filename, dbname, 
400                                           moduleSpecList, rw);
401 }
402
403 SECStatus
404 sftkdbCall_DeleteSecmodDB(const char *appName, 
405                       const char *filename, const char *dbname, 
406                       char *args, PRBool rw)
407 {
408     SECStatus rv;
409
410     rv = sftkdbLoad_Legacy(PR_FALSE);
411     if (rv != SECSuccess) {
412         return rv;
413     }
414     if (!legacy_glue_deleteSecmod) {
415         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
416         return SECFailure;
417     }
418     return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw);
419 }
420
421 SECStatus
422 sftkdbCall_AddSecmodDB(const char *appName, 
423                    const char *filename, const char *dbname, 
424                    char *module, PRBool rw)
425 {
426     SECStatus rv;
427
428     rv = sftkdbLoad_Legacy(PR_FALSE);
429     if (rv != SECSuccess) {
430         return rv;
431     }
432     if (!legacy_glue_addSecmod) {
433         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
434         return SECFailure;
435     }
436     return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw);
437 }
438
439 CK_RV
440 sftkdbCall_Shutdown(void)
441 {
442     CK_RV crv = CKR_OK;
443     char *disableUnload = NULL;
444     if (!legacy_glue_lib) {
445         return CKR_OK;
446     }
447     if (legacy_glue_shutdown) {
448 #ifdef NO_FORK_CHECK
449         PRBool parentForkedAfterC_Initialize = PR_FALSE;
450 #endif
451         crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize);
452     }
453     disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
454     if (!disableUnload) {
455         PR_UnloadLibrary(legacy_glue_lib);
456     }
457     legacy_glue_lib = NULL;
458     legacy_glue_open = NULL;
459     legacy_glue_readSecmod = NULL;
460     legacy_glue_releaseSecmod = NULL;
461     legacy_glue_deleteSecmod = NULL;
462     legacy_glue_addSecmod = NULL;
463     legacy_glue_libCheckFailed    = PR_FALSE;
464     legacy_glue_libCheckSucceeded = PR_FALSE;
465     return crv;
466 }
467     
468