diff options
-rw-r--r-- | security/nss/lib/softoken/cdbhdl.h | 8 | ||||
-rw-r--r-- | security/nss/lib/softoken/dbinit.c | 35 | ||||
-rw-r--r-- | security/nss/lib/softoken/keydb.c | 70 | ||||
-rw-r--r-- | security/nss/lib/softoken/manifest.mn | 2 | ||||
-rw-r--r-- | security/nss/lib/softoken/pcertdb.c | 59 | ||||
-rw-r--r-- | security/nss/lib/softoken/pk11db.c | 17 |
6 files changed, 141 insertions, 50 deletions
diff --git a/security/nss/lib/softoken/cdbhdl.h b/security/nss/lib/softoken/cdbhdl.h index 17fb6e638..8e309b208 100644 --- a/security/nss/lib/softoken/cdbhdl.h +++ b/security/nss/lib/softoken/cdbhdl.h @@ -63,15 +63,19 @@ struct NSSLOWCERTCertDBHandleStr { typedef DB * (*rdbfunc)(const char *appName, const char *prefix, const char *type, int flags); +typedef int (*rdbstatusfunc)(void); + +#define RDB_FAIL 1 +#define RDB_RETRY 2 DB * rdbopen(const char *appName, const char *prefix, - const char *type, int flags); + const char *type, int flags, int *status); DB *dbsopen (const char *dbname , int flags, int mode, DBTYPE type, const void * appData); SECStatus db_Copy(DB *dest,DB *src); int db_BeginTransaction(DB *db); int db_FinishTransaction(DB *db, PRBool abort); - +int db_InitComplete(DB *db); #endif diff --git a/security/nss/lib/softoken/dbinit.c b/security/nss/lib/softoken/dbinit.c index 40e295eaa..d230c9261 100644 --- a/security/nss/lib/softoken/dbinit.c +++ b/security/nss/lib/softoken/dbinit.c @@ -272,19 +272,23 @@ pk11_DBShutdown(NSSLOWCERTCertDBHandle *certHandle, } static int rdbmapflags(int flags); -static rdbfunc pk11_rdbfunc; +static rdbfunc pk11_rdbfunc = NULL; +static rdbstatusfunc pk11_rdbstatusfunc = NULL; /* NOTE: SHLIB_SUFFIX is defined on the command line */ -#define RDBLIB "rdb."SHLIB_SUFFIX +#define RDBLIB SHLIB_PREFIX"rdb."SHLIB_SUFFIX DB * rdbopen(const char *appName, const char *prefix, - const char *type, int flags) + const char *type, int flags, int *status) { PRLibrary *lib; DB *db; if (pk11_rdbfunc) { db = (*pk11_rdbfunc)(appName,prefix,type,rdbmapflags(flags)); + if (!db && status && pk11_rdbstatusfunc) { + *status = (*pk11_rdbstatusfunc)(); + } return db; } @@ -297,10 +301,14 @@ DB * rdbopen(const char *appName, const char *prefix, return NULL; } - /* get the entry point */ + /* get the entry points */ + pk11_rdbstatusfunc = (rdbstatusfunc) PR_FindSymbol(lib,"rdbstatus"); pk11_rdbfunc = (rdbfunc) PR_FindSymbol(lib,"rdbopen"); if (pk11_rdbfunc) { db = (*pk11_rdbfunc)(appName,prefix,type,rdbmapflags(flags)); + if (!db && status && pk11_rdbstatusfunc) { + *status = (*pk11_rdbstatusfunc)(); + } return db; } @@ -316,6 +324,8 @@ 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) @@ -367,6 +377,23 @@ db_FinishTransaction(DB *db, PRBool abort) return rdb->xactdone(db, abort); } +int +db_InitComplete(DB *db) +{ + struct RDBStr *rdb = (struct RDBStr *)db; + if (db->type != DB_RDB) { + return 0; + } + /* we should have addes 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 (!pk11_rdbstatusfunc) { + return 0; + } + + return rdb->dbinitcomplete(db); +} + SECStatus diff --git a/security/nss/lib/softoken/keydb.c b/security/nss/lib/softoken/keydb.c index 64ae1db76..877ead2b5 100644 --- a/security/nss/lib/softoken/keydb.c +++ b/security/nss/lib/softoken/keydb.c @@ -830,23 +830,25 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg) { SECStatus rv = SECFailure; + int status = RDB_FAIL; char *updname = NULL; DB *updatedb = NULL; PRBool updated = PR_FALSE; int ret; if (appName) { - handle->db = rdbopen( appName, prefix, "key", NO_CREATE); + handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status); } else { handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 ); } /* if create fails then we lose */ if ( handle->db == NULL ) { - return SECFailure; + return (status == RDB_RETRY) ? SECWouldBlock: SECFailure; } rv = db_BeginTransaction(handle->db); if (rv != SECSuccess) { + db_InitComplete(handle->db); return rv; } @@ -855,6 +857,7 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, if (nsslowkey_version(handle->db) == NSSLOWKEY_DB_FILE_VERSION) { /* someone else has already updated the database for us */ db_FinishTransaction(handle->db, PR_FALSE); + db_InitComplete(handle->db); return SECSuccess; } @@ -872,6 +875,7 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, db_Copy(handle->db, updatedb); (updatedb->close)(updatedb); db_FinishTransaction(handle->db,PR_FALSE); + db_InitComplete(handle->db); return SECSuccess; } } @@ -924,9 +928,34 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, loser: db_FinishTransaction(handle->db, rv != SECSuccess); + db_InitComplete(handle->db); return rv; } + +static DB * +openOldDB(const char *appName, const char *prefix, const char *dbname, + PRBool openflags, int *version) { + DB *db = NULL; + + if (appName) { + db = rdbopen( appName, prefix, "key", openflags, NULL); + } else { + db = dbopen( dbname, openflags, 0600, DB_HASH, 0 ); + } + + /* check for correct version number */ + if (db != NULL) { + *version = nsslowkey_version(db); + if (*version != NSSLOWKEY_DB_FILE_VERSION ) { + /* bogus version number record, reset the database */ + (* db->close)( db ); + db = NULL; + } + } + return db; +} + NSSLOWKEYDBHandle * nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, NSSLOWKEYDBNameFunc namecb, void *cbarg) @@ -953,25 +982,14 @@ nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : (prefix ? PORT_Strdup(prefix) : NULL); handle->readOnly = readOnly; - - if (appName) { - handle->db = rdbopen( appName, prefix, "key", openflags); - } else { - handle->db = dbopen( dbname, openflags, 0600, DB_HASH, 0 ); - } - /* check for correct version number */ - if (handle->db != NULL) { - handle->version = nsslowkey_version(handle->db); - if (handle->version == 255) { - goto loser; - } - if (handle->version != NSSLOWKEY_DB_FILE_VERSION ) { - /* bogus version number record, reset the database */ - (* handle->db->close)( handle->db ); - handle->db = NULL; - } + + handle->db = openOldDB(appName, prefix, dbname, openflags, + &handle->version); + if (handle->version == 255) { + goto loser; } + /* if first open fails, try to create a new DB */ if ( handle->db == NULL ) { @@ -980,7 +998,16 @@ nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, } rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg); - if (rv != SECSuccess) { + /* two processes started to initialize the database at the same time. + * The multiprocess code blocked the second one, then had it retry to + * see if it can just open the database normally */ + if (rv == SECWouldBlock) { + handle->db = openOldDB(appName,prefix,dbname, + openflags, &handle->version); + if (handle->db == NULL) { + goto loser; + } + } else if (rv != SECSuccess) { goto loser; } @@ -2453,7 +2480,8 @@ nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) (* handle->db->close)(handle->db); if (handle->appname) { - handle->db=rdbopen(handle->appname, handle->dbname, "key", NO_CREATE); + handle->db= + rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL); } else { handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 ); } diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn index 2d43a9db4..b362e31d0 100644 --- a/security/nss/lib/softoken/manifest.mn +++ b/security/nss/lib/softoken/manifest.mn @@ -40,7 +40,7 @@ LIBRARY_NAME = softokn LIBRARY_VERSION = 3 MAPFILE = $(OBJDIR)/softokn.def -DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" +DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" EXPORTS = \ diff --git a/security/nss/lib/softoken/pcertdb.c b/security/nss/lib/softoken/pcertdb.c index 496c50520..a4f947b75 100644 --- a/security/nss/lib/softoken/pcertdb.c +++ b/security/nss/lib/softoken/pcertdb.c @@ -3748,20 +3748,22 @@ openNewCertDB(const char *appName, const char *prefix, const char *certdbname, certDBEntryVersion *versionEntry = NULL; DB *updatedb = NULL; char *tmpname; + int status = RDB_FAIL; if (appName) { - handle->permCertDB=rdbopen( appName, prefix, "cert", NO_CREATE); + handle->permCertDB=rdbopen( appName, prefix, "cert", NO_CREATE, &status); } else { handle->permCertDB=dbopen(certdbname, NO_CREATE, 0600, DB_HASH, 0); } /* if create fails then we lose */ if ( handle->permCertDB == 0 ) { - return SECFailure; + return status == RDB_RETRY ? SECWouldBlock : SECFailure; } rv = db_BeginTransaction(handle->permCertDB); if (rv != SECSuccess) { + db_InitComplete(handle->permCertDB); return SECFailure; } @@ -3773,6 +3775,7 @@ openNewCertDB(const char *appName, const char *prefix, const char *certdbname, db_Copy(handle->permCertDB,updatedb); (*updatedb->close)(updatedb); db_FinishTransaction(handle->permCertDB,PR_FALSE); + db_InitComplete(handle->permCertDB); return(SECSuccess); } } @@ -3829,9 +3832,26 @@ openNewCertDB(const char *appName, const char *prefix, const char *certdbname, loser: db_FinishTransaction(handle->permCertDB,rv != SECSuccess); + db_InitComplete(handle->permCertDB); return rv; } +static int +nsslowcert_GetVersionNumber(NSSLOWCERTCertDBHandle *handle) +{ + certDBEntryVersion *versionEntry = NULL; + int version = 0; + + versionEntry = ReadDBVersionEntry(handle); + if ( versionEntry == NULL ) { + return 0; + } + version = versionEntry->common.version; + DestroyDBEntry((certDBEntry *)versionEntry); + return version; +} + + /* * Open the certificate database and index databases. Create them if * they are not there or bad. @@ -3845,6 +3865,7 @@ nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, int openflags; char *certdbname; certDBEntryVersion *versionEntry = NULL; + int version; certdbname = (* namecb)(cbarg, CERT_DB_FILE_VERSION); if ( certdbname == NULL ) { @@ -3857,27 +3878,16 @@ nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, * first open the permanent file based database. */ if (appName) { - handle->permCertDB = rdbopen( appName, prefix, "cert", openflags); + handle->permCertDB = rdbopen( appName, prefix, "cert", openflags, NULL); } else { handle->permCertDB = dbopen( certdbname, openflags, 0600, DB_HASH, 0 ); } /* check for correct version number */ if ( handle->permCertDB ) { - versionEntry = ReadDBVersionEntry(handle); - - if ( versionEntry == NULL ) { - /* no version number */ - certdb_Close(handle->permCertDB); - handle->permCertDB = 0; - } else if ( versionEntry->common.version != CERT_DB_FILE_VERSION ) { - /* wrong version number, can't update in place */ - DestroyDBEntry((certDBEntry *)versionEntry); - PORT_Free(certdbname); - return(SECFailure); - } else { - DestroyDBEntry((certDBEntry *)versionEntry); - versionEntry = NULL; + version = nsslowcert_GetVersionNumber(handle); + if (version != CERT_DB_FILE_VERSION ) { + goto loser; } } @@ -3890,7 +3900,20 @@ nsslowcert_OpenPermCertDB(NSSLOWCERTCertDBHandle *handle, PRBool readOnly, } rv = openNewCertDB(appName,prefix,certdbname,handle,namecb,cbarg); - if (rv != SECSuccess) { + if (rv == SECWouldBlock) { + /* only the rdb version can fail with wouldblock */ + handle->permCertDB = + rdbopen( appName, prefix, "cert", openflags, NULL); + + /* check for correct version number */ + if ( !handle->permCertDB ) { + goto loser; + } + version = nsslowcert_GetVersionNumber(handle); + if (version != CERT_DB_FILE_VERSION ) { + goto loser; + } + } else if (rv != SECSuccess) { goto loser; } diff --git a/security/nss/lib/softoken/pk11db.c b/security/nss/lib/softoken/pk11db.c index 69b34dfa4..6f6583c80 100644 --- a/security/nss/lib/softoken/pk11db.c +++ b/security/nss/lib/softoken/pk11db.c @@ -273,7 +273,10 @@ secmod_getSecmodName(char *param, char **appName, char **filename,PRBool *rw) if (pk11_argHasFlag("flags","readOnly",save_params) || pk11_argHasFlag("flags","noModDB",save_params)) *rw = PR_FALSE; - if (!secmodName || *secmodName == '\0') secmodName = PORT_Strdup(SECMOD_DB); + if (!secmodName || *secmodName == '\0') { + if (secmodName) PORT_Free(secmodName); + secmodName = PORT_Strdup(SECMOD_DB); + } *filename = secmodName; lconfigdir = pk11_EvaluateConfigDir(configdir, appName); @@ -649,18 +652,24 @@ secmod_OpenDB(const char *appName, const char *filename, const char *dbName, if (appName) { char *secname = PORT_Strdup(filename); int len = strlen(secname); + int status = RDB_FAIL; if (len >= 3 && PORT_Strcmp(&secname[len-3],".db") == 0) { secname[len-3] = 0; } - pkcs11db=rdbopen(appName, "", secname, readOnly ? NO_RDONLY:NO_CREATE); + pkcs11db= + rdbopen(appName, "", secname, readOnly ? NO_RDONLY:NO_RDWR, NULL); if (update && !pkcs11db) { DB *updatedb; - pkcs11db = rdbopen(appName, "", secname, NO_CREATE); + pkcs11db = rdbopen(appName, "", secname, NO_CREATE, &status); if (!pkcs11db) { + if (status == RDB_RETRY) { + pkcs11db= rdbopen(appName, "", secname, + readOnly ? NO_RDONLY:NO_RDWR, NULL); + } PORT_Free(secname); - return NULL; + return pkcs11db; } updatedb = dbopen(dbName, NO_RDONLY, 0600, DB_HASH, 0); if (updatedb) { |