gecko-dev/security/nss/cmd/signtool/signtool.c

1109 строки
25 KiB
C

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1994-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* 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(zipfile);
zipfile = 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;
}