lginit.c (15504B)
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 * 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 * 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 * 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 * 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 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 212 db_IsRDB(DB *db) 213 { 214 return (PRBool)db->type == DB_RDB; 215 } 216 217 int 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 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 * 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 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 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 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 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 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 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 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 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 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 * 428 lg_GetHashTable(SDB *sdb) 429 { 430 LGPrivate *lgdb_p = (LGPrivate *)sdb->private; 431 return lgdb_p->hashTable; 432 } 433 434 NSSLOWCERTCertDBHandle * 435 lg_getCertDB(SDB *sdb) 436 { 437 LGPrivate *lgdb_p = (LGPrivate *)sdb->private; 438 439 return lgdb_p->certDB; 440 } 441 442 NSSLOWKEYDBHandle * 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 453 lg_SetForkState(PRBool forked) 454 { 455 lg_parentForkedAfterC_Initialize = forked; 456 } 457 458 CK_RV 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 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 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 PR_DestroyLock(lgdb_p->dbLock); 519 goto loser; 520 } 521 522 sdb->private = lgdb_p; 523 sdb->version = 1; 524 sdb->sdb_flags = flags; 525 sdb->app_private = NULL; 526 sdb->sdb_FindObjectsInit = lg_FindObjectsInit; 527 sdb->sdb_FindObjects = lg_FindObjects; 528 sdb->sdb_FindObjectsFinal = lg_FindObjectsFinal; 529 sdb->sdb_GetAttributeValue = lg_GetAttributeValue; 530 sdb->sdb_SetAttributeValue = lg_SetAttributeValue; 531 sdb->sdb_CreateObject = lg_CreateObject; 532 sdb->sdb_DestroyObject = lg_DestroyObject; 533 sdb->sdb_GetMetaData = lg_GetMetaData; 534 sdb->sdb_PutMetaData = lg_PutMetaData; 535 sdb->sdb_DestroyMetaData = lg_DestroyMetaData; 536 sdb->sdb_Begin = lg_Begin; 537 sdb->sdb_Commit = lg_Commit; 538 sdb->sdb_Abort = lg_Abort; 539 sdb->sdb_Reset = lg_Reset; 540 sdb->sdb_Close = lg_Close; 541 sdb->sdb_SetForkState = lg_SetForkState; 542 sdb->sdb_GetNewObjectID = lg_GetNewObjectID; 543 544 *pSdb = sdb; 545 return CKR_OK; 546 547 loser: 548 if (sdb) { 549 PORT_Free(sdb); 550 } 551 if (lgdb_p) { 552 PORT_Free(lgdb_p); 553 } 554 return error; 555 } 556 557 /* 558 * OK there are now lots of options here, lets go through them all: 559 * 560 * configdir - base directory where all the cert, key, and module datbases live. 561 * certPrefix - prefix added to the beginning of the cert database example: " 562 * "https-server1-" 563 * keyPrefix - prefix added to the beginning of the key database example: " 564 * "https-server1-" 565 * secmodName - name of the security module database (usually "secmod.db"). 566 * readOnly - Boolean: true if the databases are to be openned read only. 567 * nocertdb - Don't open the cert DB and key DB's, just initialize the 568 * Volatile certdb. 569 * nomoddb - Don't open the security module DB, just initialize the 570 * PKCS #11 module. 571 * forceOpen - Continue to force initializations even if the databases cannot 572 * be opened. 573 */ 574 CK_RV 575 legacy_Open(const char *configdir, const char *certPrefix, 576 const char *keyPrefix, int certVersion, int keyVersion, 577 int flags, SDB **certDB, SDB **keyDB) 578 { 579 CK_RV crv = CKR_OK; 580 SECStatus rv; 581 PRBool readOnly = ((flags & 0x7) == SDB_RDONLY) ? PR_TRUE : PR_FALSE; 582 583 #define NSS_VERSION_VARIABLE __nss_dbm_version 584 #include "verref.h" 585 586 #ifndef NSS_FIPS_DISABLED 587 if (flags & SDB_FIPS) { 588 /* We shouldn't get here when FIPS is not enabled on the database. But 589 * we also don't care when this NSS build doesn't support FIPS. */ 590 if (!lg_FIPSEntryOK()) { 591 return CKR_DEVICE_ERROR; 592 } 593 } 594 #endif 595 596 rv = SECOID_Init(); 597 if (SECSuccess != rv) { 598 return CKR_DEVICE_ERROR; 599 } 600 nsslowcert_InitLocks(); 601 602 if (keyDB) 603 *keyDB = NULL; 604 if (certDB) 605 *certDB = NULL; 606 607 if (certDB) { 608 NSSLOWCERTCertDBHandle *certdbPtr = NULL; 609 610 crv = lg_OpenCertDB(configdir, certPrefix, readOnly, &certdbPtr); 611 if (crv != CKR_OK) { 612 goto loser; 613 } 614 crv = lg_init(certDB, flags, certdbPtr, NULL); 615 if (crv != CKR_OK) { 616 nsslowcert_ClosePermCertDB(certdbPtr); 617 goto loser; 618 } 619 } 620 if (keyDB) { 621 NSSLOWKEYDBHandle *keydbPtr; 622 623 crv = lg_OpenKeyDB(configdir, keyPrefix, readOnly, &keydbPtr); 624 if (crv != CKR_OK) { 625 goto loser; 626 } 627 crv = lg_init(keyDB, flags, NULL, keydbPtr); 628 if (crv != CKR_OK) { 629 nsslowkey_CloseKeyDB(keydbPtr); 630 goto loser; 631 } 632 if (certDB && *certDB) { 633 LGPrivate *lgdb_p = (LGPrivate *)(*certDB)->private; 634 lgdb_p->keyDB = keydbPtr; 635 } 636 } 637 638 loser: 639 if (crv != CKR_OK) { 640 if (keyDB && *keyDB) { 641 lg_Close(*keyDB); 642 *keyDB = NULL; 643 } 644 if (certDB && *certDB) { 645 lg_Close(*certDB); 646 *certDB = NULL; 647 } 648 } 649 return crv; 650 } 651 652 CK_RV 653 legacy_Shutdown(PRBool forked) 654 { 655 lg_SetForkState(forked); 656 nsslowcert_DestroyFreeLists(); 657 nsslowcert_DestroyGlobalLocks(); 658 SECOID_Shutdown(); 659 lg_SetForkState(PR_FALSE); 660 return CKR_OK; 661 }