From 9142c946e92d018081c8088699c245efaf97df02 Mon Sep 17 00:00:00 2001 From: Elio Maldonado Date: Wed, 9 Sep 2009 21:49:24 +0000 Subject: [PATCH] Patches to enable the nss sysinit module --- newargs.patch | 159 ++++++ sysinit.patch | 1465 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1624 insertions(+) create mode 100644 newargs.patch create mode 100644 sysinit.patch diff --git a/newargs.patch b/newargs.patch new file mode 100644 index 0000000..6afaf6c --- /dev/null +++ b/newargs.patch @@ -0,0 +1,159 @@ +Index: mozilla/security/nss/lib/pk11wrap/pk11pars.c +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/pk11pars.c,v +retrieving revision 1.21 +diff -u -p -r1.21 pk11pars.c +--- ./mozilla/security/nss/lib/pk11wrap/pk11pars.c 12 Nov 2005 00:14:25 -0000 1.21 ++++ ./mozilla/security/nss/lib/pk11wrap/pk11pars.c 1 Sep 2009 21:55:18 -0000 +@@ -107,6 +107,41 @@ secmod_NewModule(void) + + } + ++/* private flags. */ ++/* The meaing of these flags is as follows: ++ * ++ * SECMOD_FLAG_IS_MODULE_DB - This is a module that accesses the database of ++ * other modules to load. Module DBs are loadable modules that tells ++ * NSS which PKCS #11 modules to load and when. These module DBs are ++ * chainable. That is, one module DB can load another one. NSS system init ++ * design takes advantage of this feature. In system NSS, a fixed system ++ * module DB loads the system defined libraries, then chains out to the ++ * traditional module DBs to load any system or user configured modules ++ * (like smart cards). This bit is the same as the already existing meaning ++ * of isModuleDB = PR_TRUE. None of the other flags should be set if this ++ * flag isn't on. ++ * ++ * SECMOD_FLAG_SKIP_FIRST - This flag tells NSS to skip the first ++ * PKCS #11 module presented by a module DB. This allows the OS to load a ++ * softoken from the system module, then ask the existing module DB code to ++ * load the other PKCS #11 modules in that module DB (skipping it's request ++ * to load softoken). This gives the system init finer control over the ++ * configuration of that softoken module. ++ * ++ * SECMOD_FLAG_DEFAULT_MODDB - This flag allows system init to mark a ++ * different module DB as the 'default' module DB (the one in which ++ * 'Add module' changes will go). Without this flag NSS takes the first ++ * module as the default Module DB, but in system NSS, that first module ++ * is the system module, which is likely read only (at least to the user). ++ * This allows system NSS to delegate those changes to the user's module DB, ++ * preserving the user's ability to load new PKCS #11 modules (which only ++ * affect him), from existing applications like Firefox. ++ */ ++#define SECMOD_FLAG_IS_MODULE_DB 0x01 /* must be set if any of the other flags ++ * are set */ ++#define SECMOD_FLAG_SKIP_FIRST 0x02 ++#define SECMOD_FLAG_DEFAULT_MODDB 0x04 ++ + /* + * for 3.4 we continue to use the old SECMODModule structure + */ +@@ -137,15 +172,33 @@ SECMOD_CreateModule(const char *library, + if (slotParams) PORT_Free(slotParams); + /* new field */ + mod->trustOrder = secmod_argReadLong("trustOrder",nssc, +- SECMOD_DEFAULT_TRUST_ORDER,NULL); ++ SECMOD_DEFAULT_TRUST_ORDER,NULL); + /* new field */ + mod->cipherOrder = secmod_argReadLong("cipherOrder",nssc, +- SECMOD_DEFAULT_CIPHER_ORDER,NULL); ++ SECMOD_DEFAULT_CIPHER_ORDER,NULL); + /* new field */ + mod->isModuleDB = secmod_argHasFlag("flags","moduleDB",nssc); + mod->moduleDBOnly = secmod_argHasFlag("flags","moduleDBOnly",nssc); + if (mod->moduleDBOnly) mod->isModuleDB = PR_TRUE; + ++ /* we need more bits, but we also want to preserve binary compatibility ++ * so we overload the isModuleDB PRBool with additional flags. ++ * These flags are only valid if mod->isModuleDB is already set. ++ * NOTE: this depends on the fact that PRBool is at least a char on ++ * all platforms. These flags are only valid if moduleDB is set, so ++ * code checking if (mod->isModuleDB) will continue to work correctly. */ ++ if (mod->isModuleDB) { ++ char flags = SECMOD_FLAG_IS_MODULE_DB; ++ if (secmod_argHasFlag("flags","skipFirst",nssc)) { ++ flags |= SECMOD_FLAG_SKIP_FIRST; ++ } ++ if (secmod_argHasFlag("flags","defaultModDB",nssc)) { ++ flags |= SECMOD_FLAG_DEFAULT_MODDB; ++ } ++ /* additional moduleDB flags could be added here in the future */ ++ mod->isModuleDB = (PRBool) flags; ++ } ++ + ciphers = secmod_argGetParamValue("ciphers",nssc); + secmod_argSetNewCipherFlags(&mod->ssl[0],ciphers); + if (ciphers) PORT_Free(ciphers); +@@ -155,6 +208,22 @@ SECMOD_CreateModule(const char *library, + return mod; + } + ++PRBool ++SECMOD_GetSkipFirstFlag(SECMODModule *mod) ++{ ++ char flags = (char) mod->isModuleDB; ++ ++ return (flags & SECMOD_FLAG_SKIP_FIRST) ? PR_TRUE : PR_FALSE; ++} ++ ++PRBool ++SECMOD_GetDefaultModDBFlag(SECMODModule *mod) ++{ ++ char flags = (char) mod->isModuleDB; ++ ++ return (flags & SECMOD_FLAG_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE; ++} ++ + static char * + secmod_mkModuleSpec(SECMODModule * module) + { +@@ -333,7 +402,12 @@ SECMOD_LoadModule(char *modulespec,SECMO + if (moduleSpecList) { + char **index; + +- for (index = moduleSpecList; *index; index++) { ++ index = moduleSpecList; ++ if (*index && SECMOD_GetSkipFirstFlag(module)) { ++ index++; ++ } ++ ++ for (; *index; index++) { + SECMODModule *child; + child = SECMOD_LoadModule(*index,module,PR_TRUE); + if (!child) break; +Index: mozilla/security/nss/lib/pk11wrap/pk11util.c +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/pk11util.c,v +retrieving revision 1.55 +diff -u -p -r1.55 pk11util.c +--- ./mozilla/security/nss/lib/pk11wrap/pk11util.c 30 Jul 2009 00:29:35 -0000 1.55 ++++ ./mozilla/security/nss/lib/pk11wrap/pk11util.c 1 Sep 2009 21:55:18 -0000 +@@ -179,7 +179,10 @@ SECMOD_AddModuleToList(SECMODModule *new + SECStatus + SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) + { +- if (defaultDBModule == NULL) { ++ if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) { ++ SECMOD_DestroyModule(defaultDBModule); ++ defaultDBModule = SECMOD_ReferenceModule(newModule); ++ } else if (defaultDBModule == NULL) { + defaultDBModule = SECMOD_ReferenceModule(newModule); + } + return secmod_AddModuleToList(&modulesDB,newModule); +Index: mozilla/security/nss/lib/pk11wrap/secmod.h +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/secmod.h,v +retrieving revision 1.26 +diff -u -p -r1.26 secmod.h +--- ./mozilla/security/nss/lib/pk11wrap/secmod.h 17 Dec 2008 06:09:16 -0000 1.26 ++++ ./mozilla/security/nss/lib/pk11wrap/secmod.h 1 Sep 2009 21:55:18 -0000 +@@ -151,6 +151,10 @@ extern PK11SlotInfo *SECMOD_FindSlot(SEC + /* of modType has been installed */ + PRBool SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ); + ++/* accessors */ ++PRBool SECMOD_GetSkipFirstFlag(SECMODModule *mod); ++PRBool SECMOD_GetDefaultModDBFlag(SECMODModule *mod); ++ + /* Functions used to convert between internal & public representation + * of Mechanism Flags and Cipher Enable Flags */ + extern unsigned long SECMOD_PubMechFlagstoInternal(unsigned long publicFlags); diff --git a/sysinit.patch b/sysinit.patch new file mode 100644 index 0000000..30beaf1 --- /dev/null +++ b/sysinit.patch @@ -0,0 +1,1465 @@ +Index: ./mozilla/security/nss/cmd/manifest.mn +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/cmd/manifest.mn,v +retrieving revision 1.27 +diff -u -p -r1.27 manifest.mn +--- ./mozilla/security/nss/cmd/manifest.mn 4 Sep 2008 22:15:21 -0000 1.27 ++++ ./mozilla/security/nss/cmd/manifest.mn 9 Sep 2009 03:40:50 -0000 +@@ -75,6 +75,7 @@ DIRS = lib \ + ssltap \ + strsclnt \ + symkeyutil \ ++ sysinit \ + tests \ + tstclnt \ + vfychain \ +Index: mozilla/security/nss/cmd/sysinit/Makefile +=================================================================== +RCS file: security/nss/cmd/sysinit/Makefile +diff -N security/nss/cmd/sysinit/Makefile +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./mozilla/security/nss/cmd/sysinit/Makefile 1 Sep 2009 22:47:51 -0000 +@@ -0,0 +1,80 @@ ++#! gmake ++# ++# ***** BEGIN LICENSE BLOCK ***** ++# Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++# ++# 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 the Initial Developer are Copyright (C) 1994-2000 ++# the Initial Developer. All Rights Reserved. ++# ++# Contributor(s): ++# ++# Alternatively, the contents of this file may be used under the terms of ++# either the GNU General Public License Version 2 or later (the "GPL"), or ++# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++# in which case the provisions of the GPL or the LGPL are applicable instead ++# of those above. If you wish to allow use of your version of this file only ++# under the terms of either the GPL or the LGPL, and not to allow others to ++# use your version of this file under the terms of the MPL, indicate your ++# decision by deleting the provisions above and replace them with the notice ++# and other provisions required by the GPL or the LGPL. If you do not delete ++# the provisions above, a recipient may use your version of this file under ++# the terms of any one of the MPL, the GPL or the LGPL. ++# ++# ***** END LICENSE BLOCK ***** ++ ++####################################################################### ++# (1) Include initial platform-independent assignments (MANDATORY). # ++####################################################################### ++ ++include manifest.mn ++ ++####################################################################### ++# (2) Include "global" configuration information. (OPTIONAL) # ++####################################################################### ++ ++include $(CORE_DEPTH)/coreconf/config.mk ++ ++####################################################################### ++# (3) Include "component" configuration information. (OPTIONAL) # ++####################################################################### ++ ++####################################################################### ++# (4) Include "local" platform-dependent assignments (OPTIONAL). # ++####################################################################### ++ ++#include ../platlibs.mk ++include config.mk ++ ++####################################################################### ++# (5) Execute "global" rules. (OPTIONAL) # ++####################################################################### ++ ++include $(CORE_DEPTH)/coreconf/rules.mk ++ ++####################################################################### ++# (6) Execute "component" rules. (OPTIONAL) # ++####################################################################### ++ ++ ++ ++####################################################################### ++# (7) Execute "local" rules. (OPTIONAL). # ++####################################################################### ++ ++ ++#include ../platrules.mk ++ +Index: mozilla/security/nss/cmd/sysinit/config.mk +=================================================================== +RCS file: security/nss/cmd/sysinit/config.mk +diff -N security/nss/cmd/sysinit/config.mk +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./mozilla/security/nss/cmd/sysinit/config.mk 1 Sep 2009 22:47:51 -0000 +@@ -0,0 +1,121 @@ ++# ++# ***** BEGIN LICENSE BLOCK ***** ++# Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++# ++# 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 the Initial Developer are Copyright (C) 1994-2000 ++# the Initial Developer. All Rights Reserved. ++# ++# Contributor(s): ++# ++# Alternatively, the contents of this file may be used under the terms of ++# either the GNU General Public License Version 2 or later (the "GPL"), or ++# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++# in which case the provisions of the GPL or the LGPL are applicable instead ++# of those above. If you wish to allow use of your version of this file only ++# under the terms of either the GPL or the LGPL, and not to allow others to ++# use your version of this file under the terms of the MPL, indicate your ++# decision by deleting the provisions above and replace them with the notice ++# and other provisions required by the GPL or the LGPL. If you do not delete ++# the provisions above, a recipient may use your version of this file under ++# the terms of any one of the MPL, the GPL or the LGPL. ++# ++# ***** END LICENSE BLOCK ***** ++ ++# ++# Override TARGETS variable so that only static libraries ++# are specifed as dependencies within rules.mk. ++# ++ ++# can't do this in manifest.mn because OS_TARGET isn't defined there. ++ifeq (,$(filter-out WIN%,$(OS_TARGET))) ++ ++# don't want the 32 in the shared library name ++SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) ++IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX) ++ ++RES = $(OBJDIR)/$(LIBRARY_NAME).res ++RESNAME = $(LIBRARY_NAME).rc ++ ++ifdef NS_USE_GCC ++EXTRA_SHARED_LIBS += \ ++ -L$(DIST)/lib \ ++ -L$(NSSUTIL_LIB_DIR) \ ++ -lnssutil3 \ ++ -L$(NSPR_LIB_DIR) \ ++ -lplc4 \ ++ -lplds4 \ ++ -lnspr4\ ++ $(NULL) ++else # ! NS_USE_GCC ++EXTRA_SHARED_LIBS += \ ++ $(DIST)/lib/nssutil3.lib \ ++ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \ ++ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \ ++ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \ ++ $(NULL) ++endif # NS_USE_GCC ++ ++else ++ ++# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS) ++# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX. ++EXTRA_SHARED_LIBS += \ ++ -L$(DIST)/lib \ ++ -L$(NSSUTIL_LIB_DIR) \ ++ -lnssutil3 \ ++ -L$(NSPR_LIB_DIR) \ ++ -lplc4 \ ++ -lplds4 \ ++ -lnspr4 \ ++ $(NULL) ++ ++endif ++ ++ ++# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) ++ ++ifeq ($(OS_TARGET),SunOS) ++ifeq ($(BUILD_SUN_PKG), 1) ++# The -R '$ORIGIN' linker option instructs this library to search for its ++# dependencies in the same directory where it resides. ++ifeq ($(USE_64), 1) ++MKSHLIB += -R '$$ORIGIN:/usr/lib/mps/secv1/64:/usr/lib/mps/64' ++else ++MKSHLIB += -R '$$ORIGIN:/usr/lib/mps/secv1:/usr/lib/mps' ++endif ++else ++MKSHLIB += -R '$$ORIGIN' ++endif ++endif ++ ++ifeq ($(OS_ARCH), HP-UX) ++ifneq ($(OS_TEST), ia64) ++# pa-risc ++ifeq ($(USE_64), 1) ++MKSHLIB += +b '$$ORIGIN' ++endif ++endif ++endif ++ ++ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET))) ++ifndef NS_USE_GCC ++# Export 'mktemp' to be backward compatible with NSS 3.2.x and 3.3.x ++# but do not put it in the import library. See bug 142575. ++DEFINES += -DWIN32_NSS3_DLL_COMPAT ++DLLFLAGS += -EXPORT:mktemp=nss_mktemp,PRIVATE ++endif ++endif +Index: mozilla/security/nss/cmd/sysinit/manifest.mn +=================================================================== +RCS file: security/nss/cmd/sysinit/manifest.mn +diff -N security/nss/cmd/sysinit/manifest.mn +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./mozilla/security/nss/cmd/sysinit/manifest.mn 1 Sep 2009 22:47:51 -0000 +@@ -0,0 +1,50 @@ ++# ++# ***** BEGIN LICENSE BLOCK ***** ++# Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++# ++# 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 the Initial Developer are Copyright (C) 1994-2000 ++# the Initial Developer. All Rights Reserved. ++# ++# Contributor(s): ++# ++# Alternatively, the contents of this file may be used under the terms of ++# either the GNU General Public License Version 2 or later (the "GPL"), or ++# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++# in which case the provisions of the GPL or the LGPL are applicable instead ++# of those above. If you wish to allow use of your version of this file only ++# under the terms of either the GPL or the LGPL, and not to allow others to ++# use your version of this file under the terms of the MPL, indicate your ++# decision by deleting the provisions above and replace them with the notice ++# and other provisions required by the GPL or the LGPL. If you do not delete ++# the provisions above, a recipient may use your version of this file under ++# the terms of any one of the MPL, the GPL or the LGPL. ++# ++# ***** END LICENSE BLOCK ***** ++ ++CORE_DEPTH = ../../.. ++ ++# MODULE public and private header directories are implicitly REQUIRED. ++MODULE = nss ++ ++DEFINES = -DNSPR20 ++ ++CSRCS = nsssysinit.c ++ ++LIBRARY = nsssysinit ++LIBRARY_NAME = nsssysinit ++#LIBRARY_VERSION = 3 ++ +Index: mozilla/security/nss/cmd/sysinit/nsssysinit.c +=================================================================== +RCS file: security/nss/cmd/sysinit/nsssysinit.c +diff -N security/nss/cmd/sysinit/nsssysinit.c +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./mozilla/security/nss/cmd/sysinit/nsssysinit.c 1 Sep 2009 22:47:51 -0000 +@@ -0,0 +1,329 @@ ++/* ***** BEGIN LICENSE BLOCK ***** ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 ++ * ++ * 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 ++ * Red Hat, Inc ++ * Portions created by the Initial Developer are Copyright (C) 2009 ++ * the Initial Developer. All Rights Reserved. ++ * ++ * Contributor(s): ++ * ++ * Alternatively, the contents of this file may be used under the terms of ++ * either the GNU General Public License Version 2 or later (the "GPL"), or ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), ++ * in which case the provisions of the GPL or the LGPL are applicable instead ++ * of those above. If you wish to allow use of your version of this file only ++ * under the terms of either the GPL or the LGPL, and not to allow others to ++ * use your version of this file under the terms of the MPL, indicate your ++ * decision by deleting the provisions above and replace them with the notice ++ * and other provisions required by the GPL or the LGPL. If you do not delete ++ * the provisions above, a recipient may use your version of this file under ++ * the terms of any one of the MPL, the GPL or the LGPL. ++ * ++ * ***** END LICENSE BLOCK ***** */ ++#include "seccomon.h" ++#include "prio.h" ++#include "prprf.h" ++ ++ ++ ++/* ++ * The following provides a default example for operating systems to set up ++ * and manage applications loading NSS on their OS globally. ++ * ++ * This code hooks in to the system pkcs11.txt, which controls all the loading ++ * of pkcs11 modules common to all applications. ++ */ ++ ++/* ++ * OS Specific function to get where the NSS user database should reside. ++ */ ++ ++#ifdef XP_UNIX ++#include ++#include ++ ++int testdir(char *dir) ++{ ++ struct stat buf; ++ memset(&buf, 0, sizeof(buf)); ++ ++ if (stat(dir,&buf) < 0) { ++ return 0; ++ } ++ ++ return S_ISDIR(buf.st_mode); ++} ++ ++#define NSS_USER_PATH1 "/.pki" ++#define NSS_USER_PATH2 "/nssdb" ++char *getUserDB(void) ++{ ++ char *userdir = getenv("HOME"); ++ char *nssdir = NULL; ++ ++ if (userdir == NULL) { ++ return NULL; ++ } ++ ++ nssdir = PORT_Alloc(strlen(userdir) ++ +sizeof(NSS_USER_PATH1)+sizeof(NSS_USER_PATH2)); ++ if (nssdir == NULL) { ++ return NULL; ++ } ++ PORT_Memcpy(nssdir, userdir, strlen(userdir)+1); ++ /* verify it exists */ ++ if (!testdir(nssdir)) { ++ PORT_Free(nssdir); ++ return NULL; ++ } ++ PORT_Strcat(nssdir, NSS_USER_PATH1); ++ if (!testdir(nssdir) && mkdir(nssdir, 0760)) { ++ PORT_Free(nssdir); ++ return NULL; ++ } ++ PORT_Strcat(nssdir, NSS_USER_PATH2); ++ if (!testdir(nssdir) && mkdir(nssdir, 0760)) { ++ PORT_Free(nssdir); ++ return NULL; ++ } ++ return nssdir; ++} ++ ++#define NSS_DEFAULT_SYSTEM "/etc/pki/nssdb" ++char *getSystemDB(void) { ++ return PORT_Strdup(NSS_DEFAULT_SYSTEM); ++} ++ ++#else ++#ifdef XP_WIN ++char *getUserDB(void) ++{ ++ /* use the registry to find the user's NSS_DIR. if no entry exists, creaate ++ * one in the users Appdir location */ ++} ++ ++char *getSystemDB(void) ++{ ++ /* use the registry to find the system's NSS_DIR. if no entry exists, creaate ++ * one based on the windows system data area */ ++} ++ ++#else ++#error "Need to write getUserDB and get SystemDB functions" ++#endif ++#endif ++ ++#ifdef XP_LINUX ++PRBool getFIPSMode() ++{ ++} ++ ++#else ++PRBool getFIPSMode() ++{ ++ char *fipsEnv = getenv("NSS_FIPS"); ++ if (!fipsEnv) { ++ return 0; ++ } ++ if ((strcasecmp(fipsEnv,"fips") == 0) || ++ (strcasecmp(fipsEnv,"true") == 0) || ++ (strcasecmp(fipsEnv,"on") == 0) || ++ (strcasecmp(fipsEnv,"1") == 0)) { ++ return 1; ++ } ++ return 0; ++} ++#endif ++ ++ ++#define NSS_DEFAULT_FLAGS "flags=readonly" ++ ++/* ++ * This function builds the list of databases and modules to load, and sets ++ * their configuration. For the sample we have a fixed set. ++ * 1. We load the user's home nss database. ++ * 2. We load the user's custom PKCS #11 modules. ++ * 3. We load the system nss database readonly. ++ * ++ * Any space allocated in get_list must be freed in release_list. ++ * This function can use whatever information is available to the application. ++ * it is running in the process of the application for which it is making ++ * decisions, so it's possible to acquire the application name as part of ++ * the decision making process. ++ */ ++static char ** ++get_list(char *filename, char *stripped_parameters) ++{ ++ char **module_list = PORT_ZNewArray(char *, 4); ++ char *userdb; ++ int next = 0; ++ ++ /* can't get any space */ ++ if (module_list == NULL) { ++ return NULL; ++ } ++ ++ userdb = getUserDB(); ++ if (userdb != NULL) { ++ /* return a list of databases to open. First the user Database */ ++ module_list[next++] = PR_smprintf( ++ "library= " ++ "module=\"NSS User database\" " ++ "parameters=\"configdir='sql:%s' %s\" " ++ "NSS=\"flags=internal%s\"", ++ userdb, stripped_parameters, getFIPSMode() ? ",FIPS" : ""); ++ ++ /* now open the user's defined PKCS #11 modules */ ++ /* skip the local user DB entry */ ++ module_list[next++] = PR_smprintf( ++ "library= " ++ "module=\"NSS User database\" " ++ "parameters=\"configdir='sql:%s' %s\" " ++ "NSS=\"flags=internal,moduleDBOnly,defaultModDB,skipFirst\"", ++ userdb, stripped_parameters); ++ } ++ ++ /* now the system database (always read only) */ ++ module_list[next++] = PR_smprintf( ++ "library= " ++ "module=\"NSS system database\" " ++ "parameters=\"configdir='sql:%s' tokenDescription='NSS system database' flags=readonly\" " ++ "NSS=\"flags=internal,critical\"",filename); ++ ++ /* that was the last module */ ++ module_list[next] = 0; ++ ++ PORT_Free(userdb); ++ ++ return module_list; ++} ++ ++static char ** ++release_list(char **arg) ++{ ++ static char *success = "Success"; ++ int next; ++ ++ for (next = 0; arg[next]; next++) { ++ free(arg[next]); ++ } ++ PORT_Free(arg); ++ return &success; ++} ++ ++ ++#include "pk11pars.h" ++ ++#define TARGET_SPEC_COPY(new, start, end) \ ++ if (end > start) { \ ++ int _cnt = end - start; \ ++ PORT_Memcpy(new, start, _cnt); \ ++ new += _cnt; \ ++ } ++ ++static void ++safestrcpy(char *target, char *src) ++{ ++ while (*src) { ++ *target++ = *src++; ++ } ++ *target = 0; ++} ++ ++static SECStatus ++parse_paramters(char *parameters, char **filename, char **stripped) ++{ ++ char *sourcePrev; ++ char *sourceCurr; ++ char *targetCurr; ++ char *newStripped; ++ *filename = NULL; ++ *stripped = NULL; ++ ++ newStripped = PORT_Alloc(PORT_Strlen(parameters)+2); ++ targetCurr = newStripped; ++ sourcePrev = parameters; ++ sourceCurr = secmod_argStrip(parameters); ++ TARGET_SPEC_COPY(targetCurr, sourcePrev, sourceCurr); ++ ++ while (*sourceCurr) { ++ int next; ++ sourcePrev = sourceCurr; ++ SECMOD_HANDLE_STRING_ARG(sourceCurr, *filename, "configdir=", ++ sourcePrev = sourceCurr; ) ++ SECMOD_HANDLE_FINAL_ARG(sourceCurr); ++ TARGET_SPEC_COPY(targetCurr, sourcePrev, sourceCurr); ++ } ++ *targetCurr = 0; ++ if (*filename == NULL) { ++ PORT_Free(newStripped); ++ return SECFailure; ++ } ++ if (strncmp("sql:", *filename, 4) == 0) { ++ safestrcpy(*filename, (*filename)+4); ++ } else if (strncmp("dbm:", *filename, 4) == 0) { ++ safestrcpy(*filename, (*filename)+4); ++ } else if (strncmp("extern:", *filename, 7) == 0) { ++ safestrcpy(*filename, (*filename)+7); ++ } ++ *stripped = newStripped; ++ return SECSuccess; ++} ++ ++/* entry point */ ++char ** ++NSS_ReturnModuleSpecData(unsigned long function, char *parameters, void *args) ++{ ++ static char *chain = "Chain"; ++ char *filename = NULL; ++ char *stripped = NULL; ++ char **retString = NULL; ++ SECStatus rv; ++ ++ rv = parse_paramters(parameters, &filename, &stripped); ++ if (rv != SECSuccess) { ++ /* use defaults */ ++ filename = getSystemDB(); ++ if (!filename) { ++ return NULL; ++ } ++ stripped = PORT_Strdup(NSS_DEFAULT_FLAGS); ++ if (!stripped) { ++ free(filename); ++ return NULL; ++ } ++ } ++ switch (function) { ++ case SECMOD_MODULE_DB_FUNCTION_FIND: ++ retString = get_list(filename, stripped); ++ break; ++ case SECMOD_MODULE_DB_FUNCTION_RELEASE: ++ retString = release_list((char **)args); ++ break; ++ /* forward add/del to child */ ++ case SECMOD_MODULE_DB_FUNCTION_ADD: ++ case SECMOD_MODULE_DB_FUNCTION_DEL: ++ retString = &chain; ++ break; ++ default: ++ retString = NULL; ++ break; ++ } ++ ++ if (filename) PORT_Free(filename); ++ if (stripped) PORT_Free(stripped); ++ return retString; ++} +Index: mozilla/security/nss/lib/pk11wrap/pk11load.c +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/pk11load.c,v +retrieving revision 1.25 +diff -u -p -r1.25 pk11load.c +--- ./mozilla/security/nss/lib/pk11wrap/pk11load.c 2 Oct 2008 00:56:15 -0000 1.25 ++++ ./mozilla/security/nss/lib/pk11wrap/pk11load.c 1 Sep 2009 22:47:51 -0000 +@@ -120,15 +120,83 @@ PRBool pk11_getFinalizeModulesOption(voi + } + + /* ++ * Allow specification loading the same module more than once at init time. ++ * This enables 2 things. ++ * ++ * 1) we can load additional databases by manipulating secmod.db/pkcs11.txt. ++ * 2) we can handle the case where some library has already initialized NSS ++ * before the main application. ++ * ++ * oldModule is the module we have already initialized. ++ * char *modulespec is the full module spec for the library we want to ++ * initialize. ++ */ ++static SECStatus ++secmod_HandleReload(SECMODModule *oldModule, char *modulespec) ++{ ++ PK11SlotInfo *slot; ++ char *newModuleSpec; ++ char **children; ++ CK_SLOT_ID *ids; ++ SECStatus rv; ++ ++ /* first look for token= key words from the module spec */ ++ newModuleSpec = secmod_ParseModuleSpecForTokens(modulespec,&children,&ids); ++ if (!newModuleSpec) { ++ return SECFailure; ++ } ++ slot = SECMOD_OpenNewSlot(oldModule, newModuleSpec); ++ if (slot) { ++ int newID; ++ char **thisChild; ++ CK_SLOT_ID *thisID; ++ char *oldModuleSpec; ++ ++ newID = slot->slotID; ++ PK11_FreeSlot(slot); ++ for (thisChild=children, thisID=ids; thisChild && *thisChild; ++ thisChild++,thisID++) { ++ slot = SECMOD_OpenNewSlot(oldModule, *thisChild); ++ if (slot) { ++ *thisID = slot->slotID; ++ PK11_FreeSlot(slot); ++ } else { ++ *thisID = (CK_SLOT_ID) -1; ++ } ++ } ++ ++ /* update the old module initialization string in case we need to ++ * shutdown and reinit the whole mess (this is rare, but can happen ++ * when trying to stop smart card insertion/removal threads)... */ ++ oldModuleSpec = secmod_mkAppendTokensList(oldModule->arena, ++ oldModule->libraryParams, newModuleSpec, newID, ++ children, ids); ++ if (oldModuleSpec) { ++ oldModule->libraryParams = oldModuleSpec; ++ } ++ ++ rv = SECSuccess; ++ } ++ secmod_FreeChildren(children, ids); ++ PORT_Free(newModuleSpec); ++ return rv; ++} ++ ++/* + * collect the steps we need to initialize a module in a single function + */ + SECStatus +-secmod_ModuleInit(SECMODModule *mod, PRBool* alreadyLoaded) ++secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload, ++ PRBool* alreadyLoaded) + { + CK_C_INITIALIZE_ARGS moduleArgs; + CK_VOID_PTR pInitArgs; + CK_RV crv; + ++ if (reload) { ++ *reload = NULL; ++ } ++ + if (!mod || !alreadyLoaded) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; +@@ -144,10 +212,36 @@ secmod_ModuleInit(SECMODModule *mod, PRB + pInitArgs = &moduleArgs; + } + crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs); +- if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) && +- (!enforceAlreadyInitializedError)) { +- *alreadyLoaded = PR_TRUE; +- return SECSuccess; ++ if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) { ++ SECMODModule *oldModule = NULL; ++ ++ /* Library has already been loaded once, if caller expects it, and it ++ * has additional configuration, try reloading it as well. */ ++ if (reload != NULL && mod->libraryParams) { ++ oldModule = secmod_findModuleByFuncPtr(mod->functionList); ++ } ++ /* Library has been loaded by NSS. It means it may be capable of ++ * reloading */ ++ if (oldModule) { ++ SECStatus rv; ++ rv = secmod_HandleReload(oldModule, mod->libraryParams); ++ if (rv == SECSuccess) { ++ /* This module should go away soon, since we've ++ * simply expanded the slots on the old module. ++ * When it goes away, it should not Finalize since ++ * that will close our old module as well. Setting ++ * the function list to NULL will prevent that close */ ++ mod->functionList = NULL; ++ *reload = oldModule; ++ return SECSuccess; ++ } ++ SECMOD_DestroyModule(oldModule); ++ } ++ /* reload not possible, fall back to old semantics */ ++ if (!enforceAlreadyInitializedError) { ++ *alreadyLoaded = PR_TRUE; ++ return SECSuccess; ++ } + } + if (crv != CKR_OK) { + if (pInitArgs == NULL || +@@ -258,7 +352,7 @@ softoken_LoadDSO( void ) + * load a new module into our address space and initialize it. + */ + SECStatus +-SECMOD_LoadPKCS11Module(SECMODModule *mod) { ++secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule) { + PRLibrary *library = NULL; + CK_C_GetFunctionList entry = NULL; + char * full_name; +@@ -271,7 +365,7 @@ SECMOD_LoadPKCS11Module(SECMODModule *mo + if (mod->loaded) return SECSuccess; + + /* intenal modules get loaded from their internal list */ +- if (mod->internal) { ++ if (mod->internal && (mod->dllName == NULL)) { + /* + * Loads softoken as a dynamic library, + * even though the rest of NSS assumes this as the "internal" module. +@@ -308,26 +402,14 @@ SECMOD_LoadPKCS11Module(SECMODModule *mo + return SECFailure; + } + +-#ifdef notdef +- /* look up the library name */ +- full_name = PR_GetLibraryName(PR_GetLibraryPath(),mod->dllName); +- if (full_name == NULL) { +- return SECFailure; +- } +-#else + full_name = PORT_Strdup(mod->dllName); +-#endif + + /* load the library. If this succeeds, then we have to remember to + * unload the library if anything goes wrong from here on out... + */ + library = PR_LoadLibrary(full_name); + mod->library = (void *)library; +-#ifdef notdef +- PR_FreeLibraryName(full_name); +-#else + PORT_Free(full_name); +-#endif + + if (library == NULL) { + return SECFailure; +@@ -375,11 +457,18 @@ SECMOD_LoadPKCS11Module(SECMODModule *mo + mod->isThreadSafe = PR_TRUE; + + /* Now we initialize the module */ +- rv = secmod_ModuleInit(mod, &alreadyLoaded); ++ rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded); + if (rv != SECSuccess) { + goto fail; + } + ++ /* module has been reloaded, this module itself is done, ++ * return to the caller */ ++ if (mod->functionList == NULL) { ++ mod->loaded = PR_TRUE; /* technically the module is loaded.. */ ++ return SECSuccess; ++ } ++ + /* check the version number */ + if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2; + if (info.cryptokiVersion.major != 2) goto fail2; +@@ -460,7 +549,9 @@ SECMOD_UnloadModule(SECMODModule *mod) { + return SECFailure; + } + if (finalizeModules) { +- if (!mod->moduleDBOnly) PK11_GETTAB(mod)->C_Finalize(NULL); ++ if (mod->functionList &&!mod->moduleDBOnly) { ++ PK11_GETTAB(mod)->C_Finalize(NULL); ++ } + } + mod->moduleID = 0; + mod->loaded = PR_FALSE; +Index: mozilla/security/nss/lib/pk11wrap/pk11pars.c +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/pk11pars.c,v +retrieving revision 1.22 +diff -u -p -r1.22 pk11pars.c +--- ./mozilla/security/nss/lib/pk11wrap/pk11pars.c 1 Sep 2009 21:56:26 -0000 1.22 ++++ ./mozilla/security/nss/lib/pk11wrap/pk11pars.c 1 Sep 2009 22:47:51 -0000 +@@ -224,6 +224,389 @@ SECMOD_GetDefaultModDBFlag(SECMODModule + return (flags & SECMOD_FLAG_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE; + } + ++/* ++ * Find any token= values in the module spec. ++ * Always return a new spec which does not have any token= arguments. ++ * If token= arguments are found, Split the the various tokens defined into ++ * an array of child specs to return. ++ * ++ * Caller is responsible for freeing the child spec and the new token ++ * spec. ++ */ ++ ++#define SECMOD_SPEC_COPY(new, start, end) \ ++ if (end > start) { \ ++ int _cnt = end - start; \ ++ PORT_Memcpy(new, start, _cnt); \ ++ new += _cnt; \ ++ } ++ ++char * ++secmod_ParseModuleSpecForTokens(char *moduleSpec, char ***children, ++ CK_SLOT_ID **ids) ++{ ++ char *newSpec = PORT_Alloc(PORT_Strlen(moduleSpec)+2); ++ char *newSpecPtr = newSpec; ++ char *modulePrev = moduleSpec; ++ char *target = NULL; ++ char **childArray = NULL; ++ char *tokenIndex; ++ CK_SLOT_ID *idArray = NULL; ++ int tokenCount = 0; ++ int i; ++ ++ if (newSpec == NULL) { ++ return NULL; ++ } ++ ++ *children = NULL; ++ if (ids) { ++ *ids = NULL; ++ } ++ moduleSpec = secmod_argStrip(moduleSpec); ++ SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec); ++ ++ /* ++ * walk down the list. if we find a tokens= argument, save it, ++ * otherise copy the argument. ++ */ ++ while (*moduleSpec) { ++ int next; ++ modulePrev = moduleSpec; ++ SECMOD_HANDLE_STRING_ARG(moduleSpec, target, "tokens=", ++ modulePrev = moduleSpec; /* skip copying */ ) ++ SECMOD_HANDLE_FINAL_ARG(moduleSpec) ++ SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec); ++ } ++ *newSpecPtr = 0; ++ ++ /* no target found, return the newSpec */ ++ if (target == NULL) { ++ return newSpec; ++ } ++ ++ /* now build the child array from target */ ++ /*first count them */ ++ for (tokenIndex = secmod_argStrip(target); *tokenIndex; ++ tokenIndex = secmod_argStrip(secmod_argSkipParameter(tokenIndex))) { ++ tokenCount++; ++ } ++ ++ childArray = PORT_NewArray(char *, tokenCount+1); ++ if (childArray == NULL) { ++ /* just return the spec as is then */ ++ PORT_Free(target); ++ return newSpec; ++ } ++ if (ids) { ++ idArray = PORT_NewArray(CK_SLOT_ID, tokenCount+1); ++ if (idArray == NULL) { ++ PORT_Free(childArray); ++ PORT_Free(target); ++ return newSpec; ++ } ++ } ++ ++ /* now fill them in */ ++ for (tokenIndex = secmod_argStrip(target), i=0 ; ++ *tokenIndex && (i < tokenCount); ++ tokenIndex=secmod_argStrip(tokenIndex)) { ++ int next; ++ char *name = secmod_argGetName(tokenIndex, &next); ++ tokenIndex += next; ++ ++ if (idArray) { ++ idArray[i] = secmod_argDecodeNumber(name); ++ } ++ ++ PORT_Free(name); /* drop the explicit number */ ++ ++ /* if anything is left, copy the args to the child array */ ++ if (!secmod_argIsBlank(*tokenIndex)) { ++ childArray[i++] = secmod_argFetchValue(tokenIndex, &next); ++ tokenIndex += next; ++ } ++ } ++ ++ PORT_Free(target); ++ childArray[i] = 0; ++ if (idArray) { ++ idArray[i] = 0; ++ } ++ ++ /* return it */ ++ *children = childArray; ++ if (ids) { ++ *ids = idArray; ++ } ++ return newSpec; ++} ++ ++void ++secmod_FreeChildren(char **children, CK_SLOT_ID *ids) ++{ ++ char **thisChild = children; ++ ++ if (!children) { ++ return; ++ } ++ ++ for (thisChild = children; thisChild && *thisChild; thisChild++ ) { ++ PORT_Free(*thisChild); ++ } ++ PORT_Free(children); ++ if (ids) { ++ PORT_Free(ids); ++ } ++ return; ++} ++ ++ ++static int ++secmod_escapeSize(const char *string, char quote) ++{ ++ int escapes = 0, size = 0; ++ const char *src; ++ for (src=string; *src ; src++) { ++ if ((*src == quote) || (*src == '\\')) escapes++; ++ size++; ++ } ++ ++ return escapes+size+1; ++} ++ ++ ++/* ++ * add escapes to protect quote characters... ++ */ ++static char * ++secmod_addEscape(const char *string, char quote) ++{ ++ char *newString = 0; ++ int size = 0; ++ const char *src; ++ char *dest; ++ ++ ++ size = secmod_escapeSize(string,quote); ++ newString = PORT_ZAlloc(size); ++ if (newString == NULL) { ++ return NULL; ++ } ++ ++ for (src=string, dest=newString; *src; src++,dest++) { ++ if ((*src == '\\') || (*src == quote)) { ++ *dest++ = '\\'; ++ } ++ *dest = *src; ++ } ++ ++ return newString; ++} ++ ++static int ++secmod_doubleEscapeSize(const char *string, char quote1, char quote2) ++{ ++ int escapes = 0, size = 0; ++ const char *src; ++ for (src=string; *src ; src++) { ++ if (*src == '\\') escapes+=3; /* \\\\ */ ++ if (*src == quote1) escapes+=2; /* \\quote1 */ ++ if (*src == quote2) escapes++; /* \quote2 */ ++ size++; ++ } ++ ++ return escapes+size+1; ++} ++ ++char * ++secmod_doubleEscape(const char *string, char quote1, char quote2) ++{ ++ char *round1 = NULL; ++ char *retValue = NULL; ++ if (string == NULL) { ++ goto done; ++ } ++ round1 = secmod_addEscape(string,quote1); ++ if (round1) { ++ retValue = secmod_addEscape(round1,quote2); ++ PORT_Free(round1); ++ } ++ ++done: ++ if (retValue == NULL) { ++ retValue = PORT_Strdup(""); ++ } ++ return retValue; ++} ++ ++ ++/* ++ * caclulate the length of each child record: ++ * " 0x{id}=<{escaped_child}>" ++ */ ++static int ++secmod_getChildLength(char *child, CK_SLOT_ID id) ++{ ++ int length = secmod_doubleEscapeSize(child, '>', ']'); ++ if (id == 0) { ++ length++; ++ } ++ while (id) { ++ length++; ++ id = id >> 4; ++ } ++ length += 6; /* {sp}0x[id]=<{child}> */ ++ return length; ++} ++ ++/* ++ * Build a child record: ++ * " 0x{id}=<{escaped_child}>" ++ */ ++SECStatus ++secmod_mkTokenChild(char **next, int *length, char *child, CK_SLOT_ID id) ++{ ++ int len; ++ char *escSpec; ++ ++ len = PR_snprintf(*next, *length, " 0x%x=<",id); ++ if (len < 0) { ++ return SECFailure; ++ } ++ *next += len; ++ *length -= len; ++ escSpec = secmod_doubleEscape(child, '>', ']'); ++ if (escSpec == NULL) { ++ return SECFailure; ++ } ++ if (*child && (*escSpec == 0)) { ++ PORT_Free(escSpec); ++ return SECFailure; ++ } ++ len = strlen(escSpec); ++ if (len+1 > *length) { ++ PORT_Free(escSpec); ++ return SECFailure; ++ } ++ PORT_Memcpy(*next,escSpec, len); ++ *next += len; ++ *length -= len; ++ PORT_Free(escSpec); ++ **next = '>'; ++ (*next)++; ++ (*length)--; ++ return SECSuccess; ++} ++ ++#define TOKEN_STRING " tokens=[" ++ ++char * ++secmod_mkAppendTokensList(PRArenaPool *arena, char *oldParam, char *newToken, ++ CK_SLOT_ID newID, char **children, CK_SLOT_ID *ids) ++{ ++ char *rawParam = NULL; /* oldParam with tokens stripped off */ ++ char *newParam = NULL; /* space for the return parameter */ ++ char *nextParam = NULL; /* current end of the new parameter */ ++ char **oldChildren = NULL; ++ CK_SLOT_ID *oldIds = NULL; ++ void *mark = NULL; /* mark the arena pool in case we need ++ * to release it */ ++ int length, i, tmpLen; ++ SECStatus rv; ++ ++ /* first strip out and save the old tokenlist */ ++ rawParam = secmod_ParseModuleSpecForTokens(oldParam,&oldChildren,&oldIds); ++ if (!rawParam) { ++ goto loser; ++ } ++ ++ /* now calculate the total length of the new buffer */ ++ /* First the 'fixed stuff', length of rawparam (does not include a NULL), ++ * length of the token string (does include the NULL), closing bracket */ ++ length = strlen(rawParam) + sizeof(TOKEN_STRING) + 1; ++ /* now add then length of all the old children */ ++ for (i=0; oldChildren && oldChildren[i]; i++) { ++ length += secmod_getChildLength(oldChildren[i], oldIds[i]); ++ } ++ ++ /* add the new token */ ++ length += secmod_getChildLength(newToken, newID); ++ ++ /* and it's new children */ ++ for (i=0; children && children[i]; i++) { ++ if (ids[i] == -1) { ++ continue; ++ } ++ length += secmod_getChildLength(children[i], ids[i]); ++ } ++ ++ /* now allocate and build the string */ ++ mark = PORT_ArenaMark(arena); ++ if (!mark) { ++ goto loser; ++ } ++ newParam = PORT_ArenaAlloc(arena,length); ++ if (!newParam) { ++ goto loser; ++ } ++ ++ PORT_Strcpy(newParam, oldParam); ++ tmpLen = strlen(oldParam); ++ nextParam = newParam + tmpLen; ++ length -= tmpLen; ++ PORT_Memcpy(nextParam, TOKEN_STRING, sizeof(TOKEN_STRING)-1); ++ nextParam += sizeof(TOKEN_STRING)-1; ++ length -= sizeof(TOKEN_STRING)-1; ++ ++ for (i=0; oldChildren && oldChildren[i]; i++) { ++ rv = secmod_mkTokenChild(&nextParam,&length,oldChildren[i],oldIds[i]); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ } ++ ++ rv = secmod_mkTokenChild(&nextParam, &length, newToken, newID); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ ++ for (i=0; children && children[i]; i++) { ++ if (ids[i] == -1) { ++ continue; ++ } ++ rv = secmod_mkTokenChild(&nextParam, &length, children[i], ids[i]); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ } ++ ++ if (length < 2) { ++ goto loser; ++ } ++ ++ *nextParam++ = ']'; ++ *nextParam++ = 0; ++ ++ /* we are going to return newParam now, don't release the mark */ ++ PORT_ArenaUnmark(arena, mark); ++ mark = NULL; ++ ++loser: ++ if (mark) { ++ PORT_ArenaRelease(arena, mark); ++ newParam = NULL; /* if the mark is still active, ++ * don't return the param */ ++ } ++ if (rawParam) { ++ PORT_Free(rawParam); ++ } ++ if (oldChildren) { ++ secmod_FreeChildren(oldChildren, oldIds); ++ } ++ return newParam; ++} ++ + static char * + secmod_mkModuleSpec(SECMODModule * module) + { +@@ -365,6 +748,7 @@ SECMOD_LoadModule(char *modulespec,SECMO + char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss= NULL; + SECStatus status; + SECMODModule *module = NULL; ++ SECMODModule *oldModule = NULL; + SECStatus rv; + + /* initialize the underlying module structures */ +@@ -389,11 +773,19 @@ SECMOD_LoadModule(char *modulespec,SECMO + } + + /* load it */ +- rv = SECMOD_LoadPKCS11Module(module); ++ rv = secmod_LoadPKCS11Module(module, &oldModule); + if (rv != SECSuccess) { + goto loser; + } + ++ /* if we just reload an old module, no need to add it to any lists. ++ * we simple release all our references */ ++ if (oldModule) { ++ SECMOD_DestroyModule(module); ++ SECMOD_DestroyModule(oldModule); ++ return SECSuccess; ++ } ++ + if (recurse && module->isModuleDB) { + char ** moduleSpecList; + PORT_SetError(0); +Index: mozilla/security/nss/lib/pk11wrap/pk11util.c +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/pk11util.c,v +retrieving revision 1.56 +diff -u -p -r1.56 pk11util.c +--- ./mozilla/security/nss/lib/pk11wrap/pk11util.c 1 Sep 2009 21:56:26 -0000 1.56 ++++ ./mozilla/security/nss/lib/pk11wrap/pk11util.c 1 Sep 2009 22:47:51 -0000 +@@ -285,6 +285,30 @@ SECMOD_FindModuleByID(SECMODModuleID id) + } + + /* ++ * find the function pointer. ++ */ ++SECMODModule * ++secmod_findModuleByFuncPtr(void *funcPtr) ++{ ++ SECMODModuleList *mlp; ++ SECMODModule *module = NULL; ++ ++ SECMOD_GetReadLock(moduleLock); ++ for(mlp = modules; mlp != NULL; mlp = mlp->next) { ++ if (funcPtr == mlp->module->functionList) { ++ module = mlp->module; ++ SECMOD_ReferenceModule(module); ++ break; ++ } ++ } ++ SECMOD_ReleaseReadLock(moduleLock); ++ if (module == NULL) { ++ PORT_SetError(SEC_ERROR_NO_MODULE); ++ } ++ return module; ++} ++ ++/* + * Find the Slot based on ID and the module. + */ + PK11SlotInfo * +@@ -508,7 +532,7 @@ SECMOD_AddModule(SECMODModule *newModule + /* module already exists. */ + } + +- rv = SECMOD_LoadPKCS11Module(newModule); ++ rv = secmod_LoadPKCS11Module(newModule, NULL); + if (rv != SECSuccess) { + return rv; + } +@@ -1202,7 +1226,7 @@ SECMOD_CancelWait(SECMODModule *mod) + * we intend to use it again */ + if (CKR_OK == crv) { + PRBool alreadyLoaded; +- secmod_ModuleInit(mod, &alreadyLoaded); ++ secmod_ModuleInit(mod, NULL, &alreadyLoaded); + } else { + /* Finalized failed for some reason, notify the application + * so maybe it has a prayer of recovering... */ +@@ -1279,58 +1303,6 @@ secmod_UserDBOp(PK11SlotInfo *slot, CK_O + } + + /* +- * add escapes to protect quote characters... +- */ +-static char * +-nss_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; +-} +- +-static char * +-nss_doubleEscape(const char *string) +-{ +- char *round1 = NULL; +- char *retValue = NULL; +- if (string == NULL) { +- goto done; +- } +- round1 = nss_addEscape(string,'>'); +- if (round1) { +- retValue = nss_addEscape(round1,']'); +- PORT_Free(round1); +- } +- +-done: +- if (retValue == NULL) { +- retValue = PORT_Strdup(""); +- } +- return retValue; +-} +- +-/* + * return true if the selected slot ID is not present or doesn't exist + */ + static PRBool +@@ -1412,7 +1384,7 @@ SECMOD_OpenNewSlot(SECMODModule *mod, co + } + + /* we've found the slot, now build the moduleSpec */ +- escSpec = nss_doubleEscape(moduleSpec); ++ escSpec = secmod_doubleEscape(moduleSpec, '>', ']'); + if (escSpec == NULL) { + PK11_FreeSlot(slot); + return NULL; +Index: mozilla/security/nss/lib/pk11wrap/secmodi.h +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pk11wrap/secmodi.h,v +retrieving revision 1.31 +diff -u -p -r1.31 secmodi.h +--- ./mozilla/security/nss/lib/pk11wrap/secmodi.h 2 Dec 2008 23:24:50 -0000 1.31 ++++ ./mozilla/security/nss/lib/pk11wrap/secmodi.h 1 Sep 2009 22:47:51 -0000 +@@ -58,7 +58,8 @@ void nss_DumpModuleLog(void); + extern int secmod_PrivateModuleCount; + + extern void SECMOD_Init(void); +-SECStatus secmod_ModuleInit(SECMODModule *mod, PRBool* alreadyLoaded); ++SECStatus secmod_ModuleInit(SECMODModule *mod, SECMODModule **oldModule, ++ PRBool* alreadyLoaded); + + /* list managment */ + extern SECStatus SECMOD_AddModuleToList(SECMODModule *newModule); +@@ -73,6 +74,7 @@ extern void SECMOD_ReleaseWriteLock(SECM + + /* Operate on modules by name */ + extern SECMODModule *SECMOD_FindModuleByID(SECMODModuleID); ++extern SECMODModule *secmod_findModuleByFuncPtr(void *funcPtr); + + /* database/memory management */ + extern SECMODModuleList *SECMOD_NewModuleListElement(void); +@@ -84,10 +86,25 @@ extern unsigned long SECMOD_InternaltoPu + extern unsigned long SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags); + + /* Library functions */ +-SECStatus SECMOD_LoadPKCS11Module(SECMODModule *); ++SECStatus secmod_LoadPKCS11Module(SECMODModule *, SECMODModule **oldModule); + SECStatus SECMOD_UnloadModule(SECMODModule *); + void SECMOD_SetInternalModule(SECMODModule *); + ++/* parsing parameters */ ++/* returned char * must be freed by caller with PORT_Free */ ++/* children and ids are null terminated arrays which must be freed with ++ * secmod_FreeChildren */ ++char *secmod_ParseModuleSpecForTokens(char *moduleSpec, ++ char ***children, ++ CK_SLOT_ID **ids); ++void secmod_FreeChildren(char **children, CK_SLOT_ID *ids); ++char *secmod_mkAppendTokensList(PRArenaPool *arena, char *origModuleSpec, ++ char *newModuleSpec, CK_SLOT_ID newID, ++ char **children, CK_SLOT_ID *ids); ++char *secmod_doubleEscape(const char *string, char quote1, char quote2); ++ ++ ++ + void SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot); + CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event, + CK_VOID_PTR pdata); +Index: mozilla/security/nss/lib/pki/pki3hack.c +=================================================================== +RCS file: /cvsroot/mozilla/security/nss/lib/pki/pki3hack.c,v +retrieving revision 1.97 +diff -u -p -r1.97 pki3hack.c +--- ./mozilla/security/nss/lib/pki/pki3hack.c 30 Jul 2009 22:43:32 -0000 1.97 ++++ ./mozilla/security/nss/lib/pki/pki3hack.c 1 Sep 2009 22:47:51 -0000 +@@ -101,6 +101,11 @@ STAN_InitTokenForSlotInfo(NSSTrustDomain + NSSToken *token; + if (!td) { + td = g_default_trust_domain; ++ if (!td) { ++ /* we're called while still initting. slot will get added ++ * appropriately through normal init processes */ ++ return PR_SUCCESS; ++ } + } + token = nssToken_CreateFromPK11SlotInfo(td, slot); + PK11Slot_SetNSSToken(slot, token); +@@ -118,6 +123,11 @@ STAN_ResetTokenInterator(NSSTrustDomain + { + if (!td) { + td = g_default_trust_domain; ++ if (!td) { ++ /* we're called while still initting. slot will get added ++ * appropriately through normal init processes */ ++ return PR_SUCCESS; ++ } + } + NSSRWLock_LockWrite(td->tokensLock); + nssListIterator_Destroy(td->tokens);