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_NSS_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_NSS_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 = 1;
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_DestroyMetaData = lg_DestroyMetaData;
535 sdb->sdb_Begin = lg_Begin;
536 sdb->sdb_Commit = lg_Commit;
537 sdb->sdb_Abort = lg_Abort;
538 sdb->sdb_Reset = lg_Reset;
539 sdb->sdb_Close = lg_Close;
540 sdb->sdb_SetForkState = lg_SetForkState;
541 sdb->sdb_GetNewObjectID = lg_GetNewObjectID;
542
543 *pSdb = sdb;
544 return CKR_OK;
545
546 loser:
547 if (sdb) {
548 PORT_Free(sdb);
549 }
550 if (lgdb_p) {
551 if (lgdb_p->dbLock) {
552 PR_DestroyLock(lgdb_p->dbLock);
553 }
554 if (lgdb_p->hashTable) {
555 PL_HashTableDestroy(lgdb_p->hashTable);
556 }
557 PORT_Free(lgdb_p);
558 }
559 return error;
560 }
561
562 /*
563 * OK there are now lots of options here, lets go through them all:
564 *
565 * configdir - base directory where all the cert, key, and module datbases live.
566 * certPrefix - prefix added to the beginning of the cert database example: "
567 * "https-server1-"
568 * keyPrefix - prefix added to the beginning of the key database example: "
569 * "https-server1-"
570 * secmodName - name of the security module database (usually "secmod.db").
571 * readOnly - Boolean: true if the databases are to be openned read only.
572 * nocertdb - Don't open the cert DB and key DB's, just initialize the
573 * Volatile certdb.
574 * nomoddb - Don't open the security module DB, just initialize the
575 * PKCS #11 module.
576 * forceOpen - Continue to force initializations even if the databases cannot
577 * be opened.
578 */
579 CK_RV
legacy_Open(const char * configdir,const char * certPrefix,const char * keyPrefix,int certVersion,int keyVersion,int flags,SDB ** certDB,SDB ** keyDB)580 legacy_Open(const char *configdir, const char *certPrefix,
581 const char *keyPrefix, int certVersion, int keyVersion,
582 int flags, SDB **certDB, SDB **keyDB)
583 {
584 CK_RV crv = CKR_OK;
585 SECStatus rv;
586 PRBool readOnly = ((flags & 0x7) == SDB_RDONLY) ? PR_TRUE : PR_FALSE;
587
588 #define NSS_VERSION_VARIABLE __nss_dbm_version
589 #include "verref.h"
590
591 #ifndef NSS_FIPS_DISABLED
592 if (flags & SDB_FIPS) {
593 /* We shouldn't get here when FIPS is not enabled on the database. But
594 * we also don't care when this NSS build doesn't support FIPS. */
595 if (!lg_FIPSEntryOK()) {
596 return CKR_DEVICE_ERROR;
597 }
598 }
599 #endif
600
601 rv = SECOID_Init();
602 if (SECSuccess != rv) {
603 return CKR_DEVICE_ERROR;
604 }
605 nsslowcert_InitLocks();
606
607 if (keyDB)
608 *keyDB = NULL;
609 if (certDB)
610 *certDB = NULL;
611
612 if (certDB) {
613 NSSLOWCERTCertDBHandle *certdbPtr = NULL;
614
615 crv = lg_OpenCertDB(configdir, certPrefix, readOnly, &certdbPtr);
616 if (crv != CKR_OK) {
617 goto loser;
618 }
619 crv = lg_init(certDB, flags, certdbPtr, NULL);
620 if (crv != CKR_OK) {
621 nsslowcert_ClosePermCertDB(certdbPtr);
622 goto loser;
623 }
624 }
625 if (keyDB) {
626 NSSLOWKEYDBHandle *keydbPtr;
627
628 crv = lg_OpenKeyDB(configdir, keyPrefix, readOnly, &keydbPtr);
629 if (crv != CKR_OK) {
630 goto loser;
631 }
632 crv = lg_init(keyDB, flags, NULL, keydbPtr);
633 if (crv != CKR_OK) {
634 nsslowkey_CloseKeyDB(keydbPtr);
635 goto loser;
636 }
637 if (certDB && *certDB) {
638 LGPrivate *lgdb_p = (LGPrivate *)(*certDB)->private;
639 lgdb_p->keyDB = keydbPtr;
640 }
641 }
642
643 loser:
644 if (crv != CKR_OK) {
645 if (keyDB && *keyDB) {
646 lg_Close(*keyDB);
647 *keyDB = NULL;
648 }
649 if (certDB && *certDB) {
650 lg_Close(*certDB);
651 *certDB = NULL;
652 }
653 }
654 return crv;
655 }
656
657 CK_RV
legacy_Shutdown(PRBool forked)658 legacy_Shutdown(PRBool forked)
659 {
660 lg_SetForkState(forked);
661 nsslowcert_DestroyFreeLists();
662 nsslowcert_DestroyGlobalLocks();
663 SECOID_Shutdown();
664 lg_SetForkState(PR_FALSE);
665 return CKR_OK;
666 }
667