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 18 Sep 2009 23:38:36 -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 18 Sep 2009 23:38:36 -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 18 Sep 2009 23:38:36 -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 18 Sep 2009 23:38:36 -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 18 Sep 2009 23:38:36 -0000 @@ -0,0 +1,356 @@ +/* ***** 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 + +static PRBool getFIPSEnv() +{ + 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; +} +#ifdef XP_LINUX + +PRBool getFIPSMode() +{ + FILE *f; + char d; + size_t size; + + f = fopen("/proc/sys/crypto/fips_enabled", "r"); + if (!f) { + /* if we don't have a proc flag, fall back to the + * environment variable */ + return getFIPSEnv(); + } + + size = fread(&d, 1, 1, f); + fclose(f); + if (size != 1) + return 0; + if (d != '1') + return 0; + return 1; +} + +#else +static PRBool getFIPSMode() +{ + return getFIPSEnv(); +} +#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; +} + +/* determine what options the user was trying to open this database with */ +/* filename is the directory pointed to by configdir= */ +/* stripped is the rest of the paramters with configdir= stripped out */ +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; + } + /* strip off any directives from the filename */ + 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) +{ + 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; + /* can't add or delete from this module DB */ + case SECMOD_MODULE_DB_FUNCTION_ADD: + case SECMOD_MODULE_DB_FUNCTION_DEL: + retString = NULL; + 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);