1 /*
2  * NSS utility functions
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #include "lowkeyi.h"
9 #include "pcert.h"
10 #include "keydbi.h"
11 #include "lgdb.h"
12 #include "secoid.h"
13 #include "prenv.h"
14 #include "softkver.h"
15 
16 /* Library identity and versioning */
17 
18 #if defined(DEBUG)
19 #define _DEBUG_STRING " (debug)"
20 #else
21 #define _DEBUG_STRING ""
22 #endif
23 
24 /*
25  * Version information
26  */
27 const char __nss_dbm_version[] = "Version: NSS " SOFTOKEN_VERSION _DEBUG_STRING;
28 
29 typedef struct LGPrivateStr {
30     NSSLOWCERTCertDBHandle *certDB;
31     NSSLOWKEYDBHandle *keyDB;
32     PRLock *dbLock;
33     PLHashTable *hashTable;
34 } LGPrivate;
35 
36 static char *
lg_certdb_name_cb(void * arg,int dbVersion)37 lg_certdb_name_cb(void *arg, int dbVersion)
38 {
39     const char *configdir = (const char *)arg;
40     const char *dbver;
41     char *smpname = NULL;
42     char *dbname = NULL;
43 
44     switch (dbVersion) {
45         case 8:
46             dbver = "8";
47             break;
48         case 7:
49             dbver = "7";
50             break;
51         case 6:
52             dbver = "6";
53             break;
54         case 5:
55             dbver = "5";
56             break;
57         case 4:
58         default:
59             dbver = "";
60             break;
61     }
62 
63     /* make sure we return something allocated with PORT_ so we have properly
64      * matched frees at the end */
65     smpname = PR_smprintf(CERT_DB_FMT, configdir, dbver);
66     if (smpname) {
67         dbname = PORT_Strdup(smpname);
68         PR_smprintf_free(smpname);
69     }
70     return dbname;
71 }
72 
73 static char *
lg_keydb_name_cb(void * arg,int dbVersion)74 lg_keydb_name_cb(void *arg, int dbVersion)
75 {
76     const char *configdir = (const char *)arg;
77     const char *dbver;
78     char *smpname = NULL;
79     char *dbname = NULL;
80 
81     switch (dbVersion) {
82         case 4:
83             dbver = "4";
84             break;
85         case 3:
86             dbver = "3";
87             break;
88         case 1:
89             dbver = "1";
90             break;
91         case 2:
92         default:
93             dbver = "";
94             break;
95     }
96 
97     smpname = PR_smprintf(KEY_DB_FMT, configdir, dbver);
98     if (smpname) {
99         dbname = PORT_Strdup(smpname);
100         PR_smprintf_free(smpname);
101     }
102     return dbname;
103 }
104 
105 const char *
lg_EvaluateConfigDir(const char * configdir,char ** appName)106 lg_EvaluateConfigDir(const char *configdir, char **appName)
107 {
108     if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS) - 1) == 0) {
109         char *cdir;
110 
111         *appName = PORT_Strdup(configdir + sizeof(MULTIACCESS) - 1);
112         if (*appName == NULL) {
113             return configdir;
114         }
115         cdir = *appName;
116         while (*cdir && *cdir != ':') {
117             cdir++;
118         }
119         if (*cdir == ':') {
120             *cdir = 0;
121             cdir++;
122         }
123         configdir = cdir;
124     }
125     return configdir;
126 }
127 
128 static int rdbmapflags(int flags);
129 static rdbfunc lg_rdbfunc = NULL;
130 static rdbstatusfunc lg_rdbstatusfunc = NULL;
131 
132 /* NOTE: SHLIB_SUFFIX is defined on the command line */
133 #define RDBLIB SHLIB_PREFIX "rdb." SHLIB_SUFFIX
134 
135 DB *
rdbopen(const char * appName,const char * prefix,const char * type,int flags,int * status)136 rdbopen(const char *appName, const char *prefix,
137         const char *type, int flags, int *status)
138 {
139     PRLibrary *lib;
140     DB *db;
141     char *disableUnload = NULL;
142 
143     if (lg_rdbfunc) {
144         db = (*lg_rdbfunc)(appName, prefix, type, rdbmapflags(flags));
145         if (!db && status && lg_rdbstatusfunc) {
146             *status = (*lg_rdbstatusfunc)();
147         }
148         return db;
149     }
150 
151     /*
152      * try to open the library.
153      */
154     lib = PR_LoadLibrary(RDBLIB);
155 
156     if (!lib) {
157         return NULL;
158     }
159 
160     /* get the entry points */
161     lg_rdbstatusfunc = (rdbstatusfunc)PR_FindSymbol(lib, "rdbstatus");
162     lg_rdbfunc = (rdbfunc)PR_FindSymbol(lib, "rdbopen");
163     if (lg_rdbfunc) {
164         db = (*lg_rdbfunc)(appName, prefix, type, rdbmapflags(flags));
165         if (!db && status && lg_rdbstatusfunc) {
166             *status = (*lg_rdbstatusfunc)();
167         }
168         return db;
169     }
170 
171     /* couldn't find the entry point, unload the library and fail */
172     disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
173     if (!disableUnload) {
174         PR_UnloadLibrary(lib);
175     }
176     return NULL;
177 }
178 
179 /*
180  * the following data structures are from rdb.h.
181  */
182 struct RDBStr {
183     DB db;
184     int (*xactstart)(DB *db);
185     int (*xactdone)(DB *db, PRBool abort);
186     int version;
187     int (*dbinitcomplete)(DB *db);
188 };
189 
190 #define DB_RDB ((DBTYPE)0xff)
191 #define RDB_RDONLY 1
192 #define RDB_RDWR 2
193 #define RDB_CREATE 4
194 
195 static int
rdbmapflags(int flags)196 rdbmapflags(int flags)
197 {
198     switch (flags) {
199         case NO_RDONLY:
200             return RDB_RDONLY;
201         case NO_RDWR:
202             return RDB_RDWR;
203         case NO_CREATE:
204             return RDB_CREATE;
205         default:
206             break;
207     }
208     return 0;
209 }
210 
211 PRBool
db_IsRDB(DB * db)212 db_IsRDB(DB *db)
213 {
214     return (PRBool)db->type == DB_RDB;
215 }
216 
217 int
db_BeginTransaction(DB * db)218 db_BeginTransaction(DB *db)
219 {
220     struct RDBStr *rdb = (struct RDBStr *)db;
221     if (db->type != DB_RDB) {
222         return 0;
223     }
224 
225     return rdb->xactstart(db);
226 }
227 
228 int
db_FinishTransaction(DB * db,PRBool abort)229 db_FinishTransaction(DB *db, PRBool abort)
230 {
231     struct RDBStr *rdb = (struct RDBStr *)db;
232     if (db->type != DB_RDB) {
233         return 0;
234     }
235 
236     return rdb->xactdone(db, abort);
237 }
238 
239 static DB *
lg_getRawDB(SDB * sdb)240 lg_getRawDB(SDB *sdb)
241 {
242     NSSLOWCERTCertDBHandle *certDB;
243     NSSLOWKEYDBHandle *keyDB;
244 
245     certDB = lg_getCertDB(sdb);
246     if (certDB) {
247         return certDB->permCertDB;
248     }
249     keyDB = lg_getKeyDB(sdb);
250     if (keyDB) {
251         return keyDB->db;
252     }
253     return NULL;
254 }
255 
256 CK_RV
lg_Begin(SDB * sdb)257 lg_Begin(SDB *sdb)
258 {
259     DB *db = lg_getRawDB(sdb);
260     int ret;
261 
262     if (db == NULL) {
263         return CKR_GENERAL_ERROR; /* shouldn't happen */
264     }
265     ret = db_BeginTransaction(db);
266     if (ret != 0) {
267         return CKR_GENERAL_ERROR; /* could happen */
268     }
269     return CKR_OK;
270 }
271 
272 CK_RV
lg_Commit(SDB * sdb)273 lg_Commit(SDB *sdb)
274 {
275     DB *db = lg_getRawDB(sdb);
276     int ret;
277 
278     if (db == NULL) {
279         return CKR_GENERAL_ERROR; /* shouldn't happen */
280     }
281     ret = db_FinishTransaction(db, PR_FALSE);
282     if (ret != 0) {
283         return CKR_GENERAL_ERROR; /* could happen */
284     }
285     return CKR_OK;
286 }
287 
288 CK_RV
lg_Abort(SDB * sdb)289 lg_Abort(SDB *sdb)
290 {
291     DB *db = lg_getRawDB(sdb);
292     int ret;
293 
294     if (db == NULL) {
295         return CKR_GENERAL_ERROR; /* shouldn't happen */
296     }
297     ret = db_FinishTransaction(db, PR_TRUE);
298     if (ret != 0) {
299         return CKR_GENERAL_ERROR; /* could happen */
300     }
301     return CKR_OK;
302 }
303 
304 int
db_InitComplete(DB * db)305 db_InitComplete(DB *db)
306 {
307     struct RDBStr *rdb = (struct RDBStr *)db;
308     if (db->type != DB_RDB) {
309         return 0;
310     }
311     /* we should have added a version number to the RDBS structure. Since we
312      * didn't, we detect that we have and 'extended' structure if the rdbstatus
313      * func exists */
314     if (!lg_rdbstatusfunc) {
315         return 0;
316     }
317 
318     return rdb->dbinitcomplete(db);
319 }
320 
321 SECStatus
db_Copy(DB * dest,DB * src)322 db_Copy(DB *dest, DB *src)
323 {
324     int ret;
325     DBT key, data;
326     ret = (*src->seq)(src, &key, &data, R_FIRST);
327     if (ret) {
328         return SECSuccess;
329     }
330 
331     do {
332         (void)(*dest->put)(dest, &key, &data, R_NOOVERWRITE);
333     } while ((*src->seq)(src, &key, &data, R_NEXT) == 0);
334     (void)(*dest->sync)(dest, 0);
335 
336     return SECSuccess;
337 }
338 
339 static CK_RV
lg_OpenCertDB(const char * configdir,const char * prefix,PRBool readOnly,NSSLOWCERTCertDBHandle ** certdbPtr)340 lg_OpenCertDB(const char *configdir, const char *prefix, PRBool readOnly,
341               NSSLOWCERTCertDBHandle **certdbPtr)
342 {
343     NSSLOWCERTCertDBHandle *certdb = NULL;
344     CK_RV crv = CKR_NETSCAPE_CERTDB_FAILED;
345     SECStatus rv;
346     char *name = NULL;
347     char *appName = NULL;
348 
349     if (prefix == NULL) {
350         prefix = "";
351     }
352 
353     configdir = lg_EvaluateConfigDir(configdir, &appName);
354 
355     name = PR_smprintf("%s" PATH_SEPARATOR "%s", configdir, prefix);
356     if (name == NULL)
357         goto loser;
358 
359     certdb = (NSSLOWCERTCertDBHandle *)PORT_ZAlloc(sizeof(NSSLOWCERTCertDBHandle));
360     if (certdb == NULL)
361         goto loser;
362 
363     certdb->ref = 1;
364     /* fix when we get the DB in */
365     rv = nsslowcert_OpenCertDB(certdb, readOnly, appName, prefix,
366                                lg_certdb_name_cb, (void *)name, PR_FALSE);
367     if (rv == SECSuccess) {
368         crv = CKR_OK;
369         *certdbPtr = certdb;
370         certdb = NULL;
371     }
372 loser:
373     if (certdb)
374         PR_Free(certdb);
375     if (name)
376         PR_smprintf_free(name);
377     if (appName)
378         PORT_Free(appName);
379     return crv;
380 }
381 
382 static CK_RV
lg_OpenKeyDB(const char * configdir,const char * prefix,PRBool readOnly,NSSLOWKEYDBHandle ** keydbPtr)383 lg_OpenKeyDB(const char *configdir, const char *prefix, PRBool readOnly,
384              NSSLOWKEYDBHandle **keydbPtr)
385 {
386     NSSLOWKEYDBHandle *keydb;
387     char *name = NULL;
388     char *appName = NULL;
389 
390     if (prefix == NULL) {
391         prefix = "";
392     }
393     configdir = lg_EvaluateConfigDir(configdir, &appName);
394 
395     name = PR_smprintf("%s" PATH_SEPARATOR "%s", configdir, prefix);
396     if (name == NULL)
397         return CKR_HOST_MEMORY;
398     keydb = nsslowkey_OpenKeyDB(readOnly, appName, prefix,
399                                 lg_keydb_name_cb, (void *)name);
400     PR_smprintf_free(name);
401     if (appName)
402         PORT_Free(appName);
403     if (keydb == NULL)
404         return CKR_NETSCAPE_KEYDB_FAILED;
405     *keydbPtr = keydb;
406 
407     return CKR_OK;
408 }
409 
410 /*
411  * Accessors for the private parts of the sdb structure.
412  */
413 void
lg_DBLock(SDB * sdb)414 lg_DBLock(SDB *sdb)
415 {
416     LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
417     SKIP_AFTER_FORK(PR_Lock(lgdb_p->dbLock));
418 }
419 
420 void
lg_DBUnlock(SDB * sdb)421 lg_DBUnlock(SDB *sdb)
422 {
423     LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
424     SKIP_AFTER_FORK(PR_Unlock(lgdb_p->dbLock));
425 }
426 
427 PLHashTable *
lg_GetHashTable(SDB * sdb)428 lg_GetHashTable(SDB *sdb)
429 {
430     LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
431     return lgdb_p->hashTable;
432 }
433 
434 NSSLOWCERTCertDBHandle *
lg_getCertDB(SDB * sdb)435 lg_getCertDB(SDB *sdb)
436 {
437     LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
438 
439     return lgdb_p->certDB;
440 }
441 
442 NSSLOWKEYDBHandle *
lg_getKeyDB(SDB * sdb)443 lg_getKeyDB(SDB *sdb)
444 {
445     LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
446 
447     return lgdb_p->keyDB;
448 }
449 
450 PRBool lg_parentForkedAfterC_Initialize;
451 
452 void
lg_SetForkState(PRBool forked)453 lg_SetForkState(PRBool forked)
454 {
455     lg_parentForkedAfterC_Initialize = forked;
456 }
457 
458 CK_RV
lg_Close(SDB * sdb)459 lg_Close(SDB *sdb)
460 {
461     LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
462     lg_ClearTokenKeyHashTable(sdb);
463     if (lgdb_p) {
464         if (lgdb_p->certDB) {
465             nsslowcert_ClosePermCertDB(lgdb_p->certDB);
466         } else if (lgdb_p->keyDB) {
467             nsslowkey_CloseKeyDB(lgdb_p->keyDB);
468         }
469         if (lgdb_p->dbLock) {
470             SKIP_AFTER_FORK(PR_DestroyLock(lgdb_p->dbLock));
471         }
472         if (lgdb_p->hashTable) {
473             PL_HashTableDestroy(lgdb_p->hashTable);
474         }
475         PORT_Free(lgdb_p);
476     }
477     PORT_Free(sdb);
478     return CKR_OK;
479 }
480 
481 static PLHashNumber
lg_HashNumber(const void * key)482 lg_HashNumber(const void *key)
483 {
484     return (PLHashNumber)((char *)key - (char *)NULL);
485 }
486 
487 /*
488  * helper function to wrap a NSSLOWCERTCertDBHandle or a NSSLOWKEYDBHandle
489  * with and sdb structure.
490  */
491 CK_RV
lg_init(SDB ** pSdb,int flags,NSSLOWCERTCertDBHandle * certdbPtr,NSSLOWKEYDBHandle * keydbPtr)492 lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr,
493         NSSLOWKEYDBHandle *keydbPtr)
494 {
495     SDB *sdb = NULL;
496     LGPrivate *lgdb_p = NULL;
497     CK_RV error = CKR_HOST_MEMORY;
498 
499     *pSdb = NULL;
500     sdb = (SDB *)PORT_Alloc(sizeof(SDB));
501     if (sdb == NULL) {
502         goto loser;
503     }
504     lgdb_p = (LGPrivate *)PORT_Alloc(sizeof(LGPrivate));
505     if (lgdb_p == NULL) {
506         goto loser;
507     }
508     /* invariant fields */
509     lgdb_p->certDB = certdbPtr;
510     lgdb_p->keyDB = keydbPtr;
511     lgdb_p->dbLock = PR_NewLock();
512     if (lgdb_p->dbLock == NULL) {
513         goto loser;
514     }
515     lgdb_p->hashTable = PL_NewHashTable(64, lg_HashNumber, PL_CompareValues,
516                                         SECITEM_HashCompare, NULL, 0);
517     if (lgdb_p->hashTable == NULL) {
518         goto loser;
519     }
520 
521     sdb->private = lgdb_p;
522     sdb->version = 0;
523     sdb->sdb_flags = flags;
524     sdb->app_private = NULL;
525     sdb->sdb_FindObjectsInit = lg_FindObjectsInit;
526     sdb->sdb_FindObjects = lg_FindObjects;
527     sdb->sdb_FindObjectsFinal = lg_FindObjectsFinal;
528     sdb->sdb_GetAttributeValue = lg_GetAttributeValue;
529     sdb->sdb_SetAttributeValue = lg_SetAttributeValue;
530     sdb->sdb_CreateObject = lg_CreateObject;
531     sdb->sdb_DestroyObject = lg_DestroyObject;
532     sdb->sdb_GetMetaData = lg_GetMetaData;
533     sdb->sdb_PutMetaData = lg_PutMetaData;
534     sdb->sdb_Begin = lg_Begin;
535     sdb->sdb_Commit = lg_Commit;
536     sdb->sdb_Abort = lg_Abort;
537     sdb->sdb_Reset = lg_Reset;
538     sdb->sdb_Close = lg_Close;
539     sdb->sdb_SetForkState = lg_SetForkState;
540 
541     *pSdb = sdb;
542     return CKR_OK;
543 
544 loser:
545     if (sdb) {
546         PORT_Free(sdb);
547     }
548     if (lgdb_p) {
549         if (lgdb_p->dbLock) {
550             PR_DestroyLock(lgdb_p->dbLock);
551         }
552         if (lgdb_p->hashTable) {
553             PL_HashTableDestroy(lgdb_p->hashTable);
554         }
555         PORT_Free(lgdb_p);
556     }
557     return error;
558 }
559 
560 /*
561  * OK there are now lots of options here, lets go through them all:
562  *
563  * configdir - base directory where all the cert, key, and module datbases live.
564  * certPrefix - prefix added to the beginning of the cert database example: "
565  *              "https-server1-"
566  * keyPrefix - prefix added to the beginning of the key database example: "
567  *             "https-server1-"
568  * secmodName - name of the security module database (usually "secmod.db").
569  * readOnly - Boolean: true if the databases are to be openned read only.
570  * nocertdb - Don't open the cert DB and key DB's, just initialize the
571  *            Volatile certdb.
572  * nomoddb - Don't open the security module DB, just initialize the
573  *           PKCS #11 module.
574  * forceOpen - Continue to force initializations even if the databases cannot
575  *             be opened.
576  */
577 CK_RV
legacy_Open(const char * configdir,const char * certPrefix,const char * keyPrefix,int certVersion,int keyVersion,int flags,SDB ** certDB,SDB ** keyDB)578 legacy_Open(const char *configdir, const char *certPrefix,
579             const char *keyPrefix, int certVersion, int keyVersion,
580             int flags, SDB **certDB, SDB **keyDB)
581 {
582     CK_RV crv = CKR_OK;
583     SECStatus rv;
584     PRBool readOnly = ((flags & 0x7) == SDB_RDONLY) ? PR_TRUE : PR_FALSE;
585 
586 #define NSS_VERSION_VARIABLE __nss_dbm_version
587 #include "verref.h"
588 
589     if (flags & SDB_FIPS) {
590         if (!lg_FIPSEntryOK()) {
591             return CKR_DEVICE_ERROR;
592         }
593     }
594 
595     rv = SECOID_Init();
596     if (SECSuccess != rv) {
597         return CKR_DEVICE_ERROR;
598     }
599     nsslowcert_InitLocks();
600 
601     if (keyDB)
602         *keyDB = NULL;
603     if (certDB)
604         *certDB = NULL;
605 
606     if (certDB) {
607         NSSLOWCERTCertDBHandle *certdbPtr = NULL;
608 
609         crv = lg_OpenCertDB(configdir, certPrefix, readOnly, &certdbPtr);
610         if (crv != CKR_OK) {
611             goto loser;
612         }
613         crv = lg_init(certDB, flags, certdbPtr, NULL);
614         if (crv != CKR_OK) {
615             nsslowcert_ClosePermCertDB(certdbPtr);
616             goto loser;
617         }
618     }
619     if (keyDB) {
620         NSSLOWKEYDBHandle *keydbPtr;
621 
622         crv = lg_OpenKeyDB(configdir, keyPrefix, readOnly, &keydbPtr);
623         if (crv != CKR_OK) {
624             goto loser;
625         }
626         crv = lg_init(keyDB, flags, NULL, keydbPtr);
627         if (crv != CKR_OK) {
628             nsslowkey_CloseKeyDB(keydbPtr);
629             goto loser;
630         }
631         if (certDB && *certDB) {
632             LGPrivate *lgdb_p = (LGPrivate *)(*certDB)->private;
633             lgdb_p->keyDB = keydbPtr;
634         }
635     }
636 
637 loser:
638     if (crv != CKR_OK) {
639         if (keyDB && *keyDB) {
640             lg_Close(*keyDB);
641             *keyDB = NULL;
642         }
643         if (certDB && *certDB) {
644             lg_Close(*certDB);
645             *certDB = NULL;
646         }
647     }
648     return crv;
649 }
650 
651 CK_RV
legacy_Shutdown(PRBool forked)652 legacy_Shutdown(PRBool forked)
653 {
654     lg_SetForkState(forked);
655     nsslowcert_DestroyFreeLists();
656     nsslowcert_DestroyGlobalLocks();
657     SECOID_Shutdown();
658     lg_SetForkState(PR_FALSE);
659     return CKR_OK;
660 }
661