From a46d2916d1c48d176710bee9338204f59e3cc583 Mon Sep 17 00:00:00 2001 From: Robert Relyea Date: Wed, 26 Oct 2016 17:44:33 -0700 Subject: Bug 1312141 - SECMOD_OpenUserDB will allow multiple opens of the same database. r=mt --- lib/pk11wrap/pk11pars.c | 126 +++++++++++++++++++++++++++++++++++++++++++++--- lib/pk11wrap/pk11util.c | 31 ++++++++++++ lib/pk11wrap/secmodi.h | 4 +- 3 files changed, 152 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c index 8dd07e7e5..4c36a312a 100644 --- a/lib/pk11wrap/pk11pars.c +++ b/lib/pk11wrap/pk11pars.c @@ -17,6 +17,7 @@ #include "secerr.h" #include "nss.h" #include "utilpars.h" +#include "pk11pub.h" /* create a new module */ static SECMODModule * @@ -1114,11 +1115,41 @@ secmod_matchPrefix(char *prefix1, char *prefix2) return PR_FALSE; } +/* do two config paramters match? Not all callers are compariing + * SECMODConfigLists directly, so this function breaks them out to their + * components. */ +static PRBool +secmod_matchConfig(char *configDir1, char *configDir2, + char *certPrefix1, char *certPrefix2, + char *keyPrefix1, char *keyPrefix2, + PRBool isReadOnly1, PRBool isReadOnly2) +{ + if (strcmp(configDir1,configDir2) != 0) { + return PR_FALSE; + } + if (!secmod_matchPrefix(certPrefix1, certPrefix2)) { + return PR_FALSE; + } + if (!secmod_matchPrefix(keyPrefix1, keyPrefix2)) { + return PR_FALSE; + } + /* these last test -- if we just need the DB open read only, + * than any open will suffice, but if we requested it read/write + * and it's only open read only, we need to open it again */ + if (isReadOnly1) { + return PR_TRUE; + } + if (isReadOnly2) { /* isReadonly1 == PR_FALSE */ + return PR_FALSE; + } + return PR_FALSE; +} + /* * return true if we are requesting a database that is already openned. */ PRBool -secmod_MatchConfigList(char *spec, SECMODConfigList *conflist, int count) +secmod_MatchConfigList(const char *spec, SECMODConfigList *conflist, int count) { char *config; char *certPrefix; @@ -1142,13 +1173,10 @@ secmod_MatchConfigList(char *spec, SECMODConfigList *conflist, int count) isReadOnly = 1; } for (i=0; i < count; i++) { - if ((strcmp(config,conflist[i].config) == 0) && - secmod_matchPrefix(certPrefix, conflist[i].certPrefix) && - secmod_matchPrefix(keyPrefix, conflist[i].keyPrefix) && - /* this last test -- if we just need the DB open read only, - * than any open will suffice, but if we requested it read/write - * and it's only open read only, we need to open it again */ - (isReadOnly || !conflist[i].isReadOnly)) { + if ( secmod_matchConfig(config,conflist[i].config,certPrefix, + conflist[i].certPrefix, keyPrefix, + conflist[i].keyPrefix, isReadOnly, + conflist[i].isReadOnly) ) { ret = PR_TRUE; goto done; } @@ -1162,6 +1190,88 @@ done: return ret; } +/* + * Find the slot id from the module spec. If the slot is the database slot, we + * can get the slot id from the default database slot. + */ +CK_SLOT_ID +secmod_GetSlotIDFromModuleSpec(const char *moduleSpec, SECMODModule *module) +{ + char *tmp_spec = NULL;; + char **children, **thisChild; + CK_SLOT_ID *ids, *thisID, slotID = -1; + char *inConfig = NULL, *thisConfig = NULL; + char *inCertPrefix, *thisCertPrefix; + char *inKeyPrefix, *thisKeyPrefix; + PRBool inReadOnly,thisReadOnly; + + inConfig = secmod_getConfigDir(moduleSpec,&inCertPrefix, &inKeyPrefix, + &inReadOnly); + if (!inConfig) { + goto done; + } + + if (secmod_configIsDBM(inConfig)) { + inReadOnly = 1; + } + + tmp_spec = secmod_ParseModuleSpecForTokens(PR_TRUE, module->isFIPS, + module->libraryParams, &children, &ids); + if (tmp_spec == NULL) { + goto done; + } + + /* first check to see if the parent is the database */ + thisConfig = secmod_getConfigDir(tmp_spec,&thisCertPrefix, &thisKeyPrefix, + &thisReadOnly); + if (secmod_matchConfig(inConfig,thisConfig,inCertPrefix,thisCertPrefix, + inKeyPrefix, thisKeyPrefix, inReadOnly, thisReadOnly)) { + /* yup it's the default key slot, get the id for it */ + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + if (slot) { + slotID = slot->slotID; + PK11_FreeSlot(slot); + } + goto done; + } + + /* find id of the token */ + for (thisChild=children, thisID=ids; thisChild && *thisChild; thisChild++, + thisID++) { + thisConfig = secmod_getConfigDir(*thisChild, &thisCertPrefix, + &thisKeyPrefix, &thisReadOnly); + if (thisConfig == NULL) { + continue; + } + if (secmod_matchConfig(inConfig,thisConfig,inCertPrefix,thisCertPrefix, + inKeyPrefix, thisKeyPrefix, inReadOnly, thisReadOnly)) { + slotID = *thisID; + break; + } + PORT_Free(thisConfig); + PORT_Free(thisCertPrefix); + PORT_Free(thisKeyPrefix); + thisConfig = NULL; + } + +done: + if (inConfig) { + PORT_Free(inConfig); + PORT_Free(inCertPrefix); + PORT_Free(inKeyPrefix); + } + if (thisConfig) { + PORT_Free(thisConfig); + PORT_Free(thisCertPrefix); + PORT_Free(thisKeyPrefix); + } + if (tmp_spec) { + secmod_FreeChildren(children, ids); + PORT_Free(tmp_spec); + } + return slotID; +} + void secmod_FreeConfigList(SECMODConfigList *conflist, int count) { diff --git a/lib/pk11wrap/pk11util.c b/lib/pk11wrap/pk11util.c index 712f267f1..b174363f1 100644 --- a/lib/pk11wrap/pk11util.c +++ b/lib/pk11wrap/pk11util.c @@ -1410,6 +1410,20 @@ SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec) return slot; } +/* + * given a module spec, find the slot in the module for it. + */ +PK11SlotInfo * +secmod_FindSlotFromModuleSpec(const char *moduleSpec, SECMODModule *module) +{ + CK_SLOT_ID slot_id = secmod_GetSlotIDFromModuleSpec(moduleSpec,module); + if (slot_id == -1) { + return NULL; + } + + return SECMOD_FindSlotByID(module, slot_id); +} + /* * Open a new database using the softoken. The caller is responsible for making * sure the module spec is correct and usable. The caller should ask for one @@ -1463,6 +1477,8 @@ PK11SlotInfo * SECMOD_OpenUserDB(const char *moduleSpec) { SECMODModule *mod; + SECMODConfigList *conflist = NULL; + int count = 0; if (moduleSpec == NULL) { return NULL; @@ -1476,6 +1492,21 @@ SECMOD_OpenUserDB(const char *moduleSpec) PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return NULL; } + + /* make sure we don't open the same database twice. We only understand + * the moduleSpec for internal databases well enough to do this, so only + * do this in OpenUserDB */ + conflist = secmod_GetConfigList(mod->isFIPS, mod->libraryParams, &count); + if (conflist) { + PK11SlotInfo *slot = NULL; + if (secmod_MatchConfigList(moduleSpec, conflist, count)) { + slot = secmod_FindSlotFromModuleSpec(moduleSpec, mod); + } + secmod_FreeConfigList(conflist,count); + if (slot) { + return slot; + } + } return SECMOD_OpenNewSlot(mod, moduleSpec); } diff --git a/lib/pk11wrap/secmodi.h b/lib/pk11wrap/secmodi.h index 5bc49b438..4f85a491c 100644 --- a/lib/pk11wrap/secmodi.h +++ b/lib/pk11wrap/secmodi.h @@ -65,8 +65,10 @@ typedef struct SECMODConfigListStr SECMODConfigList; /* collect all the databases in a given spec */ SECMODConfigList *secmod_GetConfigList(PRBool isFIPS, char *spec, int *count); /* see is a spec matches a database on the list */ -PRBool secmod_MatchConfigList(char *spec, +PRBool secmod_MatchConfigList(const char *spec, SECMODConfigList *conflist, int count); +/* returns the slot id from a module and modulespec */ +CK_SLOT_ID secmod_GetSlotIDFromModuleSpec(const char *moduleSpec, SECMODModule *module); /* free our list of databases */ void secmod_FreeConfigList(SECMODConfigList *conflist, int count); -- cgit v1.2.1