diff nss/lib/softoken/legacydb/lginit.c @ 3:150b72113545

Add DBM and legacydb support
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 05 Aug 2014 18:32:02 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/softoken/legacydb/lginit.c	Tue Aug 05 18:32:02 2014 +0200
@@ -0,0 +1,664 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "lowkeyi.h"
+#include "pcert.h"
+#include "keydbi.h"
+#include "lgdb.h"
+#include "secoid.h"
+#include "prenv.h"
+#include "softkver.h"
+
+/* Library identity and versioning */
+
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
+
+/*
+ * Version information for the 'ident' and 'what commands
+ *
+ * NOTE: the first component of the concatenated rcsid string
+ * must not end in a '$' to prevent rcs keyword substitution.
+ */
+const char __nss_dbm_rcsid[] = "$Header: NSS " SOFTOKEN_VERSION _DEBUG_STRING
+        "  " __DATE__ " " __TIME__ " $";
+const char __nss_dbm_sccsid[] = "@(#)NSS " SOFTOKEN_VERSION _DEBUG_STRING
+        "  " __DATE__ " " __TIME__;
+
+typedef struct LGPrivateStr {
+    NSSLOWCERTCertDBHandle *certDB;
+    NSSLOWKEYDBHandle *keyDB;
+    PRLock *dbLock;
+    PLHashTable *hashTable;
+} LGPrivate;
+
+static char *
+lg_certdb_name_cb(void *arg, int dbVersion)
+{
+    const char *configdir = (const char *)arg;
+    const char *dbver;
+    char *smpname = NULL;
+    char *dbname = NULL;
+
+    switch (dbVersion) {
+      case 8:
+	dbver = "8";
+	break;
+      case 7:
+	dbver = "7";
+	break;
+      case 6:
+	dbver = "6";
+	break;
+      case 5:
+	dbver = "5";
+	break;
+      case 4:
+      default:
+	dbver = "";
+	break;
+    }
+
+    /* make sure we return something allocated with PORT_ so we have properly
+     * matched frees at the end */
+    smpname = PR_smprintf(CERT_DB_FMT, configdir, dbver);
+    if (smpname) {
+	dbname = PORT_Strdup(smpname);
+	PR_smprintf_free(smpname);
+    }
+    return dbname;
+}
+    
+static char *
+lg_keydb_name_cb(void *arg, int dbVersion)
+{
+    const char *configdir = (const char *)arg;
+    const char *dbver;
+    char *smpname = NULL;
+    char *dbname = NULL;
+    
+    switch (dbVersion) {
+      case 4:
+	dbver = "4";
+	break;
+      case 3:
+	dbver = "3";
+	break;
+      case 1:
+	dbver = "1";
+	break;
+      case 2:
+      default:
+	dbver = "";
+	break;
+    }
+
+    smpname = PR_smprintf(KEY_DB_FMT, configdir, dbver);
+    if (smpname) {
+	dbname = PORT_Strdup(smpname);
+	PR_smprintf_free(smpname);
+    }
+    return dbname;
+}
+
+const char *
+lg_EvaluateConfigDir(const char *configdir,char **appName)
+{
+    if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS)-1) == 0) {
+	char *cdir;
+
+	*appName = PORT_Strdup(configdir+sizeof(MULTIACCESS)-1);
+	if (*appName == NULL) {
+	    return configdir;
+	}
+	cdir = *appName;
+	while (*cdir && *cdir != ':') {
+	    cdir++;
+	}
+	if (*cdir == ':') {
+	   *cdir = 0;
+	   cdir++;
+	}
+	configdir = cdir;
+    }
+    return configdir;
+}
+
+static int rdbmapflags(int flags);
+static rdbfunc lg_rdbfunc = NULL;
+static rdbstatusfunc lg_rdbstatusfunc = NULL;
+
+/* NOTE: SHLIB_SUFFIX is defined on the command line */
+#define RDBLIB SHLIB_PREFIX"rdb."SHLIB_SUFFIX
+
+DB * rdbopen(const char *appName, const char *prefix, 
+			const char *type, int flags, int *status)
+{
+    PRLibrary *lib;
+    DB *db;
+    char *disableUnload = NULL;
+
+    if (lg_rdbfunc) {
+	db = (*lg_rdbfunc)(appName,prefix,type,rdbmapflags(flags));
+	if (!db && status && lg_rdbstatusfunc) {
+	    *status = (*lg_rdbstatusfunc)();
+	}
+	return db;
+    }
+
+    /*
+     * try to open the library.
+     */
+    lib = PR_LoadLibrary(RDBLIB);
+
+    if (!lib) {
+	return NULL;
+    }
+
+    /* get the entry points */
+    lg_rdbstatusfunc = (rdbstatusfunc) PR_FindSymbol(lib,"rdbstatus");
+    lg_rdbfunc = (rdbfunc) PR_FindSymbol(lib,"rdbopen");
+    if (lg_rdbfunc) {
+	db = (*lg_rdbfunc)(appName,prefix,type,rdbmapflags(flags));
+	if (!db && status && lg_rdbstatusfunc) {
+	    *status = (*lg_rdbstatusfunc)();
+	}
+	return db;
+    }
+
+    /* couldn't find the entry point, unload the library and fail */
+    disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
+    if (!disableUnload) {
+        PR_UnloadLibrary(lib);
+    }
+    return NULL;
+}
+
+/*
+ * the following data structures are from rdb.h.
+ */
+struct RDBStr {
+    DB	db;
+    int (*xactstart)(DB *db);
+    int (*xactdone)(DB *db, PRBool abort);
+    int version;
+    int (*dbinitcomplete)(DB *db);
+};
+
+#define DB_RDB ((DBTYPE) 0xff)
+#define RDB_RDONLY	1
+#define RDB_RDWR 	2
+#define RDB_CREATE      4
+
+static int
+rdbmapflags(int flags) {
+   switch (flags) {
+   case NO_RDONLY:
+	return RDB_RDONLY;
+   case NO_RDWR:
+	return RDB_RDWR;
+   case NO_CREATE:
+	return RDB_CREATE;
+   default:
+	break;
+   }
+   return 0;
+}
+
+PRBool
+db_IsRDB(DB *db)
+{
+    return (PRBool) db->type == DB_RDB;
+}
+
+int
+db_BeginTransaction(DB *db)
+{
+    struct RDBStr *rdb = (struct RDBStr *)db;
+    if (db->type != DB_RDB) {
+	return 0;
+    }
+
+    return rdb->xactstart(db);
+}
+
+int
+db_FinishTransaction(DB *db, PRBool abort)
+{
+    struct RDBStr *rdb = (struct RDBStr *)db;
+    if (db->type != DB_RDB) {
+	return 0;
+    }
+
+    return rdb->xactdone(db, abort);
+}
+
+static DB *
+lg_getRawDB(SDB *sdb)
+{
+    NSSLOWCERTCertDBHandle *certDB;
+    NSSLOWKEYDBHandle *keyDB;
+
+    certDB = lg_getCertDB(sdb);
+    if (certDB) {
+	return certDB->permCertDB;
+    }
+    keyDB = lg_getKeyDB(sdb);
+    if (keyDB) {
+	return keyDB->db;
+    }
+    return NULL;
+}
+
+CK_RV
+lg_Begin(SDB *sdb)
+{
+    DB *db = lg_getRawDB(sdb);
+    int ret;
+
+    if (db == NULL) {
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+    ret = db_BeginTransaction(db);
+    if (ret != 0) {
+	return CKR_GENERAL_ERROR; /* could happen */
+    }
+    return CKR_OK;
+}
+
+CK_RV
+lg_Commit(SDB *sdb)
+{
+    DB *db = lg_getRawDB(sdb);
+    int ret;
+
+    if (db == NULL) {
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+    ret = db_FinishTransaction(db, PR_FALSE);
+    if (ret != 0) {
+	return CKR_GENERAL_ERROR; /* could happen */
+    }
+    return CKR_OK;
+}
+
+CK_RV
+lg_Abort(SDB *sdb)
+{
+    DB *db = lg_getRawDB(sdb);
+    int ret;
+
+    if (db == NULL) {
+	return CKR_GENERAL_ERROR; /* shouldn't happen */
+    }
+    ret = db_FinishTransaction(db, PR_TRUE);
+    if (ret != 0) {
+	return CKR_GENERAL_ERROR; /* could happen */
+    }
+    return CKR_OK;
+}
+
+int
+db_InitComplete(DB *db)
+{
+    struct RDBStr *rdb = (struct RDBStr *)db;
+    if (db->type != DB_RDB) {
+	return 0;
+    }
+    /* we should have added a version number to the RDBS structure. Since we
+     * didn't, we detect that we have and 'extended' structure if the rdbstatus
+     * func exists */
+    if (!lg_rdbstatusfunc) {
+	return 0;
+    }
+
+    return rdb->dbinitcomplete(db);
+}
+
+
+
+SECStatus
+db_Copy(DB *dest,DB *src)
+{
+    int ret;
+    DBT key,data;
+    ret = (*src->seq)(src, &key, &data, R_FIRST);
+    if (ret)  {
+	return SECSuccess;
+    }
+
+    do {
+	(void)(*dest->put)(dest,&key,&data, R_NOOVERWRITE);
+    } while ( (*src->seq)(src, &key, &data, R_NEXT) == 0);
+    (void)(*dest->sync)(dest,0);
+
+    return SECSuccess;
+}
+
+
+static CK_RV
+lg_OpenCertDB(const char * configdir, const char *prefix, PRBool readOnly,
+    					    NSSLOWCERTCertDBHandle **certdbPtr)
+{
+    NSSLOWCERTCertDBHandle *certdb = NULL;
+    CK_RV        crv = CKR_NETSCAPE_CERTDB_FAILED;
+    SECStatus    rv;
+    char * name = NULL;
+    char * appName = NULL;
+
+    if (prefix == NULL) {
+	prefix = "";
+    }
+
+    configdir = lg_EvaluateConfigDir(configdir, &appName);
+
+    name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix);
+    if (name == NULL) goto loser;
+
+    certdb = (NSSLOWCERTCertDBHandle*)PORT_ZAlloc(sizeof(NSSLOWCERTCertDBHandle));
+    if (certdb == NULL) 
+    	goto loser;
+
+    certdb->ref = 1;
+/* fix when we get the DB in */
+    rv = nsslowcert_OpenCertDB(certdb, readOnly, appName, prefix,
+				lg_certdb_name_cb, (void *)name, PR_FALSE);
+    if (rv == SECSuccess) {
+	crv = CKR_OK;
+	*certdbPtr = certdb;
+	certdb = NULL;
+    }
+loser: 
+    if (certdb) PR_Free(certdb);
+    if (name) PR_smprintf_free(name);
+    if (appName) PORT_Free(appName);
+    return crv;
+}
+
+static CK_RV
+lg_OpenKeyDB(const char * configdir, const char *prefix, PRBool readOnly,
+    						NSSLOWKEYDBHandle **keydbPtr)
+{
+    NSSLOWKEYDBHandle *keydb;
+    char * name = NULL;
+    char * appName = NULL;
+
+    if (prefix == NULL) {
+	prefix = "";
+    }
+    configdir = lg_EvaluateConfigDir(configdir, &appName);
+
+    name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix);	
+    if (name == NULL) 
+	return CKR_HOST_MEMORY;
+    keydb = nsslowkey_OpenKeyDB(readOnly, appName, prefix, 
+					lg_keydb_name_cb, (void *)name);
+    PR_smprintf_free(name);
+    if (appName) PORT_Free(appName);
+    if (keydb == NULL)
+	return CKR_NETSCAPE_KEYDB_FAILED;
+    *keydbPtr = keydb;
+
+    return CKR_OK;
+}
+
+/*
+ * Accessors for the private parts of the sdb structure.
+ */
+void
+lg_DBLock(SDB *sdb) 
+{
+    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
+    SKIP_AFTER_FORK(PR_Lock(lgdb_p->dbLock));
+}
+
+void
+lg_DBUnlock(SDB *sdb) 
+{
+    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
+    SKIP_AFTER_FORK(PR_Unlock(lgdb_p->dbLock));
+}
+
+PLHashTable *
+lg_GetHashTable(SDB *sdb) 
+{
+    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
+    return lgdb_p->hashTable;
+}
+
+NSSLOWCERTCertDBHandle *
+lg_getCertDB(SDB *sdb)
+{
+    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
+
+    return lgdb_p->certDB;
+}
+
+NSSLOWKEYDBHandle *
+lg_getKeyDB(SDB *sdb)
+{
+    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
+
+    return lgdb_p->keyDB;
+}
+
+PRBool lg_parentForkedAfterC_Initialize;
+
+void lg_SetForkState(PRBool forked)
+{
+    lg_parentForkedAfterC_Initialize = forked;
+}
+
+CK_RV
+lg_Close(SDB *sdb)
+{
+    LGPrivate *lgdb_p = (LGPrivate *)sdb->private;
+    lg_ClearTokenKeyHashTable(sdb);
+    if (lgdb_p) {
+    	if (lgdb_p->certDB) {
+	    nsslowcert_ClosePermCertDB(lgdb_p->certDB);
+	} else if (lgdb_p->keyDB) {
+	    nsslowkey_CloseKeyDB(lgdb_p->keyDB);
+	}
+	if (lgdb_p->dbLock) {
+	    SKIP_AFTER_FORK(PR_DestroyLock(lgdb_p->dbLock));
+	}
+	if (lgdb_p->hashTable) {
+	    PL_HashTableDestroy(lgdb_p->hashTable);
+	}
+	PORT_Free(lgdb_p);
+    }
+    PORT_Free(sdb);
+    return CKR_OK;
+}
+
+static PLHashNumber
+lg_HashNumber(const void *key)
+{
+    return (PLHashNumber) key;
+}
+
+PRIntn
+lg_CompareValues(const void *v1, const void *v2)
+{
+    PLHashNumber value1 = (PLHashNumber) v1;
+    PLHashNumber value2 = (PLHashNumber) v2;
+    return (value1 == value2);
+}
+
+/*
+ * helper function to wrap a NSSLOWCERTCertDBHandle or a NSSLOWKEYDBHandle
+ * with and sdb structure.
+ */
+CK_RV 
+lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr,
+	 NSSLOWKEYDBHandle *keydbPtr)
+{
+    SDB *sdb = NULL;
+    LGPrivate *lgdb_p = NULL;
+    CK_RV error = CKR_HOST_MEMORY;
+
+    *pSdb = NULL;
+    sdb = (SDB *) PORT_Alloc(sizeof(SDB));
+    if (sdb == NULL) {
+	goto loser;
+    }
+    lgdb_p = (LGPrivate *) PORT_Alloc(sizeof(LGPrivate));
+    if (lgdb_p == NULL) {
+	goto loser;
+    }
+    /* invariant fields */
+    lgdb_p->certDB = certdbPtr;
+    lgdb_p->keyDB = keydbPtr;
+    lgdb_p->dbLock = PR_NewLock();
+    if (lgdb_p->dbLock == NULL) {
+	goto loser;
+    }
+    lgdb_p->hashTable = PL_NewHashTable(64, lg_HashNumber, lg_CompareValues,
+			SECITEM_HashCompare, NULL, 0);
+    if (lgdb_p->hashTable == NULL) {
+	goto loser;
+    }
+
+    sdb->private = lgdb_p;
+    sdb->version = 0;
+    /*sdb->sdb_type = SDB_LEGACY; */
+    sdb->sdb_flags = flags;
+    sdb->app_private = NULL;
+    sdb->sdb_FindObjectsInit = lg_FindObjectsInit;
+    sdb->sdb_FindObjects = lg_FindObjects;
+    sdb->sdb_FindObjectsFinal = lg_FindObjectsFinal;
+    sdb->sdb_GetAttributeValue = lg_GetAttributeValue;
+    sdb->sdb_SetAttributeValue = lg_SetAttributeValue;
+    sdb->sdb_CreateObject = lg_CreateObject;
+    sdb->sdb_DestroyObject = lg_DestroyObject;
+    sdb->sdb_GetMetaData = lg_GetMetaData;
+    sdb->sdb_PutMetaData = lg_PutMetaData;
+    sdb->sdb_Begin = lg_Begin;
+    sdb->sdb_Commit = lg_Commit;
+    sdb->sdb_Abort = lg_Abort;
+    sdb->sdb_Reset = lg_Reset;
+    sdb->sdb_Close = lg_Close;
+    sdb->sdb_SetForkState = lg_SetForkState;
+
+    *pSdb = sdb;
+    return CKR_OK;
+
+loser:
+    if (sdb) {
+	PORT_Free(sdb);
+    }
+    if (lgdb_p) {
+	if (lgdb_p->dbLock) {
+	    PR_DestroyLock(lgdb_p->dbLock);
+	}
+	if (lgdb_p->hashTable) {
+	    PL_HashTableDestroy(lgdb_p->hashTable);
+	}
+	PORT_Free(lgdb_p);
+    }
+    return error;
+
+}
+
+/*
+ * OK there are now lots of options here, lets go through them all:
+ *
+ * configdir - base directory where all the cert, key, and module datbases live.
+ * certPrefix - prefix added to the beginning of the cert database example: "
+ * 			"https-server1-"
+ * keyPrefix - prefix added to the beginning of the key database example: "
+ * 			"https-server1-"
+ * secmodName - name of the security module database (usually "secmod.db").
+ * readOnly - Boolean: true if the databases are to be openned read only.
+ * nocertdb - Don't open the cert DB and key DB's, just initialize the 
+ *			Volatile certdb.
+ * nomoddb - Don't open the security module DB, just initialize the 
+ *			PKCS #11 module.
+ * forceOpen - Continue to force initializations even if the databases cannot
+ * 			be opened.
+ */
+CK_RV
+legacy_Open(const char *configdir, const char *certPrefix, 
+	    const char *keyPrefix, int certVersion, int keyVersion,
+	    int flags, SDB **certDB, SDB **keyDB)
+{
+    CK_RV crv = CKR_OK;
+    SECStatus rv;
+    PRBool readOnly = (flags == SDB_RDONLY)? PR_TRUE: PR_FALSE;
+    volatile char c; /* force a reference that won't get optimized away */
+
+    c = __nss_dbm_rcsid[0] + __nss_dbm_sccsid[0];
+
+    rv = SECOID_Init();
+    if (SECSuccess != rv) {
+        return CKR_DEVICE_ERROR;
+    }
+    nsslowcert_InitLocks();
+
+    if (keyDB) *keyDB = NULL;
+    if (certDB) *certDB = NULL;
+
+    if (certDB) {
+	NSSLOWCERTCertDBHandle *certdbPtr;
+
+	crv = lg_OpenCertDB(configdir, certPrefix, readOnly, &certdbPtr);
+	if (crv != CKR_OK) {
+	    goto loser;
+	}
+	crv = lg_init(certDB, flags, certdbPtr, NULL);
+	if (crv != CKR_OK) {
+	    nsslowcert_ClosePermCertDB(certdbPtr);
+	    goto loser;
+	}
+    }
+    if (keyDB) {
+	NSSLOWKEYDBHandle *keydbPtr;
+
+	crv = lg_OpenKeyDB(configdir, keyPrefix, readOnly, &keydbPtr);
+	if (crv != CKR_OK) {
+	    goto loser;
+	}
+	crv = lg_init(keyDB, flags, NULL, keydbPtr);
+	if (crv != CKR_OK) {
+	    nsslowkey_CloseKeyDB(keydbPtr);
+	    goto loser;
+	}
+	if (certDB && *certDB) {
+	    LGPrivate *lgdb_p = (LGPrivate *)(*certDB)->private;
+	    lgdb_p->keyDB = keydbPtr;
+	}
+    }
+
+loser:
+    if (crv != CKR_OK) {
+	if (keyDB && *keyDB) {
+	    lg_Close(*keyDB);
+	    *keyDB = NULL;
+	}
+	if (certDB && *certDB) {
+	    lg_Close(*certDB);
+	    *certDB = NULL;
+	}
+    }
+    return crv;
+}
+
+CK_RV
+legacy_Shutdown(PRBool forked)
+{
+    lg_SetForkState(forked);
+    nsslowcert_DestroyFreeLists();
+    nsslowcert_DestroyGlobalLocks();
+    SECOID_Shutdown();
+    lg_SetForkState(PR_FALSE);
+    return CKR_OK;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)