summaryrefslogtreecommitdiff
path: root/security/nss/lib/softoken/pk11db.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/softoken/pk11db.c')
-rw-r--r--security/nss/lib/softoken/pk11db.c883
1 files changed, 883 insertions, 0 deletions
diff --git a/security/nss/lib/softoken/pk11db.c b/security/nss/lib/softoken/pk11db.c
new file mode 100644
index 000000000..5f9d35524
--- /dev/null
+++ b/security/nss/lib/softoken/pk11db.c
@@ -0,0 +1,883 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+/*
+ * The following code handles the storage of PKCS 11 modules used by the
+ * NSS. This file is written to abstract away how the modules are
+ * stored so we can deside that later.
+ */
+
+#include "pk11pars.h"
+#include "pkcs11i.h"
+#include "mcom_db.h"
+#include "cdbhdl.h"
+
+#define FREE_CLEAR(p) if (p) { PORT_Free(p); p = NULL; }
+
+static void
+secmod_parseTokenFlags(char *tmp, pk11_token_parameters *parsed) {
+ parsed->readOnly = pk11_argHasFlag("flags","readOnly",tmp);
+ parsed->noCertDB = pk11_argHasFlag("flags","noCertDB",tmp);
+ parsed->noKeyDB = pk11_argHasFlag("flags","noKeyDB",tmp);
+ parsed->forceOpen = pk11_argHasFlag("flags","forceOpen",tmp);
+ parsed->pwRequired = pk11_argHasFlag("flags","passwordRequired",tmp);
+ parsed->optimizeSpace = pk11_argHasFlag("flags","optimizeSpace",tmp);
+ return;
+}
+
+static void
+secmod_parseFlags(char *tmp, pk11_parameters *parsed) {
+ parsed->noModDB = pk11_argHasFlag("flags","noModDB",tmp);
+ parsed->readOnly = pk11_argHasFlag("flags","readOnly",tmp);
+ /* keep legacy interface working */
+ parsed->noCertDB = pk11_argHasFlag("flags","noCertDB",tmp);
+ parsed->forceOpen = pk11_argHasFlag("flags","forceOpen",tmp);
+ parsed->pwRequired = pk11_argHasFlag("flags","passwordRequired",tmp);
+ parsed->optimizeSpace = pk11_argHasFlag("flags","optimizeSpace",tmp);
+ return;
+}
+
+CK_RV
+secmod_parseTokenParameters(char *param, pk11_token_parameters *parsed)
+{
+ int next;
+ char *tmp;
+ char *index;
+ index = pk11_argStrip(param);
+
+ while (*index) {
+ PK11_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->certPrefix,"certPrefix=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->keyPrefix,"keyPrefix=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->tokdes,"tokenDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->slotdes,"slotDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,tmp,"minPWLen=",
+ if(tmp) { parsed->minPW=atoi(tmp); PORT_Free(tmp); })
+ PK11_HANDLE_STRING_ARG(index,tmp,"flags=",
+ if(tmp) { secmod_parseTokenFlags(param,parsed); PORT_Free(tmp); })
+ PK11_HANDLE_FINAL_ARG(index)
+ }
+ return CKR_OK;
+}
+
+static void
+secmod_parseTokens(char *tokenParams, pk11_parameters *parsed)
+{
+ char *tokenIndex;
+ pk11_token_parameters *tokens = NULL;
+ int i=0,count = 0,next;
+
+ if ((tokenParams == NULL) || (*tokenParams == 0)) return;
+
+ /* first count the number of slots */
+ for (tokenIndex = pk11_argStrip(tokenParams); *tokenIndex;
+ tokenIndex = pk11_argStrip(pk11_argSkipParameter(tokenIndex))) {
+ count++;
+ }
+
+ /* get the data structures */
+ tokens = (pk11_token_parameters *)
+ PORT_ZAlloc(count*sizeof(pk11_token_parameters));
+ if (tokens == NULL) return;
+
+ for (tokenIndex = pk11_argStrip(tokenParams), i = 0;
+ *tokenIndex && i < count ; i++ ) {
+ char *name;
+ name = pk11_argGetName(tokenIndex,&next);
+ tokenIndex += next;
+
+ tokens[i].slotID = pk11_argDecodeNumber(name);
+ tokens[i].readOnly = PR_TRUE;
+ tokens[i].noCertDB = PR_TRUE;
+ tokens[i].noKeyDB = PR_TRUE;
+ if (!pk11_argIsBlank(*tokenIndex)) {
+ char *args = pk11_argFetchValue(tokenIndex,&next);
+ tokenIndex += next;
+ if (args) {
+ secmod_parseTokenParameters(args,&tokens[i]);
+ PORT_Free(args);
+ }
+ }
+ if (name) PORT_Free(name);
+ tokenIndex = pk11_argStrip(tokenIndex);
+ }
+ parsed->token_count = i;
+ parsed->tokens = tokens;
+ return;
+}
+
+CK_RV
+secmod_parseParameters(char *param, pk11_parameters *parsed, PRBool isFIPS)
+{
+ int next;
+ char *tmp;
+ char *index;
+ char *certPrefix = NULL, *keyPrefix = NULL;
+ char *tokdes = NULL, *ptokdes = NULL;
+ char *slotdes = NULL, *pslotdes = NULL;
+ char *fslotdes = NULL, *fpslotdes = NULL;
+ char *minPW = NULL;
+ index = pk11_argStrip(param);
+
+ PORT_Memset(parsed, 0, sizeof(pk11_parameters));
+
+ while (*index) {
+ PK11_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->secmodName,"secmod=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->man,"manufacturerID=",;)
+ PK11_HANDLE_STRING_ARG(index,parsed->libdes,"libraryDescription=",;)
+ /* constructed values, used so legacy interfaces still work */
+ PK11_HANDLE_STRING_ARG(index,certPrefix,"certPrefix=",;)
+ PK11_HANDLE_STRING_ARG(index,keyPrefix,"keyPrefix=",;)
+ PK11_HANDLE_STRING_ARG(index,tokdes,"cryptoTokenDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,ptokdes,"dbTokenDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,slotdes,"cryptoSlotDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,pslotdes,"dbSlotDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,fslotdes,"FIPSSlotDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,minPW,"FIPSTokenDescription=",;)
+ PK11_HANDLE_STRING_ARG(index,tmp,"minPWLen=",;)
+
+ PK11_HANDLE_STRING_ARG(index,tmp,"flags=",
+ if(tmp) { secmod_parseFlags(param,parsed); PORT_Free(tmp); })
+ PK11_HANDLE_STRING_ARG(index,tmp,"tokens=",
+ if(tmp) { secmod_parseTokens(tmp,parsed); PORT_Free(tmp); })
+ PK11_HANDLE_FINAL_ARG(index)
+ }
+ if (parsed->tokens == NULL) {
+ int count = isFIPS ? 1 : 2;
+ int index = count-1;
+ pk11_token_parameters *tokens = NULL;
+
+ tokens = (pk11_token_parameters *)
+ PORT_ZAlloc(count*sizeof(pk11_token_parameters));
+ if (tokens == NULL) {
+ goto loser;
+ }
+ parsed->tokens = tokens;
+ parsed->token_count = count;
+ tokens[index].slotID = isFIPS ? FIPS_SLOT_ID : PRIVATE_KEY_SLOT_ID;
+ tokens[index].certPrefix = certPrefix;
+ tokens[index].keyPrefix = keyPrefix;
+ tokens[index].minPW = minPW ? atoi(minPW) : 0;
+ tokens[index].readOnly = parsed->readOnly;
+ tokens[index].noCertDB = parsed->noCertDB;
+ tokens[index].noKeyDB = parsed->noCertDB;
+ tokens[index].forceOpen = parsed->forceOpen;
+ tokens[index].pwRequired = parsed->pwRequired;
+ tokens[index].optimizeSpace = parsed->optimizeSpace;
+ tokens[0].optimizeSpace = parsed->optimizeSpace;
+ certPrefix = NULL;
+ keyPrefix = NULL;
+ if (isFIPS) {
+ tokens[index].tokdes = fslotdes;
+ tokens[index].slotdes = fpslotdes;
+ fslotdes = NULL;
+ fpslotdes = NULL;
+ } else {
+ tokens[index].tokdes = ptokdes;
+ tokens[index].slotdes = pslotdes;
+ tokens[0].slotID = NETSCAPE_SLOT_ID;
+ tokens[0].tokdes = tokdes;
+ tokens[0].slotdes = slotdes;
+ tokens[0].noCertDB = PR_TRUE;
+ tokens[0].noKeyDB = PR_TRUE;
+ ptokdes = NULL;
+ pslotdes = NULL;
+ tokdes = NULL;
+ slotdes = NULL;
+ }
+ }
+
+loser:
+ FREE_CLEAR(certPrefix);
+ FREE_CLEAR(keyPrefix);
+ FREE_CLEAR(tokdes);
+ FREE_CLEAR(ptokdes);
+ FREE_CLEAR(slotdes);
+ FREE_CLEAR(pslotdes);
+ FREE_CLEAR(fslotdes);
+ FREE_CLEAR(fpslotdes);
+ FREE_CLEAR(minPW);
+ return CKR_OK;
+}
+
+void
+secmod_freeParams(pk11_parameters *params)
+{
+ int i;
+
+ for (i=0; i < params->token_count; i++) {
+ FREE_CLEAR(params->tokens[i].configdir);
+ FREE_CLEAR(params->tokens[i].certPrefix);
+ FREE_CLEAR(params->tokens[i].keyPrefix);
+ FREE_CLEAR(params->tokens[i].tokdes);
+ FREE_CLEAR(params->tokens[i].slotdes);
+ }
+
+ FREE_CLEAR(params->configdir);
+ FREE_CLEAR(params->secmodName);
+ FREE_CLEAR(params->man);
+ FREE_CLEAR(params->libdes);
+ FREE_CLEAR(params->tokens);
+}
+
+
+char *
+secmod_getSecmodName(char *param, char **appName, char **filename,PRBool *rw)
+{
+ int next;
+ char *configdir = NULL;
+ char *secmodName = NULL;
+ char *value = NULL;
+ char *save_params = param;
+ const char *lconfigdir;
+ param = pk11_argStrip(param);
+
+
+ while (*param) {
+ PK11_HANDLE_STRING_ARG(param,configdir,"configDir=",;)
+ PK11_HANDLE_STRING_ARG(param,secmodName,"secmod=",;)
+ PK11_HANDLE_FINAL_ARG(param)
+ }
+
+ *rw = PR_TRUE;
+ 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);
+ *filename = secmodName;
+
+ lconfigdir = pk11_EvaluateConfigDir(configdir, appName);
+
+ if (lconfigdir) {
+ value = PR_smprintf("%s" PATH_SEPARATOR "%s",lconfigdir,secmodName);
+ } else {
+ value = PR_smprintf("%s",secmodName);
+ }
+ if (configdir) PORT_Free(configdir);
+ return value;
+}
+
+/* Construct a database key for a given module */
+static SECStatus secmod_MakeKey(DBT *key, char * module) {
+ int len = 0;
+ char *commonName;
+
+ commonName = pk11_argGetParamValue("name",module);
+ if (commonName == NULL) {
+ commonName = pk11_argGetParamValue("library",module);
+ }
+ if (commonName == NULL) return SECFailure;
+ len = PORT_Strlen(commonName);
+ key->data = commonName;
+ key->size = len;
+ return SECSuccess;
+}
+
+/* free out constructed database key */
+static void
+secmod_FreeKey(DBT *key)
+{
+ if (key->data) {
+ PORT_Free(key->data);
+ }
+ key->data = NULL;
+ key->size = 0;
+}
+
+typedef struct secmodDataStr secmodData;
+typedef struct secmodSlotDataStr secmodSlotData;
+struct secmodDataStr {
+ unsigned char major;
+ unsigned char minor;
+ unsigned char nameStart[2];
+ unsigned char slotOffset[2];
+ unsigned char internal;
+ unsigned char fips;
+ unsigned char ssl[8];
+ unsigned char trustOrder[4];
+ unsigned char cipherOrder[4];
+ unsigned char reserved1;
+ unsigned char isModuleDB;
+ unsigned char isModuleDBOnly;
+ unsigned char isCritical;
+ unsigned char reserved[4];
+ unsigned char names[6]; /* enough space for the length fields */
+};
+
+struct secmodSlotDataStr {
+ unsigned char slotID[4];
+ unsigned char defaultFlags[4];
+ unsigned char timeout[4];
+ unsigned char askpw;
+ unsigned char hasRootCerts;
+ unsigned char reserved[18]; /* this makes it a round 32 bytes */
+};
+
+#define SECMOD_DB_VERSION_MAJOR 0
+#define SECMOD_DB_VERSION_MINOR 6
+#define SECMOD_DB_EXT1_VERSION_MAJOR 0
+#define SECMOD_DB_EXT1_VERSION_MINOR 6
+#define SECMOD_DB_NOUI_VERSION_MAJOR 0
+#define SECMOD_DB_NOUI_VERSION_MINOR 4
+
+#define SECMOD_PUTSHORT(dest,src) \
+ (dest)[1] = (unsigned char) ((src)&0xff); \
+ (dest)[0] = (unsigned char) (((src) >> 8) & 0xff);
+#define SECMOD_PUTLONG(dest,src) \
+ (dest)[3] = (unsigned char) ((src)&0xff); \
+ (dest)[2] = (unsigned char) (((src) >> 8) & 0xff); \
+ (dest)[1] = (unsigned char) (((src) >> 16) & 0xff); \
+ (dest)[0] = (unsigned char) (((src) >> 24) & 0xff);
+#define SECMOD_GETSHORT(src) \
+ ((unsigned short) (((src)[0] << 8) | (src)[1]))
+#define SECMOD_GETLONG(src) \
+ ((unsigned long) (( (unsigned long) (src)[0] << 24) | \
+ ( (unsigned long) (src)[1] << 16) | \
+ ( (unsigned long) (src)[2] << 8) | \
+ (unsigned long) (src)[3]))
+
+/*
+ * build a data base entry from a module
+ */
+static SECStatus
+secmod_EncodeData(DBT *data, char * module)
+{
+ secmodData *encoded = NULL;
+ secmodSlotData *slot;
+ unsigned char *dataPtr;
+ unsigned short len, len2 = 0, len3 = 0;
+ int count = 0;
+ unsigned short offset;
+ int dataLen, i;
+ unsigned long order;
+ unsigned long ssl[2];
+ char *commonName = NULL , *dllName = NULL, *param = NULL, *nss = NULL;
+ char *slotParams, *ciphers;
+ PK11PreSlotInfo *slotInfo = NULL;
+ SECStatus rv = SECFailure;
+
+ rv = pk11_argParseModuleSpec(module,&dllName,&commonName,&param,&nss);
+ if (rv != SECSuccess) return rv;
+ rv = SECFailure;
+
+ if (commonName == NULL) {
+ /* set error */
+ goto loser;
+ }
+
+ len = PORT_Strlen(commonName);
+ if (dllName) {
+ len2 = PORT_Strlen(dllName);
+ }
+ if (param) {
+ len3 = PORT_Strlen(param);
+ }
+
+ slotParams = pk11_argGetParamValue("slotParams",nss);
+ slotInfo = pk11_argParseSlotInfo(NULL,slotParams,&count);
+ if (slotParams) PORT_Free(slotParams);
+
+ if (count && slotInfo == NULL) {
+ /* set error */
+ goto loser;
+ }
+
+ dataLen = sizeof(secmodData) + len + len2 + len3 + sizeof(unsigned short) +
+ count*sizeof(secmodSlotData);
+
+ data->data = (unsigned char *) PORT_ZAlloc(dataLen);
+ encoded = (secmodData *)data->data;
+ dataPtr = (unsigned char *) data->data;
+ data->size = dataLen;
+
+ if (encoded == NULL) {
+ /* set error */
+ goto loser;
+ }
+
+ encoded->major = SECMOD_DB_VERSION_MAJOR;
+ encoded->minor = SECMOD_DB_VERSION_MINOR;
+ encoded->internal = (unsigned char)
+ (pk11_argHasFlag("flags","internal",nss) ? 1 : 0);
+ encoded->fips = (unsigned char)
+ (pk11_argHasFlag("flags","FIPS",nss) ? 1 : 0);
+ encoded->isModuleDB = (unsigned char)
+ (pk11_argHasFlag("flags","isModuleDB",nss) ? 1 : 0);
+ encoded->isModuleDBOnly = (unsigned char)
+ (pk11_argHasFlag("flags","isModuleDBOnly",nss) ? 1 : 0);
+ encoded->isCritical = (unsigned char)
+ (pk11_argHasFlag("flags","critical",nss) ? 1 : 0);
+
+ order = pk11_argReadLong("trustOrder",nss, PK11_DEFAULT_TRUST_ORDER, NULL);
+ SECMOD_PUTLONG(encoded->trustOrder,order);
+ order = pk11_argReadLong("cipherOrder",nss,PK11_DEFAULT_CIPHER_ORDER,NULL);
+ SECMOD_PUTLONG(encoded->cipherOrder,order);
+
+
+ ciphers = pk11_argGetParamValue("ciphers",nss);
+ pk11_argSetNewCipherFlags(&ssl[0], ciphers);
+ SECMOD_PUTLONG(encoded->ssl,ssl[0]);
+ SECMOD_PUTLONG(&encoded->ssl[4],ssl[1]);
+
+ offset = (unsigned short) &(((secmodData *)0)->names[0]);
+ SECMOD_PUTSHORT(encoded->nameStart,offset);
+ offset = offset + len + len2 + len3 + 3*sizeof(unsigned short);
+ SECMOD_PUTSHORT(encoded->slotOffset,offset);
+
+
+ SECMOD_PUTSHORT(&dataPtr[offset],((unsigned short)count));
+ slot = (secmodSlotData *)(dataPtr+offset+sizeof(unsigned short));
+
+ offset = 0;
+ SECMOD_PUTSHORT(encoded->names,len);
+ offset += sizeof(unsigned short);
+ PORT_Memcpy(&encoded->names[offset],commonName,len);
+ offset += len;
+
+
+ SECMOD_PUTSHORT(&encoded->names[offset],len2);
+ offset += sizeof(unsigned short);
+ if (len2) PORT_Memcpy(&encoded->names[offset],dllName,len2);
+ offset += len2;
+
+ SECMOD_PUTSHORT(&encoded->names[offset],len3);
+ offset += sizeof(unsigned short);
+ if (len3) PORT_Memcpy(&encoded->names[offset],param,len3);
+ offset += len3;
+
+ if (count) {
+ for (i=0; i < count; i++) {
+ SECMOD_PUTLONG(slot[i].slotID, slotInfo[i].slotID);
+ SECMOD_PUTLONG(slot[i].defaultFlags,
+ slotInfo[i].defaultFlags);
+ SECMOD_PUTLONG(slot[i].timeout,slotInfo[i].timeout);
+ slot[i].askpw = slotInfo[i].askpw;
+ slot[i].hasRootCerts = slotInfo[i].hasRootCerts;
+ PORT_Memset(slot[i].reserved, 0, sizeof(slot[i].reserved));
+ }
+ }
+ rv = SECSuccess;
+
+loser:
+ if (commonName) PORT_Free(commonName);
+ if (dllName) PORT_Free(dllName);
+ if (param) PORT_Free(param);
+ if (slotInfo) PORT_Free(slotInfo);
+ return rv;
+
+}
+
+static void
+secmod_FreeData(DBT *data)
+{
+ if (data->data) {
+ PORT_Free(data->data);
+ }
+}
+
+/*
+ * build a module from the data base entry.
+ */
+static char *
+secmod_DecodeData(char *defParams, DBT *data, PRBool *retInternal)
+{
+ secmodData *encoded;
+ secmodSlotData *slots;
+ char *commonName = NULL,*dllName = NULL,*parameters = NULL;
+ unsigned char *names;
+ unsigned short len;
+ unsigned long slotCount;
+ unsigned short offset;
+ PRBool isOldVersion = PR_FALSE;
+ PRBool internal, isFIPS, isModuleDB=PR_FALSE, isModuleDBOnly=PR_FALSE;
+ PRBool extended=PR_FALSE;
+ PRBool hasRootCerts=PR_FALSE,hasRootTrust=PR_FALSE;
+ unsigned long trustOrder=PK11_DEFAULT_TRUST_ORDER,
+ cipherOrder=PK11_DEFAULT_CIPHER_ORDER;
+ unsigned long ssl0=0, ssl1=0;
+ char **slotStrings = NULL;
+ unsigned long slotID,defaultFlags,timeout;
+ char *nss,*moduleSpec;
+ int i;
+
+ PLArenaPool *arena;
+
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL) return NULL;
+
+ encoded = (secmodData *)data->data;
+ names = (unsigned char *)data->data;
+ offset = SECMOD_GETSHORT(encoded->slotOffset);
+ slots = (secmodSlotData *) (names + offset + 2);
+ slotCount = SECMOD_GETSHORT(names + offset);
+ names += SECMOD_GETSHORT(encoded->nameStart);
+
+ * retInternal = internal = (encoded->internal != 0) ? PR_TRUE: PR_FALSE;
+ isFIPS = (encoded->fips != 0) ? PR_TRUE: PR_FALSE;
+ len = SECMOD_GETSHORT(names);
+
+ if (internal && (encoded->major == SECMOD_DB_NOUI_VERSION_MAJOR) &&
+ (encoded->minor <= SECMOD_DB_NOUI_VERSION_MINOR)) {
+ isOldVersion = PR_TRUE;
+ }
+
+ if ((encoded->major == SECMOD_DB_EXT1_VERSION_MAJOR) &&
+ (encoded->minor >= SECMOD_DB_EXT1_VERSION_MINOR)) {
+ trustOrder = SECMOD_GETLONG(encoded->trustOrder);
+ cipherOrder = SECMOD_GETLONG(encoded->cipherOrder);
+ isModuleDB = (encoded->isModuleDB != 0) ? PR_TRUE: PR_FALSE;
+ isModuleDBOnly = (encoded->isModuleDBOnly != 0) ? PR_TRUE: PR_FALSE;
+ extended = PR_TRUE;
+ }
+
+ if (internal && !extended) {
+ trustOrder = 0;
+ cipherOrder = 100;
+ }
+
+ /* decode the common name */
+ commonName = (char*)PORT_ArenaAlloc(arena,len+1);
+ if (commonName == NULL) {
+ PORT_FreeArena(arena,PR_TRUE);
+ return NULL;
+ }
+ PORT_Memcpy(commonName,&names[2],len);
+ commonName[len] = 0;
+
+ /* decode the DLL name */
+ names += len+2;
+ len = SECMOD_GETSHORT(names);
+ if (len) {
+ dllName = (char*)PORT_ArenaAlloc(arena,len + 1);
+ if (dllName == NULL) {
+ PORT_FreeArena(arena,PR_TRUE);
+ return NULL;
+ }
+ PORT_Memcpy(dllName,&names[2],len);
+ dllName[len] = 0;
+ }
+ if (!internal && extended) {
+ names += len+2;
+ len = SECMOD_GETSHORT(names);
+ if (len) {
+ parameters = (char*)PORT_ArenaAlloc(arena,len + 1);
+ if (parameters == NULL) {
+ PORT_FreeArena(arena,PR_TRUE);
+ return NULL;
+ }
+ PORT_Memcpy(parameters,&names[2],len);
+ parameters[len] = 0;
+ }
+ }
+ if (internal) {
+ parameters = PORT_ArenaStrdup(arena,defParams);
+ }
+
+ /* decode SSL cipher enable flags */
+ ssl0 = SECMOD_GETLONG(encoded->ssl);
+ ssl1 = SECMOD_GETLONG(&encoded->ssl[4]);
+
+ /* slotCount; */
+ slotStrings = (char **)PORT_ArenaAlloc(arena, slotCount * sizeof(char *));
+ for (i=0; i < (int) slotCount; i++) {
+ slotID = SECMOD_GETLONG(slots[i].slotID);
+ defaultFlags = SECMOD_GETLONG(slots[i].defaultFlags);
+ if (isOldVersion && internal && (slotID != 2)) {
+ unsigned long internalFlags=
+ pk11_argSlotFlags("slotFlags",SECMOD_SLOT_FLAGS);
+ defaultFlags |= internalFlags;
+ }
+ timeout = SECMOD_GETLONG(slots[i].timeout);
+ hasRootCerts = slots[i].hasRootCerts;
+ if (hasRootCerts && !extended) {
+ trustOrder = 100;
+ }
+
+ slotStrings[i] = pk11_mkSlotString(slotID, defaultFlags, timeout,
+ (unsigned char)slots[i].askpw,
+ (unsigned char)hasRootCerts,
+ (unsigned char)hasRootTrust);
+ }
+
+ nss = pk11_mkNSS(slotStrings, slotCount, internal, isFIPS, isModuleDB,
+ isModuleDBOnly, internal, trustOrder, cipherOrder, ssl0, ssl1);
+ moduleSpec = pk11_mkNewModuleSpec(dllName,commonName,parameters,nss);
+ PR_smprintf_free(nss);
+ PORT_FreeArena(arena,PR_TRUE);
+
+ return (moduleSpec);
+}
+
+
+
+static DB *
+secmod_OpenDB(const char *appName, const char *filename, const char *dbName,
+ PRBool readOnly, PRBool update)
+{
+ DB *pkcs11db = NULL;
+
+
+ if (appName) {
+ char *secname = PORT_Strdup(filename);
+ int len = strlen(secname);
+
+ if (len >= 3 && PORT_Strcmp(&secname[len-3],".db") == 0) {
+ secname[len-3] = 0;
+ }
+ pkcs11db=rdbopen(appName, "", secname, readOnly ? NO_RDONLY:NO_CREATE);
+ if (update && !pkcs11db) {
+ DB *updatedb;
+
+ pkcs11db = rdbopen(appName, "", secname, NO_CREATE);
+ if (!pkcs11db) {
+ PORT_Free(secname);
+ return NULL;
+ }
+ updatedb = dbopen(dbName, NO_RDONLY, 0600, DB_HASH, 0);
+ if (updatedb) {
+ db_Copy(pkcs11db,updatedb);
+ (*updatedb->close)(updatedb);
+ } else {
+ (*pkcs11db->close)(pkcs11db);
+ PORT_Free(secname);
+ return NULL;
+ }
+ }
+ PORT_Free(secname);
+ return pkcs11db;
+ }
+
+ /* I'm sure we should do more checks here sometime... */
+ pkcs11db = dbopen(dbName, readOnly ? NO_RDONLY : NO_RDWR, 0600, DB_HASH, 0);
+
+ /* didn't exist? create it */
+ if (pkcs11db == NULL) {
+ if (readOnly)
+ return NULL;
+
+ pkcs11db = dbopen( dbName, NO_CREATE, 0600, DB_HASH, 0 );
+ if (pkcs11db)
+ (* pkcs11db->sync)(pkcs11db, 0);
+ }
+ return pkcs11db;
+}
+
+static void
+secmod_CloseDB(DB *pkcs11db)
+{
+ (*pkcs11db->close)(pkcs11db);
+}
+
+static char *
+secmod_addEscape(const char *string, char quote)
+{
+ char *newString = 0;
+ int escapes = 0, size = 0;
+ const char *src;
+ char *dest;
+
+ for (src=string; *src ; src++) {
+ if ((*src == quote) || (*src == '\\')) escapes++;
+ size++;
+ }
+
+ newString = PORT_ZAlloc(escapes+size+1);
+ if (newString == NULL) {
+ return NULL;
+ }
+
+ for (src=string, dest=newString; *src; src++,dest++) {
+ if ((*src == '\\') || (*src == quote)) {
+ *dest++ = '\\';
+ }
+ *dest = *src;
+ }
+
+ return newString;
+}
+
+#define SECMOD_STEP 10
+#define PK11_DEFAULT_INTERNAL_INIT "library= name=\"NSS Internal PKCS #11 Module\" parameters=\"%s\" NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={%s askpw=any timeout=30})\""
+/*
+ * Read all the existing modules in
+ */
+char **
+secmod_ReadPermDB(const char *appName, const char *filename,
+ const char *dbname, char *params, PRBool rw)
+{
+ DBT key,data;
+ int ret;
+ DB *pkcs11db = NULL;
+ char **moduleList = NULL;
+ int moduleCount = 1;
+ int useCount = SECMOD_STEP;
+
+ moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **));
+ if (moduleList == NULL) return NULL;
+
+ pkcs11db = secmod_OpenDB(appName,filename,dbname,PR_TRUE,rw);
+ if (pkcs11db == NULL) goto done;
+
+ /* read and parse the file or data base */
+ ret = (*pkcs11db->seq)(pkcs11db, &key, &data, R_FIRST);
+ if (ret) goto done;
+
+
+ do {
+ char *moduleString;
+ PRBool internal = PR_FALSE;
+ if ((moduleCount+1) >= useCount) {
+ useCount += SECMOD_STEP;
+ moduleList =
+ (char **)PORT_Realloc(moduleList,useCount*sizeof(char *));
+ if (moduleList == NULL) goto done;
+ PORT_Memset(&moduleList[moduleCount+1],0,
+ sizeof(char *)*SECMOD_STEP);
+ }
+ moduleString = secmod_DecodeData(params,&data,&internal);
+ if (internal) {
+ moduleList[0] = moduleString;
+ } else {
+ moduleList[moduleCount] = moduleString;
+ moduleCount++;
+ }
+ } while ( (*pkcs11db->seq)(pkcs11db, &key, &data, R_NEXT) == 0);
+
+done:
+ if (!moduleList[0]) {
+ char * newparams = secmod_addEscape(params,'"');
+ if (newparams) {
+ moduleList[0] = PR_smprintf(PK11_DEFAULT_INTERNAL_INIT,newparams,
+ SECMOD_SLOT_FLAGS);
+ PORT_Free(newparams);
+ }
+ }
+ /* deal with trust cert db here */
+
+ if (pkcs11db) {
+ secmod_CloseDB(pkcs11db);
+ } else {
+ secmod_AddPermDB(appName,filename,dbname,moduleList[0], rw) ;
+ }
+ return moduleList;
+}
+
+SECStatus
+secmod_ReleasePermDBData(const char *appName, const char *filename,
+ const char *dbname, char **moduleSpecList, PRBool rw)
+{
+ char **index;
+ for(index = moduleSpecList; *index; index++) {
+ PR_smprintf_free(*index);
+ }
+ PORT_Free(moduleSpecList);
+ return SECSuccess;
+}
+
+/*
+ * Delete a module from the Data Base
+ */
+SECStatus
+secmod_DeletePermDB(const char *appName, const char *filename,
+ const char *dbname, char *args, PRBool rw)
+{
+ DBT key;
+ SECStatus rv = SECFailure;
+ DB *pkcs11db = NULL;
+ int ret;
+
+ if (!rw) return SECFailure;
+
+ /* make sure we have a db handle */
+ pkcs11db = secmod_OpenDB(appName,filename,dbname,PR_FALSE,PR_FALSE);
+ if (pkcs11db == NULL) {
+ return SECFailure;
+ }
+
+ rv = secmod_MakeKey(&key,args);
+ if (rv != SECSuccess) goto done;
+ rv = SECFailure;
+ ret = (*pkcs11db->del)(pkcs11db, &key, 0);
+ secmod_FreeKey(&key);
+ if (ret != 0) goto done;
+
+
+ ret = (*pkcs11db->sync)(pkcs11db, 0);
+ if (ret == 0) rv = SECSuccess;
+
+done:
+ secmod_CloseDB(pkcs11db);
+ return rv;
+}
+
+/*
+ * Add a module to the Data base
+ */
+SECStatus
+secmod_AddPermDB(const char *appName, const char *filename,
+ const char *dbname, char *module, PRBool rw)
+{
+ DBT key,data;
+ SECStatus rv = SECFailure;
+ DB *pkcs11db = NULL;
+ int ret;
+
+
+ if (!rw) return SECFailure;
+
+ /* make sure we have a db handle */
+ pkcs11db = secmod_OpenDB(appName,filename,dbname,PR_FALSE,PR_FALSE);
+ if (pkcs11db == NULL) {
+ return SECFailure;
+ }
+
+ rv = secmod_MakeKey(&key,module);
+ if (rv != SECSuccess) goto done;
+ rv = secmod_EncodeData(&data,module);
+ if (rv != SECSuccess) {
+ secmod_FreeKey(&key);
+ goto done;
+ }
+ rv = SECFailure;
+ ret = (*pkcs11db->put)(pkcs11db, &key, &data, 0);
+ secmod_FreeKey(&key);
+ secmod_FreeData(&data);
+ if (ret != 0) goto done;
+
+ ret = (*pkcs11db->sync)(pkcs11db, 0);
+ if (ret == 0) rv = SECSuccess;
+
+done:
+ secmod_CloseDB(pkcs11db);
+ return rv;
+}