summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/modutil
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /security/nss/cmd/modutil
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'security/nss/cmd/modutil')
-rw-r--r--security/nss/cmd/modutil/Makefile54
-rw-r--r--security/nss/cmd/modutil/README7
-rw-r--r--security/nss/cmd/modutil/error.h139
-rw-r--r--security/nss/cmd/modutil/install-ds.c1525
-rw-r--r--security/nss/cmd/modutil/install-ds.h260
-rw-r--r--security/nss/cmd/modutil/install.c959
-rw-r--r--security/nss/cmd/modutil/install.h100
-rw-r--r--security/nss/cmd/modutil/installparse.c434
-rw-r--r--security/nss/cmd/modutil/installparse.h7
-rw-r--r--security/nss/cmd/modutil/installparse.l137
-rw-r--r--security/nss/cmd/modutil/installparse.y104
-rw-r--r--security/nss/cmd/modutil/instsec.c153
-rw-r--r--security/nss/cmd/modutil/lex.Pk11Install_yy.c1607
-rw-r--r--security/nss/cmd/modutil/manifest.mn34
-rw-r--r--security/nss/cmd/modutil/modutil.c970
-rw-r--r--security/nss/cmd/modutil/modutil.gyp44
-rw-r--r--security/nss/cmd/modutil/modutil.h40
-rw-r--r--security/nss/cmd/modutil/pk11.c960
-rw-r--r--security/nss/cmd/modutil/pk11jar.html279
-rw-r--r--security/nss/cmd/modutil/rules.mk26
-rw-r--r--security/nss/cmd/modutil/specification.html322
21 files changed, 8161 insertions, 0 deletions
diff --git a/security/nss/cmd/modutil/Makefile b/security/nss/cmd/modutil/Makefile
new file mode 100644
index 000000000..fc7b4b122
--- /dev/null
+++ b/security/nss/cmd/modutil/Makefile
@@ -0,0 +1,54 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (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 $(CORE_DEPTH)/coreconf/zlib.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
+
+#
+# Cancel the built-in implicit yacc and lex rules.
+#
+
+%.c: %.y
+%.c: %.l
diff --git a/security/nss/cmd/modutil/README b/security/nss/cmd/modutil/README
new file mode 100644
index 000000000..12d192c9f
--- /dev/null
+++ b/security/nss/cmd/modutil/README
@@ -0,0 +1,7 @@
+ CRYPTOGRAPHIC MODULE UTILITY (modutil)
+ VERSION 1.0
+ ===============================================
+
+The file specification.html documentats the software.
+
+The file pk11jar.html documents the PKCS #11 JAR format.
diff --git a/security/nss/cmd/modutil/error.h b/security/nss/cmd/modutil/error.h
new file mode 100644
index 000000000..b328afebc
--- /dev/null
+++ b/security/nss/cmd/modutil/error.h
@@ -0,0 +1,139 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MODUTIL_ERROR_H
+#define MODUTIL_ERROR_H
+
+/*
+ * The values of these enumerated constants are immutable and must not be
+ * changed.
+ */
+typedef enum {
+ NO_ERR = 0,
+ INVALID_USAGE_ERR,
+ UNEXPECTED_ARG_ERR,
+ UNKNOWN_OPTION_ERR,
+ MULTIPLE_COMMAND_ERR,
+ OPTION_NEEDS_ARG_ERR,
+ DUPLICATE_OPTION_ERR,
+ MISSING_PARAM_ERR,
+ INVALID_FIPS_ARG,
+ NO_COMMAND_ERR,
+ NO_DBDIR_ERR,
+ FIPS_SWITCH_FAILED_ERR,
+ FIPS_ALREADY_ON_ERR,
+ FIPS_ALREADY_OFF_ERR,
+ FILE_ALREADY_EXISTS_ERR,
+ FILE_DOESNT_EXIST_ERR,
+ FILE_NOT_READABLE_ERR,
+ FILE_NOT_WRITEABLE_ERR,
+ DIR_DOESNT_EXIST_ERR,
+ DIR_NOT_READABLE_ERR,
+ DIR_NOT_WRITEABLE_ERR,
+ INVALID_CONSTANT_ERR,
+ ADD_MODULE_FAILED_ERR,
+ UNUSED_ERR, /* reserved for future use */
+ OUT_OF_MEM_ERR,
+ DELETE_INTERNAL_ERR,
+ DELETE_FAILED_ERR,
+ NO_LIST_LOCK_ERR,
+ NO_MODULE_LIST_ERR,
+ NO_SUCH_MODULE_ERR,
+ MOD_INFO_ERR,
+ SLOT_INFO_ERR,
+ TOKEN_INFO_ERR,
+ NO_SUCH_TOKEN_ERR,
+ CHANGEPW_FAILED_ERR,
+ BAD_PW_ERR,
+ DB_ACCESS_ERR,
+ AUTHENTICATION_FAILED_ERR,
+ NO_SUCH_SLOT_ERR,
+ ENABLE_FAILED_ERR,
+ UPDATE_MOD_FAILED_ERR,
+ DEFAULT_FAILED_ERR,
+ UNDEFAULT_FAILED_ERR,
+ STDIN_READ_ERR,
+ UNSPECIFIED_ERR,
+ NOCERTDB_MISUSE_ERR,
+ NSS_INITIALIZE_FAILED_ERR,
+
+ LAST_ERR /* must be last */
+} Error;
+#define SUCCESS NO_ERR
+
+/* !!! Should move this into its own .c and un-static it. */
+static char *errStrings[] = {
+ "Operation completed successfully.\n",
+ "ERROR: Invalid command line.\n",
+ "ERROR: Not expecting argument \"%s\".\n",
+ "ERROR: Unknown option: %s.\n",
+ "ERROR: %s: multiple commands are not allowed on the command line.\n",
+ "ERROR: %s: option needs an argument.\n",
+ "ERROR: %s: option cannot be given more than once.\n",
+ "ERROR: Command \"%s\" requires parameter \"%s\".\n",
+ "ERROR: Argument to -fips must be \"true\" or \"false\".\n",
+ "ERROR: No command was specified.\n",
+ "ERROR: Cannot determine database directory: use the -dbdir option.\n",
+ "ERROR: Unable to switch FIPS modes.\n",
+ "FIPS mode already enabled.\n",
+ "FIPS mode already disabled.\n",
+ "ERROR: File \"%s\" already exists.\n",
+ "ERROR: File \"%s\" does not exist.\n",
+ "ERROR: File \"%s\" is not readable.\n",
+ "ERROR: File \"%s\" is not writeable.\n",
+ "ERROR: Directory \"%s\" does not exist.\n",
+ "ERROR: Directory \"%s\" is not readable.\n",
+ "ERROR: Directory \"%s\" is not writeable.\n",
+ "\"%s\" is not a recognized value.\n",
+ "ERROR: Failed to add module \"%s\". Probable cause : \"%s\".\n",
+ "Unused error string",
+ "ERROR: Out of memory.\n",
+ "ERROR: Cannot delete internal module.\n",
+ "ERROR: Failed to delete module \"%s\".\n",
+ "ERROR: Unable to obtain lock on module list.\n",
+ "ERROR: Unable to obtain module list.\n",
+ "ERROR: Module \"%s\" not found in database.\n",
+ "ERROR: Unable to get information about module \"%s\".\n",
+ "ERROR: Unable to get information about slot \"%s\".\n",
+ "ERROR: Unable to get information about token \"%s\".\n",
+ "ERROR: Token \"%s\" not found.\n",
+ "ERROR: Unable to change password on token \"%s\".\n",
+ "ERROR: Incorrect password.\n",
+ "ERROR: Unable to access database \"%s\".\n",
+ "ERROR: Unable to authenticate to token \"%s\".\n",
+ "ERROR: Slot \"%s\" not found.\n",
+ "ERROR: Failed to %s slot \"%s\".\n",
+ "ERROR: Failed to update module \"%s\".\n",
+ "ERROR: Failed to change defaults.\n",
+ "ERROR: Failed to change default.\n",
+ "ERROR: Unable to read from standard input.\n",
+ "ERROR: Unknown error occurred.\n",
+ "ERROR: -nocertdb option can only be used with the -jar command.\n"
+ "ERROR: NSS_Initialize() failed.\n"
+};
+
+typedef enum {
+ FIPS_ENABLED_MSG = 0,
+ FIPS_DISABLED_MSG,
+ USING_DBDIR_MSG,
+ CREATING_DB_MSG,
+ ADD_MODULE_SUCCESS_MSG,
+ DELETE_SUCCESS_MSG,
+ CHANGEPW_SUCCESS_MSG,
+ BAD_PW_MSG,
+ PW_MATCH_MSG,
+ DONE_MSG,
+ ENABLE_SUCCESS_MSG,
+ DEFAULT_SUCCESS_MSG,
+ UNDEFAULT_SUCCESS_MSG,
+ BROWSER_RUNNING_MSG,
+ ABORTING_MSG,
+
+ LAST_MSG /* must be last */
+} Message;
+
+/* defined in modutil.c */
+extern char *msgStrings[];
+
+#endif /* MODUTIL_ERROR_H */
diff --git a/security/nss/cmd/modutil/install-ds.c b/security/nss/cmd/modutil/install-ds.c
new file mode 100644
index 000000000..c8fef7897
--- /dev/null
+++ b/security/nss/cmd/modutil/install-ds.c
@@ -0,0 +1,1525 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "install-ds.h"
+#include <prmem.h>
+#include <plstr.h>
+#include <prprf.h>
+#include <string.h>
+
+#define PORT_Strcasecmp PL_strcasecmp
+
+#define MODULE_FILE_STRING "ModuleFile"
+#define MODULE_NAME_STRING "ModuleName"
+#define MECH_FLAGS_STRING "DefaultMechanismFlags"
+#define CIPHER_FLAGS_STRING "DefaultCipherFlags"
+#define FILES_STRING "Files"
+#define FORWARD_COMPATIBLE_STRING "ForwardCompatible"
+#define PLATFORMS_STRING "Platforms"
+#define RELATIVE_DIR_STRING "RelativePath"
+#define ABSOLUTE_DIR_STRING "AbsolutePath"
+#define FILE_PERMISSIONS_STRING "FilePermissions"
+#define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform"
+#define EXECUTABLE_STRING "Executable"
+
+#define DEFAULT_PERMISSIONS 0777
+
+#define PLATFORM_SEPARATOR_CHAR ':'
+
+/* Error codes */
+enum {
+ BOGUS_RELATIVE_DIR = 0,
+ BOGUS_ABSOLUTE_DIR,
+ BOGUS_FILE_PERMISSIONS,
+ NO_RELATIVE_DIR,
+ NO_ABSOLUTE_DIR,
+ EMPTY_PLATFORM_STRING,
+ BOGUS_PLATFORM_STRING,
+ REPEAT_MODULE_FILE,
+ REPEAT_MODULE_NAME,
+ BOGUS_MODULE_FILE,
+ BOGUS_MODULE_NAME,
+ REPEAT_MECH,
+ BOGUS_MECH_FLAGS,
+ REPEAT_CIPHER,
+ BOGUS_CIPHER_FLAGS,
+ REPEAT_FILES,
+ REPEAT_EQUIV,
+ BOGUS_EQUIV,
+ EQUIV_TOO_MUCH_INFO,
+ NO_FILES,
+ NO_MODULE_FILE,
+ NO_MODULE_NAME,
+ NO_PLATFORMS,
+ EQUIV_LOOP,
+ UNKNOWN_MODULE_FILE
+};
+
+/* Indexed by the above error codes */
+static const char* errString[] = {
+ "%s: Invalid relative directory",
+ "%s: Invalid absolute directory",
+ "%s: Invalid file permissions",
+ "%s: No relative directory specified",
+ "%s: No absolute directory specified",
+ "Empty string given for platform name",
+ "%s: invalid platform string",
+ "More than one ModuleFile entry given for platform %s",
+ "More than one ModuleName entry given for platform %s",
+ "Invalid ModuleFile specification for platform %s",
+ "Invalid ModuleName specification for platform %s",
+ "More than one DefaultMechanismFlags entry given for platform %s",
+ "Invalid DefaultMechanismFlags specification for platform %s",
+ "More than one DefaultCipherFlags entry given for platform %s",
+ "Invalid DefaultCipherFlags entry given for platform %s",
+ "More than one Files entry given for platform %s",
+ "More than one EquivalentPlatform entry given for platform %s",
+ "Invalid EquivalentPlatform specification for platform %s",
+ "Module %s uses an EquivalentPlatform but also specifies its own"
+ " information",
+ "No Files specification in module %s",
+ "No ModuleFile specification in module %s",
+ "No ModuleName specification in module %s",
+ "No Platforms specification in installer script",
+ "Platform %s has an equivalency loop",
+ "Module file \"%s\" in platform \"%s\" does not exist"
+};
+
+static char* PR_Strdup(const char* str);
+
+#define PAD(x) \
+ { \
+ int i; \
+ for (i = 0; i < x; i++) \
+ printf(" "); \
+ }
+#define PADINC 4
+
+Pk11Install_File*
+Pk11Install_File_new()
+{
+ Pk11Install_File* new_this;
+ new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File));
+ Pk11Install_File_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_File_init(Pk11Install_File* _this)
+{
+ _this->jarPath = NULL;
+ _this->relativePath = NULL;
+ _this->absolutePath = NULL;
+ _this->executable = PR_FALSE;
+ _this->permissions = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_File
+// Class: Pk11Install_File
+// Notes: Destructor.
+*/
+void
+Pk11Install_File_delete(Pk11Install_File* _this)
+{
+ Pk11Install_File_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_File
+*/
+void
+Pk11Install_File_Cleanup(Pk11Install_File* _this)
+{
+ if (_this->jarPath) {
+ PR_Free(_this->jarPath);
+ _this->jarPath = NULL;
+ }
+ if (_this->relativePath) {
+ PR_Free(_this->relativePath);
+ _this->relativePath = NULL;
+ }
+ if (_this->absolutePath) {
+ PR_Free(_this->absolutePath);
+ _this->absolutePath = NULL;
+ }
+
+ _this->permissions = 0;
+ _this->executable = PR_FALSE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_File
+// Notes: Creates a file data structure from a syntax tree.
+// Returns: NULL for success, otherwise an error message.
+*/
+char*
+Pk11Install_File_Generate(Pk11Install_File* _this,
+ const Pk11Install_Pair* pair)
+{
+ Pk11Install_ListIter* iter;
+ Pk11Install_Value* val;
+ Pk11Install_Pair* subpair;
+ Pk11Install_ListIter* subiter;
+ Pk11Install_Value* subval;
+ char* errStr;
+ char* endp;
+ PRBool gotPerms;
+
+ iter = NULL;
+ subiter = NULL;
+ errStr = NULL;
+ gotPerms = PR_FALSE;
+
+ /* Clear out old values */
+ Pk11Install_File_Cleanup(_this);
+
+ _this->jarPath = PR_Strdup(pair->key);
+
+ /* Go through all the pairs under this file heading */
+ iter = Pk11Install_ListIter_new(pair->list);
+ for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
+ if (val->type == PAIR_VALUE) {
+ subpair = val->pair;
+
+ /* Relative directory */
+ if (!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) {
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR],
+ _this->jarPath);
+ goto loser;
+ }
+ _this->relativePath = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+
+ /* Absolute directory */
+ } else if (!PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) {
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR],
+ _this->jarPath);
+ goto loser;
+ }
+ _this->absolutePath = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+
+ /* file permissions */
+ } else if (!PORT_Strcasecmp(subpair->key,
+ FILE_PERMISSIONS_STRING)) {
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE) ||
+ !subval->string || !subval->string[0]) {
+ errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
+ _this->jarPath);
+ goto loser;
+ }
+ _this->permissions = (int)strtol(subval->string, &endp, 8);
+ if (*endp != '\0') {
+ errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
+ _this->jarPath);
+ goto loser;
+ }
+ gotPerms = PR_TRUE;
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ } else {
+ if (!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) {
+ _this->executable = PR_TRUE;
+ }
+ }
+ }
+
+ /* Default permission value */
+ if (!gotPerms) {
+ _this->permissions = DEFAULT_PERMISSIONS;
+ }
+
+ /* Make sure we got all the information */
+ if (!_this->relativePath && !_this->absolutePath) {
+ errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
+ goto loser;
+ }
+#if 0
+ if(!_this->relativePath ) {
+ errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath);
+ goto loser;
+ }
+ if(!_this->absolutePath) {
+ errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
+ goto loser;
+ }
+#endif
+
+loser:
+ if (iter) {
+ Pk11Install_ListIter_delete(&iter);
+ }
+ if (subiter) {
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_File
+*/
+void
+Pk11Install_File_Print(Pk11Install_File* _this, int pad)
+{
+ PAD(pad);
+ printf("jarPath: %s\n",
+ _this->jarPath ? _this->jarPath : "<NULL>");
+ PAD(pad);
+ printf("relativePath: %s\n",
+ _this->relativePath ? _this->relativePath : "<NULL>");
+ PAD(pad);
+ printf("absolutePath: %s\n",
+ _this->absolutePath ? _this->absolutePath : "<NULL>");
+ PAD(pad);
+ printf("permissions: %o\n", _this->permissions);
+}
+
+Pk11Install_PlatformName*
+Pk11Install_PlatformName_new()
+{
+ Pk11Install_PlatformName* new_this;
+ new_this = (Pk11Install_PlatformName*)
+ PR_Malloc(sizeof(Pk11Install_PlatformName));
+ Pk11Install_PlatformName_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this)
+{
+ _this->OS = NULL;
+ _this->verString = NULL;
+ _this->numDigits = 0;
+ _this->arch = NULL;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_PlatformName
+// Class: Pk11Install_PlatformName
+*/
+void
+Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this)
+{
+ Pk11Install_PlatformName_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_PlatformName
+*/
+void
+Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this)
+{
+ if (_this->OS) {
+ PR_Free(_this->OS);
+ _this->OS = NULL;
+ }
+ if (_this->verString) {
+ int i;
+ for (i = 0; i < _this->numDigits; i++) {
+ PR_Free(_this->verString[i]);
+ }
+ PR_Free(_this->verString);
+ _this->verString = NULL;
+ }
+ if (_this->arch) {
+ PR_Free(_this->arch);
+ _this->arch = NULL;
+ }
+ _this->numDigits = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_PlatformName
+// Notes: Extracts the information from a platform string.
+*/
+char*
+Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this,
+ const char* str)
+{
+ char* errStr;
+ char* copy;
+ char *end, *start; /* start and end of a section (OS, version, arch)*/
+ char *pend, *pstart; /* start and end of one portion of version*/
+ char* endp; /* used by strtol*/
+ int periods, i;
+
+ errStr = NULL;
+ copy = NULL;
+
+ if (!str) {
+ errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]);
+ goto loser;
+ }
+ copy = PR_Strdup(str);
+
+ /*
+ // Get the OS
+ */
+ end = strchr(copy, PLATFORM_SEPARATOR_CHAR);
+ if (!end || end == copy) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ *end = '\0';
+
+ _this->OS = PR_Strdup(copy);
+
+ /*
+ // Get the digits of the version of form: x.x.x (arbitrary number of digits)
+ */
+
+ start = end + 1;
+ end = strchr(start, PLATFORM_SEPARATOR_CHAR);
+ if (!end) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ *end = '\0';
+
+ if (end != start) {
+ /* Find out how many periods*/
+ periods = 0;
+ pstart = start;
+ while ((pend = strchr(pstart, '.'))) {
+ periods++;
+ pstart = pend + 1;
+ }
+ _this->numDigits = 1 + periods;
+ _this->verString = (char**)PR_Malloc(sizeof(char*) * _this->numDigits);
+
+ pstart = start;
+ i = 0;
+ /* Get the digits before each period*/
+ while ((pend = strchr(pstart, '.'))) {
+ if (pend == pstart) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ *pend = '\0';
+ _this->verString[i] = PR_Strdup(pstart);
+ endp = pend;
+ if (endp == pstart || (*endp != '\0')) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ pstart = pend + 1;
+ i++;
+ }
+ /* Last digit comes after the last period*/
+ if (*pstart == '\0') {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ _this->verString[i] = PR_Strdup(pstart);
+ /*
+ if(endp==pstart || (*endp != '\0')) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ */
+ } else {
+ _this->verString = NULL;
+ _this->numDigits = 0;
+ }
+
+ /*
+ // Get the architecture
+ */
+ start = end + 1;
+ if (strchr(start, PLATFORM_SEPARATOR_CHAR)) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ _this->arch = PR_Strdup(start);
+
+ if (copy) {
+ PR_Free(copy);
+ }
+ return NULL;
+loser:
+ if (_this->OS) {
+ PR_Free(_this->OS);
+ _this->OS = NULL;
+ }
+ if (_this->verString) {
+ for (i = 0; i < _this->numDigits; i++) {
+ PR_Free(_this->verString[i]);
+ }
+ PR_Free(_this->verString);
+ _this->verString = NULL;
+ }
+ _this->numDigits = 0;
+ if (_this->arch) {
+ PR_Free(_this->arch);
+ _this->arch = NULL;
+ }
+ if (copy) {
+ PR_Free(copy);
+ }
+
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: operator ==
+// Class: Pk11Install_PlatformName
+// Returns: PR_TRUE if the platform have the same OS, arch, and version
+*/
+PRBool
+Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp)
+{
+ int i;
+
+ if (!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
+ return PR_FALSE;
+ }
+
+ if (PORT_Strcasecmp(_this->OS, cmp->OS) ||
+ PORT_Strcasecmp(_this->arch, cmp->arch) ||
+ _this->numDigits != cmp->numDigits) {
+ return PR_FALSE;
+ }
+
+ for (i = 0; i < _this->numDigits; i++) {
+ if (PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) {
+ return PR_FALSE;
+ }
+ }
+ return PR_TRUE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: operator <=
+// Class: Pk11Install_PlatformName
+// Returns: PR_TRUE if the platform have the same OS and arch and a lower
+// or equal release.
+*/
+PRBool
+Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp)
+{
+ return (Pk11Install_PlatformName_equal(_this, cmp) ||
+ Pk11Install_PlatformName_lt(_this, cmp))
+ ? PR_TRUE
+ : PR_FALSE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: operator <
+// Class: Pk11Install_PlatformName
+// Returns: PR_TRUE if the platform have the same OS and arch and a greater
+// release.
+*/
+PRBool
+Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp)
+{
+ int i, scmp;
+
+ if (!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
+ return PR_FALSE;
+ }
+
+ if (PORT_Strcasecmp(_this->OS, cmp->OS)) {
+ return PR_FALSE;
+ }
+ if (PORT_Strcasecmp(_this->arch, cmp->arch)) {
+ return PR_FALSE;
+ }
+
+ for (i = 0; (i < _this->numDigits) && (i < cmp->numDigits); i++) {
+ scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]);
+ if (scmp > 0) {
+ return PR_FALSE;
+ } else if (scmp < 0) {
+ return PR_TRUE;
+ }
+ }
+ /* All the digits they have in common are the same. */
+ if (_this->numDigits < cmp->numDigits) {
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: GetString
+// Class: Pk11Install_PlatformName
+// Returns: String composed of OS, release, and architecture separated
+// by the separator char. Memory is allocated by this function
+// but is the responsibility of the caller to de-allocate.
+*/
+char*
+Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this)
+{
+ char* ret;
+ char* ver;
+ char* OS_;
+ char* arch_;
+
+ OS_ = NULL;
+ arch_ = NULL;
+
+ OS_ = _this->OS ? _this->OS : "";
+ arch_ = _this->arch ? _this->arch : "";
+
+ ver = Pk11Install_PlatformName_GetVerString(_this);
+ ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver,
+ PLATFORM_SEPARATOR_CHAR, arch_);
+
+ PR_Free(ver);
+
+ return ret;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: GetVerString
+// Class: Pk11Install_PlatformName
+// Returns: The version string for this platform, in the form x.x.x with an
+// arbitrary number of digits. Memory allocated by function,
+// must be de-allocated by caller.
+*/
+char*
+Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this)
+{
+ char* tmp;
+ char* ret;
+ int i;
+ char buf[80];
+
+ tmp = (char*)PR_Malloc(80 * _this->numDigits + 1);
+ tmp[0] = '\0';
+
+ for (i = 0; i < _this->numDigits - 1; i++) {
+ sprintf(buf, "%s.", _this->verString[i]);
+ strcat(tmp, buf);
+ }
+ if (i < _this->numDigits) {
+ sprintf(buf, "%s", _this->verString[i]);
+ strcat(tmp, buf);
+ }
+
+ ret = PR_Strdup(tmp);
+ free(tmp);
+
+ return ret;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_PlatformName
+*/
+void
+Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad)
+{
+ char* str = NULL;
+ PAD(pad);
+ printf("OS: %s\n", _this->OS ? _this->OS : "<NULL>");
+ PAD(pad);
+ printf("Digits: ");
+ if (_this->numDigits == 0) {
+ printf("None\n");
+ } else {
+ str = Pk11Install_PlatformName_GetVerString(_this);
+ printf("%s\n", str);
+ PR_Free(str);
+ }
+ PAD(pad);
+ printf("arch: %s\n", _this->arch ? _this->arch : "<NULL>");
+}
+
+Pk11Install_Platform*
+Pk11Install_Platform_new()
+{
+ Pk11Install_Platform* new_this;
+ new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform));
+ Pk11Install_Platform_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_Platform_init(Pk11Install_Platform* _this)
+{
+ Pk11Install_PlatformName_init(&_this->name);
+ Pk11Install_PlatformName_init(&_this->equivName);
+ _this->equiv = NULL;
+ _this->usesEquiv = PR_FALSE;
+ _this->moduleFile = NULL;
+ _this->moduleName = NULL;
+ _this->modFile = -1;
+ _this->mechFlags = 0;
+ _this->cipherFlags = 0;
+ _this->files = NULL;
+ _this->numFiles = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_Platform
+// Class: Pk11Install_Platform
+*/
+void
+Pk11Install_Platform_delete(Pk11Install_Platform* _this)
+{
+ Pk11Install_Platform_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_Platform
+*/
+void
+Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this)
+{
+ int i;
+ if (_this->moduleFile) {
+ PR_Free(_this->moduleFile);
+ _this->moduleFile = NULL;
+ }
+ if (_this->moduleName) {
+ PR_Free(_this->moduleName);
+ _this->moduleName = NULL;
+ }
+ if (_this->files) {
+ for (i = 0; i < _this->numFiles; i++) {
+ Pk11Install_File_delete(&_this->files[i]);
+ }
+ PR_Free(_this->files);
+ _this->files = NULL;
+ }
+ _this->equiv = NULL;
+ _this->usesEquiv = PR_FALSE;
+ _this->modFile = -1;
+ _this->numFiles = 0;
+ _this->mechFlags = _this->cipherFlags = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_Platform
+// Notes: Creates a platform data structure from a syntax tree.
+// Returns: NULL for success, otherwise an error message.
+*/
+char*
+Pk11Install_Platform_Generate(Pk11Install_Platform* _this,
+ const Pk11Install_Pair* pair)
+{
+ char* errStr;
+ char* endptr;
+ char* tmp;
+ int i;
+ Pk11Install_ListIter* iter;
+ Pk11Install_Value* val;
+ Pk11Install_Value* subval;
+ Pk11Install_Pair* subpair;
+ Pk11Install_ListIter* subiter;
+ PRBool gotModuleFile, gotModuleName, gotMech,
+ gotCipher, gotFiles, gotEquiv;
+
+ errStr = NULL;
+ iter = subiter = NULL;
+ val = subval = NULL;
+ subpair = NULL;
+ gotModuleFile = gotModuleName = gotMech = gotCipher = gotFiles = gotEquiv = PR_FALSE;
+ Pk11Install_Platform_Cleanup(_this);
+
+ errStr = Pk11Install_PlatformName_Generate(&_this->name, pair->key);
+ if (errStr) {
+ tmp = PR_smprintf("%s: %s", pair->key, errStr);
+ PR_smprintf_free(errStr);
+ errStr = tmp;
+ goto loser;
+ }
+
+ iter = Pk11Install_ListIter_new(pair->list);
+ for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
+ if (val->type == PAIR_VALUE) {
+ subpair = val->pair;
+
+ if (!PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) {
+ if (gotModuleFile) {
+ errStr = PR_smprintf(errString[REPEAT_MODULE_FILE],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_MODULE_FILE],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->moduleFile = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+ gotModuleFile = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)) {
+ if (gotModuleName) {
+ errStr = PR_smprintf(errString[REPEAT_MODULE_NAME],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_MODULE_NAME],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->moduleName = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+ gotModuleName = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) {
+ endptr = NULL;
+
+ if (gotMech) {
+ errStr = PR_smprintf(errString[REPEAT_MECH],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->mechFlags = strtol(subval->string, &endptr, 0);
+ if (*endptr != '\0' || (endptr == subval->string)) {
+ errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ gotMech = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, CIPHER_FLAGS_STRING)) {
+ endptr = NULL;
+
+ if (gotCipher) {
+ errStr = PR_smprintf(errString[REPEAT_CIPHER],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->cipherFlags = strtol(subval->string, &endptr, 0);
+ if (*endptr != '\0' || (endptr == subval->string)) {
+ errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ gotCipher = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, FILES_STRING)) {
+ if (gotFiles) {
+ errStr = PR_smprintf(errString[REPEAT_FILES],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ _this->numFiles = subpair->list->numPairs;
+ _this->files = (Pk11Install_File*)
+ PR_Malloc(sizeof(Pk11Install_File) * _this->numFiles);
+ for (i = 0; i < _this->numFiles; i++,
+ Pk11Install_ListIter_nextItem(subiter)) {
+ Pk11Install_File_init(&_this->files[i]);
+ val = subiter->current;
+ if (val && (val->type == PAIR_VALUE)) {
+ errStr = Pk11Install_File_Generate(&_this->files[i], val->pair);
+ if (errStr) {
+ tmp = PR_smprintf("%s: %s",
+ Pk11Install_PlatformName_GetString(&_this->name), errStr);
+ PR_smprintf_free(errStr);
+ errStr = tmp;
+ goto loser;
+ }
+ }
+ }
+ gotFiles = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key,
+ EQUIVALENT_PLATFORM_STRING)) {
+ if (gotEquiv) {
+ errStr = PR_smprintf(errString[REPEAT_EQUIV],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_EQUIV],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ errStr = Pk11Install_PlatformName_Generate(&_this->equivName,
+ subval->string);
+ if (errStr) {
+ tmp = PR_smprintf("%s: %s",
+ Pk11Install_PlatformName_GetString(&_this->name), errStr);
+ tmp = PR_smprintf("%s: %s",
+ Pk11Install_PlatformName_GetString(&_this->name), errStr);
+ PR_smprintf_free(errStr);
+ errStr = tmp;
+ goto loser;
+ }
+ _this->usesEquiv = PR_TRUE;
+ }
+ }
+ }
+
+ /* Make sure we either have an EquivalentPlatform or all the other info */
+ if (_this->usesEquiv &&
+ (gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) {
+ errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ if (!gotFiles && !_this->usesEquiv) {
+ errStr = PR_smprintf(errString[NO_FILES],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ if (!gotModuleFile && !_this->usesEquiv) {
+ errStr = PR_smprintf(errString[NO_MODULE_FILE],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ if (!gotModuleName && !_this->usesEquiv) {
+ errStr = PR_smprintf(errString[NO_MODULE_NAME],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+
+ /* Point the modFile pointer to the correct file */
+ if (gotModuleFile) {
+ for (i = 0; i < _this->numFiles; i++) {
+ if (!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath)) {
+ _this->modFile = i;
+ break;
+ }
+ }
+ if (_this->modFile == -1) {
+ errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE],
+ _this->moduleFile,
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ }
+
+loser:
+ if (iter) {
+ PR_Free(iter);
+ }
+ if (subiter) {
+ PR_Free(subiter);
+ }
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_Platform
+*/
+void
+Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad)
+{
+ int i;
+
+ PAD(pad);
+ printf("Name:\n");
+ Pk11Install_PlatformName_Print(&_this->name, pad + PADINC);
+ PAD(pad);
+ printf("equivName:\n");
+ Pk11Install_PlatformName_Print(&_this->equivName, pad + PADINC);
+ PAD(pad);
+ if (_this->usesEquiv) {
+ printf("Uses equiv, which points to:\n");
+ Pk11Install_Platform_Print(_this->equiv, pad + PADINC);
+ } else {
+ printf("Doesn't use equiv\n");
+ }
+ PAD(pad);
+ printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile
+ : "<NULL>");
+ PAD(pad);
+ printf("mechFlags: %lx\n", _this->mechFlags);
+ PAD(pad);
+ printf("cipherFlags: %lx\n", _this->cipherFlags);
+ PAD(pad);
+ printf("Files:\n");
+ for (i = 0; i < _this->numFiles; i++) {
+ Pk11Install_File_Print(&_this->files[i], pad + PADINC);
+ PAD(pad);
+ printf("--------------------\n");
+ }
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Pk11Install_Info
+// Class: Pk11Install_Info
+*/
+Pk11Install_Info*
+Pk11Install_Info_new()
+{
+ Pk11Install_Info* new_this;
+ new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info));
+ Pk11Install_Info_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_Info_init(Pk11Install_Info* _this)
+{
+ _this->platforms = NULL;
+ _this->numPlatforms = 0;
+ _this->forwardCompatible = NULL;
+ _this->numForwardCompatible = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_Info
+// Class: Pk11Install_Info
+*/
+void
+Pk11Install_Info_delete(Pk11Install_Info* _this)
+{
+ Pk11Install_Info_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_Info
+*/
+void
+Pk11Install_Info_Cleanup(Pk11Install_Info* _this)
+{
+ int i;
+ if (_this->platforms) {
+ for (i = 0; i < _this->numPlatforms; i++) {
+ Pk11Install_Platform_delete(&_this->platforms[i]);
+ }
+ PR_Free(&_this->platforms);
+ _this->platforms = NULL;
+ _this->numPlatforms = 0;
+ }
+
+ if (_this->forwardCompatible) {
+ for (i = 0; i < _this->numForwardCompatible; i++) {
+ Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]);
+ }
+ PR_Free(&_this->forwardCompatible);
+ _this->numForwardCompatible = 0;
+ }
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_Info
+// Takes: Pk11Install_ValueList *list, the top-level list
+// resulting from parsing an installer file.
+// Returns: char*, NULL if successful, otherwise an error string.
+// Caller is responsible for freeing memory.
+*/
+char*
+Pk11Install_Info_Generate(Pk11Install_Info* _this,
+ const Pk11Install_ValueList* list)
+{
+ char* errStr;
+ Pk11Install_ListIter* iter;
+ Pk11Install_Value* val;
+ Pk11Install_Pair* pair;
+ Pk11Install_ListIter* subiter;
+ Pk11Install_Value* subval;
+ Pk11Install_Platform *first, *second;
+ int i, j;
+
+ errStr = NULL;
+ iter = subiter = NULL;
+ Pk11Install_Info_Cleanup(_this);
+
+ iter = Pk11Install_ListIter_new(list);
+ for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
+ if (val->type == PAIR_VALUE) {
+ pair = val->pair;
+
+ if (!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) {
+ subiter = Pk11Install_ListIter_new(pair->list);
+ _this->numForwardCompatible = pair->list->numStrings;
+ _this->forwardCompatible = (Pk11Install_PlatformName*)
+ PR_Malloc(sizeof(Pk11Install_PlatformName) *
+ _this->numForwardCompatible);
+ for (i = 0; i < _this->numForwardCompatible; i++,
+ Pk11Install_ListIter_nextItem(subiter)) {
+ subval = subiter->current;
+ if (subval->type == STRING_VALUE) {
+ errStr = Pk11Install_PlatformName_Generate(
+ &_this->forwardCompatible[i], subval->string);
+ if (errStr) {
+ goto loser;
+ }
+ }
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ } else if (!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) {
+ subiter = Pk11Install_ListIter_new(pair->list);
+ _this->numPlatforms = pair->list->numPairs;
+ _this->platforms = (Pk11Install_Platform*)
+ PR_Malloc(sizeof(Pk11Install_Platform) *
+ _this->numPlatforms);
+ for (i = 0; i < _this->numPlatforms; i++,
+ Pk11Install_ListIter_nextItem(subiter)) {
+ Pk11Install_Platform_init(&_this->platforms[i]);
+ subval = subiter->current;
+ if (subval->type == PAIR_VALUE) {
+ errStr = Pk11Install_Platform_Generate(&_this->platforms[i], subval->pair);
+ if (errStr) {
+ goto loser;
+ }
+ }
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ }
+ }
+
+ if (_this->numPlatforms == 0) {
+ errStr = PR_smprintf(errString[NO_PLATFORMS]);
+ goto loser;
+ }
+
+ /*
+ //
+ // Now process equivalent platforms
+ //
+
+ // First the naive pass
+ */
+ for (i = 0; i < _this->numPlatforms; i++) {
+ if (_this->platforms[i].usesEquiv) {
+ _this->platforms[i].equiv = NULL;
+ for (j = 0; j < _this->numPlatforms; j++) {
+ if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName,
+ &_this->platforms[j].name)) {
+ if (i == j) {
+ errStr = PR_smprintf(errString[EQUIV_LOOP],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ _this->platforms[i].equiv = &_this->platforms[j];
+ break;
+ }
+ }
+ if (_this->platforms[i].equiv == NULL) {
+ errStr = PR_smprintf(errString[BOGUS_EQUIV],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ }
+ }
+
+ /*
+ // Now the intelligent pass, which will also detect loops.
+ // We will send two pointers through the linked list of equivalent
+ // platforms. Both start with the current node. "first" traverses
+ // two nodes for each iteration. "second" lags behind, only traversing
+ // one node per iteration. Eventually one of two things will happen:
+ // first will hit the end of the list (a platform that doesn't use
+ // an equivalency), or first will equal second if there is a loop.
+ */
+ for (i = 0; i < _this->numPlatforms; i++) {
+ if (_this->platforms[i].usesEquiv) {
+ second = _this->platforms[i].equiv;
+ if (!second->usesEquiv) {
+ /* The first link is the terminal node */
+ continue;
+ }
+ first = second->equiv;
+ while (first->usesEquiv) {
+ if (first == second) {
+ errStr = PR_smprintf(errString[EQUIV_LOOP],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ first = first->equiv;
+ if (!first->usesEquiv) {
+ break;
+ }
+ if (first == second) {
+ errStr = PR_smprintf(errString[EQUIV_LOOP],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ second = second->equiv;
+ first = first->equiv;
+ }
+ _this->platforms[i].equiv = first;
+ }
+ }
+
+loser:
+ if (iter) {
+ Pk11Install_ListIter_delete(&iter);
+ }
+ if (subiter) {
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: GetBestPlatform
+// Class: Pk11Install_Info
+// Takes: char *myPlatform, the platform we are currently running
+// on.
+*/
+Pk11Install_Platform*
+Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char* myPlatform)
+{
+ Pk11Install_PlatformName plat;
+ char* errStr;
+ int i, j;
+
+ errStr = NULL;
+
+ Pk11Install_PlatformName_init(&plat);
+ if ((errStr = Pk11Install_PlatformName_Generate(&plat, myPlatform))) {
+ PR_smprintf_free(errStr);
+ return NULL;
+ }
+
+ /* First try real platforms */
+ for (i = 0; i < _this->numPlatforms; i++) {
+ if (Pk11Install_PlatformName_equal(&_this->platforms[i].name, &plat)) {
+ if (_this->platforms[i].equiv) {
+ return _this->platforms[i].equiv;
+ } else {
+ return &_this->platforms[i];
+ }
+ }
+ }
+
+ /* Now try forward compatible platforms */
+ for (i = 0; i < _this->numForwardCompatible; i++) {
+ if (Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i], &plat)) {
+ break;
+ }
+ }
+ if (i == _this->numForwardCompatible) {
+ return NULL;
+ }
+
+ /* Got a forward compatible name, find the actual platform. */
+ for (j = 0; j < _this->numPlatforms; j++) {
+ if (Pk11Install_PlatformName_equal(&_this->platforms[j].name,
+ &_this->forwardCompatible[i])) {
+ if (_this->platforms[j].equiv) {
+ return _this->platforms[j].equiv;
+ } else {
+ return &_this->platforms[j];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_Info
+*/
+void
+Pk11Install_Info_Print(Pk11Install_Info* _this, int pad)
+{
+ int i;
+
+ PAD(pad);
+ printf("Forward Compatible:\n");
+ for (i = 0; i < _this->numForwardCompatible; i++) {
+ Pk11Install_PlatformName_Print(&_this->forwardCompatible[i], pad + PADINC);
+ PAD(pad);
+ printf("-------------------\n");
+ }
+ PAD(pad);
+ printf("Platforms:\n");
+ for (i = 0; i < _this->numPlatforms; i++) {
+ Pk11Install_Platform_Print(&_this->platforms[i], pad + PADINC);
+ PAD(pad);
+ printf("-------------------\n");
+ }
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+*/
+static char*
+PR_Strdup(const char* str)
+{
+ char* tmp;
+ tmp = (char*)PR_Malloc((unsigned int)(strlen(str) + 1));
+ strcpy(tmp, str);
+ return tmp;
+}
+
+/* The global value list, the top of the tree */
+Pk11Install_ValueList* Pk11Install_valueList = NULL;
+
+/****************************************************************************/
+void
+Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this,
+ Pk11Install_Value* item)
+{
+ _this->numItems++;
+ if (item->type == STRING_VALUE) {
+ _this->numStrings++;
+ } else {
+ _this->numPairs++;
+ }
+ item->next = _this->head;
+ _this->head = item;
+}
+
+/****************************************************************************/
+Pk11Install_ListIter*
+Pk11Install_ListIter_new_default()
+{
+ Pk11Install_ListIter* new_this;
+ new_this = (Pk11Install_ListIter*)
+ PR_Malloc(sizeof(Pk11Install_ListIter));
+ Pk11Install_ListIter_init(new_this);
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ListIter_init(Pk11Install_ListIter* _this)
+{
+ _this->list = NULL;
+ _this->current = NULL;
+}
+
+/****************************************************************************/
+Pk11Install_ListIter*
+Pk11Install_ListIter_new(const Pk11Install_ValueList* _list)
+{
+ Pk11Install_ListIter* new_this;
+ new_this = (Pk11Install_ListIter*)
+ PR_Malloc(sizeof(Pk11Install_ListIter));
+ new_this->list = _list;
+ new_this->current = _list->head;
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ListIter_delete(Pk11Install_ListIter** _this)
+{
+ (*_this)->list = NULL;
+ (*_this)->current = NULL;
+ PR_Free(*_this);
+ *_this = NULL;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ListIter_reset(Pk11Install_ListIter* _this)
+{
+ if (_this->list) {
+ _this->current = _this->list->head;
+ }
+}
+
+/*************************************************************************/
+Pk11Install_Value*
+Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this)
+{
+ if (_this->current) {
+ _this->current = _this->current->next;
+ }
+
+ return _this->current;
+}
+
+/****************************************************************************/
+Pk11Install_ValueList*
+Pk11Install_ValueList_new()
+{
+ Pk11Install_ValueList* new_this;
+ new_this = (Pk11Install_ValueList*)
+ PR_Malloc(sizeof(Pk11Install_ValueList));
+ new_this->numItems = 0;
+ new_this->numPairs = 0;
+ new_this->numStrings = 0;
+ new_this->head = NULL;
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ValueList_delete(Pk11Install_ValueList* _this)
+{
+
+ Pk11Install_Value* tmp;
+ Pk11Install_Value* list;
+ list = _this->head;
+
+ while (list != NULL) {
+ tmp = list;
+ list = list->next;
+ PR_Free(tmp);
+ }
+ PR_Free(_this);
+}
+
+/****************************************************************************/
+Pk11Install_Value*
+Pk11Install_Value_new_default()
+{
+ Pk11Install_Value* new_this;
+ new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value));
+ new_this->type = STRING_VALUE;
+ new_this->string = NULL;
+ new_this->pair = NULL;
+ new_this->next = NULL;
+ return new_this;
+}
+
+/****************************************************************************/
+Pk11Install_Value*
+Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr)
+{
+ Pk11Install_Value* new_this;
+ new_this = Pk11Install_Value_new_default();
+ new_this->type = _type;
+ if (_type == STRING_VALUE) {
+ new_this->pair = NULL;
+ new_this->string = ptr.string;
+ } else {
+ new_this->string = NULL;
+ new_this->pair = ptr.pair;
+ }
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_Value_delete(Pk11Install_Value* _this)
+{
+ if (_this->type == STRING_VALUE) {
+ PR_Free(_this->string);
+ } else {
+ PR_Free(_this->pair);
+ }
+}
+
+/****************************************************************************/
+Pk11Install_Pair*
+Pk11Install_Pair_new_default()
+{
+ return Pk11Install_Pair_new(NULL, NULL);
+}
+
+/****************************************************************************/
+Pk11Install_Pair*
+Pk11Install_Pair_new(char* _key, Pk11Install_ValueList* _list)
+{
+ Pk11Install_Pair* new_this;
+ new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair));
+ new_this->key = _key;
+ new_this->list = _list;
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_Pair_delete(Pk11Install_Pair* _this)
+{
+ PR_Free(_this->key);
+ Pk11Install_ValueList_delete(_this->list);
+}
+
+/*************************************************************************/
+void
+Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad)
+{
+ while (_this) {
+ /*PAD(pad); printf("**Pair\n");
+ PAD(pad); printf("***Key====\n");*/
+ PAD(pad);
+ printf("%s {\n", _this->key);
+ /*PAD(pad); printf("====\n");*/
+ /*PAD(pad); printf("***ValueList\n");*/
+ Pk11Install_ValueList_Print(_this->list, pad + PADINC);
+ PAD(pad);
+ printf("}\n");
+ }
+}
+
+/*************************************************************************/
+void
+Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad)
+{
+ Pk11Install_Value* v;
+
+ /*PAD(pad);printf("**Value List**\n");*/
+ for (v = _this->head; v != NULL; v = v->next) {
+ Pk11Install_Value_Print(v, pad);
+ }
+}
+
+/*************************************************************************/
+void
+Pk11Install_Value_Print(Pk11Install_Value* _this, int pad)
+{
+ /*PAD(pad); printf("**Value, type=%s\n",
+ type==STRING_VALUE ? "string" : "pair");*/
+ if (_this->type == STRING_VALUE) {
+ /*PAD(pad+PADINC); printf("====\n");*/
+ PAD(pad);
+ printf("%s\n", _this->string);
+ /*PAD(pad+PADINC); printf("====\n");*/
+ } else {
+ Pk11Install_Pair_Print(_this->pair, pad + PADINC);
+ }
+}
diff --git a/security/nss/cmd/modutil/install-ds.h b/security/nss/cmd/modutil/install-ds.h
new file mode 100644
index 000000000..70813f603
--- /dev/null
+++ b/security/nss/cmd/modutil/install-ds.h
@@ -0,0 +1,260 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef INSTALL_DS_H
+#define INSTALL_DS_H
+
+#include <stdio.h>
+#include <prio.h>
+#include <prmem.h>
+
+extern PRFileDesc* Pk11Install_FD;
+extern int Pk11Install_yylex();
+extern int Pk11Install_yylinenum;
+extern char* Pk11Install_yyerrstr;
+
+typedef enum { STRING_VALUE,
+ PAIR_VALUE } ValueType;
+
+typedef struct Pk11Install_Pair_str Pk11Install_Pair;
+typedef union Pk11Install_Pointer_str Pk11Install_Pointer;
+typedef struct Pk11Install_Value_str Pk11Install_Value;
+typedef struct Pk11Install_ValueList_str Pk11Install_ValueList;
+typedef struct Pk11Install_ListIter_str Pk11Install_ListIter;
+typedef struct Pk11Install_File_str Pk11Install_File;
+typedef struct Pk11Install_PlatformName_str Pk11Install_PlatformName;
+typedef struct Pk11Install_Platform_str Pk11Install_Platform;
+typedef struct Pk11Install_Info_str Pk11Install_Info;
+
+extern Pk11Install_Pointer Pk11Install_yylval;
+extern Pk11Install_ValueList* Pk11Install_valueList;
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Pk11Install_Pair
+//////////////////////////////////////////////////////////////////////////
+*/
+
+struct Pk11Install_Pair_str {
+ char* key;
+ Pk11Install_ValueList* list;
+};
+
+Pk11Install_Pair*
+Pk11Install_Pair_new_default();
+Pk11Install_Pair*
+Pk11Install_Pair_new(char* _key, Pk11Install_ValueList* _list);
+void
+Pk11Install_Pair_delete(Pk11Install_Pair* _this);
+void
+Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad);
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Pk11Install_Pointer
+//////////////////////////////////////////////////////////////////////////
+*/
+union Pk11Install_Pointer_str {
+ Pk11Install_ValueList* list;
+ Pk11Install_Value* value;
+ Pk11Install_Pair* pair;
+ char* string;
+};
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Pk11Install_Value
+//////////////////////////////////////////////////////////////////////////
+*/
+struct Pk11Install_Value_str {
+
+ ValueType type;
+ char* string;
+ Pk11Install_Pair* pair;
+ struct Pk11Install_Value_str* next;
+};
+
+Pk11Install_Value*
+Pk11Install_Value_new_default();
+Pk11Install_Value*
+Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr);
+void
+Pk11Install_Value_delete(Pk11Install_Value* _this);
+void
+Pk11Install_Value_Print(Pk11Install_Value* _this, int pad);
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Pk11Install_ValueList
+//////////////////////////////////////////////////////////////////////////
+*/
+struct Pk11Install_ValueList_str {
+ int numItems;
+ int numPairs;
+ int numStrings;
+ Pk11Install_Value* head;
+};
+
+Pk11Install_ValueList*
+Pk11Install_ValueList_new();
+void
+Pk11Install_ValueList_delete(Pk11Install_ValueList* _this);
+void
+Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this,
+ Pk11Install_Value* item);
+void
+Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad);
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Pk11Install_ListIter
+//////////////////////////////////////////////////////////////////////////
+*/
+struct Pk11Install_ListIter_str {
+ const Pk11Install_ValueList* list;
+ Pk11Install_Value* current;
+};
+
+Pk11Install_ListIter*
+Pk11Install_ListIter_new_default();
+void
+Pk11Install_ListIter_init(Pk11Install_ListIter* _this);
+Pk11Install_ListIter*
+Pk11Install_ListIter_new(const Pk11Install_ValueList* _list);
+void
+Pk11Install_ListIter_delete(Pk11Install_ListIter** _this);
+void
+Pk11Install_ListIter_reset(Pk11Install_ListIter* _this);
+Pk11Install_Value*
+Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this);
+
+/************************************************************************
+ *
+ * Pk11Install_File
+ */
+struct Pk11Install_File_str {
+ char* jarPath;
+ char* relativePath;
+ char* absolutePath;
+ PRBool executable;
+ int permissions;
+};
+
+Pk11Install_File*
+Pk11Install_File_new();
+void
+Pk11Install_File_init(Pk11Install_File* _this);
+void
+Pk11Install_file_delete(Pk11Install_File* _this);
+/*// Parses a syntax tree to obtain all attributes.
+// Returns NULL for success, error message if parse error.*/
+char*
+Pk11Install_File_Generate(Pk11Install_File* _this,
+ const Pk11Install_Pair* pair);
+void
+Pk11Install_File_Print(Pk11Install_File* _this, int pad);
+void
+Pk11Install_File_Cleanup(Pk11Install_File* _this);
+
+/************************************************************************
+ *
+ * Pk11Install_PlatformName
+ */
+struct Pk11Install_PlatformName_str {
+ char* OS;
+ char** verString;
+ int numDigits;
+ char* arch;
+};
+
+Pk11Install_PlatformName*
+Pk11Install_PlatformName_new();
+void
+Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this);
+void
+Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this);
+char*
+Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this,
+ const char* str);
+char*
+Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this);
+char*
+Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this);
+void
+Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad);
+void
+Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this);
+PRBool
+Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp);
+PRBool
+Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp);
+PRBool
+Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp);
+
+/************************************************************************
+ *
+ * Pk11Install_Platform
+ */
+struct Pk11Install_Platform_str {
+ Pk11Install_PlatformName name;
+ Pk11Install_PlatformName equivName;
+ struct Pk11Install_Platform_str* equiv;
+ PRBool usesEquiv;
+ char* moduleFile;
+ char* moduleName;
+ int modFile;
+ unsigned long mechFlags;
+ unsigned long cipherFlags;
+ Pk11Install_File* files;
+ int numFiles;
+};
+
+Pk11Install_Platform*
+Pk11Install_Platform_new();
+void
+Pk11Install_Platform_init(Pk11Install_Platform* _this);
+void
+Pk11Install_Platform_delete(Pk11Install_Platform* _this);
+/*// Returns NULL for success, error message if parse error.*/
+char*
+Pk11Install_Platform_Generate(Pk11Install_Platform* _this,
+ const Pk11Install_Pair* pair);
+void
+Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad);
+void
+Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this);
+
+/************************************************************************
+ *
+ * Pk11Install_Info
+ */
+struct Pk11Install_Info_str {
+ Pk11Install_Platform* platforms;
+ int numPlatforms;
+ Pk11Install_PlatformName* forwardCompatible;
+ int numForwardCompatible;
+};
+
+Pk11Install_Info*
+Pk11Install_Info_new();
+void
+Pk11Install_Info_init(Pk11Install_Info* _this);
+void
+Pk11Install_Info_delete(Pk11Install_Info* _this);
+/*// Returns NULL for success, error message if parse error.*/
+char*
+Pk11Install_Info_Generate(Pk11Install_Info* _this,
+ const Pk11Install_ValueList* list);
+/*// Returns NULL if there is no matching platform*/
+Pk11Install_Platform*
+Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char* myPlatform);
+void
+Pk11Install_Info_Print(Pk11Install_Info* _this, int pad);
+void
+Pk11Install_Info_Cleanup(Pk11Install_Info* _this);
+
+#endif /* INSTALL_DS_H */
diff --git a/security/nss/cmd/modutil/install.c b/security/nss/cmd/modutil/install.c
new file mode 100644
index 000000000..ea4aeb77c
--- /dev/null
+++ b/security/nss/cmd/modutil/install.c
@@ -0,0 +1,959 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "install.h"
+#include "install-ds.h"
+#include <prerror.h>
+#include <prlock.h>
+#include <prio.h>
+#include <prmem.h>
+#include <prprf.h>
+#include <prsystem.h>
+#include <prproces.h>
+
+#ifdef XP_UNIX
+/* for chmod */
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+/*extern "C" {*/
+#include <jar.h>
+/*}*/
+
+extern /*"C"*/
+ int
+ Pk11Install_AddNewModule(char *moduleName, char *dllPath,
+ unsigned long defaultMechanismFlags,
+ unsigned long cipherEnableFlags);
+extern /*"C"*/
+ short
+ Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out,
+ PRBool query);
+extern /*"C"*/
+ const char *
+ mySECU_ErrorString(PRErrorCode errnum);
+extern int Pk11Install_yyparse();
+
+#define INSTALL_METAINFO_TAG "Pkcs11_install_script"
+#define SCRIPT_TEMP_FILE "pkcs11inst.tmp"
+#define ROOT_MARKER "%root%"
+#define TEMP_MARKER "%temp%"
+#define PRINTF_ROOT_MARKER "%%root%%"
+#define TEMPORARY_DIRECTORY_NAME "pk11inst.dir"
+#define JAR_BASE_END (JAR_BASE + 100)
+
+static PRLock *errorHandlerLock = NULL;
+static Pk11Install_ErrorHandler errorHandler = NULL;
+static char *PR_Strdup(const char *str);
+static int rm_dash_r(char *path);
+static int make_dirs(char *path, int file_perms);
+static int dir_perms(int perms);
+
+static Pk11Install_Error DoInstall(JAR *jar, const char *installDir,
+ const char *tempDir, Pk11Install_Platform *platform,
+ PRFileDesc *feedback, PRBool noverify);
+
+static char *errorString[] = {
+ "Operation was successful", /* PK11_INSTALL_NO_ERROR */
+ "Directory \"%s\" does not exist", /* PK11_INSTALL_DIR_DOESNT_EXIST */
+ "File \"%s\" does not exist", /* PK11_INSTALL_FILE_DOESNT_EXIST */
+ "File \"%s\" is not readable", /* PK11_INSTALL_FILE_NOT_READABLE */
+ "%s", /* PK11_INSTALL_ERROR_STRING */
+ "Error in JAR file %s: %s", /* PK11_INSTALL_JAR_ERROR */
+ "No Pkcs11_install_script specified in JAR metainfo file",
+ /* PK11_INSTALL_NO_INSTALLER_SCRIPT */
+ "Could not delete temporary file \"%s\"",
+ /*PK11_INSTALL_DELETE_TEMP_FILE */
+ "Could not open temporary file \"%s\"", /*PK11_INSTALL_OPEN_SCRIPT_FILE*/
+ "%s: %s", /* PK11_INSTALL_SCRIPT_PARSE */
+ "Error in script: %s",
+ "Unable to obtain system platform information",
+ "Installer script has no information about the current platform (%s)",
+ "Relative directory \"%s\" does not contain " PRINTF_ROOT_MARKER,
+ "Module File \"%s\" not found",
+ "Error occurred installing module \"%s\" into database",
+ "Error extracting \"%s\" from JAR file: %s",
+ "Directory \"%s\" is not writeable",
+ "Could not create directory \"%s\"",
+ "Could not remove directory \"%s\"",
+ "Unable to execute \"%s\"",
+ "Unable to wait for process \"%s\"",
+ "\"%s\" returned error code %d",
+ "User aborted operation",
+ "Unspecified error"
+};
+
+enum {
+ INSTALLED_FILE_MSG = 0,
+ INSTALLED_MODULE_MSG,
+ INSTALLER_SCRIPT_NAME,
+ MY_PLATFORM_IS,
+ USING_PLATFORM,
+ PARSED_INSTALL_SCRIPT,
+ EXEC_FILE_MSG,
+ EXEC_SUCCESS,
+ INSTALLATION_COMPLETE_MSG,
+ USER_ABORT
+};
+
+static char *msgStrings[] = {
+ "Installed file %s to %s\n",
+ "Installed module \"%s\" into module database\n",
+ "Using installer script \"%s\"\n",
+ "Current platform is %s\n",
+ "Using installation parameters for platform %s\n",
+ "Successfully parsed installation script\n",
+ "Executing \"%s\"...\n",
+ "\"%s\" executed successfully\n",
+ "\nInstallation completed successfully\n",
+ "\nAborting...\n"
+};
+
+/**************************************************************************
+ * S t r i n g N o d e
+ */
+typedef struct StringNode_str {
+ char *str;
+ struct StringNode_str *next;
+} StringNode;
+
+StringNode *
+StringNode_new()
+{
+ StringNode *new_this;
+ new_this = (StringNode *)PR_Malloc(sizeof(StringNode));
+ PORT_Assert(new_this != NULL);
+ new_this->str = NULL;
+ new_this->next = NULL;
+ return new_this;
+}
+
+void
+StringNode_delete(StringNode *s)
+{
+ if (s->str) {
+ PR_Free(s->str);
+ s->str = NULL;
+ }
+}
+
+/*************************************************************************
+ * S t r i n g L i s t
+ */
+typedef struct StringList_str {
+ StringNode *head;
+ StringNode *tail;
+} StringList;
+
+void
+StringList_new(StringList *list)
+{
+ list->head = NULL;
+ list->tail = NULL;
+}
+
+void
+StringList_delete(StringList *list)
+{
+ StringNode *tmp;
+ while (list->head) {
+ tmp = list->head;
+ list->head = list->head->next;
+ StringNode_delete(tmp);
+ }
+}
+
+void
+StringList_Append(StringList *list, char *str)
+{
+ if (!str) {
+ return;
+ }
+
+ if (!list->tail) {
+ /* This is the first element */
+ list->head = list->tail = StringNode_new();
+ } else {
+ list->tail->next = StringNode_new();
+ list->tail = list->tail->next;
+ }
+
+ list->tail->str = PR_Strdup(str);
+ list->tail->next = NULL; /* just to be sure */
+}
+
+/**************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ S e t E r r o r H a n d l e r
+ *
+ * Sets the error handler to be used by the library. Returns the current
+ * error handler function.
+ */
+Pk11Install_ErrorHandler
+Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler)
+{
+ Pk11Install_ErrorHandler old;
+
+ if (!errorHandlerLock) {
+ errorHandlerLock = PR_NewLock();
+ }
+
+ PR_Lock(errorHandlerLock);
+
+ old = errorHandler;
+ errorHandler = handler;
+
+ PR_Unlock(errorHandlerLock);
+
+ return old;
+}
+
+/**************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ I n i t
+ *
+ * Does initialization that otherwise would be done on the fly. Only
+ * needs to be called by multithreaded apps, before they make any calls
+ * to this library.
+ */
+void
+Pk11Install_Init()
+{
+ if (!errorHandlerLock) {
+ errorHandlerLock = PR_NewLock();
+ }
+}
+
+/**************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ R e l e a s e
+ *
+ * Releases static data structures used by the library. Don't use the
+ * library after calling this, unless you call Pk11Install_Init()
+ * first. This function doesn't have to be called at all unless you're
+ * really anal about freeing memory before your program exits.
+ */
+void
+Pk11Install_Release()
+{
+ if (errorHandlerLock) {
+ PR_Free(errorHandlerLock);
+ errorHandlerLock = NULL;
+ }
+}
+
+/*************************************************************************
+ *
+ * e r r o r
+ *
+ * Takes an error code and its arguments, creates the error string,
+ * and sends the string to the handler function if it exists.
+ */
+
+#ifdef OSF1
+/* stdarg has already been pulled in from NSPR */
+#undef va_start
+#undef va_end
+#undef va_arg
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+
+#ifdef OSF1
+static void
+error(long va_alist, ...)
+#else
+static void
+error(PRErrorCode errcode, ...)
+#endif
+{
+
+ va_list ap;
+ char *errstr;
+ Pk11Install_ErrorHandler handler;
+
+ if (!errorHandlerLock) {
+ errorHandlerLock = PR_NewLock();
+ }
+
+ PR_Lock(errorHandlerLock);
+
+ handler = errorHandler;
+
+ PR_Unlock(errorHandlerLock);
+
+ if (handler) {
+#ifdef OSF1
+ va_start(ap);
+ errstr = PR_vsmprintf(errorString[va_arg(ap, Pk11Install_Error)], ap);
+#else
+ va_start(ap, errcode);
+ errstr = PR_vsmprintf(errorString[errcode], ap);
+#endif
+ handler(errstr);
+ PR_smprintf_free(errstr);
+ va_end(ap);
+ }
+}
+
+/*************************************************************************
+ *
+ * j a r _ c a l l b a c k
+ */
+static int
+jar_callback(int status, JAR *foo, const char *bar, char *pathname,
+ char *errortext)
+{
+ char *string;
+
+ string = PR_smprintf("JAR error %d: %s in file %s\n", status, errortext,
+ pathname);
+ error(PK11_INSTALL_ERROR_STRING, string);
+ PR_smprintf_free(string);
+ return 0;
+}
+
+/*************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ D o I n s t a l l
+ *
+ * jarFile is the path of a JAR in the PKCS #11 module JAR format.
+ * installDir is the directory relative to which files will be
+ * installed.
+ */
+Pk11Install_Error
+Pk11Install_DoInstall(char *jarFile, const char *installDir,
+ const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify)
+{
+ JAR *jar;
+ char *installer;
+ unsigned long installer_len;
+ int status;
+ Pk11Install_Error ret;
+ PRBool made_temp_file;
+ Pk11Install_Info installInfo;
+ Pk11Install_Platform *platform;
+ char *errMsg;
+ char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH],
+ arch[SYS_INFO_BUFFER_LENGTH];
+ char *myPlatform;
+
+ jar = NULL;
+ ret = PK11_INSTALL_UNSPECIFIED;
+ made_temp_file = PR_FALSE;
+ errMsg = NULL;
+ Pk11Install_Info_init(&installInfo);
+
+ /*
+ printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n",
+ jarFile, installDir, tempDir);
+ */
+
+ /*
+ * Check out jarFile and installDir for validity
+ */
+ if (PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
+ error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir);
+ return PK11_INSTALL_DIR_DOESNT_EXIST;
+ }
+ if (!tempDir) {
+ tempDir = ".";
+ }
+ if (PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
+ error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir);
+ return PK11_INSTALL_DIR_DOESNT_EXIST;
+ }
+ if (PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
+ error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir);
+ return PK11_INSTALL_DIR_NOT_WRITEABLE;
+ }
+ if ((PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS)) {
+ error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile);
+ return PK11_INSTALL_FILE_DOESNT_EXIST;
+ }
+ if (PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS) {
+ error(PK11_INSTALL_FILE_NOT_READABLE, jarFile);
+ return PK11_INSTALL_FILE_NOT_READABLE;
+ }
+
+ /*
+ * Extract the JAR file
+ */
+ jar = JAR_new();
+ JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback);
+
+ if (noverify) {
+ status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url");
+ } else {
+ status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url");
+ }
+ if ((status < 0) || (jar->valid < 0)) {
+ if (status >= JAR_BASE && status <= JAR_BASE_END) {
+ error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status));
+ } else {
+ error(PK11_INSTALL_JAR_ERROR, jarFile,
+ mySECU_ErrorString(PORT_GetError()));
+ }
+ ret = PK11_INSTALL_JAR_ERROR;
+ goto loser;
+ }
+ /*printf("passed the archive\n");*/
+
+ /*
+ * Show the user security information, allow them to abort or continue
+ */
+ if (Pk11Install_UserVerifyJar(jar, PR_STDOUT,
+ force ? PR_FALSE
+ : PR_TRUE) &&
+ !force) {
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[USER_ABORT]);
+ }
+ ret = PK11_INSTALL_USER_ABORT;
+ goto loser;
+ }
+
+ /*
+ * Get the name of the installation file
+ */
+ if (JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void **)&installer,
+ (unsigned long *)&installer_len)) {
+ error(PK11_INSTALL_NO_INSTALLER_SCRIPT);
+ ret = PK11_INSTALL_NO_INSTALLER_SCRIPT;
+ goto loser;
+ }
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer);
+ }
+
+ /*
+ * Extract the installation file
+ */
+ if (PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ if (PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) {
+ error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE);
+ ret = PK11_INSTALL_DELETE_TEMP_FILE;
+ goto loser;
+ }
+ }
+ if (noverify) {
+ status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE);
+ } else {
+ status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE);
+ }
+ if (status) {
+ if (status >= JAR_BASE && status <= JAR_BASE_END) {
+ error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status));
+ } else {
+ error(PK11_INSTALL_JAR_EXTRACT, installer,
+ mySECU_ErrorString(PORT_GetError()));
+ }
+ ret = PK11_INSTALL_JAR_EXTRACT;
+ goto loser;
+ } else {
+ made_temp_file = PR_TRUE;
+ }
+
+ /*
+ * Parse the installation file into a syntax tree
+ */
+ Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0);
+ if (!Pk11Install_FD) {
+ error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE);
+ ret = PK11_INSTALL_OPEN_SCRIPT_FILE;
+ goto loser;
+ }
+ if (Pk11Install_yyparse()) {
+ error(PK11_INSTALL_SCRIPT_PARSE, installer,
+ Pk11Install_yyerrstr ? Pk11Install_yyerrstr : "");
+ ret = PK11_INSTALL_SCRIPT_PARSE;
+ goto loser;
+ }
+
+#if 0
+ /* for debugging */
+ Pk11Install_valueList->Print(0);
+#endif
+
+ /*
+ * From the syntax tree, build a semantic structure
+ */
+ errMsg = Pk11Install_Info_Generate(&installInfo, Pk11Install_valueList);
+ if (errMsg) {
+ error(PK11_INSTALL_SEMANTIC, errMsg);
+ ret = PK11_INSTALL_SEMANTIC;
+ goto loser;
+ }
+#if 0
+ installInfo.Print(0);
+#endif
+
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]);
+ }
+
+ /*
+ * Figure out which platform to use
+ */
+ {
+ sysname[0] = release[0] = arch[0] = '\0';
+
+ if ((PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH) !=
+ PR_SUCCESS) ||
+ (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH) !=
+ PR_SUCCESS) ||
+ (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH) !=
+ PR_SUCCESS)) {
+ error(PK11_INSTALL_SYSINFO);
+ ret = PK11_INSTALL_SYSINFO;
+ goto loser;
+ }
+ myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch);
+ platform = Pk11Install_Info_GetBestPlatform(&installInfo, myPlatform);
+ if (!platform) {
+ error(PK11_INSTALL_NO_PLATFORM, myPlatform);
+ PR_smprintf_free(myPlatform);
+ ret = PK11_INSTALL_NO_PLATFORM;
+ goto loser;
+ }
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform);
+ PR_fprintf(feedback, msgStrings[USING_PLATFORM],
+ Pk11Install_PlatformName_GetString(&platform->name));
+ }
+ PR_smprintf_free(myPlatform);
+ }
+
+ /* Run the install for that platform */
+ ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify);
+ if (ret) {
+ goto loser;
+ }
+
+ ret = PK11_INSTALL_SUCCESS;
+loser:
+ if (Pk11Install_valueList) {
+ Pk11Install_ValueList_delete(Pk11Install_valueList);
+ Pk11Install_valueList = NULL;
+ }
+ if (jar) {
+ JAR_destroy(jar);
+ }
+ if (made_temp_file) {
+ PR_Delete(SCRIPT_TEMP_FILE);
+ }
+ if (errMsg) {
+ PR_smprintf_free(errMsg);
+ }
+ return ret;
+}
+
+/*
+/////////////////////////////////////////////////////////////////////////
+// actually run the installation, copying files to and fro
+*/
+static Pk11Install_Error
+DoInstall(JAR *jar, const char *installDir, const char *tempDir,
+ Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify)
+{
+ Pk11Install_File *file;
+ Pk11Install_Error ret;
+ char *modDest;
+ char *cp;
+ int i;
+ int status;
+ char *tempname, *temp;
+ StringList executables;
+ StringNode *execNode;
+ PRProcessAttr *attr;
+ PRProcess *proc;
+ char *argv[2];
+ char *envp[1];
+ int errcode;
+
+ ret = PK11_INSTALL_UNSPECIFIED;
+ modDest = NULL;
+ tempname = NULL;
+
+ StringList_new(&executables);
+ /*
+ // Create Temporary directory
+ */
+ tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME);
+ if (PR_Access(tempname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ /* Left over from previous run? Delete it. */
+ rm_dash_r(tempname);
+ }
+ if (PR_MkDir(tempname, 0700) != PR_SUCCESS) {
+ error(PK11_INSTALL_CREATE_DIR, tempname);
+ ret = PK11_INSTALL_CREATE_DIR;
+ goto loser;
+ }
+
+ /*
+ // Install all the files
+ */
+ for (i = 0; i < platform->numFiles; i++) {
+ char *dest;
+ file = &platform->files[i];
+
+ if (file->relativePath) {
+ PRBool foundMarker = PR_FALSE;
+ char *reldir = PR_Strdup(file->relativePath);
+
+ if (!reldir) {
+ error(PK11_INSTALL_UNSPECIFIED);
+ goto loser;
+ }
+
+ /* Replace all the markers with the directories for which they stand */
+ while (1) {
+ if ((cp = PL_strcasestr(reldir, ROOT_MARKER))) {
+ /* Has a %root% marker */
+ *cp = '\0';
+ temp = PR_smprintf("%s%s%s", reldir, installDir,
+ cp + strlen(ROOT_MARKER));
+ PR_Free(reldir);
+ reldir = temp;
+ foundMarker = PR_TRUE;
+ } else if ((cp = PL_strcasestr(reldir, TEMP_MARKER))) {
+ /* Has a %temp% marker */
+ *cp = '\0';
+ temp = PR_smprintf("%s%s%s", reldir, tempname,
+ cp + strlen(TEMP_MARKER));
+ PR_Free(reldir);
+ reldir = temp;
+ foundMarker = PR_TRUE;
+ } else {
+ break;
+ }
+ }
+ if (!foundMarker) {
+ /* Has no markers...this isn't really a relative directory */
+ error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath);
+ ret = PK11_INSTALL_BOGUS_REL_DIR;
+ PR_Free(reldir);
+ goto loser;
+ }
+ dest = reldir;
+ } else if (file->absolutePath) {
+ dest = PR_Strdup(file->absolutePath);
+ } else {
+ error(PK11_INSTALL_UNSPECIFIED);
+ goto loser;
+ }
+
+ /* Remember if this is the module file, we'll need to add it later */
+ if (i == platform->modFile) {
+ modDest = PR_Strdup(dest);
+ }
+
+ /* Remember is this is an executable, we'll need to run it later */
+ if (file->executable) {
+ StringList_Append(&executables, dest);
+ /*executables.Append(dest);*/
+ }
+
+ /* Make sure the directory we are targetting exists */
+ if (make_dirs(dest, file->permissions)) {
+ ret = PK11_INSTALL_CREATE_DIR;
+ goto loser;
+ }
+
+ /* Actually extract the file onto the filesystem */
+ if (noverify) {
+ status = JAR_extract(jar, (char *)file->jarPath, dest);
+ } else {
+ status = JAR_verified_extract(jar, (char *)file->jarPath, dest);
+ }
+ if (status) {
+ if (status >= JAR_BASE && status <= JAR_BASE_END) {
+ error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
+ JAR_get_error(status));
+ } else {
+ error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
+ mySECU_ErrorString(PORT_GetError()));
+ }
+ ret = PK11_INSTALL_JAR_EXTRACT;
+ goto loser;
+ }
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG],
+ file->jarPath, dest);
+ }
+
+/* no NSPR command to change permissions? */
+#ifdef XP_UNIX
+ (void)chmod(dest, file->permissions);
+#endif
+
+ PR_Free(dest);
+ }
+ /* Make sure we found the module file */
+ if (!modDest) {
+ /* Internal problem here, since every platform is supposed to have
+ a module file */
+ error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName);
+ ret = PK11_INSTALL_NO_MOD_FILE;
+ goto loser;
+ }
+
+ /*
+ // Execute any executable files
+ */
+ {
+ argv[1] = NULL;
+ envp[0] = NULL;
+ for (execNode = executables.head; execNode; execNode = execNode->next) {
+ attr = PR_NewProcessAttr();
+ argv[0] = PR_Strdup(execNode->str);
+
+ /* Announce our intentions */
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str);
+ }
+
+ /* start the process */
+ if (!(proc = PR_CreateProcess(execNode->str, argv, envp, attr))) {
+ PR_Free(argv[0]);
+ PR_DestroyProcessAttr(attr);
+ error(PK11_INSTALL_EXEC_FILE, execNode->str);
+ ret = PK11_INSTALL_EXEC_FILE;
+ goto loser;
+ }
+
+ /* wait for it to finish */
+ if (PR_WaitProcess(proc, &errcode) != PR_SUCCESS) {
+ PR_Free(argv[0]);
+ PR_DestroyProcessAttr(attr);
+ error(PK11_INSTALL_WAIT_PROCESS, execNode->str);
+ ret = PK11_INSTALL_WAIT_PROCESS;
+ goto loser;
+ }
+
+ /* What happened? */
+ if (errcode) {
+ /* process returned an error */
+ error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode);
+ } else if (feedback) {
+ /* process ran successfully */
+ PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str);
+ }
+
+ PR_Free(argv[0]);
+ PR_DestroyProcessAttr(attr);
+ }
+ }
+
+ /*
+ // Add the module
+ */
+ status = Pk11Install_AddNewModule((char *)platform->moduleName,
+ (char *)modDest, platform->mechFlags, platform->cipherFlags);
+
+ if (status != SECSuccess) {
+ error(PK11_INSTALL_ADD_MODULE, platform->moduleName);
+ ret = PK11_INSTALL_ADD_MODULE;
+ goto loser;
+ }
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG],
+ platform->moduleName);
+ }
+
+ if (feedback) {
+ PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]);
+ }
+
+ ret = PK11_INSTALL_SUCCESS;
+
+loser:
+ if (modDest) {
+ PR_Free(modDest);
+ }
+ if (tempname) {
+ PRFileInfo info;
+ if (PR_GetFileInfo(tempname, &info) == PR_SUCCESS) {
+ if (info.type == PR_FILE_DIRECTORY) {
+ /* Recursively remove temporary directory */
+ if (rm_dash_r(tempname)) {
+ error(PK11_INSTALL_REMOVE_DIR,
+ tempname);
+ ret = PK11_INSTALL_REMOVE_DIR;
+ }
+ }
+ }
+ PR_Free(tempname);
+ }
+ StringList_delete(&executables);
+ return ret;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+*/
+static char *
+PR_Strdup(const char *str)
+{
+ char *tmp = (char *)PR_Malloc(strlen(str) + 1);
+ strcpy(tmp, str);
+ return tmp;
+}
+
+/*
+ * r m _ d a s h _ r
+ *
+ * Remove a file, or a directory recursively.
+ *
+ */
+static int
+rm_dash_r(char *path)
+{
+ PRDir *dir;
+ PRDirEntry *entry;
+ PRFileInfo fileinfo;
+ char filename[240];
+
+ if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
+ /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
+ return -1;
+ }
+ if (fileinfo.type == PR_FILE_DIRECTORY) {
+
+ dir = PR_OpenDir(path);
+ if (!dir) {
+ return -1;
+ }
+
+ /* Recursively delete all entries in the directory */
+ while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
+ sprintf(filename, "%s/%s", path, entry->name);
+ if (rm_dash_r(filename)) {
+ PR_CloseDir(dir);
+ return -1;
+ }
+ }
+
+ if (PR_CloseDir(dir) != PR_SUCCESS) {
+ return -1;
+ }
+
+ /* Delete the directory itself */
+ if (PR_RmDir(path) != PR_SUCCESS) {
+ return -1;
+ }
+ } else {
+ if (PR_Delete(path) != PR_SUCCESS) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/***************************************************************************
+ *
+ * m a k e _ d i r s
+ *
+ * Ensure that the directory portion of the path exists. This may require
+ * making the directory, and its parent, and its parent's parent, etc.
+ */
+static int
+make_dirs(char *path, int file_perms)
+{
+ char *Path;
+ char *start;
+ char *sep;
+ int ret = 0;
+ PRFileInfo info;
+
+ if (!path) {
+ return 0;
+ }
+
+ Path = PR_Strdup(path);
+ start = strpbrk(Path, "/\\");
+ if (!start) {
+ return 0;
+ }
+ start++; /* start right after first slash */
+
+ /* Each time through the loop add one more directory. */
+ while ((sep = strpbrk(start, "/\\"))) {
+ *sep = '\0';
+
+ if (PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
+ /* No such dir, we have to create it */
+ if (PR_MkDir(Path, dir_perms(file_perms)) != PR_SUCCESS) {
+ error(PK11_INSTALL_CREATE_DIR, Path);
+ ret = PK11_INSTALL_CREATE_DIR;
+ goto loser;
+ }
+ } else {
+ /* something exists by this name, make sure it's a directory */
+ if (info.type != PR_FILE_DIRECTORY) {
+ error(PK11_INSTALL_CREATE_DIR, Path);
+ ret = PK11_INSTALL_CREATE_DIR;
+ goto loser;
+ }
+ }
+
+ /* If this is the lowest directory level, make sure it is writeable */
+ if (!strpbrk(sep + 1, "/\\")) {
+ if (PR_Access(Path, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
+ error(PK11_INSTALL_DIR_NOT_WRITEABLE, Path);
+ ret = PK11_INSTALL_DIR_NOT_WRITEABLE;
+ goto loser;
+ }
+ }
+
+ start = sep + 1; /* start after the next slash */
+ *sep = '/';
+ }
+
+loser:
+ PR_Free(Path);
+ return ret;
+}
+
+/*************************************************************************
+ * d i r _ p e r m s
+ *
+ * Guesses the desired permissions on a directory based on the permissions
+ * of a file that will be stored in it. Give read, write, and
+ * execute to the owner (so we can create the file), read and
+ * execute to anyone who has read permissions on the file, and write
+ * to anyone who has write permissions on the file.
+ */
+static int
+dir_perms(int perms)
+{
+ int ret = 0;
+
+ /* owner */
+ ret |= 0700;
+
+ /* group */
+ if (perms & 0040) {
+ /* read on the file -> read and execute on the directory */
+ ret |= 0050;
+ }
+ if (perms & 0020) {
+ /* write on the file -> write on the directory */
+ ret |= 0020;
+ }
+
+ /* others */
+ if (perms & 0004) {
+ /* read on the file -> read and execute on the directory */
+ ret |= 0005;
+ }
+ if (perms & 0002) {
+ /* write on the file -> write on the directory */
+ ret |= 0002;
+ }
+
+ return ret;
+}
diff --git a/security/nss/cmd/modutil/install.h b/security/nss/cmd/modutil/install.h
new file mode 100644
index 000000000..5d6d3eaba
--- /dev/null
+++ b/security/nss/cmd/modutil/install.h
@@ -0,0 +1,100 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef PK11INSTALL_H
+#define PK11INSTALL_H
+
+#include <prio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*Pk11Install_ErrorHandler)(char *);
+
+typedef enum {
+ PK11_INSTALL_NO_ERROR = 0,
+ PK11_INSTALL_DIR_DOESNT_EXIST,
+ PK11_INSTALL_FILE_DOESNT_EXIST,
+ PK11_INSTALL_FILE_NOT_READABLE,
+ PK11_INSTALL_ERROR_STRING,
+ PK11_INSTALL_JAR_ERROR,
+ PK11_INSTALL_NO_INSTALLER_SCRIPT,
+ PK11_INSTALL_DELETE_TEMP_FILE,
+ PK11_INSTALL_OPEN_SCRIPT_FILE,
+ PK11_INSTALL_SCRIPT_PARSE,
+ PK11_INSTALL_SEMANTIC,
+ PK11_INSTALL_SYSINFO,
+ PK11_INSTALL_NO_PLATFORM,
+ PK11_INSTALL_BOGUS_REL_DIR,
+ PK11_INSTALL_NO_MOD_FILE,
+ PK11_INSTALL_ADD_MODULE,
+ PK11_INSTALL_JAR_EXTRACT,
+ PK11_INSTALL_DIR_NOT_WRITEABLE,
+ PK11_INSTALL_CREATE_DIR,
+ PK11_INSTALL_REMOVE_DIR,
+ PK11_INSTALL_EXEC_FILE,
+ PK11_INSTALL_WAIT_PROCESS,
+ PK11_INSTALL_PROC_ERROR,
+ PK11_INSTALL_USER_ABORT,
+ PK11_INSTALL_UNSPECIFIED
+} Pk11Install_Error;
+#define PK11_INSTALL_SUCCESS PK11_INSTALL_NO_ERROR
+
+/**************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ I n i t
+ *
+ * Does initialization that otherwise would be done on the fly. Only
+ * needs to be called by multithreaded apps, before they make any calls
+ * to this library.
+ */
+void
+Pk11Install_Init();
+
+/**************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ S e t E r r o r H a n d l e r
+ *
+ * Sets the error handler to be used by the library. Returns the current
+ * error handler function.
+ */
+Pk11Install_ErrorHandler
+Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler);
+
+/**************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ R e l e a s e
+ *
+ * Releases static data structures used by the library. Don't use the
+ * library after calling this, unless you call Pk11Install_Init()
+ * first. This function doesn't have to be called at all unless you're
+ * really anal about freeing memory before your program exits.
+ */
+void
+Pk11Install_Release();
+
+/*************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ D o I n s t a l l
+ *
+ * jarFile is the path of a JAR in the PKCS #11 module JAR format.
+ * installDir is the directory relative to which files will be
+ * installed.
+ * feedback is a file descriptor to which to write informative (not error)
+ * status messages: what files are being installed, what modules are being
+ * installed. If feedback==NULL, no messages will be displayed.
+ * If force != 0, interactive prompts will be suppressed.
+ * If noverify == PR_TRUE, signatures won't be checked on the JAR file.
+ */
+Pk11Install_Error
+Pk11Install_DoInstall(char *jarFile, const char *installDir,
+ const char *tempDir, PRFileDesc *feedback, short force,
+ PRBool noverify);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*PK11INSTALL_H*/
diff --git a/security/nss/cmd/modutil/installparse.c b/security/nss/cmd/modutil/installparse.c
new file mode 100644
index 000000000..d35d048dd
--- /dev/null
+++ b/security/nss/cmd/modutil/installparse.c
@@ -0,0 +1,434 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef lint
+char yysccsid[] = "@(#)yaccpar 1.4 (Berkeley) 02/25/90";
+#endif
+#line 37 "installparse.y"
+
+#define yyparse Pk11Install_yyparse
+#define yylex Pk11Install_yylex
+#define yyerror Pk11Install_yyerror
+#define yychar Pk11Install_yychar
+#define yyval Pk11Install_yyval
+#define yylval Pk11Install_yylval
+#define yydebug Pk11Install_yydebug
+#define yynerrs Pk11Install_yynerrs
+#define yyerrflag Pk11Install_yyerrflag
+#define yyss Pk11Install_yyss
+#define yyssp Pk11Install_yyssp
+#define yyvs Pk11Install_yyvs
+#define yyvsp Pk11Install_yyvsp
+#define yylhs Pk11Install_yylhs
+#define yylen Pk11Install_yylen
+#define yydefred Pk11Install_yydefred
+#define yydgoto Pk11Install_yydgoto
+#define yysindex Pk11Install_yysindex
+#define yyrindex Pk11Install_yyrindex
+#define yygindex Pk11Install_yygindex
+#define yytable Pk11Install_yytable
+#define yycheck Pk11Install_yycheck
+#define yyname Pk11Install_yyname
+#define yyrule Pk11Install_yyrule
+
+/* C Stuff */
+#include "install-ds.h"
+#include <prprf.h>
+
+#define YYSTYPE Pk11Install_Pointer
+extern char *Pk11Install_yytext;
+char *Pk11Install_yyerrstr = NULL;
+
+#line 40 "ytab.c"
+#define OPENBRACE 257
+#define CLOSEBRACE 258
+#define STRING 259
+#define YYERRCODE 256
+/* clang-format on */
+short yylhs[] = {
+ -1,
+ 0, 1, 1, 2, 2, 3, 4,
+};
+short yylen[] = {
+ 2,
+ 1, 2, 0, 1, 1, 4, 1,
+};
+short yydefred[] = {
+ 0,
+ 0, 0, 1, 0, 4, 0, 2, 0, 0, 6,
+};
+short yydgoto[] = {
+ 2,
+ 3, 4, 5, 6,
+};
+short yysindex[] = {
+ -257,
+ 0, 0, 0, -257, 0, -252, 0, -257, -251, 0,
+};
+short yyrindex[] = {
+ 6,
+ 1, 0, 0, 3, 0, 0, 0, -250, 0, 0,
+};
+short yygindex[] = {
+ 0,
+ -4, 0, 0, 0,
+};
+#define YYTABLESIZE 261
+short yytable[] = {
+ 7,
+ 5, 1, 3, 9, 8, 3, 10, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 5, 5,
+ 3,
+};
+short yycheck[] = {
+ 4,
+ 0, 259, 0, 8, 257, 0, 258, 258, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 257, 258, 259,
+ 258,
+};
+/* clang-format on */
+#define YYFINAL 2
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 259
+#if YYDEBUG
+char *yyname[] = {
+ "end-of-file", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "OPENBRACE", "CLOSEBRACE", "STRING",
+};
+char *yyrule[] = {
+ "$accept : toplist",
+ "toplist : valuelist",
+ "valuelist : value valuelist",
+ "valuelist :",
+ "value : key_value_pair",
+ "value : STRING",
+ "key_value_pair : key OPENBRACE valuelist CLOSEBRACE",
+ "key : STRING",
+};
+#endif
+#ifndef YYSTYPE
+typedef int YYSTYPE;
+#endif
+#define yyclearin (yychar = (-1))
+#define yyerrok (yyerrflag = 0)
+#ifndef YYSTACKSIZE
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 300
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+#define yystacksize YYSTACKSIZE
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#line 118 "installparse.y"
+/*----------------------- Program Section --------------------------------*/
+
+/*************************************************************************/
+void
+Pk11Install_yyerror(char *message)
+{
+ char *tmp;
+ if (Pk11Install_yyerrstr) {
+ tmp = PR_smprintf("%sline %d: %s\n", Pk11Install_yyerrstr,
+ Pk11Install_yylinenum, message);
+ PR_smprintf_free(Pk11Install_yyerrstr);
+ } else {
+ tmp = PR_smprintf("line %d: %s\n", Pk11Install_yylinenum, message);
+ }
+ Pk11Install_yyerrstr = tmp;
+}
+#line 191 "ytab.c"
+#define YYABORT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+ register int yym, yyn, yystate;
+#if YYDEBUG
+ register char *yys;
+ extern char *PR_GetEnvSecure();
+
+ if ((yys = PR_GetEnvSecure("YYDEBUG")) != NULL) {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = (-1);
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+ *yyssp = yystate = 0;
+
+yyloop:
+ if ((yyn = yydefred[yystate]) != 0)
+ goto yyreduce;
+ if (yychar < 0) {
+ if ((yychar = yylex()) < 0)
+ yychar = 0;
+#if YYDEBUG
+ if (yydebug) {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN)
+ yys = yyname[yychar];
+ if (!yys)
+ yys = "illegal-symbol";
+ printf("yydebug: state %d, reading %d (%s)\n", yystate,
+ yychar, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar) {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, shifting to state %d\n",
+ yystate, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1) {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ yychar = (-1);
+ if (yyerrflag > 0)
+ --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar) {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag)
+ goto yyinrecovery;
+#ifdef lint
+ goto yynewerror;
+yynewerror:
+#endif
+ yyerror("syntax error");
+#ifdef lint
+ goto yyerrlab;
+yyerrlab:
+#endif
+ ++yynerrs;
+yyinrecovery:
+ if (yyerrflag < 3) {
+ yyerrflag = 3;
+ for (;;) {
+ if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, error recovery shifting\
+ to state %d\n",
+ *yyssp, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1) {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ goto yyloop;
+ } else {
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: error recovery discarding state %d\n",
+ *yyssp);
+#endif
+ if (yyssp <= yyss)
+ goto yyabort;
+ --yyssp;
+ --yyvsp;
+ }
+ }
+ } else {
+ if (yychar == 0)
+ goto yyabort;
+#if YYDEBUG
+ if (yydebug) {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN)
+ yys = yyname[yychar];
+ if (!yys)
+ yys = "illegal-symbol";
+ printf("yydebug: state %d, error recovery discards token %d (%s)\n",
+ yystate, yychar, yys);
+ }
+#endif
+ yychar = (-1);
+ goto yyloop;
+ }
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("yydebug: state %d, reducing by rule %d (%s)\n",
+ yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ yyval = yyvsp[1 - yym];
+ switch (yyn) {
+ case 1:
+#line 84 "installparse.y"
+ {
+ Pk11Install_valueList = yyvsp[0].list;
+ } break;
+ case 2:
+#line 89 "installparse.y"
+ {
+ Pk11Install_ValueList_AddItem(yyvsp[0].list, yyvsp[-1].value);
+ yyval.list = yyvsp[0].list;
+ } break;
+ case 3:
+#line 94 "installparse.y"
+ {
+ yyval.list = Pk11Install_ValueList_new();
+ } break;
+ case 4:
+#line 99 "installparse.y"
+ {
+ yyval.value = Pk11Install_Value_new(PAIR_VALUE, yyvsp[0]);
+ } break;
+ case 5:
+#line 103 "installparse.y"
+ {
+ yyval.value = Pk11Install_Value_new(STRING_VALUE, yyvsp[0]);
+ } break;
+ case 6:
+#line 108 "installparse.y"
+ {
+ yyval.pair = Pk11Install_Pair_new(yyvsp[-3].string, yyvsp[-1].list);
+ } break;
+ case 7:
+#line 113 "installparse.y"
+ {
+ yyval.string = yyvsp[0].string;
+ } break;
+#line 374 "ytab.c"
+ }
+ yyssp -= yym;
+ yystate = *yyssp;
+ yyvsp -= yym;
+ yym = yylhs[yyn];
+ if (yystate == 0 && yym == 0) {
+#ifdef YYDEBUG
+ if (yydebug)
+ printf("yydebug: after reduction, shifting from state 0 to\
+ state %d\n",
+ YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yyssp = YYFINAL;
+ *++yyvsp = yyval;
+ if (yychar < 0) {
+ if ((yychar = yylex()) < 0)
+ yychar = 0;
+#if YYDEBUG
+ if (yydebug) {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN)
+ yys = yyname[yychar];
+ if (!yys)
+ yys = "illegal-symbol";
+ printf("yydebug: state %d, reading %d (%s)\n",
+ YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == 0)
+ goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#ifdef YYDEBUG
+ if (yydebug)
+ printf("yydebug: after reduction, shifting from state %d \
+to state %d\n",
+ *yyssp, yystate);
+#endif
+ if (yyssp >= yyss + yystacksize - 1) {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate;
+ *++yyvsp = yyval;
+ goto yyloop;
+yyoverflow:
+ yyerror("yacc stack overflow");
+yyabort:
+ return (1);
+yyaccept:
+ return (0);
+}
diff --git a/security/nss/cmd/modutil/installparse.h b/security/nss/cmd/modutil/installparse.h
new file mode 100644
index 000000000..2c02b57b6
--- /dev/null
+++ b/security/nss/cmd/modutil/installparse.h
@@ -0,0 +1,7 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#define OPENBRACE 257
+#define CLOSEBRACE 258
+#define STRING 259
diff --git a/security/nss/cmd/modutil/installparse.l b/security/nss/cmd/modutil/installparse.l
new file mode 100644
index 000000000..71fb56101
--- /dev/null
+++ b/security/nss/cmd/modutil/installparse.l
@@ -0,0 +1,137 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+/* lex file for analyzing PKCS #11 Module installation instructions */
+
+/*----------------------------- Definitions ---------------------------*/
+%{
+#include <string.h>
+
+#include "install-ds.h" /* defines tokens and data structures */
+#include "installparse.h" /* produced by yacc -d */
+#include <prprf.h>
+static char *putSimpleString(char*); /* return copy of string */
+static char *putComplexString(char*); /* strip out quotes, deal with */
+ /* escaped characters */
+
+void Pk11Install_yyerror(char *);
+
+/* Overrides to use NSPR */
+#define malloc PR_Malloc
+#define realloc PR_Realloc
+#define free PR_Free
+
+int Pk11Install_yylinenum=1;
+static char *err;
+
+#define YY_NEVER_INTERACTIVE 1
+#define yyunput Pkcs11Install_yyunput
+
+/* This is the default YY_INPUT modified for NSPR */
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) { \
+ char c; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ PR_Read(Pk11Install_FD, &c, 1)==1 && c != '\n'; ++n ) { \
+ buf[n] = c; \
+ } \
+ if ( c == '\n' ) { \
+ buf[n++] = c; \
+ } \
+ result = n; \
+ } else { \
+ result = PR_Read(Pk11Install_FD, buf, max_size); \
+ }
+
+%}
+
+/*** Regular expression definitions ***/
+/* simple_string has no whitespace, quotes, or braces */
+simple_string [^ \t\r\n\""{""}"]+
+
+/* complex_string is enclosed in quotes. Inside the quotes, quotes and
+ backslashes must be backslash-escaped. No newlines or carriage returns
+ are allowed inside the quotes. Otherwise, anything goes. */
+complex_string \"([^\"\\\r\n]|(\\\")|(\\\\))+\"
+
+/* Standard whitespace */
+whitespace [ \t\r]+
+
+other .
+
+/*---------------------------- Actions --------------------------------*/
+%%
+
+"{" return OPENBRACE;
+"}" return CLOSEBRACE;
+{simple_string} {Pk11Install_yylval.string =
+ putSimpleString(Pk11Install_yytext);
+ return STRING;}
+{complex_string} {Pk11Install_yylval.string =
+ putComplexString(Pk11Install_yytext);
+ return STRING;}
+
+"\n" Pk11Install_yylinenum++;
+
+{whitespace} ;
+
+{other} {err = PR_smprintf("Invalid lexeme: %s",Pk11Install_yytext);
+ Pk11Install_yyerror(err);
+ PR_smprintf_free(err);
+ return 1;
+ }
+
+%%
+/*------------------------ Program Section ----------------------------*/
+
+PRFileDesc *Pk11Install_FD=NULL;
+
+/*************************************************************************/
+/* dummy function required by lex */
+int Pk11Install_yywrap(void) { return 1;}
+
+/*************************************************************************/
+/* Return a copy of the given string */
+static char*
+putSimpleString(char *str)
+{
+ char *tmp = (char*) PR_Malloc(strlen(str)+1);
+ strcpy(tmp, str);
+ return tmp;
+}
+
+/*************************************************************************/
+/* Strip out quotes, replace escaped characters with what they stand for.
+ This function assumes that what is passed in is actually a complex
+ string, so error checking is lax. */
+static char*
+putComplexString(char *str)
+{
+ int size, i,j;
+ char *tmp;
+
+ if(!str) {
+ return NULL;
+ }
+ size = strlen(str);
+
+ /* Allocate the new space. This string will actually be too big,
+ since quotes and backslashes will be stripped out. But that's ok. */
+ tmp = (char*) PR_Malloc(size+1);
+
+ /* Copy it over */
+ for(i=0, j=0; i < size; i++) {
+ if(str[i]=='\"') {
+ continue; /* skip un-escaped quotes */
+ } else if(str[i]=='\\') {
+ ++i; /* escaped character. skip the backslash */
+ }
+ tmp[j++] = str[i];
+ }
+ tmp[j] = '\0';
+
+ return tmp;
+}
diff --git a/security/nss/cmd/modutil/installparse.y b/security/nss/cmd/modutil/installparse.y
new file mode 100644
index 000000000..b6d701136
--- /dev/null
+++ b/security/nss/cmd/modutil/installparse.y
@@ -0,0 +1,104 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* yacc file for parsing PKCS #11 module installation instructions */
+/*------------------------ Definition Section ---------------------------*/
+
+%{
+#define yyparse Pk11Install_yyparse
+#define yylex Pk11Install_yylex
+#define yyerror Pk11Install_yyerror
+#define yychar Pk11Install_yychar
+#define yyval Pk11Install_yyval
+#define yylval Pk11Install_yylval
+#define yydebug Pk11Install_yydebug
+#define yynerrs Pk11Install_yynerrs
+#define yyerrflag Pk11Install_yyerrflag
+#define yyss Pk11Install_yyss
+#define yyssp Pk11Install_yyssp
+#define yyvs Pk11Install_yyvs
+#define yyvsp Pk11Install_yyvsp
+#define yylhs Pk11Install_yylhs
+#define yylen Pk11Install_yylen
+#define yydefred Pk11Install_yydefred
+#define yydgoto Pk11Install_yydgoto
+#define yysindex Pk11Install_yysindex
+#define yyrindex Pk11Install_yyrindex
+#define yygindex Pk11Install_yygindex
+#define yytable Pk11Install_yytable
+#define yycheck Pk11Install_yycheck
+#define yyname Pk11Install_yyname
+#define yyrule Pk11Install_yyrule
+
+/* C Stuff */
+#include "install-ds.h"
+#include <prprf.h>
+
+#define YYSTYPE Pk11Install_Pointer
+extern char *Pk11Install_yytext;
+char *Pk11Install_yyerrstr=NULL;
+
+%}
+
+/* Tokens */
+%token OPENBRACE
+%token CLOSEBRACE
+%token STRING
+%start toplist
+
+%%
+
+/*--------------------------- Productions -------------------------------*/
+
+toplist : valuelist
+{
+ Pk11Install_valueList = $1.list;
+}
+
+valuelist : value valuelist
+{
+ Pk11Install_ValueList_AddItem($2.list,$1.value);
+ $$.list = $2.list;
+}
+|
+{
+ $$.list = Pk11Install_ValueList_new();
+};
+
+value : key_value_pair
+{
+ $$.value= Pk11Install_Value_new(PAIR_VALUE,$1);
+}
+| STRING
+{
+ $$.value= Pk11Install_Value_new(STRING_VALUE, $1);
+};
+
+key_value_pair : key OPENBRACE valuelist CLOSEBRACE
+{
+ $$.pair = Pk11Install_Pair_new($1.string,$3.list);
+};
+
+key : STRING
+{
+ $$.string = $1.string;
+};
+
+%%
+/*----------------------- Program Section --------------------------------*/
+
+/*************************************************************************/
+void
+Pk11Install_yyerror(char *message)
+{
+ char *tmp;
+ if(Pk11Install_yyerrstr) {
+ tmp=PR_smprintf("%sline %d: %s\n", Pk11Install_yyerrstr,
+ Pk11Install_yylinenum, message);
+ PR_smprintf_free(Pk11Install_yyerrstr);
+ } else {
+ tmp = PR_smprintf("line %d: %s\n", Pk11Install_yylinenum, message);
+ }
+ Pk11Install_yyerrstr=tmp;
+}
diff --git a/security/nss/cmd/modutil/instsec.c b/security/nss/cmd/modutil/instsec.c
new file mode 100644
index 000000000..95191e729
--- /dev/null
+++ b/security/nss/cmd/modutil/instsec.c
@@ -0,0 +1,153 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <plarena.h>
+#include <prerror.h>
+#include <prio.h>
+#include <prprf.h>
+#include <seccomon.h>
+#include <secmod.h>
+#include <jar.h>
+#include <secutil.h>
+
+/* These are installation functions that make calls to the security library.
+ * We don't want to include security include files in the C++ code too much.
+ */
+
+static char *PR_fgets(char *buf, int size, PRFileDesc *file);
+
+/***************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ A d d N e w M o d u l e
+ */
+int
+Pk11Install_AddNewModule(char *moduleName, char *dllPath,
+ unsigned long defaultMechanismFlags,
+ unsigned long cipherEnableFlags)
+{
+ return (SECMOD_AddNewModule(moduleName, dllPath,
+ SECMOD_PubMechFlagstoInternal(defaultMechanismFlags),
+ SECMOD_PubCipherFlagstoInternal(cipherEnableFlags)) == SECSuccess)
+ ? 0
+ : -1;
+}
+
+/*************************************************************************
+ *
+ * P k 1 1 I n s t a l l _ U s e r V e r i f y J a r
+ *
+ * Gives the user feedback on the signatures of a JAR files, asks them
+ * whether they actually want to continue.
+ * Assumes the jar structure has already been created and is valid.
+ * Returns 0 if the user wants to continue the installation, nonzero
+ * if the user wishes to abort.
+ */
+short
+Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out, PRBool query)
+{
+ JAR_Context *ctx;
+ JAR_Cert *fing;
+ JAR_Item *item;
+ char stdinbuf[80];
+ int count = 0;
+
+ CERTCertificate *cert, *prev = NULL;
+
+ PR_fprintf(out, "\nThis installation JAR file was signed by:\n");
+
+ ctx = JAR_find(jar, NULL, jarTypeSign);
+
+ while (JAR_find_next(ctx, &item) >= 0) {
+ fing = (JAR_Cert *)item->data;
+ cert = fing->cert;
+ if (cert == prev) {
+ continue;
+ }
+
+ count++;
+ PR_fprintf(out, "----------------------------------------------\n");
+ if (cert) {
+ if (cert->nickname) {
+ PR_fprintf(out, "**NICKNAME**\n%s\n", cert->nickname);
+ }
+ if (cert->subjectName) {
+ PR_fprintf(out, "**SUBJECT NAME**\n%s\n", cert->subjectName);
+ }
+ if (cert->issuerName) {
+ PR_fprintf(out, "**ISSUER NAME**\n%s\n", cert->issuerName);
+ }
+ } else {
+ PR_fprintf(out, "No matching certificate could be found.\n");
+ }
+ PR_fprintf(out, "----------------------------------------------\n\n");
+
+ prev = cert;
+ }
+
+ JAR_find_end(ctx);
+
+ if (count == 0) {
+ PR_fprintf(out, "No signatures found: JAR FILE IS UNSIGNED.\n");
+ }
+
+ if (query) {
+ PR_fprintf(out,
+ "Do you wish to continue this installation? (y/n) ");
+
+ if (PR_fgets(stdinbuf, 80, PR_STDIN) != NULL) {
+ char *response;
+
+ if ((response = strtok(stdinbuf, " \t\n\r"))) {
+ if (!PL_strcasecmp(response, "y") ||
+ !PL_strcasecmp(response, "yes")) {
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+/**************************************************************************
+ *
+ * P R _ f g e t s
+ *
+ * fgets implemented with NSPR.
+ */
+static char *
+PR_fgets(char *buf, int size, PRFileDesc *file)
+{
+ int i;
+ int status;
+ char c;
+
+ i = 0;
+ while (i < size - 1) {
+ status = PR_Read(file, (void *)&c, 1);
+ if (status == -1) {
+ return NULL;
+ } else if (status == 0) {
+ break;
+ }
+ buf[i++] = c;
+ if (c == '\n') {
+ break;
+ }
+ }
+ buf[i] = '\0';
+
+ return buf;
+}
+
+/**************************************************************************
+ *
+ * m y S E C U _ E r r o r S t r i n g
+ *
+ */
+const char *
+mySECU_ErrorString(PRErrorCode errnum)
+{
+ return SECU_Strerror(errnum);
+}
diff --git a/security/nss/cmd/modutil/lex.Pk11Install_yy.c b/security/nss/cmd/modutil/lex.Pk11Install_yy.c
new file mode 100644
index 000000000..4fa3d766e
--- /dev/null
+++ b/security/nss/cmd/modutil/lex.Pk11Install_yy.c
@@ -0,0 +1,1607 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#define yy_create_buffer Pk11Install_yy_create_buffer
+#define yy_delete_buffer Pk11Install_yy_delete_buffer
+#define yy_scan_buffer Pk11Install_yy_scan_buffer
+#define yy_scan_string Pk11Install_yy_scan_string
+#define yy_scan_bytes Pk11Install_yy_scan_bytes
+#define yy_flex_debug Pk11Install_yy_flex_debug
+#define yy_init_buffer Pk11Install_yy_init_buffer
+#define yy_flush_buffer Pk11Install_yy_flush_buffer
+#define yy_load_buffer_state Pk11Install_yy_load_buffer_state
+#define yy_switch_to_buffer Pk11Install_yy_switch_to_buffer
+#define yyin Pk11Install_yyin
+#define yyleng Pk11Install_yyleng
+#define yylex Pk11Install_yylex
+#define yyout Pk11Install_yyout
+#define yyrestart Pk11Install_yyrestart
+#define yytext Pk11Install_yytext
+#define yywrap Pk11Install_yywrap
+
+#line 20 "lex.Pk11Install_yy.c"
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+//#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+#pragma warn - rch
+#pragma warn - use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int)(unsigned char)c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin)
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } while (0)
+
+#define unput(c) yyunput(c, yytext_ptr)
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+struct yy_buffer_state {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+/* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *)0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO((FILE * input_file));
+
+void yy_switch_to_buffer YY_PROTO((YY_BUFFER_STATE new_buffer));
+void yy_load_buffer_state YY_PROTO((void));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO((FILE * file, int size));
+void yy_delete_buffer YY_PROTO((YY_BUFFER_STATE b));
+void yy_init_buffer YY_PROTO((YY_BUFFER_STATE b, FILE *file));
+void yy_flush_buffer YY_PROTO((YY_BUFFER_STATE b));
+#define YY_FLUSH_BUFFER yy_flush_buffer(yy_current_buffer)
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO((char *base, yy_size_t size));
+YY_BUFFER_STATE yy_scan_string YY_PROTO((yyconst char *yy_str));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO((yyconst char *bytes, int len));
+
+static void *yy_flex_alloc YY_PROTO((yy_size_t));
+static void *yy_flex_realloc YY_PROTO((void *, yy_size_t));
+static void yy_flex_free YY_PROTO((void *));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if (!yy_current_buffer) \
+ yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if (!yy_current_buffer) \
+ yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *)0, *yyout = (FILE *)0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO((void));
+static yy_state_type yy_try_NUL_trans YY_PROTO((yy_state_type current_state));
+static int yy_get_next_buffer YY_PROTO((void));
+static void yy_fatal_error YY_PROTO((yyconst char msg[]));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int)(yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 8
+#define YY_END_OF_BUFFER 9
+static yyconst short int yy_accept[16] =
+ { 0,
+ 0, 0, 9, 3, 6, 5, 7, 1, 2, 3,
+ 6, 0, 0, 4, 0 };
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 6, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 7, 1, 8, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1 };
+
+static yyconst int yy_meta[9] =
+ { 0,
+ 1, 2, 3, 4, 3, 1, 5, 5 };
+
+static yyconst short int yy_base[19] =
+ { 0,
+ 0, 0, 19, 0, 0, 21, 12, 21, 21, 0,
+ 0, 4, 6, 21, 21, 13, 11, 15 };
+
+static yyconst short int yy_def[19] =
+ { 0,
+ 15, 1, 15, 16, 17, 15, 18, 15, 15, 16,
+ 17, 18, 15, 15, 0, 15, 15, 15 };
+
+static yyconst short int yy_nxt[30] =
+ { 0,
+ 4, 5, 6, 5, 7, 4, 8, 9, 14, 13,
+ 12, 12, 11, 10, 11, 12, 12, 13, 15, 12,
+ 3, 15, 15, 15, 15, 15, 15, 15, 15 };
+
+static yyconst short int yy_chk[30] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 12, 12,
+ 13, 13, 17, 16, 17, 18, 18, 7, 3, 18,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15 };
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "installparse.l"
+#define INITIAL 0
+/* lex file for analyzing PKCS #11 Module installation instructions */
+/*----------------------------- Definitions ---------------------------*/
+#line 5 "installparse.l"
+#include <string.h>
+
+#include "install-ds.h" /* defines tokens and data structures */
+#include "installparse.h" /* produced by yacc -d */
+#include <prprf.h>
+static char *putSimpleString(char *); /* return copy of string */
+static char *putComplexString(char *); /* strip out quotes, deal with */
+ /* escaped characters */
+
+void Pk11Install_yyerror(char *);
+
+/* Overrides to use NSPR */
+#define malloc PR_Malloc
+#define realloc PR_Realloc
+#define free PR_Free
+
+int Pk11Install_yylinenum = 1;
+static char *err;
+
+#define YY_NEVER_INTERACTIVE 1
+#define yyunput Pkcs11Install_yyunput
+
+/* This is the default YY_INPUT modified for NSPR */
+#define YY_INPUT(buf, result, max_size) \
+ if (yy_current_buffer->yy_is_interactive) { \
+ char c; \
+ int n; \
+ for (n = 0; n < max_size && \
+ PR_Read(Pk11Install_FD, &c, 1) == 1 && c != '\n'; \
+ ++n) { \
+ buf[n] = c; \
+ } \
+ if (c == '\n') { \
+ buf[n++] = c; \
+ } \
+ result = n; \
+ } else { \
+ result = PR_Read(Pk11Install_FD, buf, max_size); \
+ }
+
+/*** Regular expression definitions ***/
+/* simple_string has no whitespace, quotes, or braces */
+/* complex_string is enclosed in quotes. Inside the quotes, quotes and
+ backslashes must be backslash-escaped. Otherwise, anything goes. */
+/* Standard whitespace */
+/*---------------------------- Actions --------------------------------*/
+#line 437 "lex.Pk11Install_yy.cpp"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO((void));
+#else
+extern int yywrap YY_PROTO((void));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO((int c, char *buf_ptr));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO((char *, yyconst char *, int));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO((yyconst char *));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO((void));
+#else
+static int input YY_PROTO((void));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO((int new_state));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO((void));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO((void));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void)fwrite(yytext, yyleng, 1, yyout)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ if (yy_current_buffer->yy_is_interactive) { \
+ int c = '*', n; \
+ for (n = 0; n < max_size && \
+ (c = getc(yyin)) != EOF && c != '\n'; \
+ ++n) \
+ buf[n] = (char)c; \
+ if (c == '\n') \
+ buf[n++] = (char)c; \
+ if (c == EOF && ferror(yyin)) \
+ YY_FATAL_ERROR("input in flex scanner failed"); \
+ result = n; \
+ } else if (((result = fread(buf, 1, max_size, yyin)) == 0) && \
+ ferror(yyin)) \
+ YY_FATAL_ERROR("input in flex scanner failed");
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error(msg)
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO((void))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 60 "installparse.l"
+
+#line 591 "lex.Pk11Install_yy.cpp"
+
+ if (yy_init) {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if (!yy_start)
+ yy_start = 1; /* first start state */
+
+ if (!yyin)
+ yyin = stdin;
+
+ if (!yyout)
+ yyout = stdout;
+
+ if (!yy_current_buffer)
+ yy_current_buffer =
+ yy_create_buffer(yyin, YY_BUF_SIZE);
+
+ yy_load_buffer_state();
+ }
+
+ while (1) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_match:
+ do {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if (yy_accept[yy_current_state]) {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
+ yy_current_state = (int)yy_def[yy_current_state];
+ if (yy_current_state >= 16)
+ yy_c = yy_meta[(unsigned int)yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
+ ++yy_cp;
+ } while (yy_base[yy_current_state] != 21);
+
+ yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if (yy_act == 0) { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+ do_action: /* This label is used only to access EOF actions. */
+
+ switch (yy_act) { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+ case 1:
+ YY_RULE_SETUP
+#line 62 "installparse.l"
+ return OPENBRACE;
+ YY_BREAK
+ case 2:
+ YY_RULE_SETUP
+#line 63 "installparse.l"
+ return CLOSEBRACE;
+ YY_BREAK
+ case 3:
+ YY_RULE_SETUP
+#line 64 "installparse.l"
+ {
+ Pk11Install_yylval.string =
+ putSimpleString(Pk11Install_yytext);
+ return STRING;
+ }
+ YY_BREAK
+ case 4:
+ YY_RULE_SETUP
+#line 67 "installparse.l"
+ {
+ Pk11Install_yylval.string =
+ putComplexString(Pk11Install_yytext);
+ return STRING;
+ }
+ YY_BREAK
+ case 5:
+ YY_RULE_SETUP
+#line 71 "installparse.l"
+ Pk11Install_yylinenum++;
+ YY_BREAK
+ case 6:
+ YY_RULE_SETUP
+#line 73 "installparse.l"
+ ;
+ YY_BREAK
+ case 7:
+ YY_RULE_SETUP
+#line 75 "installparse.l"
+ {
+ err =
+ PR_smprintf("Invalid lexeme: %s", Pk11Install_yytext);
+ Pk11Install_yyerror(err);
+ PR_smprintf_free(err);
+ return 1;
+ }
+ YY_BREAK
+ case 8:
+ YY_RULE_SETUP
+#line 81 "installparse.l"
+ ECHO;
+ YY_BREAK
+#line 722 "lex.Pk11Install_yy.cpp"
+ case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER: {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int)(yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if (yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW) {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if (yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars]) { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans(yy_current_state);
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if (yy_next_state) {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else
+ switch (yy_get_next_buffer()) {
+ case EOB_ACT_END_OF_FILE: {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if (yywrap()) {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else {
+ if (!yy_did_buffer_switch_on_eof)
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found");
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int
+yy_get_next_buffer()
+{
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed");
+
+ if (yy_current_buffer->yy_fill_buffer == 0) { /* Don't try to fill the buffer, so this is an EOF. */
+ if (yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1) {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int)(yy_c_buf_p - yytext_ptr) - 1;
+
+ for (i = 0; i < number_to_move; ++i)
+ *(dest++) = *(source++);
+
+ if (yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING)
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while (num_to_read <= 0) { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+ "input buffer overflow, can't enlarge buffer because scanner uses REJECT");
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int)(yy_c_buf_p - b->yy_ch_buf);
+
+ if (b->yy_is_our_buffer) {
+ int new_size = b->yy_buf_size * 2;
+
+ if (new_size <= 0)
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc((void *)b->yy_ch_buf,
+ b->yy_buf_size + 2);
+ } else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if (!b->yy_ch_buf)
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow");
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if (num_to_read > YY_READ_BUF_SIZE)
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT((&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read);
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if (yy_n_chars == 0) {
+ if (number_to_move == YY_MORE_ADJ) {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin);
+ }
+
+ else {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type
+yy_get_previous_state()
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+
+ for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp) {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if (yy_accept[yy_current_state]) {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
+ yy_current_state = (int)yy_def[yy_current_state];
+ if (yy_current_state >= 16)
+ yy_c = yy_meta[(unsigned int)yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type
+yy_try_NUL_trans(yy_state_type yy_current_state)
+#else
+static yy_state_type yy_try_NUL_trans(yy_current_state)
+ yy_state_type yy_current_state;
+#endif
+{
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if (yy_accept[yy_current_state]) {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
+ yy_current_state = (int)yy_def[yy_current_state];
+ if (yy_current_state >= 16)
+ yy_c = yy_meta[(unsigned int)yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
+ yy_is_jam = (yy_current_state == 15);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void
+yyunput(int c, register char *yy_bp)
+#else
+static void yyunput(c, yy_bp) int c;
+register char *yy_bp;
+#endif
+{
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if (yy_cp < yy_current_buffer->yy_ch_buf + 2) { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size +
+ 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while (source > yy_current_buffer->yy_ch_buf)
+ *--dest = *--source;
+
+ yy_cp += (int)(dest - source);
+ yy_bp += (int)(dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
+ YY_FATAL_ERROR("flex scanner push-back overflow");
+ }
+
+ *--yy_cp = (char)c;
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+}
+#endif /* ifndef YY_NO_UNPUT */
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int
+yyinput()
+#else
+static int
+input()
+#endif
+{
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if (*yy_c_buf_p == YY_END_OF_BUFFER_CHAR) {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if (yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars])
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch (yy_get_next_buffer()) {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin);
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE: {
+ if (yywrap())
+ return EOF;
+
+ if (!yy_did_buffer_switch_on_eof)
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *)yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+#ifdef YY_USE_PROTOS
+void
+yyrestart(FILE *input_file)
+#else
+void yyrestart(input_file)
+ FILE *input_file;
+#endif
+{
+ if (!yy_current_buffer)
+ yy_current_buffer = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+ yy_init_buffer(yy_current_buffer, input_file);
+ yy_load_buffer_state();
+}
+
+#ifdef YY_USE_PROTOS
+void
+yy_switch_to_buffer(YY_BUFFER_STATE new_buffer)
+#else
+void yy_switch_to_buffer(new_buffer)
+ YY_BUFFER_STATE new_buffer;
+#endif
+{
+ if (yy_current_buffer == new_buffer)
+ return;
+
+ if (yy_current_buffer) {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+}
+
+#ifdef YY_USE_PROTOS
+void
+yy_load_buffer_state(void)
+#else
+void
+yy_load_buffer_state()
+#endif
+{
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+}
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE
+yy_create_buffer(FILE *file, int size)
+#else
+YY_BUFFER_STATE yy_create_buffer(file, size)
+ FILE *file;
+int size;
+#endif
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE)yy_flex_alloc(sizeof(struct yy_buffer_state));
+ if (!b)
+ YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *)yy_flex_alloc(b->yy_buf_size + 2);
+ if (!b->yy_ch_buf)
+ YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b, file);
+
+ return b;
+}
+
+#ifdef YY_USE_PROTOS
+void
+yy_delete_buffer(YY_BUFFER_STATE b)
+#else
+void yy_delete_buffer(b)
+ YY_BUFFER_STATE b;
+#endif
+{
+ if (!b)
+ return;
+
+ if (b == yy_current_buffer)
+ yy_current_buffer = (YY_BUFFER_STATE)0;
+
+ if (b->yy_is_our_buffer)
+ yy_flex_free((void *)b->yy_ch_buf);
+
+ yy_flex_free((void *)b);
+}
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO((int));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void
+yy_init_buffer(YY_BUFFER_STATE b, FILE *file)
+#else
+void yy_init_buffer(b, file)
+ YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+{
+ yy_flush_buffer(b);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty(fileno(file)) > 0) : 0;
+#endif
+#endif
+}
+
+#ifdef YY_USE_PROTOS
+void
+yy_flush_buffer(YY_BUFFER_STATE b)
+#else
+void yy_flush_buffer(b)
+ YY_BUFFER_STATE b;
+#endif
+
+{
+ if (!b)
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if (b == yy_current_buffer)
+ yy_load_buffer_state();
+}
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE
+yy_scan_buffer(char *base, yy_size_t size)
+#else
+YY_BUFFER_STATE yy_scan_buffer(base, size) char *base;
+yy_size_t size;
+#endif
+{
+ YY_BUFFER_STATE b;
+
+ if (size < 2 ||
+ base[size - 2] != YY_END_OF_BUFFER_CHAR ||
+ base[size - 1] != YY_END_OF_BUFFER_CHAR)
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE)yy_flex_alloc(sizeof(struct yy_buffer_state));
+ if (!b)
+ YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()");
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b);
+
+ return b;
+}
+#endif
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE
+yy_scan_string(yyconst char *yy_str)
+#else
+YY_BUFFER_STATE yy_scan_string(yy_str)
+ yyconst char *yy_str;
+#endif
+{
+ int len;
+ for (len = 0; yy_str[len]; ++len)
+ ;
+
+ return yy_scan_bytes(yy_str, len);
+}
+#endif
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE
+yy_scan_bytes(yyconst char *bytes, int len)
+#else
+YY_BUFFER_STATE yy_scan_bytes(bytes, len)
+ yyconst char *bytes;
+int len;
+#endif
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *)yy_flex_alloc(n);
+ if (!buf)
+ YY_FATAL_ERROR("out of dynamic memory in yy_scan_bytes()");
+
+ for (i = 0; i < len; ++i)
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len + 1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf, n);
+ if (!b)
+ YY_FATAL_ERROR("bad buffer in yy_scan_bytes()");
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+#endif
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void
+yy_push_state(int new_state)
+#else
+static void yy_push_state(new_state) int new_state;
+#endif
+{
+ if (yy_start_stack_ptr >= yy_start_stack_depth) {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof(int);
+
+ if (!yy_start_stack)
+ yy_start_stack = (int *)yy_flex_alloc(new_size);
+
+ else
+ yy_start_stack = (int *)yy_flex_realloc(
+ (void *)yy_start_stack, new_size);
+
+ if (!yy_start_stack)
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack");
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+}
+#endif
+
+#ifndef YY_NO_POP_STATE
+static void
+yy_pop_state()
+{
+ if (--yy_start_stack_ptr < 0)
+ YY_FATAL_ERROR("start-condition stack underflow");
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+}
+#endif
+
+#ifndef YY_NO_TOP_STATE
+static int
+yy_top_state()
+{
+ return yy_start_stack[yy_start_stack_ptr - 1];
+}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void
+yy_fatal_error(yyconst char msg[])
+#else
+static void yy_fatal_error(msg) char msg[];
+#endif
+{
+ (void)fprintf(stderr, "%s\n", msg);
+ exit(YY_EXIT_FAILURE);
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } while (0)
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void
+yy_flex_strncpy(char *s1, yyconst char *s2, int n)
+#else
+static void yy_flex_strncpy(s1, s2, n) char *s1;
+yyconst char *s2;
+int n;
+#endif
+{
+ register int i;
+ for (i = 0; i < n; ++i)
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int
+yy_flex_strlen(yyconst char *s)
+#else
+static int yy_flex_strlen(s)
+ yyconst char *s;
+#endif
+{
+ register int n;
+ for (n = 0; s[n]; ++n)
+ ;
+
+ return n;
+}
+#endif
+
+#ifdef YY_USE_PROTOS
+static void *
+yy_flex_alloc(yy_size_t size)
+#else
+static void *yy_flex_alloc(size)
+ yy_size_t size;
+#endif
+{
+ return (void *)malloc(size);
+}
+
+#ifdef YY_USE_PROTOS
+static void *
+yy_flex_realloc(void *ptr, yy_size_t size)
+#else
+static void *yy_flex_realloc(ptr, size) void *ptr;
+yy_size_t size;
+#endif
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *)realloc((char *)ptr, size);
+}
+
+#ifdef YY_USE_PROTOS
+static void
+yy_flex_free(void *ptr)
+#else
+static void yy_flex_free(ptr) void *ptr;
+#endif
+{
+ free(ptr);
+}
+
+#if YY_MAIN
+int
+main()
+{
+ yylex();
+ return 0;
+}
+#endif
+#line 81 "installparse.l"
+
+/*------------------------ Program Section ----------------------------*/
+
+PRFileDesc *Pk11Install_FD = NULL;
+
+/*************************************************************************/
+/* dummy function required by lex */
+int
+Pk11Install_yywrap(void)
+{
+ return 1;
+}
+
+/*************************************************************************/
+/* Return a copy of the given string */
+static char *
+putSimpleString(char *str)
+{
+ char *tmp = (char *)PR_Malloc(strlen(str) + 1);
+ strcpy(tmp, str);
+ return tmp;
+}
+
+/*************************************************************************/
+/* Strip out quotes, replace escaped characters with what they stand for.
+ This function assumes that what is passed in is actually a complex
+ string, so error checking is lax. */
+static char *
+putComplexString(char *str)
+{
+ int size, i, j;
+ char *tmp;
+
+ if (!str) {
+ return NULL;
+ }
+ size = strlen(str);
+
+ /* Allocate the new space. This string will actually be too big,
+ since quotes and backslashes will be stripped out. But that's ok. */
+ tmp = (char *)PR_Malloc(size + 1);
+
+ /* Copy it over */
+ for (i = 0, j = 0; i < size; i++) {
+ if (str[i] == '\"') {
+ continue; /* skip un-escaped quotes */
+ } else if (str[i] == '\\') {
+ ++i; /* escaped character. skip the backslash */
+ }
+ tmp[j++] = str[i];
+ }
+ tmp[j] = '\0';
+
+ return tmp;
+}
diff --git a/security/nss/cmd/modutil/manifest.mn b/security/nss/cmd/modutil/manifest.mn
new file mode 100644
index 000000000..a92ca68c1
--- /dev/null
+++ b/security/nss/cmd/modutil/manifest.mn
@@ -0,0 +1,34 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+CORE_DEPTH = ../..
+
+MODULE = sectools
+
+EXPORTS =
+
+CSRCS = modutil.c \
+ pk11.c \
+ instsec.c \
+ install.c \
+ installparse.c \
+ install-ds.c \
+ lex.Pk11Install_yy.c \
+ $(NULL)
+
+CPPSRCS =
+
+PROGRAM = modutil
+
+REQUIRES = seccmd nss dbm
+
+DEFINES = -DNSPR20 -DYY_NO_UNPUT -DYY_NO_INPUT
+
+# sigh
+#INCLUDES += -I$(CORE_DEPTH)/nss/lib/pk11wrap
+
+# USE_STATIC_LIBS = 1
+
+EXTRA_LIBS = $(JAR_LIBS)
diff --git a/security/nss/cmd/modutil/modutil.c b/security/nss/cmd/modutil/modutil.c
new file mode 100644
index 000000000..02972f7b4
--- /dev/null
+++ b/security/nss/cmd/modutil/modutil.c
@@ -0,0 +1,970 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* To edit this file, set TABSTOPS to 4 spaces.
+ * This is not the normal NSS convention.
+ */
+
+#include "modutil.h"
+#include "install.h"
+#include <plstr.h>
+#include "certdb.h" /* for CERT_DB_FILE_VERSION */
+#include "nss.h"
+
+static void install_error(char* message);
+static char* PR_fgets(char* buf, int size, PRFileDesc* file);
+static char* progName;
+
+/* This enum must be kept in sync with the commandNames list */
+typedef enum {
+ NO_COMMAND,
+ ADD_COMMAND,
+ CHANGEPW_COMMAND,
+ CREATE_COMMAND,
+ DEFAULT_COMMAND,
+ DELETE_COMMAND,
+ DISABLE_COMMAND,
+ ENABLE_COMMAND,
+ FIPS_COMMAND,
+ JAR_COMMAND,
+ LIST_COMMAND,
+ RAW_LIST_COMMAND,
+ RAW_ADD_COMMAND,
+ CHKFIPS_COMMAND,
+ UNDEFAULT_COMMAND
+} Command;
+
+/* This list must be kept in sync with the Command enum */
+static char* commandNames[] = {
+ "(no command)",
+ "-add",
+ "-changepw",
+ "-create",
+ "-default",
+ "-delete",
+ "-disable",
+ "-enable",
+ "-fips",
+ "-jar",
+ "-list",
+ "-rawlist",
+ "-rawadd",
+ "-chkfips",
+ "-undefault"
+};
+
+/* this enum must be kept in sync with the optionStrings list */
+typedef enum {
+ ADD_ARG = 0,
+ RAW_ADD_ARG,
+ CHANGEPW_ARG,
+ CIPHERS_ARG,
+ CREATE_ARG,
+ DBDIR_ARG,
+ DBPREFIX_ARG,
+ DEFAULT_ARG,
+ DELETE_ARG,
+ DISABLE_ARG,
+ ENABLE_ARG,
+ FIPS_ARG,
+ FORCE_ARG,
+ JAR_ARG,
+ LIBFILE_ARG,
+ LIST_ARG,
+ RAW_LIST_ARG,
+ MECHANISMS_ARG,
+ NEWPWFILE_ARG,
+ PWFILE_ARG,
+ SLOT_ARG,
+ UNDEFAULT_ARG,
+ INSTALLDIR_ARG,
+ TEMPDIR_ARG,
+ SECMOD_ARG,
+ NOCERTDB_ARG,
+ STRING_ARG,
+ CHKFIPS_ARG,
+
+ NUM_ARGS /* must be last */
+} Arg;
+
+/* This list must be kept in sync with the Arg enum */
+static char* optionStrings[] = {
+ "-add",
+ "-rawadd",
+ "-changepw",
+ "-ciphers",
+ "-create",
+ "-dbdir",
+ "-dbprefix",
+ "-default",
+ "-delete",
+ "-disable",
+ "-enable",
+ "-fips",
+ "-force",
+ "-jar",
+ "-libfile",
+ "-list",
+ "-rawlist",
+ "-mechanisms",
+ "-newpwfile",
+ "-pwfile",
+ "-slot",
+ "-undefault",
+ "-installdir",
+ "-tempdir",
+ "-secmod",
+ "-nocertdb",
+ "-string",
+ "-chkfips",
+};
+
+char* msgStrings[] = {
+ "FIPS mode enabled.\n",
+ "FIPS mode disabled.\n",
+ "Using database directory %s...\n",
+ "Creating \"%s\"...",
+ "Module \"%s\" added to database.\n",
+ "Module \"%s\" deleted from database.\n",
+ "Token \"%s\" password changed successfully.\n",
+ "Incorrect password, try again...\n",
+ "Passwords do not match, try again...\n",
+ "done.\n",
+ "Slot \"%s\" %s.\n",
+ "Successfully changed defaults.\n",
+ "Successfully changed defaults.\n",
+ "\nWARNING: Performing this operation while the browser is running could cause"
+ "\ncorruption of your security databases. If the browser is currently running,"
+ "\nyou should exit browser before continuing this operation. Type "
+ "\n'q <enter>' to abort, or <enter> to continue: ",
+ "\nAborting...\n"
+};
+
+/* Increment i if doing so would have i still be less than j. If you
+ are able to do this, return 0. Otherwise return 1. */
+#define TRY_INC(i, j) (((i + 1) < j) ? (++i, 0) : 1)
+
+/********************************************************************
+ *
+ * file-wide variables obtained from the command line
+ */
+static Command command = NO_COMMAND;
+static char* pwFile = NULL;
+static char* newpwFile = NULL;
+static char* moduleName = NULL;
+static char* moduleSpec = NULL;
+static char* slotName = NULL;
+static char* secmodName = NULL;
+static char* tokenName = NULL;
+static char* libFile = NULL;
+static char* dbdir = NULL;
+static char* dbprefix = "";
+static char* secmodString = NULL;
+static char* mechanisms = NULL;
+static char* ciphers = NULL;
+static char* fipsArg = NULL;
+static char* jarFile = NULL;
+static char* installDir = NULL;
+static char* tempDir = NULL;
+static short force = 0;
+static PRBool nocertdb = PR_FALSE;
+
+/*******************************************************************
+ *
+ * p a r s e _ a r g s
+ */
+static Error
+parse_args(int argc, char* argv[])
+{
+ int i;
+ char* arg;
+ int optionType;
+
+ /* Loop over all arguments */
+ for (i = 1; i < argc; i++) {
+ arg = argv[i];
+
+ /* Make sure this is an option and not some floating argument */
+ if (arg[0] != '-') {
+ PR_fprintf(PR_STDERR, errStrings[UNEXPECTED_ARG_ERR], argv[i]);
+ return UNEXPECTED_ARG_ERR;
+ }
+
+ /* Find which option this is */
+ for (optionType = 0; optionType < NUM_ARGS; optionType++) {
+ if (!strcmp(arg, optionStrings[optionType])) {
+ break;
+ }
+ }
+
+ /* Deal with this specific option */
+ switch (optionType) {
+ case NUM_ARGS:
+ default:
+ PR_fprintf(PR_STDERR, errStrings[UNKNOWN_OPTION_ERR], arg);
+ return UNKNOWN_OPTION_ERR;
+ break;
+ case ADD_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = ADD_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case CHANGEPW_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = CHANGEPW_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ tokenName = argv[i];
+ break;
+ case CIPHERS_ARG:
+ if (ciphers != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ ciphers = argv[i];
+ break;
+ case CREATE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = CREATE_COMMAND;
+ break;
+ case DBDIR_ARG:
+ if (dbdir != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ dbdir = argv[i];
+ break;
+ case DBPREFIX_ARG:
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ dbprefix = argv[i];
+ break;
+ case UNDEFAULT_ARG:
+ case DEFAULT_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ if (optionType == DEFAULT_ARG) {
+ command = DEFAULT_COMMAND;
+ } else {
+ command = UNDEFAULT_COMMAND;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case DELETE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = DELETE_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case DISABLE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = DISABLE_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case ENABLE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = ENABLE_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case FIPS_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = FIPS_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ fipsArg = argv[i];
+ break;
+ case CHKFIPS_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = CHKFIPS_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ fipsArg = argv[i];
+ break;
+ case FORCE_ARG:
+ force = 1;
+ break;
+ case NOCERTDB_ARG:
+ nocertdb = PR_TRUE;
+ break;
+ case INSTALLDIR_ARG:
+ if (installDir != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ installDir = argv[i];
+ break;
+ case TEMPDIR_ARG:
+ if (tempDir != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ tempDir = argv[i];
+ break;
+ case JAR_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = JAR_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ jarFile = argv[i];
+ break;
+ case LIBFILE_ARG:
+ if (libFile != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ libFile = argv[i];
+ break;
+ case LIST_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = LIST_COMMAND;
+ /* This option may or may not have an argument */
+ if ((i + 1 < argc) && (argv[i + 1][0] != '-')) {
+ moduleName = argv[++i];
+ }
+ break;
+ case RAW_LIST_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = RAW_LIST_COMMAND;
+ /* This option may or may not have an argument */
+ if ((i + 1 < argc) && (argv[i + 1][0] != '-')) {
+ moduleName = argv[++i];
+ }
+ break;
+ case RAW_ADD_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = RAW_ADD_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleSpec = argv[i];
+ break;
+ case MECHANISMS_ARG:
+ if (mechanisms != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ mechanisms = argv[i];
+ break;
+ case NEWPWFILE_ARG:
+ if (newpwFile != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ newpwFile = argv[i];
+ break;
+ case PWFILE_ARG:
+ if (pwFile != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ pwFile = argv[i];
+ break;
+ case SLOT_ARG:
+ if (slotName != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ slotName = argv[i];
+ break;
+ case SECMOD_ARG:
+ if (secmodName != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ secmodName = argv[i];
+ break;
+ case STRING_ARG:
+ if (secmodString != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ secmodString = argv[i];
+ break;
+ }
+ }
+ return SUCCESS;
+}
+
+/************************************************************************
+ *
+ * v e r i f y _ p a r a m s
+ */
+static Error
+verify_params()
+{
+ switch (command) {
+ case ADD_COMMAND:
+ if (libFile == NULL) {
+ PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
+ commandNames[ADD_COMMAND], optionStrings[LIBFILE_ARG]);
+ return MISSING_PARAM_ERR;
+ }
+ break;
+ case CHANGEPW_COMMAND:
+ break;
+ case CREATE_COMMAND:
+ break;
+ case DELETE_COMMAND:
+ break;
+ case DISABLE_COMMAND:
+ break;
+ case ENABLE_COMMAND:
+ break;
+ case FIPS_COMMAND:
+ case CHKFIPS_COMMAND:
+ if (PL_strcasecmp(fipsArg, "true") &&
+ PL_strcasecmp(fipsArg, "false")) {
+ PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]);
+ return INVALID_FIPS_ARG;
+ }
+ break;
+ case JAR_COMMAND:
+ if (installDir == NULL) {
+ PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
+ commandNames[JAR_COMMAND], optionStrings[INSTALLDIR_ARG]);
+ return MISSING_PARAM_ERR;
+ }
+ break;
+ case LIST_COMMAND:
+ case RAW_LIST_COMMAND:
+ break;
+ case RAW_ADD_COMMAND:
+ break;
+ case UNDEFAULT_COMMAND:
+ case DEFAULT_COMMAND:
+ if (mechanisms == NULL) {
+ PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
+ commandNames[command], optionStrings[MECHANISMS_ARG]);
+ return MISSING_PARAM_ERR;
+ }
+ break;
+ default:
+ /* Ignore this here */
+ break;
+ }
+
+ return SUCCESS;
+}
+
+/********************************************************************
+ *
+ * i n i t _ c r y p t o
+ *
+ * Does crypto initialization that all commands will require.
+ * If -nocertdb option is specified, don't open key or cert db (we don't
+ * need them if we aren't going to be verifying signatures). This is
+ * because serverland doesn't always have cert and key database files
+ * available.
+ *
+ * This function is ill advised. Names and locations of databases are
+ * private to NSS proper. Such functions only confuse other users.
+ *
+ */
+static Error
+check_crypto(PRBool create, PRBool readOnly)
+{
+ char* dir;
+ char* moddbname = NULL;
+ Error retval;
+ static const char multiaccess[] = { "multiaccess:" };
+
+ dir = SECU_ConfigDirectory(dbdir); /* dir is never NULL */
+ if (dir[0] == '\0') {
+ PR_fprintf(PR_STDERR, errStrings[NO_DBDIR_ERR]);
+ retval = NO_DBDIR_ERR;
+ goto loser;
+ }
+ if (strncmp(dir, multiaccess, sizeof multiaccess - 1) == 0) {
+ /* won't attempt to handle the multiaccess case. */
+ return SUCCESS;
+ }
+#ifdef notdef
+ /* Make sure db directory exists and is readable */
+ if (PR_Access(dir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dir);
+ retval = DIR_DOESNT_EXIST_ERR;
+ goto loser;
+ } else if (PR_Access(dir, PR_ACCESS_READ_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dir);
+ retval = DIR_NOT_READABLE_ERR;
+ goto loser;
+ }
+
+ if (secmodName == NULL) {
+ secmodName = "secmod.db";
+ }
+
+ moddbname = PR_smprintf("%s/%s", dir, secmodName);
+ if (!moddbname)
+ return OUT_OF_MEM_ERR;
+
+ /* Check for the proper permissions on databases */
+ if (create) {
+ /* Make sure dbs don't already exist, and the directory is
+ writeable */
+ if (PR_Access(moddbname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[FILE_ALREADY_EXISTS_ERR],
+ moddbname);
+ retval = FILE_ALREADY_EXISTS_ERR;
+ goto loser;
+ } else if (PR_Access(dir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dir);
+ retval = DIR_NOT_WRITEABLE_ERR;
+ goto loser;
+ }
+ } else {
+ /* Make sure dbs are readable and writeable */
+ if (PR_Access(moddbname, PR_ACCESS_READ_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], moddbname);
+ retval = FILE_NOT_READABLE_ERR;
+ goto loser;
+ }
+
+ /* Check for write access if we'll be making changes */
+ if (!readOnly) {
+ if (PR_Access(moddbname, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR],
+ moddbname);
+ retval = FILE_NOT_WRITEABLE_ERR;
+ goto loser;
+ }
+ }
+ PR_fprintf(PR_STDOUT, msgStrings[USING_DBDIR_MSG],
+ SECU_ConfigDirectory(NULL));
+ }
+#endif
+ retval = SUCCESS;
+loser:
+ if (moddbname) {
+ PR_Free(moddbname);
+ }
+ return retval;
+}
+
+static Error
+init_crypto(PRBool create, PRBool readOnly)
+{
+
+ PRUint32 flags = 0;
+ SECStatus rv;
+ Error retval;
+ /* Open/create key database */
+
+ if (readOnly)
+ flags |= NSS_INIT_READONLY;
+ if (nocertdb)
+ flags |= NSS_INIT_NOCERTDB;
+ rv = NSS_Initialize(SECU_ConfigDirectory(NULL), dbprefix, dbprefix,
+ secmodName, flags);
+ if (rv != SECSuccess) {
+ SECU_PrintPRandOSError(progName);
+ retval = NSS_INITIALIZE_FAILED_ERR;
+ } else
+ retval = SUCCESS;
+
+ return retval;
+}
+
+/*************************************************************************
+ *
+ * u s a g e
+ */
+static void
+usage()
+{
+ PR_fprintf(PR_STDOUT,
+ "\nNetscape Cryptographic Module Utility\n"
+ "Usage: modutil [command] [options]\n\n"
+ " COMMANDS\n"
+ "---------------------------------------------------------------------------\n"
+ "-add MODULE_NAME Add the named module to the module database\n"
+ " -libfile LIBRARY_FILE The name of the file (.so or .dll)\n"
+ " containing the implementation of PKCS #11\n"
+ " [-ciphers CIPHER_LIST] Enable the given ciphers on this module\n"
+ " [-mechanisms MECHANISM_LIST] Make the module a default provider of the\n"
+ " given mechanisms\n"
+ " [-string CONFIG_STRING] Pass a configuration string to this module\n"
+ "-changepw TOKEN Change the password on the named token\n"
+ " [-pwfile FILE] The old password is in this file\n"
+ " [-newpwfile FILE] The new password is in this file\n"
+ "-chkfips [ true | false ] If true, verify FIPS mode. If false,\n"
+ " verify not FIPS mode\n"
+ "-create Create a new set of security databases\n"
+ "-default MODULE Make the given module a default provider\n"
+ " -mechanisms MECHANISM_LIST of the given mechanisms\n"
+ " [-slot SLOT] limit change to only the given slot\n"
+ "-delete MODULE Remove the named module from the module\n"
+ " database\n"
+ "-disable MODULE Disable the named module\n"
+ " [-slot SLOT] Disable only the named slot on the module\n"
+ "-enable MODULE Enable the named module\n"
+ " [-slot SLOT] Enable only the named slot on the module\n"
+ "-fips [ true | false ] If true, enable FIPS mode. If false,\n"
+ " disable FIPS mode\n"
+ "-force Do not run interactively\n"
+ "-jar JARFILE Install a PKCS #11 module from the given\n"
+ " JAR file in the PKCS #11 JAR format\n"
+ " -installdir DIR Use DIR as the root directory of the\n"
+ " installation\n"
+ " [-tempdir DIR] Use DIR as the temporary installation\n"
+ " directory. If not specified, the current\n"
+ " directory is used\n"
+ "-list [MODULE] Lists information about the specified module\n"
+ " or about all modules if none is specified\n"
+ "-rawadd MODULESPEC Add module spec string to secmod DB\n"
+ "-rawlist [MODULE] Display module spec(s) for one or all\n"
+ " loadable modules\n"
+ "-undefault MODULE The given module is NOT a default provider\n"
+ " -mechanisms MECHANISM_LIST of the listed mechanisms\n"
+ " [-slot SLOT] limit change to only the given slot\n"
+ "---------------------------------------------------------------------------\n"
+ "\n"
+ " OPTIONS\n"
+ "---------------------------------------------------------------------------\n"
+ "-dbdir DIR Directory DIR contains the security databases\n"
+ "-dbprefix prefix Prefix for the security databases\n"
+ "-nocertdb Do not load certificate or key databases. No\n"
+ " verification will be performed on JAR files.\n"
+ "-secmod secmodName Name of the security modules file\n"
+ "---------------------------------------------------------------------------\n"
+ "\n"
+ "Mechanism lists are colon-separated. The following mechanisms are recognized:\n"
+ "RSA, DSA, DH, RC2, RC4, RC5, AES, CAMELLIA, DES, MD2, MD5, SHA1, SHA256, SHA512,\n"
+ "SSL, TLS, RANDOM, and FRIENDLY\n"
+ "\n"
+ "Cipher lists are colon-separated. The following ciphers are recognized:\n"
+ "\n"
+ "\nQuestions or bug reports should be sent to modutil-support@netscape.com.\n");
+}
+
+/*************************************************************************
+ *
+ * m a i n
+ */
+int
+main(int argc, char* argv[])
+{
+ int errcode = SUCCESS;
+ PRBool createdb, readOnly;
+#define STDINBUF_SIZE 80
+ char stdinbuf[STDINBUF_SIZE];
+
+ progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ if (parse_args(argc, argv) != SUCCESS) {
+ usage();
+ errcode = INVALID_USAGE_ERR;
+ goto loser;
+ }
+
+ if (verify_params() != SUCCESS) {
+ usage();
+ errcode = INVALID_USAGE_ERR;
+ goto loser;
+ }
+
+ if (command == NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[NO_COMMAND_ERR]);
+ usage();
+ errcode = INVALID_USAGE_ERR;
+ goto loser;
+ }
+
+ /* Set up crypto stuff */
+ createdb = command == CREATE_COMMAND;
+ readOnly = ((command == LIST_COMMAND) ||
+ (command == CHKFIPS_COMMAND) ||
+ (command == RAW_LIST_COMMAND));
+
+ /* Make sure browser is not running if we're writing to a database */
+ /* Do this before initializing crypto */
+ if (!readOnly && !force) {
+ char* response;
+
+ PR_fprintf(PR_STDOUT, msgStrings[BROWSER_RUNNING_MSG]);
+ if (!PR_fgets(stdinbuf, STDINBUF_SIZE, PR_STDIN)) {
+ PR_fprintf(PR_STDERR, errStrings[STDIN_READ_ERR]);
+ errcode = STDIN_READ_ERR;
+ goto loser;
+ }
+ if ((response = strtok(stdinbuf, " \r\n\t"))) {
+ if (!PL_strcasecmp(response, "q")) {
+ PR_fprintf(PR_STDOUT, msgStrings[ABORTING_MSG]);
+ errcode = SUCCESS;
+ goto loser;
+ }
+ }
+ PR_fprintf(PR_STDOUT, "\n");
+ }
+
+ errcode = check_crypto(createdb, readOnly);
+ if (errcode != SUCCESS) {
+ goto loser;
+ }
+
+ if ((command == RAW_LIST_COMMAND) || (command == RAW_ADD_COMMAND)) {
+ if (!moduleName) {
+ char *readOnlyStr, *noCertDBStr, *sep;
+ if (!secmodName)
+ secmodName = "secmod.db";
+ if (!dbprefix)
+ dbprefix = "";
+ sep = ((command == RAW_LIST_COMMAND) && nocertdb) ? "," : " ";
+ readOnlyStr = (command == RAW_LIST_COMMAND) ? "readOnly" : "";
+ noCertDBStr = nocertdb ? "noCertDB" : "";
+ SECU_ConfigDirectory(dbdir);
+
+ moduleName = PR_smprintf(
+ "name=\"NSS default Module DB\" parameters=\"configdir=%s certPrefix=%s "
+ "keyPrefix=%s secmod=%s flags=%s%s%s\" NSS=\"flags=internal,moduleDB,"
+ "moduleDBOnly,critical\"",
+ SECU_ConfigDirectory(NULL), dbprefix, dbprefix,
+ secmodName, readOnlyStr, sep, noCertDBStr);
+ }
+ if (command == RAW_LIST_COMMAND) {
+ errcode = RawListModule(moduleName);
+ } else {
+ PORT_Assert(moduleSpec);
+ errcode = RawAddModule(moduleName, moduleSpec);
+ }
+ goto loser;
+ }
+
+ errcode = init_crypto(createdb, readOnly);
+ if (errcode != SUCCESS) {
+ goto loser;
+ }
+
+ errcode = LoadMechanismList();
+ if (errcode != SUCCESS) {
+ goto loser;
+ }
+
+ /* Execute the command */
+ switch (command) {
+ case ADD_COMMAND:
+ errcode = AddModule(moduleName, libFile, ciphers, mechanisms, secmodString);
+ break;
+ case CHANGEPW_COMMAND:
+ errcode = ChangePW(tokenName, pwFile, newpwFile);
+ break;
+ case CREATE_COMMAND:
+ /* The work was already done in init_crypto() */
+ break;
+ case DEFAULT_COMMAND:
+ errcode = SetDefaultModule(moduleName, slotName, mechanisms);
+ break;
+ case DELETE_COMMAND:
+ errcode = DeleteModule(moduleName);
+ break;
+ case DISABLE_COMMAND:
+ errcode = EnableModule(moduleName, slotName, PR_FALSE);
+ break;
+ case ENABLE_COMMAND:
+ errcode = EnableModule(moduleName, slotName, PR_TRUE);
+ break;
+ case FIPS_COMMAND:
+ errcode = FipsMode(fipsArg);
+ break;
+ case CHKFIPS_COMMAND:
+ errcode = ChkFipsMode(fipsArg);
+ break;
+ case JAR_COMMAND:
+ Pk11Install_SetErrorHandler(install_error);
+ errcode = Pk11Install_DoInstall(jarFile, installDir, tempDir,
+ PR_STDOUT, force, nocertdb);
+ break;
+ case LIST_COMMAND:
+ if (moduleName) {
+ errcode = ListModule(moduleName);
+ } else {
+ errcode = ListModules();
+ }
+ break;
+ case UNDEFAULT_COMMAND:
+ errcode = UnsetDefaultModule(moduleName, slotName, mechanisms);
+ break;
+ default:
+ PR_fprintf(PR_STDERR, "This command is not supported yet.\n");
+ errcode = INVALID_USAGE_ERR;
+ break;
+ }
+
+ if (NSS_Shutdown() != SECSuccess) {
+ exit(1);
+ }
+
+loser:
+ PR_Cleanup();
+ return errcode;
+}
+
+/************************************************************************
+ *
+ * i n s t a l l _ e r r o r
+ *
+ * Callback function to handle errors in PK11 JAR file installation.
+ */
+static void
+install_error(char* message)
+{
+ PR_fprintf(PR_STDERR, "Install error: %s\n", message);
+}
+
+/*************************************************************************
+ *
+ * o u t _ o f _ m e m o r y
+ */
+void
+out_of_memory(void)
+{
+ PR_fprintf(PR_STDERR, errStrings[OUT_OF_MEM_ERR]);
+ exit(OUT_OF_MEM_ERR);
+}
+
+/**************************************************************************
+ *
+ * P R _ f g e t s
+ *
+ * fgets implemented with NSPR.
+ */
+static char*
+PR_fgets(char* buf, int size, PRFileDesc* file)
+{
+ int i;
+ int status;
+ char c;
+
+ i = 0;
+ while (i < size - 1) {
+ status = PR_Read(file, (void*)&c, 1);
+ if (status == -1) {
+ return NULL;
+ } else if (status == 0) {
+ break;
+ }
+ buf[i++] = c;
+ if (c == '\n') {
+ break;
+ }
+ }
+ buf[i] = '\0';
+
+ return buf;
+}
diff --git a/security/nss/cmd/modutil/modutil.gyp b/security/nss/cmd/modutil/modutil.gyp
new file mode 100644
index 000000000..5d0f87a65
--- /dev/null
+++ b/security/nss/cmd/modutil/modutil.gyp
@@ -0,0 +1,44 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi',
+ '../../cmd/platlibs.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'modutil',
+ 'type': 'executable',
+ 'sources': [
+ 'install-ds.c',
+ 'install.c',
+ 'installparse.c',
+ 'instsec.c',
+ 'lex.Pk11Install_yy.c',
+ 'modutil.c',
+ 'pk11.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/exports.gyp:dbm_exports',
+ '<(DEPTH)/lib/jar/jar.gyp:jar',
+ '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib'
+ ]
+ }
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ '<(nss_private_dist_dir)/nss',
+ '<(nss_private_dist_dir)/dbm'
+ ],
+ 'defines': [
+ 'NSPR20',
+ 'YY_NO_UNPUT',
+ 'YY_NO_INPUT'
+ ]
+ },
+ 'variables': {
+ 'module': 'sectools'
+ }
+}
diff --git a/security/nss/cmd/modutil/modutil.h b/security/nss/cmd/modutil/modutil.h
new file mode 100644
index 000000000..127d0d0da
--- /dev/null
+++ b/security/nss/cmd/modutil/modutil.h
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MODUTIL_H
+#define MODUTIL_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include <prio.h>
+#include <prprf.h>
+#include <prinit.h>
+#include <prlock.h>
+#include <prmem.h>
+#include <plarena.h>
+
+#include "seccomon.h"
+#include "secmod.h"
+#include "secutil.h"
+
+#include "error.h"
+
+Error LoadMechanismList(void);
+Error FipsMode(char *arg);
+Error ChkFipsMode(char *arg);
+Error AddModule(char *moduleName, char *libFile, char *ciphers,
+ char *mechanisms, char *modparms);
+Error DeleteModule(char *moduleName);
+Error ListModule(char *moduleName);
+Error ListModules();
+Error ChangePW(char *tokenName, char *pwFile, char *newpwFile);
+Error EnableModule(char *moduleName, char *slotName, PRBool enable);
+Error RawAddModule(char *dbmodulespec, char *modulespec);
+Error RawListModule(char *modulespec);
+Error SetDefaultModule(char *moduleName, char *slotName, char *mechanisms);
+Error UnsetDefaultModule(char *moduleName, char *slotName, char *mechanisms);
+void out_of_memory(void);
+
+#endif /*MODUTIL_H*/
diff --git a/security/nss/cmd/modutil/pk11.c b/security/nss/cmd/modutil/pk11.c
new file mode 100644
index 000000000..9c460ecd8
--- /dev/null
+++ b/security/nss/cmd/modutil/pk11.c
@@ -0,0 +1,960 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* To edit this file, set TABSTOPS to 4 spaces.
+ * This is not the normal NSS convention.
+ */
+
+#include "modutil.h"
+#include "pk11func.h"
+
+/*************************************************************************
+ *
+ * F i p s M o d e
+ * If arg=="true", enable FIPS mode on the internal module. If arg=="false",
+ * disable FIPS mode on the internal module.
+ */
+Error
+FipsMode(char *arg)
+{
+ char *internal_name;
+
+ if (!PORT_Strcasecmp(arg, "true")) {
+ if (!PK11_IsFIPS()) {
+ internal_name = PR_smprintf("%s",
+ SECMOD_GetInternalModule()->commonName);
+ if (SECMOD_DeleteInternalModule(internal_name) != SECSuccess) {
+ PR_fprintf(PR_STDERR, "%s\n", SECU_Strerror(PORT_GetError()));
+ PR_smprintf_free(internal_name);
+ PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]);
+ return FIPS_SWITCH_FAILED_ERR;
+ }
+ PR_smprintf_free(internal_name);
+ if (!PK11_IsFIPS()) {
+ PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]);
+ return FIPS_SWITCH_FAILED_ERR;
+ }
+ PR_fprintf(PR_STDOUT, msgStrings[FIPS_ENABLED_MSG]);
+ } else {
+ PR_fprintf(PR_STDERR, errStrings[FIPS_ALREADY_ON_ERR]);
+ return FIPS_ALREADY_ON_ERR;
+ }
+ } else if (!PORT_Strcasecmp(arg, "false")) {
+ if (PK11_IsFIPS()) {
+ internal_name = PR_smprintf("%s",
+ SECMOD_GetInternalModule()->commonName);
+ if (SECMOD_DeleteInternalModule(internal_name) != SECSuccess) {
+ PR_fprintf(PR_STDERR, "%s\n", SECU_Strerror(PORT_GetError()));
+ PR_smprintf_free(internal_name);
+ PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]);
+ return FIPS_SWITCH_FAILED_ERR;
+ }
+ PR_smprintf_free(internal_name);
+ if (PK11_IsFIPS()) {
+ PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]);
+ return FIPS_SWITCH_FAILED_ERR;
+ }
+ PR_fprintf(PR_STDOUT, msgStrings[FIPS_DISABLED_MSG]);
+ } else {
+ PR_fprintf(PR_STDERR, errStrings[FIPS_ALREADY_OFF_ERR]);
+ return FIPS_ALREADY_OFF_ERR;
+ }
+ } else {
+ PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]);
+ return INVALID_FIPS_ARG;
+ }
+
+ return SUCCESS;
+}
+
+/*************************************************************************
+ *
+ * C h k F i p s M o d e
+ * If arg=="true", verify FIPS mode is enabled on the internal module.
+ * If arg=="false", verify FIPS mode is disabled on the internal module.
+ */
+Error
+ChkFipsMode(char *arg)
+{
+ if (!PORT_Strcasecmp(arg, "true")) {
+ if (PK11_IsFIPS()) {
+ PR_fprintf(PR_STDOUT, msgStrings[FIPS_ENABLED_MSG]);
+ } else {
+ PR_fprintf(PR_STDOUT, msgStrings[FIPS_DISABLED_MSG]);
+ return FIPS_SWITCH_FAILED_ERR;
+ }
+
+ } else if (!PORT_Strcasecmp(arg, "false")) {
+ if (!PK11_IsFIPS()) {
+ PR_fprintf(PR_STDOUT, msgStrings[FIPS_DISABLED_MSG]);
+ } else {
+ PR_fprintf(PR_STDOUT, msgStrings[FIPS_ENABLED_MSG]);
+ return FIPS_SWITCH_FAILED_ERR;
+ }
+ } else {
+ PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]);
+ return INVALID_FIPS_ARG;
+ }
+
+ return SUCCESS;
+}
+
+/************************************************************************
+ * Cipher and Mechanism name-bitmask translation tables
+ */
+
+typedef struct {
+ const char *name;
+ unsigned long mask;
+} MaskString;
+
+static const MaskString cipherStrings[] = {
+ { "FORTEZZA", PUBLIC_CIPHER_FORTEZZA_FLAG }
+};
+static const int numCipherStrings =
+ sizeof(cipherStrings) / sizeof(cipherStrings[0]);
+
+/* Initialized by LoadMechanismList */
+static MaskString *mechanismStrings = NULL;
+static int numMechanismStrings = 0;
+const static PK11DefaultArrayEntry *pk11_DefaultArray = NULL;
+static int pk11_DefaultArraySize = 0;
+
+/* Maximum length of a colon-separated list of all the strings in an
+ * array. */
+#define MAX_STRING_LIST_LEN 240 /* or less */
+
+Error
+LoadMechanismList(void)
+{
+ int i;
+
+ if (pk11_DefaultArray == NULL) {
+ pk11_DefaultArray = PK11_GetDefaultArray(&pk11_DefaultArraySize);
+ if (pk11_DefaultArray == NULL) {
+ /* should assert. This shouldn't happen */
+ return UNSPECIFIED_ERR;
+ }
+ }
+ if (mechanismStrings != NULL) {
+ return SUCCESS;
+ }
+
+ /* build the mechanismStrings array */
+ mechanismStrings = PORT_NewArray(MaskString, pk11_DefaultArraySize);
+ if (mechanismStrings == NULL) {
+ return OUT_OF_MEM_ERR;
+ }
+ numMechanismStrings = pk11_DefaultArraySize;
+ for (i = 0; i < numMechanismStrings; i++) {
+ const char *name = pk11_DefaultArray[i].name;
+ unsigned long flag = pk11_DefaultArray[i].flag;
+ /* map new name to old */
+ switch (flag) {
+ case SECMOD_FORTEZZA_FLAG:
+ name = "FORTEZZA";
+ break;
+ case SECMOD_SHA1_FLAG:
+ name = "SHA1";
+ break;
+ case SECMOD_CAMELLIA_FLAG:
+ name = "CAMELLIA";
+ break;
+ case SECMOD_RANDOM_FLAG:
+ name = "RANDOM";
+ break;
+ case SECMOD_FRIENDLY_FLAG:
+ name = "FRIENDLY";
+ break;
+ default:
+ break;
+ }
+ mechanismStrings[i].name = name;
+ mechanismStrings[i].mask = SECMOD_InternaltoPubMechFlags(flag);
+ }
+ return SUCCESS;
+}
+
+/************************************************************************
+ *
+ * g e t F l a g s F r o m S t r i n g
+ *
+ * Parses a mechanism list passed on the command line and converts it
+ * to an unsigned long bitmask.
+ * string is a colon-separated string of constants
+ * array is an array of MaskStrings.
+ * elements is the number of elements in array.
+ */
+static unsigned long
+getFlagsFromString(char *string, const MaskString array[], int elements)
+{
+ unsigned long ret = 0;
+ short i = 0;
+ char *cp;
+ char *buf;
+ char *end;
+
+ if (!string || !string[0]) {
+ return ret;
+ }
+
+ /* Make a temporary copy of the string */
+ buf = PR_Malloc(strlen(string) + 1);
+ if (!buf) {
+ out_of_memory();
+ }
+ strcpy(buf, string);
+
+ /* Look at each element of the list passed in */
+ for (cp = buf; cp && *cp; cp = (end ? end + 1 : NULL)) {
+ /* Look at the string up to the next colon */
+ end = strchr(cp, ':');
+ if (end) {
+ *end = '\0';
+ }
+
+ /* Find which element this is */
+ for (i = 0; i < elements; i++) {
+ if (!PORT_Strcasecmp(cp, array[i].name)) {
+ break;
+ }
+ }
+ if (i == elements) {
+ /* Skip a bogus string, but print a warning message */
+ PR_fprintf(PR_STDERR, errStrings[INVALID_CONSTANT_ERR], cp);
+ continue;
+ }
+ ret |= array[i].mask;
+ }
+
+ PR_Free(buf);
+ return ret;
+}
+
+/**********************************************************************
+ *
+ * g e t S t r i n g F r o m F l a g s
+ *
+ * The return string's memory is owned by this function. Copy it
+ * if you need it permanently or you want to change it.
+ */
+static char *
+getStringFromFlags(unsigned long flags, const MaskString array[], int elements)
+{
+ static char buf[MAX_STRING_LIST_LEN];
+ int i;
+ int count = 0;
+
+ buf[0] = '\0';
+ for (i = 0; i < elements; i++) {
+ if (flags & array[i].mask) {
+ ++count;
+ if (count != 1) {
+ strcat(buf, ":");
+ }
+ strcat(buf, array[i].name);
+ }
+ }
+ return buf;
+}
+
+/**********************************************************************
+ *
+ * A d d M o d u l e
+ *
+ * Add the named module, with the given library file, ciphers, and
+ * default mechanism flags
+ */
+Error
+AddModule(char *moduleName, char *libFile, char *cipherString,
+ char *mechanismString, char *modparms)
+{
+ unsigned long ciphers;
+ unsigned long mechanisms;
+ SECStatus status;
+
+ mechanisms =
+ getFlagsFromString(mechanismString, mechanismStrings,
+ numMechanismStrings);
+ ciphers =
+ getFlagsFromString(cipherString, cipherStrings, numCipherStrings);
+
+ status =
+ SECMOD_AddNewModuleEx(moduleName, libFile,
+ SECMOD_PubMechFlagstoInternal(mechanisms),
+ SECMOD_PubCipherFlagstoInternal(ciphers),
+ modparms, NULL);
+
+ if (status != SECSuccess) {
+ char *errtxt = NULL;
+ PRInt32 copied = 0;
+ if (PR_GetErrorTextLength()) {
+ errtxt = PR_Malloc(PR_GetErrorTextLength() + 1);
+ copied = PR_GetErrorText(errtxt);
+ }
+ if (copied && errtxt) {
+ PR_fprintf(PR_STDERR, errStrings[ADD_MODULE_FAILED_ERR],
+ moduleName, errtxt);
+ PR_Free(errtxt);
+ } else {
+ PR_fprintf(PR_STDERR, errStrings[ADD_MODULE_FAILED_ERR],
+ moduleName, SECU_Strerror(PORT_GetError()));
+ }
+ return ADD_MODULE_FAILED_ERR;
+ } else {
+ PR_fprintf(PR_STDOUT, msgStrings[ADD_MODULE_SUCCESS_MSG], moduleName);
+ return SUCCESS;
+ }
+}
+
+/***********************************************************************
+ *
+ * D e l e t e M o d u l e
+ *
+ * Deletes the named module from the database.
+ */
+Error
+DeleteModule(char *moduleName)
+{
+ SECStatus status;
+ int type;
+
+ status = SECMOD_DeleteModule(moduleName, &type);
+
+ if (status != SECSuccess) {
+ if (type == SECMOD_FIPS || type == SECMOD_INTERNAL) {
+ PR_fprintf(PR_STDERR, errStrings[DELETE_INTERNAL_ERR]);
+ return DELETE_INTERNAL_ERR;
+ } else {
+ PR_fprintf(PR_STDERR, errStrings[DELETE_FAILED_ERR], moduleName);
+ return DELETE_FAILED_ERR;
+ }
+ }
+
+ PR_fprintf(PR_STDOUT, msgStrings[DELETE_SUCCESS_MSG], moduleName);
+ return SUCCESS;
+}
+
+/************************************************************************
+ *
+ * R a w L i s t M o d u l e s
+ *
+ * Lists all the modules in the database, along with their slots and tokens.
+ */
+Error
+RawListModule(char *modulespec)
+{
+ SECMODModule *module;
+ char **moduleSpecList;
+
+ module = SECMOD_LoadModule(modulespec, NULL, PR_FALSE);
+ if (module == NULL) {
+ /* handle error */
+ return NO_SUCH_MODULE_ERR;
+ }
+
+ moduleSpecList = SECMOD_GetModuleSpecList(module);
+ if (!moduleSpecList || !moduleSpecList[0]) {
+ SECU_PrintError("modutil",
+ "no specs in secmod DB");
+ return NO_SUCH_MODULE_ERR;
+ }
+
+ for (; *moduleSpecList; moduleSpecList++) {
+ printf("%s\n\n", *moduleSpecList);
+ }
+
+ return SUCCESS;
+}
+
+Error
+RawAddModule(char *dbmodulespec, char *modulespec)
+{
+ SECMODModule *module;
+ SECMODModule *dbmodule;
+
+ dbmodule = SECMOD_LoadModule(dbmodulespec, NULL, PR_TRUE);
+ if (dbmodule == NULL) {
+ /* handle error */
+ return NO_SUCH_MODULE_ERR;
+ }
+
+ module = SECMOD_LoadModule(modulespec, dbmodule, PR_FALSE);
+ if (module == NULL) {
+ /* handle error */
+ return NO_SUCH_MODULE_ERR;
+ }
+
+ if (SECMOD_UpdateModule(module) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[UPDATE_MOD_FAILED_ERR], modulespec);
+ return UPDATE_MOD_FAILED_ERR;
+ }
+ return SUCCESS;
+}
+
+static void
+printModule(SECMODModule *module, int *count)
+{
+ int slotCount = module->loaded ? module->slotCount : 0;
+ int i;
+
+ if ((*count)++) {
+ PR_fprintf(PR_STDOUT, "\n");
+ }
+ PR_fprintf(PR_STDOUT, "%3d. %s\n", *count, module->commonName);
+
+ if (module->dllName) {
+ PR_fprintf(PR_STDOUT, "\tlibrary name: %s\n", module->dllName);
+ }
+
+ if (slotCount == 0) {
+ PR_fprintf(PR_STDOUT,
+ "\t slots: There are no slots attached to this module\n");
+ } else {
+ PR_fprintf(PR_STDOUT, "\t slots: %d slot%s attached\n",
+ slotCount, (slotCount == 1 ? "" : "s"));
+ }
+
+ if (module->loaded == 0) {
+ PR_fprintf(PR_STDOUT, "\tstatus: Not loaded\n");
+ } else {
+ PR_fprintf(PR_STDOUT, "\tstatus: loaded\n");
+ }
+
+ /* Print slot and token names */
+ for (i = 0; i < slotCount; i++) {
+ PK11SlotInfo *slot = module->slots[i];
+
+ PR_fprintf(PR_STDOUT, "\n");
+ PR_fprintf(PR_STDOUT, "\t slot: %s\n", PK11_GetSlotName(slot));
+ PR_fprintf(PR_STDOUT, "\ttoken: %s\n", PK11_GetTokenName(slot));
+ }
+ return;
+}
+
+/************************************************************************
+ *
+ * L i s t M o d u l e s
+ *
+ * Lists all the modules in the database, along with their slots and tokens.
+ */
+Error
+ListModules()
+{
+ SECMODListLock *lock;
+ SECMODModuleList *list;
+ SECMODModuleList *deadlist;
+ SECMODModuleList *mlp;
+ Error ret = UNSPECIFIED_ERR;
+ int count = 0;
+
+ lock = SECMOD_GetDefaultModuleListLock();
+ if (!lock) {
+ PR_fprintf(PR_STDERR, errStrings[NO_LIST_LOCK_ERR]);
+ return NO_LIST_LOCK_ERR;
+ }
+
+ SECMOD_GetReadLock(lock);
+
+ list = SECMOD_GetDefaultModuleList();
+ deadlist = SECMOD_GetDeadModuleList();
+ if (!list && !deadlist) {
+ PR_fprintf(PR_STDERR, errStrings[NO_MODULE_LIST_ERR]);
+ ret = NO_MODULE_LIST_ERR;
+ goto loser;
+ }
+
+ PR_fprintf(PR_STDOUT,
+ "\nListing of PKCS #11 Modules\n"
+ "-----------------------------------------------------------\n");
+
+ for (mlp = list; mlp != NULL; mlp = mlp->next) {
+ printModule(mlp->module, &count);
+ }
+ for (mlp = deadlist; mlp != NULL; mlp = mlp->next) {
+ printModule(mlp->module, &count);
+ }
+
+ PR_fprintf(PR_STDOUT,
+ "-----------------------------------------------------------\n");
+
+ ret = SUCCESS;
+
+loser:
+ SECMOD_ReleaseReadLock(lock);
+ return ret;
+}
+
+/* Strings describing PK11DisableReasons */
+static char *disableReasonStr[] = {
+ "no reason",
+ "user disabled",
+ "could not initialize token",
+ "could not verify token",
+ "token not present"
+};
+static int numDisableReasonStr =
+ sizeof(disableReasonStr) / sizeof(disableReasonStr[0]);
+
+/***********************************************************************
+ *
+ * L i s t M o d u l e
+ *
+ * Lists detailed information about the named module.
+ */
+Error
+ListModule(char *moduleName)
+{
+ SECMODModule *module = NULL;
+ PK11SlotInfo *slot;
+ int slotnum;
+ CK_INFO modinfo;
+ CK_SLOT_INFO slotinfo;
+ CK_TOKEN_INFO tokeninfo;
+ char *ciphers, *mechanisms;
+ PK11DisableReasons reason;
+ Error rv = SUCCESS;
+
+ if (!moduleName) {
+ return SUCCESS;
+ }
+
+ module = SECMOD_FindModule(moduleName);
+ if (!module) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName);
+ rv = NO_SUCH_MODULE_ERR;
+ goto loser;
+ }
+
+ if ((module->loaded) &&
+ (PK11_GetModInfo(module, &modinfo) != SECSuccess)) {
+ PR_fprintf(PR_STDERR, errStrings[MOD_INFO_ERR], moduleName);
+ rv = MOD_INFO_ERR;
+ goto loser;
+ }
+
+ /* Module info */
+ PR_fprintf(PR_STDOUT,
+ "\n-----------------------------------------------------------\n");
+ PR_fprintf(PR_STDOUT, "Name: %s\n", module->commonName);
+ if (module->internal || !module->dllName) {
+ PR_fprintf(PR_STDOUT, "Library file: **Internal ONLY module**\n");
+ } else {
+ PR_fprintf(PR_STDOUT, "Library file: %s\n", module->dllName);
+ }
+
+ if (module->loaded) {
+ PR_fprintf(PR_STDOUT, "Manufacturer: %.32s\n", modinfo.manufacturerID);
+ PR_fprintf(PR_STDOUT, "Description: %.32s\n", modinfo.libraryDescription);
+ PR_fprintf(PR_STDOUT, "PKCS #11 Version %d.%d\n",
+ modinfo.cryptokiVersion.major, modinfo.cryptokiVersion.minor);
+ PR_fprintf(PR_STDOUT, "Library Version: %d.%d\n",
+ modinfo.libraryVersion.major, modinfo.libraryVersion.minor);
+ } else {
+ PR_fprintf(PR_STDOUT, "* Module not loaded\n");
+ }
+ /* Get cipher and mechanism flags */
+ ciphers = getStringFromFlags(module->ssl[0], cipherStrings,
+ numCipherStrings);
+ if (ciphers[0] == '\0') {
+ ciphers = "None";
+ }
+ PR_fprintf(PR_STDOUT, "Cipher Enable Flags: %s\n", ciphers);
+ mechanisms = NULL;
+ if (module->slotCount > 0) {
+ mechanisms = getStringFromFlags(
+ PK11_GetDefaultFlags(module->slots[0]),
+ mechanismStrings, numMechanismStrings);
+ }
+ if ((mechanisms == NULL) || (mechanisms[0] == '\0')) {
+ mechanisms = "None";
+ }
+ PR_fprintf(PR_STDOUT, "Default Mechanism Flags: %s\n", mechanisms);
+
+#define PAD " "
+
+ /* Loop over each slot */
+ for (slotnum = 0; slotnum < module->slotCount; slotnum++) {
+ slot = module->slots[slotnum];
+ if (PK11_GetSlotInfo(slot, &slotinfo) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[SLOT_INFO_ERR],
+ PK11_GetSlotName(slot));
+ rv = SLOT_INFO_ERR;
+ continue;
+ }
+
+ /* Slot Info */
+ PR_fprintf(PR_STDOUT, "\n" PAD "Slot: %s\n", PK11_GetSlotName(slot));
+ mechanisms = getStringFromFlags(PK11_GetDefaultFlags(slot),
+ mechanismStrings, numMechanismStrings);
+ if (mechanisms[0] == '\0') {
+ mechanisms = "None";
+ }
+ PR_fprintf(PR_STDOUT, PAD "Slot Mechanism Flags: %s\n", mechanisms);
+ PR_fprintf(PR_STDOUT, PAD "Manufacturer: %.32s\n",
+ slotinfo.manufacturerID);
+ if (PK11_IsHW(slot)) {
+ PR_fprintf(PR_STDOUT, PAD "Type: Hardware\n");
+ } else {
+ PR_fprintf(PR_STDOUT, PAD "Type: Software\n");
+ }
+ PR_fprintf(PR_STDOUT, PAD "Version Number: %d.%d\n",
+ slotinfo.hardwareVersion.major, slotinfo.hardwareVersion.minor);
+ PR_fprintf(PR_STDOUT, PAD "Firmware Version: %d.%d\n",
+ slotinfo.firmwareVersion.major, slotinfo.firmwareVersion.minor);
+ if (PK11_IsDisabled(slot)) {
+ reason = PK11_GetDisabledReason(slot);
+ if (reason < numDisableReasonStr) {
+ PR_fprintf(PR_STDOUT, PAD "Status: DISABLED (%s)\n",
+ disableReasonStr[reason]);
+ } else {
+ PR_fprintf(PR_STDOUT, PAD "Status: DISABLED\n");
+ }
+ } else {
+ PR_fprintf(PR_STDOUT, PAD "Status: Enabled\n");
+ }
+
+ if (PK11_GetTokenInfo(slot, &tokeninfo) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[TOKEN_INFO_ERR],
+ PK11_GetTokenName(slot));
+ rv = TOKEN_INFO_ERR;
+ continue;
+ }
+
+ /* Token Info */
+ PR_fprintf(PR_STDOUT, PAD "Token Name: %.32s\n",
+ tokeninfo.label);
+ PR_fprintf(PR_STDOUT, PAD "Token Manufacturer: %.32s\n",
+ tokeninfo.manufacturerID);
+ PR_fprintf(PR_STDOUT, PAD "Token Model: %.16s\n", tokeninfo.model);
+ PR_fprintf(PR_STDOUT, PAD "Token Serial Number: %.16s\n",
+ tokeninfo.serialNumber);
+ PR_fprintf(PR_STDOUT, PAD "Token Version: %d.%d\n",
+ tokeninfo.hardwareVersion.major, tokeninfo.hardwareVersion.minor);
+ PR_fprintf(PR_STDOUT, PAD "Token Firmware Version: %d.%d\n",
+ tokeninfo.firmwareVersion.major, tokeninfo.firmwareVersion.minor);
+ if (tokeninfo.flags & CKF_WRITE_PROTECTED) {
+ PR_fprintf(PR_STDOUT, PAD "Access: Write Protected\n");
+ } else {
+ PR_fprintf(PR_STDOUT, PAD "Access: NOT Write Protected\n");
+ }
+ if (tokeninfo.flags & CKF_LOGIN_REQUIRED) {
+ PR_fprintf(PR_STDOUT, PAD "Login Type: Login required\n");
+ } else {
+ PR_fprintf(PR_STDOUT, PAD
+ "Login Type: Public (no login required)\n");
+ }
+ if (tokeninfo.flags & CKF_USER_PIN_INITIALIZED) {
+ PR_fprintf(PR_STDOUT, PAD "User Pin: Initialized\n");
+ } else {
+ PR_fprintf(PR_STDOUT, PAD "User Pin: NOT Initialized\n");
+ }
+ }
+ PR_fprintf(PR_STDOUT,
+ "\n-----------------------------------------------------------\n");
+loser:
+ if (module) {
+ SECMOD_DestroyModule(module);
+ }
+ return rv;
+}
+
+/************************************************************************
+ *
+ * C h a n g e P W
+ */
+Error
+ChangePW(char *tokenName, char *pwFile, char *newpwFile)
+{
+ char *oldpw = NULL, *newpw = NULL, *newpw2 = NULL;
+ PK11SlotInfo *slot;
+ Error ret = UNSPECIFIED_ERR;
+ PRBool matching;
+
+ slot = PK11_FindSlotByName(tokenName);
+ if (!slot) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_TOKEN_ERR], tokenName);
+ return NO_SUCH_TOKEN_ERR;
+ }
+
+ /* Get old password */
+ if (!PK11_NeedUserInit(slot)) {
+ if (pwFile) {
+ oldpw = SECU_FilePasswd(NULL, PR_FALSE, pwFile);
+ if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[BAD_PW_ERR]);
+ ret = BAD_PW_ERR;
+ goto loser;
+ }
+ } else {
+ for (matching = PR_FALSE; !matching;) {
+ oldpw = SECU_GetPasswordString(NULL, "Enter old password: ");
+ if (PK11_CheckUserPassword(slot, oldpw) == SECSuccess) {
+ matching = PR_TRUE;
+ } else {
+ PR_fprintf(PR_STDOUT, msgStrings[BAD_PW_MSG]);
+ }
+ }
+ }
+ }
+
+ /* Get new password */
+ if (newpwFile) {
+ newpw = SECU_FilePasswd(NULL, PR_FALSE, newpwFile);
+ } else {
+ for (matching = PR_FALSE; !matching;) {
+ newpw = SECU_GetPasswordString(NULL, "Enter new password: ");
+ newpw2 = SECU_GetPasswordString(NULL, "Re-enter new password: ");
+ if (strcmp(newpw, newpw2)) {
+ PR_fprintf(PR_STDOUT, msgStrings[PW_MATCH_MSG]);
+ PORT_ZFree(newpw, strlen(newpw));
+ PORT_ZFree(newpw2, strlen(newpw2));
+ } else {
+ matching = PR_TRUE;
+ }
+ }
+ }
+
+ /* Change the password */
+ if (PK11_NeedUserInit(slot)) {
+ if (PK11_InitPin(slot, NULL /*ssopw*/, newpw) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[CHANGEPW_FAILED_ERR], tokenName);
+ ret = CHANGEPW_FAILED_ERR;
+ goto loser;
+ }
+ } else {
+ if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[CHANGEPW_FAILED_ERR], tokenName);
+ ret = CHANGEPW_FAILED_ERR;
+ goto loser;
+ }
+ }
+
+ PR_fprintf(PR_STDOUT, msgStrings[CHANGEPW_SUCCESS_MSG], tokenName);
+ ret = SUCCESS;
+
+loser:
+ if (oldpw) {
+ PORT_ZFree(oldpw, strlen(oldpw));
+ }
+ if (newpw) {
+ PORT_ZFree(newpw, strlen(newpw));
+ }
+ if (newpw2) {
+ PORT_ZFree(newpw2, strlen(newpw2));
+ }
+ PK11_FreeSlot(slot);
+
+ return ret;
+}
+
+/***********************************************************************
+ *
+ * E n a b l e M o d u l e
+ *
+ * If enable==PR_TRUE, enables the module or slot.
+ * If enable==PR_FALSE, disables the module or slot.
+ * moduleName is the name of the module.
+ * slotName is the name of the slot. It is optional.
+ */
+Error
+EnableModule(char *moduleName, char *slotName, PRBool enable)
+{
+ int i;
+ SECMODModule *module = NULL;
+ PK11SlotInfo *slot = NULL;
+ PRBool found = PR_FALSE;
+ Error rv;
+
+ module = SECMOD_FindModule(moduleName);
+ if (!module) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName);
+ rv = NO_SUCH_MODULE_ERR;
+ goto loser;
+ }
+
+ for (i = 0; i < module->slotCount; i++) {
+ slot = module->slots[i];
+ if (slotName && strcmp(PK11_GetSlotName(slot), slotName)) {
+ /* Not the right slot */
+ continue;
+ }
+ if (enable) {
+ if (!PK11_UserEnableSlot(slot)) {
+ PR_fprintf(PR_STDERR, errStrings[ENABLE_FAILED_ERR],
+ "enable", PK11_GetSlotName(slot));
+ rv = ENABLE_FAILED_ERR;
+ goto loser;
+ } else {
+ found = PR_TRUE;
+ PR_fprintf(PR_STDOUT, msgStrings[ENABLE_SUCCESS_MSG],
+ PK11_GetSlotName(slot), "enabled");
+ }
+ } else {
+ if (!PK11_UserDisableSlot(slot)) {
+ PR_fprintf(PR_STDERR, errStrings[ENABLE_FAILED_ERR],
+ "disable", PK11_GetSlotName(slot));
+ rv = ENABLE_FAILED_ERR;
+ goto loser;
+ } else {
+ found = PR_TRUE;
+ PR_fprintf(PR_STDOUT, msgStrings[ENABLE_SUCCESS_MSG],
+ PK11_GetSlotName(slot), "disabled");
+ }
+ }
+ }
+
+ if (slotName && !found) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_SLOT_ERR], slotName);
+ rv = NO_SUCH_SLOT_ERR;
+ goto loser;
+ }
+
+ /* Delete and re-add module to save changes */
+ if (SECMOD_UpdateModule(module) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[UPDATE_MOD_FAILED_ERR], moduleName);
+ rv = UPDATE_MOD_FAILED_ERR;
+ goto loser;
+ }
+
+ rv = SUCCESS;
+loser:
+ if (module) {
+ SECMOD_DestroyModule(module);
+ }
+ return rv;
+}
+
+/*************************************************************************
+ *
+ * S e t D e f a u l t M o d u l e
+ *
+ */
+Error
+SetDefaultModule(char *moduleName, char *slotName, char *mechanisms)
+{
+ SECMODModule *module = NULL;
+ PK11SlotInfo *slot;
+ int s, i;
+ unsigned long mechFlags = getFlagsFromString(mechanisms, mechanismStrings,
+ numMechanismStrings);
+ PRBool found = PR_FALSE;
+ Error errcode = UNSPECIFIED_ERR;
+
+ mechFlags = SECMOD_PubMechFlagstoInternal(mechFlags);
+
+ module = SECMOD_FindModule(moduleName);
+ if (!module) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName);
+ errcode = NO_SUCH_MODULE_ERR;
+ goto loser;
+ }
+
+ /* Go through each slot */
+ for (s = 0; s < module->slotCount; s++) {
+ slot = module->slots[s];
+
+ if ((slotName != NULL) &&
+ !((strcmp(PK11_GetSlotName(slot), slotName) == 0) ||
+ (strcmp(PK11_GetTokenName(slot), slotName) == 0))) {
+ /* we are only interested in changing the one slot */
+ continue;
+ }
+
+ found = PR_TRUE;
+
+ /* Go through each mechanism */
+ for (i = 0; i < pk11_DefaultArraySize; i++) {
+ if (pk11_DefaultArray[i].flag & mechFlags) {
+ /* Enable this default mechanism */
+ PK11_UpdateSlotAttribute(slot, &(pk11_DefaultArray[i]),
+ PR_TRUE);
+ }
+ }
+ }
+ if (slotName && !found) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_SLOT_ERR], slotName);
+ errcode = NO_SUCH_SLOT_ERR;
+ goto loser;
+ }
+
+ /* Delete and re-add module to save changes */
+ if (SECMOD_UpdateModule(module) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[DEFAULT_FAILED_ERR],
+ moduleName);
+ errcode = DEFAULT_FAILED_ERR;
+ goto loser;
+ }
+
+ PR_fprintf(PR_STDOUT, msgStrings[DEFAULT_SUCCESS_MSG]);
+
+ errcode = SUCCESS;
+loser:
+ if (module) {
+ SECMOD_DestroyModule(module);
+ }
+ return errcode;
+}
+
+/************************************************************************
+ *
+ * U n s e t D e f a u l t M o d u l e
+ */
+Error
+UnsetDefaultModule(char *moduleName, char *slotName, char *mechanisms)
+{
+ SECMODModule *module = NULL;
+ PK11SlotInfo *slot;
+ int s, i;
+ unsigned long mechFlags = getFlagsFromString(mechanisms,
+ mechanismStrings, numMechanismStrings);
+ PRBool found = PR_FALSE;
+ Error rv;
+
+ mechFlags = SECMOD_PubMechFlagstoInternal(mechFlags);
+
+ module = SECMOD_FindModule(moduleName);
+ if (!module) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName);
+ rv = NO_SUCH_MODULE_ERR;
+ goto loser;
+ }
+
+ for (s = 0; s < module->slotCount; s++) {
+ slot = module->slots[s];
+ if ((slotName != NULL) &&
+ !((strcmp(PK11_GetSlotName(slot), slotName) == 0) ||
+ (strcmp(PK11_GetTokenName(slot), slotName) == 0))) {
+ /* we are only interested in changing the one slot */
+ continue;
+ }
+ for (i = 0; i < pk11_DefaultArraySize; i++) {
+ if (pk11_DefaultArray[i].flag & mechFlags) {
+ PK11_UpdateSlotAttribute(slot, &(pk11_DefaultArray[i]),
+ PR_FALSE);
+ }
+ }
+ }
+ if (slotName && !found) {
+ PR_fprintf(PR_STDERR, errStrings[NO_SUCH_SLOT_ERR], slotName);
+ rv = NO_SUCH_SLOT_ERR;
+ goto loser;
+ }
+
+ /* Delete and re-add module to save changes */
+ if (SECMOD_UpdateModule(module) != SECSuccess) {
+ PR_fprintf(PR_STDERR, errStrings[UNDEFAULT_FAILED_ERR],
+ moduleName);
+ rv = UNDEFAULT_FAILED_ERR;
+ goto loser;
+ }
+
+ PR_fprintf(PR_STDOUT, msgStrings[UNDEFAULT_SUCCESS_MSG]);
+ rv = SUCCESS;
+loser:
+ if (module) {
+ SECMOD_DestroyModule(module);
+ }
+ return rv;
+}
diff --git a/security/nss/cmd/modutil/pk11jar.html b/security/nss/cmd/modutil/pk11jar.html
new file mode 100644
index 000000000..bb50b8f3e
--- /dev/null
+++ b/security/nss/cmd/modutil/pk11jar.html
@@ -0,0 +1,279 @@
+<html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<head>
+<title>PKCS #11 JAR Format</title>
+</head>
+<body bgcolor=white text=black link=blue vlink=purple alink=red>
+<center><h1>PKCS #11 JAR Format</h1></center>
+
+<p>PKCS #11 modules can be packaged into JAR files that support automatic
+installation onto the filesystem and into the security module database.
+The JAR file should contain:
+<ul>
+<li>All files that will be installed onto the target machine. This will
+include at least the PKCS #11 module library file (.DLL or .so), and
+may also include any other file that should be installed (such as
+documentation).
+<li>A script to perform the installation.
+</ul>
+The script can be in one of two forms. If the JAR file is to be
+run by Communicator (or any program that interprets Javascript), the
+instructions will be in the form of a SmartUpdate script.
+<a href="http://devedge/library/documentation/security/jmpkcs/">Documentation
+</a> on creating this script can be found on DevEdge.
+
+<p>If the
+JAR file is to be run by a server, modutil, or any other program that
+doesn't interpret Javascript, a special information file must be included
+in the format described in this document.
+
+<h2>Declaring the Script in the Manifest File</h2>
+The script can have any name, but it must be declared in the manifest file
+of the JAR archive. The metainfo tag for this is
+<code>Pkcs11_install_script</code>. Meta-information is put in the manifest
+file by putting it in a file which is passed to
+<a href="http://developer.netscape.com/software/index_frame.html?content=signedobj/jarpack.html#signtool1.3">Signtool</a>. For example,
+suppose the PKCS #11 installer script is in the file <code>pk11install</code>.
+In Signtool's metainfo file, you would have a line like this:
+<blockquote><pre>
++ Pkcs11_install_script: pk11install
+</pre></blockquote>
+
+<h2>Sample Script File</h2>
+<blockquote><pre>
+ForwardCompatible { IRIX:6.2:mips Solaris:5.5.1:sparc }
+Platforms {
+ WINNT::x86 {
+ ModuleName { "Fortezza Module" }
+ ModuleFile { win32/fort32.dll }
+ DefaultMechanismFlags{0x0001}
+ DefaultCipherFlags{0x0001}
+ Files {
+ win32/setup.exe {
+ Executable
+ RelativePath { %temp%/setup.exe }
+ }
+ win32/setup.hlp {
+ RelativePath { %temp%/setup.hlp }
+ }
+ win32/setup.cab {
+ RelativePath { %temp%/setup.cab }
+ }
+ }
+ }
+ WIN95::x86 {
+ EquivalentPlatform {WINNT::x86}
+ }
+ Solaris:5.5.1:sparc {
+ ModuleName { "Fortezza UNIX Module" }
+ ModuleFile { unix/fort.so }
+ DefaultMechanismFlags{0x0001}
+ CipherEnableFlags{0x0001}
+ Files {
+ unix/fort.so {
+ RelativePath{%root%/lib/fort.so}
+ AbsolutePath{/usr/local/netscape/lib/fort.so}
+ FilePermissions{555}
+ }
+ xplat/instr.html {
+ RelativePath{%root%/docs/inst.html}
+ AbsolutePath{/usr/local/netscape/docs/inst.html}
+ FilePermissions{555}
+ }
+ }
+ }
+ IRIX:6.2:mips {
+ EquivalentPlatform { Solaris:5.5.1:sparc }
+ }
+}
+</pre></blockquote>
+
+<hr>
+
+<h2>Script File Grammar</h2>
+<blockquote><pre>
+--> <i>valuelist</i>
+
+<i>valuelist</i> --> <i>value</i> <i>valuelist</i>
+<i> </i> <i>&lt;null&gt;</i>
+
+<i>value</i> --> <i>key_value_pair</i>
+<i> </i> <i>string</i>
+
+<i>key_value_pair</i> --> <i>key</i> { <i>valuelist</i> }
+
+<i>key</i> --> <i>string</i>
+
+<i>string</i> --> <i>simple_string</i>
+<i> </i> "<i>complex_string</i>"
+
+<i>simple_string</i> --> [^ \t\n\""{""}"]+ <font size=-1><i>(no whitespace, quotes, or braces)</i></font>
+
+<i>complex_string</i> --> ([^\"\\\r\n]|(\\\")|(\\\\))+ <font size=-1><i>(quotes and backslashes must be escaped with a backslash, no newlines or carriage returns are allowed in the string)</i></font>
+</pre></blockquote>
+Outside of complex strings, all whitespace (space, tab, newline) is considered
+equal and is used only to delimit tokens.
+
+<hr>
+
+<h2>Keys</h2>
+Keys are case-insensitive.
+<h3>Global Keys</h3>
+<dl>
+<dt><code>ForwardCompatible</code>
+<dd>Gives a list of platforms that are forward compatible. If the current
+platform cannot be found in the list of supported platforms, then the
+ForwardCompatible list will be checked for any platforms that have the same
+OS and architecture and an earlier version. If one is found, its
+attributes will be used for the current platform.
+<dt><code>Platforms</code> (<i>required</i>)
+<dd>Gives a list of platforms. Each entry in the list is itself a key-value
+pair:
+the key is the name of the platform, and the valuelist contains various
+attributes of the platform. The ModuleName, ModuleFile, and Files attributes
+must be specified, unless an EquivalentPlatform attribute is specified.
+The platform string is in the following
+format: <u><i>system name</i></u>:<u><i>os release</i></u>:<u><i>architecture</i></u>. The installer
+will obtain these values from NSPR. <u><i>os release</i></u> is an empty
+string on non-UNIX operating systems. The following system names and platforms
+are currently defined by NSPR:<code>
+<ul>
+<li>AIX (rs6000)
+<li>BSDI (x86)
+<li>FREEBSD (x86)
+<li>HPUX (hppa1.1)
+<li>IRIX (mips)
+<li>LINUX (ppc, alpha, x86)
+<li>MacOS (PowerPC) </code>(<i>Note: NSPR actually defines the OS as
+"</i><code>Mac OS</code><i>". The
+space makes the name unsuitable for being embedded in identifiers. Until
+NSPR changes, you will have to add some special code to deal with this case.
+</i>)<code>
+<li>NCR (x86)
+<li>NEC (mips)
+<li>OS2 (x86)
+<li>OSF (alpha)
+<li>ReliantUNIX (mips)
+<li>SCO (x86)
+<li>SOLARIS (sparc)
+<li>SONY (mips)
+<li>SUNOS (sparc)
+<li>UnixWare (x86)
+<li>WIN95 (x86)
+<li>WINNT (x86)
+</ul>
+</code>
+Examples of valid platform strings: <code>IRIX:6.2:mips, Solaris:5.5.1:sparc,
+Linux:2.0.32:x86, WIN95::x86</code>.
+</dl>
+
+<h3>Per-Platform Keys</h3>
+These keys only have meaning within the value list of an entry in
+the <code>Platforms</code> list.
+<dl>
+<dt><code>ModuleName</code> (<i>required</i>)
+<dd>Gives the common name for the module. This name will be used to
+reference the module from Communicator, modutil, servers, or any other
+program that uses the Netscape security module database.
+<dt><code>ModuleFile</code> (<i>required</i>)
+<dd>Names the PKCS #11 module file (DLL or .so) for this platform. The name
+is given as the relative path of the file within the JAR archive.
+<dt><code>Files</code> (<i>required</i>)
+<dd>Lists the files that should be installed for this module. Each entry
+in the file list is a key-value pair: the key is the path of the file in
+the JAR archive, and
+the valuelist contains attributes of the file. At least RelativePath and
+AbsoluteDir must be specified in this valuelist.
+<dt><code>DefaultMechanismFlags</code>
+<dd>This key-value pair specifies
+of which mechanisms this module will be a default provider. It is a bitstring
+specified in hexadecimal (0x) format. It is constructed as a bitwise OR
+of the following constants. If the <code>DefaultMechanismFlags</code>
+entry is omitted, the value will default to 0x0.
+<blockquote><pre>
+RSA: 0x0000 0001
+DSA: 0x0000 0002
+RC2: 0x0000 0004
+RC4: 0x0000 0008
+DES: 0x0000 0010
+DH: 0x0000 0020
+FORTEZZA: 0x0000 0040
+RC5: 0x0000 0080
+SHA1: 0x0000 0100
+MD5: 0x0000 0200
+MD2: 0x0000 0400
+RANDOM: 0x0800 0000
+FRIENDLY: 0x1000 0000
+OWN_PW_DEFAULTS: 0x2000 0000
+DISABLE: 0x4000 0000
+</pre></blockquote>
+<dt><code>CipherEnableFlags</code>
+<dd>This key-value pair specifies
+which SSL ciphers will be enabled. It is a bitstring specified in
+hexadecimal (0x) format. It is constructed as a bitwise OR of the following
+constants. If the <code>CipherEnableFlags</code> entry is omitted, the
+value will default to 0x0.
+<blockquote><pre>
+FORTEZZA: 0x0000 0001
+</pre></blockquote>
+<dt><code>EquivalentPlatform</code>
+<dd>Specifies that the attributes of the named platform should also be used
+for the current platform. Saves typing when there is more than one platform
+that uses the same settings.
+</dl>
+
+<h3>Per-File Keys</h3>
+These keys only have meaning within the valuelist of an entry in a
+<code>Files</code> list. At least one of <code>RelativePath</code> and
+<code>AbsolutePath</code> must be specified. If both are specified, the
+relative path will be tried first and the absolute path used only if no
+relative root directory is provided by the installer program.
+<dl>
+<dt><code>RelativePath</code>
+<dd>Specifies the destination directory of the file, relative to some directory
+decided at install-time. Two variables can be used in the relative
+path, "%root%" and "%temp%". "%root%" will be replaced at run-time with
+the directory relative to which files should be installed; for
+example, it may be the server's root directory or Communicator's root
+directory. "%temp%" is a directory that will be created at the beginning
+of the installation and destroyed at the end of the installation. Its purpose
+is to hold executable files (such as setup programs), or files that are
+used by these programs. For example, a Windows installation might consist
+of a <code>setup.exe</code> installation program, a help file, and a .cab file
+containing compressed information. All these files could be installed into the
+temporary directory. Files destined for the temporary directory are guaranteed
+to be in place before any executable file is run, and will not be deleted
+until all executable files have finished.
+<dt><code>AbsoluteDir</code>
+<dd>Specifies the destination directory of the file as an absolute path.
+This will only be used if the installer is unable to determine a
+relative directory.
+<dt><code>Executable</code>
+<dd>This string specifies that the file is to be executed during the
+course of the
+installation. Typically this would be used for a setup program provided
+by a module vendor, such as a self-extracting <code>setup.exe</code>.
+More than one file can be specified as executable, in which case they will
+be run in the order they are specified in the script file.
+<dt><code>FilePermissions</code>
+<dd>This string is interpreted as a string of octal digits, according to the
+standard UNIX format. It is a bitwise OR of the following constants:
+<blockquote><pre>
+user read: 400
+user write: 200
+user execute: 100
+group read: 040
+group write: 020
+group execute: 010
+other read: 004
+other write: 002
+other execute: 001
+</pre></blockquote>
+Some platforms may not understand these permissions. They will only be
+applied insofar as makes sense for the current platform. If this attribute
+is omitted, a default of 777 is assumed.
+
+</body>
+</html>
diff --git a/security/nss/cmd/modutil/rules.mk b/security/nss/cmd/modutil/rules.mk
new file mode 100644
index 000000000..3ad6a97f1
--- /dev/null
+++ b/security/nss/cmd/modutil/rules.mk
@@ -0,0 +1,26 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Some versions of yacc generate files that include platform-specific
+# system headers. For example, the yacc in Solaris 2.6 inserts
+# #include <values.h>
+# which does not exist on NT. For portability, always use Berkeley
+# yacc (such as the yacc in Linux) to generate files.
+#
+
+generate: installparse.c installparse.l
+
+installparse.c:
+ yacc -p Pk11Install_yy -d installparse.y
+ mv y.tab.c installparse.c
+ mv y.tab.h installparse.h
+
+installparse.l:
+ lex -olex.Pk11Install_yy.c -PPk11Install_yy installparse.l
+ @echo
+ @echo "**YOU MUST COMMENT OUT UNISTD.H FROM lex.Pk11Install_yy.cpp**"
+
+install.c: install-ds.h install.h
diff --git a/security/nss/cmd/modutil/specification.html b/security/nss/cmd/modutil/specification.html
new file mode 100644
index 000000000..6477a37ce
--- /dev/null
+++ b/security/nss/cmd/modutil/specification.html
@@ -0,0 +1,322 @@
+<html>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<head>
+<title>Modutil Specification</title>
+</head>
+<body bgcolor=white fgcolor=black>
+<center><h1>PKCS #11 Module Management Utility
+<br><i>Specification</i></h1></center>
+
+<!---------------------------------------------------------------------->
+<!-------------------------- capabilities ------------------------------>
+<!---------------------------------------------------------------------->
+<h2>Capabilities</h2>
+<ul>
+<li>Add a PKCS #11 module, specifying a name and library file.
+(<a href="#add">-add</a>)
+<li>Add a PKCS #11 module from a server-formatted JAR file.
+(<a href="#jar">-jar</a>)
+<li>Change the password on or initialize a token.
+(<a href="#changepw">-changepw</a>)
+<li>Create databases (secmod[ule].db, key3.db, cert7.db) from scratch.
+(<a href="#create">-create</a>)
+<li>Switch to and from FIPS-140 compliant mode.
+(<a href="#fips">-fips</a>)
+<li>Delete a PKCS #11 module. (<a href="#delete">-delete</a>)
+<li>List installed PKCS #11 modules. (<a href="#list">-list</a>)
+<li>List detailed info on a particular module and its tokens, including
+whether needs login, is hardware, needs user init
+(<a href="#list">-list</a>)
+<li>Specify which modules should be the default provider of various
+cryptographic operations.(<a href="#default">-default</a>,
+<a href="#undefault">-undefault</a>)
+<li>Disable and enable slots, find out whether and why they are disabled.
+(<a href="#disable">-disable</a>, <a href="#enable">-enable</a>,
+<a href="#list">-list</a>)
+</ul>
+
+<hr>
+
+<!---------------------------------------------------------------------->
+<!-------------------------- Usage ------------------------------------->
+<!---------------------------------------------------------------------->
+<h2>Usage</h2>
+<code>modutil [<i>command</i>] [<i>options</i>]</code>
+<p>At most one command can be specified. With no arguments,
+<code>modutil</code> prints a usage message.
+<h3>Commands:</h3>
+<table border>
+<tr bgcolor="#cccccc">
+<th>Command</th><th>Description</th>
+</tr>
+
+<!---------------------------- -add ------------------------------>
+<tr>
+<td> <a name="add"></a>
+<code>-add <u><i>module name</i></u> -libfile <u><i>library file</i></u>
+ [-ciphers <u><i>cipher enable list</i></u>]
+ [-mechanisms <u><i>default mechanism list</i></u>]
+</code></td>
+<td>Adds a new module to the database with the given name.
+
+<p><u><i>library file</i></u> is the path of the DLL or other library file
+containing the module's implementation of the PKCS #11 interface.
+
+<p><u><i>cipher enable flags</i></u> is a colon-separated list of ciphers
+that will be enabled on this module. The list should be enclosed within quotes
+if necessary to prevent shell interpretation. The following ciphers are
+currently available:
+<ul>
+<li>FORTEZZA
+</ul>
+
+<p><u><i>default mechanism flags</i></u> is a colon-separated list of
+mechanisms for which this module should be the default provider. The
+list should be enclosed within quotes if necessary to prevent shell
+interpretation. <b>This
+list does not enable the mechanisms; it only specifies that this module
+will be a default provider for the listed mechanisms.</b> If more than
+one module claims to be a default provider for a given mechanism, it is
+undefined which will actually be chosen to provide that mechanism. The
+following mechanisms are currently available:
+<ul>
+<li>RSA
+<li>DSA
+<li>RC2
+<li>RC4
+<li>RC5
+<li>DES
+<li>DH
+<li>FORTEZZA
+<li>SHA1
+<li>MD5
+<li>MD2
+<li>RANDOM <i>(random number generation)</i>
+<li>FRIENDLY <i>(certificates are publicly-readable)</i>
+</ul>
+</td>
+</tr>
+
+<!-------------------------- -changepw ------------------------------------->
+<tr>
+<td><a name="changepw"></a><code>-changepw <u><i>token name</i></u>
+[-pwfile <u><i>old password file</i></u>]
+[-newpwfile <u><i>new password file</i></u>]</code></td>
+<td>Changes the password on the named token. If the token has not been
+initialized, this command will initialize the PIN.
+If a password file is given, the password will be read from that file;
+otherwise, the password will be obtained interactively.
+<b>Storing passwords in a file is much less secure than supplying them
+interactively.</b>
+<p>The password on the Netscape internal module cannot be changed if
+the <code>-nocertdb</code> option is specified.
+</td>
+</tr>
+
+<!-------------------------- -create ------------------------------------->
+<tr>
+<td><a name="create"></a><code>-create</code></td>
+<td>Creates a new secmod[ule].db, key3.db, and cert7.db in the directory
+specified with the
+<code>-dbdir</code> option, if one is specified. If no directory is
+specified, UNIX systems will use the user's .netscape directory, while other
+systems will return with an error message. If any of these databases already
+exist in the chosen directory, an error message is returned.
+<p>If used with <code>-nocertdb</code>, only secmod[ule].db will be created;
+cert7.db and key3.db will not be created.
+</td>
+</tr>
+
+<!------------------------------ -default -------------------------------->
+<tr>
+<td> <a name="default"></a> <code>-default <u><i>module name</i></u>
+-mechanisms <u><i>mechanism list</i></u></code>
+</td>
+<td>Specifies that the given module will be a default provider of the
+listed mechanisms. The mechanism list is the same as in the <code>-add</code>
+command.
+</td>
+</tr>
+
+<!-------------------------- -delete ------------------------------------->
+<tr>
+<td><a name="delete"></a><code>-delete <u><i>module name</i></u></code></td>
+<td>Deletes the named module from the database</td>
+</tr>
+
+<!-------------------------- -disable ------------------------------------->
+<tr>
+<td> <a name="disable"></a> <code>-disable <u><i>module name</i></u>
+[-slot <u><i>slot name</i></u>]</code></td>
+<td>Disables the named slot. If no slot is specified, all slots on
+the module are disabled.</td>
+</tr>
+
+<!-------------------------- -enable ------------------------------------->
+<tr>
+<td> <a name="enable"></a> <code>-enable <u><i>module name</i></u>
+[-slot <u><i>slot name</i></u>]</code></td>
+<td>Enables the named slot. If no slot is specified, all slots on
+the module are enabled.</td>
+</tr>
+
+<!-------------------------- -fips ------------------------------------->
+<tr>
+<td><a name="fips"></a><code>-fips [true | false]</code></td>
+<td>Enables or disables FIPS mode on the internal module. Passing
+<code>true</code> enables FIPS mode, passing <code>false</code> disables
+FIPS mode.</td>
+</tr>
+
+<!-------------------------- -force ------------------------------------->
+<tr>
+<td><a name="force"></a><code>-force</code></td>
+<td>Disables interactive prompts, so modutil can be run in a script.
+Should only be used by experts, since the prompts may relate to security
+or database integrity. Before using this option, test the command
+interactively once to see the warnings that are produced.</td>
+</tr>
+
+<!-------------------------- -jar ------------------------------------->
+<tr>
+<td><a name="jar"></a><code>-jar <u><i>JAR file</i></u>
+-installdir <u><i>root installation directory</i></u>
+[-tempdir <u><i>temporary directory</i></u>]</code></td>
+<td>Adds a new module from the given JAR file. The JAR file uses the
+server <a href="pk11jar.html">PKCS #11 JAR format</a> to describe the names of
+any files that need to be installed, the name of the module, mechanism flags,
+and cipher flags. The <u><i>root installation directory</i></u>
+is the directory relative to which files will be installed. This should be a
+ directory
+under which it would be natural to store dynamic library files, such as
+a server's root directory, or Communicator's root directory.
+The <u><i>temporary directory</i></u> is where temporary modutil files
+will be created in the course of the installation. If no temporary directory
+is specified, the current directory will be used.
+<p>If used with the <code>-nocertdb</code> option, the signatures on the JAR
+file will not be checked.</td>
+</tr>
+
+<!----------------------------- -list ------------------------------>
+<tr>
+<td><a name="list"></a><code>-list [<u><i>module name</i></u>]</code></td>
+<td>Without an argument, lists the PKCS #11 modules present in the module
+database.
+<blockquote>
+<pre>
+% <b>modutil -list</b>
+Using database directory /u/nicolson/.netscape...
+
+Listing of PKCS #11 Modules
+-----------------------------------------------------------
+ 1. Netscape Internal PKCS #11 Module
+ slots: 2 slots attached
+ status: loaded
+
+ slot: Communicator Internal Cryptographic Services Version 4.0
+ token: Communicator Generic Crypto Svcs
+
+ slot: Communicator User Private Key and Certificate Services
+ token: Communicator Certificate DB
+-----------------------------------------------------------
+</pre>
+</blockquote>
+<p>With an argument, provides a detailed description of the named module
+and its slots and tokens.
+<blockquote>
+<pre>
+% <b>modutil -list "Netscape Internal PKCS #11 Module"</b>
+Using database directory /u/nicolson/.netscape...
+
+-----------------------------------------------------------
+Name: Netscape Internal PKCS #11 Module
+Library file: **Internal ONLY module**
+Manufacturer: Netscape Communications Corp
+Description: Communicator Internal Crypto Svc
+PKCS #11 Version 2.0
+Library Version: 4.0
+Cipher Enable Flags: None
+Default Mechanism Flags: RSA:DSA:RC2:RC4:DES:SHA1:MD5:MD2
+
+ Slot: Communicator Internal Cryptographic Services Version 4.0
+ Manufacturer: Netscape Communications Corp
+ Type: Software
+ Version Number: 4.1
+ Firmware Version: 0.0
+ Status: Enabled
+ Token Name: Communicator Generic Crypto Svcs
+ Token Manufacturer: Netscape Communications Corp
+ Token Model: Libsec 4.0
+ Token Serial Number: 0000000000000000
+ Token Version: 4.0
+ Token Firmware Version: 0.0
+ Access: Write Protected
+ Login Type: Public (no login required)
+ User Pin: NOT Initialized
+
+ Slot: Communicator User Private Key and Certificate Services
+ Manufacturer: Netscape Communications Corp
+ Type: Software
+ Version Number: 3.0
+ Firmware Version: 0.0
+ Status: Enabled
+ Token Name: Communicator Certificate DB
+ Token Manufacturer: Netscape Communications Corp
+ Token Model: Libsec 4.0
+ Token Serial Number: 0000000000000000
+ Token Version: 7.0
+ Token Firmware Version: 0.0
+ Access: NOT Write Protected
+ Login Type: Login required
+ User Pin: Initialized
+
+-----------------------------------------------------------
+</pre>
+</blockquote>
+</td>
+</tr>
+
+<!------------------------------ Undefault ------------------------------->
+<tr>
+<td><a name="undefault"></a><code>-undefault <u><i>module name</i></u>
+-mechanisms <u><i>mechanism list</i></u></code></td>
+<td>Specifies that the given module will NOT be a default provider of
+the listed mechanisms. This command clears the default mechanism flags
+for the given module.</td>
+</tr>
+
+</table>
+
+<!------------------------------------------------------------------------>
+<!------------------------------ Options --------------------------------->
+<!------------------------------------------------------------------------>
+<h3>Options:</h3>
+<table border>
+<tr bgcolor="#cccccc"><th>Option</th><th>Description</th> </tr>
+
+<!------------------------------ -dbdir ---------------------------------->
+<tr>
+<td><code>-dbdir <u><i>directory</i></u></code></td>
+<td>Specifies which directory holds the module database. On UNIX systems,
+the user's netscape directory is the default. On other systems, there is
+no default, and this option must be used.</td>
+</tr>
+
+<!------------------------------ -dbdir ---------------------------------->
+<tr>
+<td><code>-nocertdb</code></td>
+<td>Do not open the certificate or key databases. This has several effects.
+With the <code>-create</code> command, this means that only a secmod.db file
+will be created; cert7.db and key3.db will not be created. With the
+<code>-jar</code> command, signatures on the JAR file will not be checked.
+With the <code>-changepw</code> command, the password on the Netscape internal
+module cannot be set or changed, since this password is stored in key3.db.
+</td>
+</tr>
+
+</table>
+
+</body>
+</html>