summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/signtool/signtool.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--security/nss/cmd/signtool/signtool.c1066
1 files changed, 1066 insertions, 0 deletions
diff --git a/security/nss/cmd/signtool/signtool.c b/security/nss/cmd/signtool/signtool.c
new file mode 100644
index 0000000000..915a00fbc1
--- /dev/null
+++ b/security/nss/cmd/signtool/signtool.c
@@ -0,0 +1,1066 @@
+/* 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/. */
+
+/*
+ * SIGNTOOL
+ *
+ * A command line tool to create manifest files
+ * from a directory hierarchy. It is assumed that
+ * the tree will be equivalent to what resides
+ * or will reside in an archive.
+ *
+ *
+ */
+
+#include "nss.h"
+#include "signtool.h"
+#include "prmem.h"
+#include "prio.h"
+
+/***********************************************************************
+ * Global Variable Definitions
+ */
+char *progName; /* argv[0] */
+
+/* password data */
+secuPWData pwdata = { PW_NONE, 0 };
+
+/* directories or files to exclude in descent */
+PLHashTable *excludeDirs = NULL;
+static PRBool exclusionsGiven = PR_FALSE;
+
+/* zatharus is the man who knows no time, dies tragic death */
+int no_time = 0;
+
+/* -b basename of .rsa, .sf files */
+char *base = DEFAULT_BASE_NAME;
+
+/* Only sign files with this extension */
+PLHashTable *extensions = NULL;
+PRBool extensionsGiven = PR_FALSE;
+
+char *scriptdir = NULL;
+
+int verbosity = 0;
+
+PRFileDesc *outputFD = NULL, *errorFD = NULL;
+
+int errorCount = 0, warningCount = 0;
+
+int compression_level = DEFAULT_COMPRESSION_LEVEL;
+PRBool compression_level_specified = PR_FALSE;
+
+int xpi_arc = 0;
+
+/* Command-line arguments */
+static char *genkey = NULL;
+static char *verify = NULL;
+static char *zipfile = NULL;
+static char *cert_dir = NULL;
+static int javascript = 0;
+static char *jartree = NULL;
+static char *keyName = NULL;
+static char *metafile = NULL;
+static char *install_script = NULL;
+static int list_certs = 0;
+static int list_modules = 0;
+static int optimize = 0;
+static int enableOCSP = 0;
+static char *tell_who = NULL;
+static char *outfile = NULL;
+static char *cmdFile = NULL;
+static PRBool noRecurse = PR_FALSE;
+static PRBool leaveArc = PR_FALSE;
+static int keySize = -1;
+static char *token = NULL;
+
+typedef enum {
+ UNKNOWN_OPT,
+ HELP_OPT,
+ LONG_HELP_OPT,
+ BASE_OPT,
+ COMPRESSION_OPT,
+ CERT_DIR_OPT,
+ EXTENSION_OPT,
+ INSTALL_SCRIPT_OPT,
+ SCRIPTDIR_OPT,
+ CERTNAME_OPT,
+ LIST_OBJSIGN_CERTS_OPT,
+ LIST_ALL_CERTS_OPT,
+ METAFILE_OPT,
+ OPTIMIZE_OPT,
+ ENABLE_OCSP_OPT,
+ PASSWORD_OPT,
+ VERIFY_OPT,
+ WHO_OPT,
+ EXCLUDE_OPT,
+ NO_TIME_OPT,
+ JAVASCRIPT_OPT,
+ ZIPFILE_OPT,
+ GENKEY_OPT,
+ MODULES_OPT,
+ NORECURSE_OPT,
+ SIGNDIR_OPT,
+ OUTFILE_OPT,
+ COMMAND_FILE_OPT,
+ LEAVE_ARC_OPT,
+ VERBOSITY_OPT,
+ KEYSIZE_OPT,
+ TOKEN_OPT,
+ XPI_ARC_OPT
+}
+
+OPT_TYPE;
+
+typedef enum {
+ DUPLICATE_OPTION_ERR = 0,
+ OPTION_NEEDS_ARG_ERR
+}
+
+Error;
+
+static char *errStrings[] = {
+ "warning: %s option specified more than once.\n"
+ "Only last specification will be used.\n",
+ "ERROR: option \"%s\" requires an argument.\n"
+};
+
+static int ProcessOneOpt(OPT_TYPE type, char *arg);
+
+/*********************************************************************
+ *
+ * P r o c e s s C o m m a n d F i l e
+ */
+int
+ProcessCommandFile()
+{
+ PRFileDesc *fd;
+#define CMD_FILE_BUFSIZE 1024
+ char buf[CMD_FILE_BUFSIZE];
+ char *equals;
+ int linenum = 0;
+ int retval = -1;
+ OPT_TYPE type;
+
+ fd = PR_Open(cmdFile, PR_RDONLY, 0777);
+ if (!fd) {
+ PR_fprintf(errorFD, "ERROR: Unable to open command file %s.\n");
+ errorCount++;
+ return -1;
+ }
+
+ while (pr_fgets(buf, CMD_FILE_BUFSIZE, fd)) {
+ char *eol;
+ linenum++;
+
+ /* Chop off final newline */
+ eol = PL_strchr(buf, '\r');
+ if (!eol) {
+ eol = PL_strchr(buf, '\n');
+ }
+ if (eol)
+ *eol = '\0';
+
+ equals = PL_strchr(buf, '=');
+ if (!equals) {
+ continue;
+ }
+
+ *equals = '\0';
+ equals++;
+
+ /* Now buf points to the attribute, and equals points to the value. */
+
+ /* This is pretty straightforward, just deal with whatever attribute
+ * this is */
+ if (!PL_strcasecmp(buf, "basename")) {
+ type = BASE_OPT;
+ } else if (!PL_strcasecmp(buf, "compression")) {
+ type = COMPRESSION_OPT;
+ } else if (!PL_strcasecmp(buf, "certdir")) {
+ type = CERT_DIR_OPT;
+ } else if (!PL_strcasecmp(buf, "extension")) {
+ type = EXTENSION_OPT;
+ } else if (!PL_strcasecmp(buf, "generate")) {
+ type = GENKEY_OPT;
+ } else if (!PL_strcasecmp(buf, "installScript")) {
+ type = INSTALL_SCRIPT_OPT;
+ } else if (!PL_strcasecmp(buf, "javascriptdir")) {
+ type = SCRIPTDIR_OPT;
+ } else if (!PL_strcasecmp(buf, "htmldir")) {
+ type = JAVASCRIPT_OPT;
+ if (jartree) {
+ PR_fprintf(errorFD,
+ "warning: directory to be signed specified more than once."
+ " Only last specification will be used.\n");
+ warningCount++;
+ PR_Free(jartree);
+ jartree = NULL;
+ }
+ jartree = PL_strdup(equals);
+ } else if (!PL_strcasecmp(buf, "certname")) {
+ type = CERTNAME_OPT;
+ } else if (!PL_strcasecmp(buf, "signdir")) {
+ type = SIGNDIR_OPT;
+ } else if (!PL_strcasecmp(buf, "list")) {
+ type = LIST_OBJSIGN_CERTS_OPT;
+ } else if (!PL_strcasecmp(buf, "listall")) {
+ type = LIST_ALL_CERTS_OPT;
+ } else if (!PL_strcasecmp(buf, "metafile")) {
+ type = METAFILE_OPT;
+ } else if (!PL_strcasecmp(buf, "modules")) {
+ type = MODULES_OPT;
+ } else if (!PL_strcasecmp(buf, "optimize")) {
+ type = OPTIMIZE_OPT;
+ } else if (!PL_strcasecmp(buf, "ocsp")) {
+ type = ENABLE_OCSP_OPT;
+ } else if (!PL_strcasecmp(buf, "password")) {
+ type = PASSWORD_OPT;
+ } else if (!PL_strcasecmp(buf, "verify")) {
+ type = VERIFY_OPT;
+ } else if (!PL_strcasecmp(buf, "who")) {
+ type = WHO_OPT;
+ } else if (!PL_strcasecmp(buf, "exclude")) {
+ type = EXCLUDE_OPT;
+ } else if (!PL_strcasecmp(buf, "notime")) {
+ type = NO_TIME_OPT;
+ } else if (!PL_strcasecmp(buf, "jarfile")) {
+ type = ZIPFILE_OPT;
+ } else if (!PL_strcasecmp(buf, "outfile")) {
+ type = OUTFILE_OPT;
+ } else if (!PL_strcasecmp(buf, "leavearc")) {
+ type = LEAVE_ARC_OPT;
+ } else if (!PL_strcasecmp(buf, "verbosity")) {
+ type = VERBOSITY_OPT;
+ } else if (!PL_strcasecmp(buf, "keysize")) {
+ type = KEYSIZE_OPT;
+ } else if (!PL_strcasecmp(buf, "token")) {
+ type = TOKEN_OPT;
+ } else if (!PL_strcasecmp(buf, "xpi")) {
+ type = XPI_ARC_OPT;
+ } else {
+ PR_fprintf(errorFD,
+ "warning: unknown attribute \"%s\" in command file, line %d.\n",
+ buf, linenum);
+ warningCount++;
+ type = UNKNOWN_OPT;
+ }
+
+ /* Process the option, whatever it is */
+ if (type != UNKNOWN_OPT) {
+ if (ProcessOneOpt(type, equals) == -1) {
+ goto finish;
+ }
+ }
+ }
+
+ retval = 0;
+
+finish:
+ PR_Close(fd);
+ return retval;
+}
+
+/*********************************************************************
+ *
+ * p a r s e _ a r g s
+ */
+static int
+parse_args(int argc, char *argv[])
+{
+ char *opt;
+ char *arg;
+ int needsInc = 0;
+ int i;
+ OPT_TYPE type;
+
+ /* Loop over all arguments */
+ for (i = 1; i < argc; i++) {
+ opt = argv[i];
+ arg = NULL;
+
+ if (opt[0] == '-') {
+ if (opt[1] == '-') {
+ /* word option */
+ if (i < argc - 1) {
+ needsInc = 1;
+ arg = argv[i + 1];
+ } else {
+ arg = NULL;
+ }
+
+ if (!PL_strcasecmp(opt + 2, "norecurse")) {
+ type = NORECURSE_OPT;
+ } else if (!PL_strcasecmp(opt + 2, "leavearc")) {
+ type = LEAVE_ARC_OPT;
+ } else if (!PL_strcasecmp(opt + 2, "verbosity")) {
+ type = VERBOSITY_OPT;
+ } else if (!PL_strcasecmp(opt + 2, "outfile")) {
+ type = OUTFILE_OPT;
+ } else if (!PL_strcasecmp(opt + 2, "keysize")) {
+ type = KEYSIZE_OPT;
+ } else if (!PL_strcasecmp(opt + 2, "token")) {
+ type = TOKEN_OPT;
+ } else {
+ PR_fprintf(errorFD, "warning: unknown option: %s\n",
+ opt);
+ warningCount++;
+ type = UNKNOWN_OPT;
+ }
+ } else {
+ /* char option */
+ if (opt[2] != '\0') {
+ arg = opt + 2;
+ } else if (i < argc - 1) {
+ needsInc = 1;
+ arg = argv[i + 1];
+ } else {
+ arg = NULL;
+ }
+
+ switch (opt[1]) {
+ case 'b':
+ type = BASE_OPT;
+ break;
+ case 'c':
+ type = COMPRESSION_OPT;
+ break;
+ case 'd':
+ type = CERT_DIR_OPT;
+ break;
+ case 'e':
+ type = EXTENSION_OPT;
+ break;
+ case 'f':
+ type = COMMAND_FILE_OPT;
+ break;
+ case 'h':
+ type = HELP_OPT;
+ break;
+ case 'H':
+ type = LONG_HELP_OPT;
+ break;
+ case 'i':
+ type = INSTALL_SCRIPT_OPT;
+ break;
+ case 'j':
+ type = SCRIPTDIR_OPT;
+ break;
+ case 'k':
+ type = CERTNAME_OPT;
+ break;
+ case 'l':
+ type = LIST_OBJSIGN_CERTS_OPT;
+ break;
+ case 'L':
+ type = LIST_ALL_CERTS_OPT;
+ break;
+ case 'm':
+ type = METAFILE_OPT;
+ break;
+ case 'o':
+ type = OPTIMIZE_OPT;
+ break;
+ case 'O':
+ type = ENABLE_OCSP_OPT;
+ break;
+ case 'p':
+ type = PASSWORD_OPT;
+ break;
+ case 'v':
+ type = VERIFY_OPT;
+ break;
+ case 'w':
+ type = WHO_OPT;
+ break;
+ case 'x':
+ type = EXCLUDE_OPT;
+ break;
+ case 'X':
+ type = XPI_ARC_OPT;
+ break;
+ case 'z':
+ type = NO_TIME_OPT;
+ break;
+ case 'J':
+ type = JAVASCRIPT_OPT;
+ break;
+ case 'Z':
+ type = ZIPFILE_OPT;
+ break;
+ case 'G':
+ type = GENKEY_OPT;
+ break;
+ case 'M':
+ type = MODULES_OPT;
+ break;
+ case 's':
+ type = KEYSIZE_OPT;
+ break;
+ case 't':
+ type = TOKEN_OPT;
+ break;
+ default:
+ type = UNKNOWN_OPT;
+ PR_fprintf(errorFD, "warning: unrecognized option: -%c.\n",
+ opt[1]);
+ warningCount++;
+ break;
+ }
+ }
+ } else {
+ type = UNKNOWN_OPT;
+ if (i == argc - 1) {
+ if (jartree) {
+ PR_fprintf(errorFD,
+ "warning: directory to be signed specified more than once.\n"
+ " Only last specification will be used.\n");
+ warningCount++;
+ PR_Free(jartree);
+ jartree = NULL;
+ }
+ jartree = PL_strdup(opt);
+ } else {
+ PR_fprintf(errorFD, "warning: unrecognized option: %s\n", opt);
+ warningCount++;
+ }
+ }
+
+ if (type != UNKNOWN_OPT) {
+ short ateArg = ProcessOneOpt(type, arg);
+ if (ateArg == -1) {
+ /* error */
+ return -1;
+ }
+ if (ateArg && needsInc) {
+ i++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*********************************************************************
+ *
+ * P r o c e s s O n e O p t
+ *
+ * Since options can come from different places (command file, word options,
+ * char options), this is a central function that is called to deal with
+ * them no matter where they come from.
+ *
+ * type is the type of option.
+ * arg is the argument to the option, possibly NULL.
+ * Returns 1 if the argument was eaten, 0 if it wasn't, and -1 for error.
+ */
+static int
+ProcessOneOpt(OPT_TYPE type, char *arg)
+{
+ int ate = 0;
+
+ switch (type) {
+ case HELP_OPT:
+ Usage();
+ break;
+ case LONG_HELP_OPT:
+ LongUsage();
+ break;
+ case BASE_OPT:
+ if (base) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-b");
+ warningCount++;
+ PR_Free(base);
+ base = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-b");
+ errorCount++;
+ goto loser;
+ }
+ base = PL_strdup(arg);
+ ate = 1;
+ break;
+ case COMPRESSION_OPT:
+ if (compression_level_specified) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-c");
+ warningCount++;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-c");
+ errorCount++;
+ goto loser;
+ }
+ compression_level = atoi(arg);
+ compression_level_specified = PR_TRUE;
+ ate = 1;
+ break;
+ case CERT_DIR_OPT:
+ if (cert_dir) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-d");
+ warningCount++;
+ PR_Free(cert_dir);
+ cert_dir = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-d");
+ errorCount++;
+ goto loser;
+ }
+ cert_dir = PL_strdup(arg);
+ ate = 1;
+ break;
+ case EXTENSION_OPT:
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "extension (-e)");
+ errorCount++;
+ goto loser;
+ }
+ PL_HashTableAdd(extensions, arg, arg);
+ extensionsGiven = PR_TRUE;
+ ate = 1;
+ break;
+ case INSTALL_SCRIPT_OPT:
+ if (install_script) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "installScript (-i)");
+ warningCount++;
+ PR_Free(install_script);
+ install_script = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "installScript (-i)");
+ errorCount++;
+ goto loser;
+ }
+ install_script = PL_strdup(arg);
+ ate = 1;
+ break;
+ case SCRIPTDIR_OPT:
+ if (scriptdir) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "javascriptdir (-j)");
+ warningCount++;
+ PR_Free(scriptdir);
+ scriptdir = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "javascriptdir (-j)");
+ errorCount++;
+ goto loser;
+ }
+ scriptdir = PL_strdup(arg);
+ ate = 1;
+ break;
+ case CERTNAME_OPT:
+ if (keyName) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "keyName (-k)");
+ warningCount++;
+ PR_Free(keyName);
+ keyName = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "keyName (-k)");
+ errorCount++;
+ goto loser;
+ }
+ keyName = PL_strdup(arg);
+ ate = 1;
+ break;
+ case LIST_OBJSIGN_CERTS_OPT:
+ case LIST_ALL_CERTS_OPT:
+ if (list_certs != 0) {
+ PR_fprintf(errorFD,
+ "warning: only one of -l and -L may be specified.\n");
+ warningCount++;
+ }
+ list_certs = (type == LIST_OBJSIGN_CERTS_OPT ? 1 : 2);
+ break;
+ case METAFILE_OPT:
+ if (metafile) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "metafile (-m)");
+ warningCount++;
+ PR_Free(metafile);
+ metafile = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "metafile (-m)");
+ errorCount++;
+ goto loser;
+ }
+ metafile = PL_strdup(arg);
+ ate = 1;
+ break;
+ case OPTIMIZE_OPT:
+ optimize = 1;
+ break;
+ case ENABLE_OCSP_OPT:
+ enableOCSP = 1;
+ break;
+ case PASSWORD_OPT:
+ if (pwdata.data) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "password (-p)");
+ warningCount++;
+ PR_Free(pwdata.data);
+ pwdata.data = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "password (-p)");
+ errorCount++;
+ goto loser;
+ }
+ pwdata.source = PW_PLAINTEXT;
+ pwdata.data = PL_strdup(arg);
+ ate = 1;
+ break;
+ case VERIFY_OPT:
+ if (verify) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "verify (-v)");
+ warningCount++;
+ PR_Free(verify);
+ verify = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "verify (-v)");
+ errorCount++;
+ goto loser;
+ }
+ verify = PL_strdup(arg);
+ ate = 1;
+ break;
+ case WHO_OPT:
+ if (tell_who) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "who (-v)");
+ warningCount++;
+ PR_Free(tell_who);
+ tell_who = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "who (-w)");
+ errorCount++;
+ goto loser;
+ }
+ tell_who = PL_strdup(arg);
+ ate = 1;
+ break;
+ case EXCLUDE_OPT:
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "exclude (-x)");
+ errorCount++;
+ goto loser;
+ }
+ PL_HashTableAdd(excludeDirs, arg, arg);
+ exclusionsGiven = PR_TRUE;
+ ate = 1;
+ break;
+ case NO_TIME_OPT:
+ no_time = 1;
+ break;
+ case JAVASCRIPT_OPT:
+ javascript++;
+ break;
+ case ZIPFILE_OPT:
+ if (zipfile) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "jarfile (-Z)");
+ warningCount++;
+ PR_Free(zipfile);
+ zipfile = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "jarfile (-Z)");
+ errorCount++;
+ goto loser;
+ }
+ zipfile = PL_strdup(arg);
+ ate = 1;
+ break;
+ case GENKEY_OPT:
+ if (genkey) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "generate (-G)");
+ warningCount++;
+ PR_Free(genkey);
+ genkey = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "generate (-G)");
+ errorCount++;
+ goto loser;
+ }
+ genkey = PL_strdup(arg);
+ ate = 1;
+ break;
+ case MODULES_OPT:
+ list_modules++;
+ break;
+ case SIGNDIR_OPT:
+ if (jartree) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "signdir");
+ warningCount++;
+ PR_Free(jartree);
+ jartree = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "signdir");
+ errorCount++;
+ goto loser;
+ }
+ jartree = PL_strdup(arg);
+ ate = 1;
+ break;
+ case OUTFILE_OPT:
+ if (outfile) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "outfile");
+ warningCount++;
+ PR_Free(outfile);
+ outfile = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "outfile");
+ errorCount++;
+ goto loser;
+ }
+ outfile = PL_strdup(arg);
+ ate = 1;
+ break;
+ case COMMAND_FILE_OPT:
+ if (cmdFile) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
+ "-f");
+ warningCount++;
+ PR_Free(cmdFile);
+ cmdFile = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "-f");
+ errorCount++;
+ goto loser;
+ }
+ cmdFile = PL_strdup(arg);
+ ate = 1;
+ break;
+ case NORECURSE_OPT:
+ noRecurse = PR_TRUE;
+ break;
+ case LEAVE_ARC_OPT:
+ leaveArc = PR_TRUE;
+ break;
+ case VERBOSITY_OPT:
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
+ "--verbosity");
+ errorCount++;
+ goto loser;
+ }
+ verbosity = atoi(arg);
+ ate = 1;
+ break;
+ case KEYSIZE_OPT:
+ if (keySize != -1) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-s");
+ warningCount++;
+ }
+ keySize = atoi(arg);
+ ate = 1;
+ if (keySize < 1 || keySize > MAX_RSA_KEY_SIZE) {
+ PR_fprintf(errorFD, "Invalid key size: %d.\n", keySize);
+ errorCount++;
+ goto loser;
+ }
+ break;
+ case TOKEN_OPT:
+ if (token) {
+ PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-t");
+ PR_Free(token);
+ token = NULL;
+ }
+ if (!arg) {
+ PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-t");
+ errorCount++;
+ goto loser;
+ }
+ token = PL_strdup(arg);
+ ate = 1;
+ break;
+ case XPI_ARC_OPT:
+ xpi_arc = 1;
+ break;
+ default:
+ PR_fprintf(errorFD, "warning: unknown option\n");
+ warningCount++;
+ break;
+ }
+
+ return ate;
+loser:
+ return -1;
+}
+
+/*********************************************************************
+ *
+ * m a i n
+ */
+int
+main(int argc, char *argv[])
+{
+ PRBool readOnly;
+ int retval = 0;
+
+ outputFD = PR_STDOUT;
+ errorFD = PR_STDERR;
+
+ progName = argv[0];
+
+ if (argc < 2) {
+ Usage();
+ }
+
+ excludeDirs = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
+ PL_CompareStrings, NULL, NULL);
+ extensions = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
+ PL_CompareStrings, NULL, NULL);
+
+ if (parse_args(argc, argv)) {
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* Parse the command file if one was given */
+ if (cmdFile) {
+ if (ProcessCommandFile()) {
+ retval = -1;
+ goto cleanup;
+ }
+ }
+
+ /* Set up output redirection */
+ if (outfile) {
+ if (PR_Access(outfile, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ /* delete the file if it is already present */
+ PR_fprintf(errorFD,
+ "warning: %s already exists and will be overwritten.\n",
+ outfile);
+ warningCount++;
+ if (PR_Delete(outfile) != PR_SUCCESS) {
+ PR_fprintf(errorFD, "ERROR: unable to delete %s.\n", outfile);
+ errorCount++;
+ exit(ERRX);
+ }
+ }
+ outputFD = PR_Open(outfile,
+ PR_WRONLY |
+ PR_CREATE_FILE | PR_TRUNCATE,
+ 0777);
+ if (!outputFD) {
+ PR_fprintf(errorFD, "ERROR: Unable to create %s.\n",
+ outfile);
+ errorCount++;
+ exit(ERRX);
+ }
+ errorFD = outputFD;
+ }
+
+ /* This seems to be a fairly common user error */
+
+ if (verify && list_certs > 0) {
+ PR_fprintf(errorFD, "%s: Can't use -l and -v at the same time\n",
+ PROGRAM_NAME);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* -J assumes -Z now */
+
+ if (javascript && zipfile) {
+ PR_fprintf(errorFD, "%s: Can't use -J and -Z at the same time\n",
+ PROGRAM_NAME);
+ PR_fprintf(errorFD, "%s: -J option will create the jar files for you\n",
+ PROGRAM_NAME);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* -X needs -Z */
+
+ if (xpi_arc && !zipfile) {
+ PR_fprintf(errorFD, "%s: option XPI (-X) requires option jarfile (-Z)\n",
+ PROGRAM_NAME);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* Less common mixing of -L with various options */
+
+ if (list_certs > 0 &&
+ (tell_who || zipfile || javascript ||
+ scriptdir || extensionsGiven || exclusionsGiven || install_script)) {
+ PR_fprintf(errorFD, "%s: Can't use -l or -L with that option\n",
+ PROGRAM_NAME);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ if (!cert_dir)
+ cert_dir = get_default_cert_dir();
+
+ VerifyCertDir(cert_dir, keyName);
+
+ if (compression_level < MIN_COMPRESSION_LEVEL ||
+ compression_level > MAX_COMPRESSION_LEVEL) {
+ PR_fprintf(errorFD, "Compression level must be between %d and %d.\n",
+ MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ if (jartree && !keyName) {
+ PR_fprintf(errorFD, "You must specify a key with which to sign.\n");
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ readOnly = (genkey == NULL); /* only key generation requires write */
+ if (InitCrypto(cert_dir, readOnly)) {
+ PR_fprintf(errorFD, "ERROR: Cryptographic initialization failed.\n");
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ if (enableOCSP) {
+ SECStatus rv = CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
+ if (rv != SECSuccess) {
+ PR_fprintf(errorFD, "ERROR: Attempt to enable OCSP Checking failed.\n");
+ errorCount++;
+ retval = -1;
+ }
+ }
+
+ if (verify) {
+ if (VerifyJar(verify)) {
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+ } else if (list_certs) {
+ if (ListCerts(keyName, list_certs)) {
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+ } else if (list_modules) {
+ JarListModules();
+ } else if (genkey) {
+ if (GenerateCert(genkey, keySize, token)) {
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+ } else if (tell_who) {
+ if (JarWho(tell_who)) {
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+ } else if (javascript && jartree) {
+ /* make sure directory exists */
+ PRDir *dir;
+ dir = PR_OpenDir(jartree);
+ if (!dir) {
+ PR_fprintf(errorFD, "ERROR: unable to open directory %s.\n",
+ jartree);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ } else {
+ PR_CloseDir(dir);
+ }
+
+ /* undo junk from prior runs of signtool*/
+ if (RemoveAllArc(jartree)) {
+ PR_fprintf(errorFD, "Error removing archive directories under %s\n",
+ jartree);
+ errorCount++;
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* traverse all the htm|html files in the directory */
+ if (InlineJavaScript(jartree, !noRecurse)) {
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* sign any resultant .arc directories created in above step */
+ if (SignAllArc(jartree, keyName, javascript, metafile, install_script,
+ optimize, !noRecurse)) {
+ retval = -1;
+ goto cleanup;
+ }
+
+ if (!leaveArc) {
+ RemoveAllArc(jartree);
+ }
+
+ if (errorCount > 0 || warningCount > 0) {
+ PR_fprintf(outputFD, "%d error%s, %d warning%s.\n",
+ errorCount,
+ errorCount == 1 ? "" : "s", warningCount, warningCount == 1 ? "" : "s");
+ } else {
+ PR_fprintf(outputFD, "Directory %s signed successfully.\n",
+ jartree);
+ }
+ } else if (jartree) {
+ SignArchive(jartree, keyName, zipfile, javascript, metafile,
+ install_script, optimize, !noRecurse);
+ } else
+ Usage();
+
+cleanup:
+ if (extensions) {
+ PL_HashTableDestroy(extensions);
+ extensions = NULL;
+ }
+ if (excludeDirs) {
+ PL_HashTableDestroy(excludeDirs);
+ excludeDirs = NULL;
+ }
+ if (outputFD != PR_STDOUT) {
+ PR_Close(outputFD);
+ }
+ rm_dash_r(TMP_OUTPUT);
+ if (retval == 0) {
+ if (NSS_Shutdown() != SECSuccess) {
+ exit(1);
+ }
+ }
+ return retval;
+}