nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / cmd / signtool / signtool.c
blob132b8dd75b85e8a9a10de7c9e1661abb9df1348a
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * SIGNTOOL
40 * A command line tool to create manifest files
41 * from a directory hierarchy. It is assumed that
42 * the tree will be equivalent to what resides
43 * or will reside in an archive.
48 #include "nss.h"
49 #include "signtool.h"
50 #include "prmem.h"
51 #include "prio.h"
53 /***********************************************************************
54 * Global Variable Definitions
56 char *progName; /* argv[0] */
58 /* password on command line. Use for build testing only */
59 char *password = NULL;
61 /* directories or files to exclude in descent */
62 PLHashTable *excludeDirs = NULL;
63 static PRBool exclusionsGiven = PR_FALSE;
65 /* zatharus is the man who knows no time, dies tragic death */
66 int no_time = 0;
68 /* -b basename of .rsa, .sf files */
69 char *base = DEFAULT_BASE_NAME;
71 /* Only sign files with this extension */
72 PLHashTable *extensions = NULL;
73 PRBool extensionsGiven = PR_FALSE;
75 char *scriptdir = NULL;
77 int verbosity = 0;
79 PRFileDesc *outputFD = NULL, *errorFD = NULL;
81 int errorCount = 0, warningCount = 0;
83 int compression_level = DEFAULT_COMPRESSION_LEVEL;
84 PRBool compression_level_specified = PR_FALSE;
86 int xpi_arc = 0;
88 /* Command-line arguments */
89 static char *genkey = NULL;
90 static char *verify = NULL;
91 static char *zipfile = NULL;
92 static char *cert_dir = NULL;
93 static int javascript = 0;
94 static char *jartree = NULL;
95 static char *keyName = NULL;
96 static char *metafile = NULL;
97 static char *install_script = NULL;
98 static int list_certs = 0;
99 static int list_modules = 0;
100 static int optimize = 0;
101 static int enableOCSP = 0;
102 static char *tell_who = NULL;
103 static char *outfile = NULL;
104 static char *cmdFile = NULL;
105 static PRBool noRecurse = PR_FALSE;
106 static PRBool leaveArc = PR_FALSE;
107 static int keySize = -1;
108 static char *token = NULL;
110 typedef enum {
111 UNKNOWN_OPT,
112 HELP_OPT,
113 LONG_HELP_OPT,
114 BASE_OPT,
115 COMPRESSION_OPT,
116 CERT_DIR_OPT,
117 EXTENSION_OPT,
118 INSTALL_SCRIPT_OPT,
119 SCRIPTDIR_OPT,
120 CERTNAME_OPT,
121 LIST_OBJSIGN_CERTS_OPT,
122 LIST_ALL_CERTS_OPT,
123 METAFILE_OPT,
124 OPTIMIZE_OPT,
125 ENABLE_OCSP_OPT,
126 PASSWORD_OPT,
127 VERIFY_OPT,
128 WHO_OPT,
129 EXCLUDE_OPT,
130 NO_TIME_OPT,
131 JAVASCRIPT_OPT,
132 ZIPFILE_OPT,
133 GENKEY_OPT,
134 MODULES_OPT,
135 NORECURSE_OPT,
136 SIGNDIR_OPT,
137 OUTFILE_OPT,
138 COMMAND_FILE_OPT,
139 LEAVE_ARC_OPT,
140 VERBOSITY_OPT,
141 KEYSIZE_OPT,
142 TOKEN_OPT,
143 XPI_ARC_OPT
147 OPT_TYPE;
149 typedef enum {
150 DUPLICATE_OPTION_ERR = 0,
151 OPTION_NEEDS_ARG_ERR
155 Error;
157 static char *errStrings[] = {
158 "warning: %s option specified more than once.\n"
159 "Only last specification will be used.\n",
160 "ERROR: option \"%s\" requires an argument.\n"
164 static int ProcessOneOpt(OPT_TYPE type, char *arg);
166 /*********************************************************************
168 * P r o c e s s C o m m a n d F i l e
171 ProcessCommandFile()
173 PRFileDesc * fd;
174 #define CMD_FILE_BUFSIZE 1024
175 char buf[CMD_FILE_BUFSIZE];
176 char *equals;
177 int linenum = 0;
178 int retval = -1;
179 OPT_TYPE type;
181 fd = PR_Open(cmdFile, PR_RDONLY, 0777);
182 if (!fd) {
183 PR_fprintf(errorFD, "ERROR: Unable to open command file %s.\n");
184 errorCount++;
185 return - 1;
188 while (pr_fgets(buf, CMD_FILE_BUFSIZE, fd), buf && *buf != '\0') {
189 char *eol;
190 linenum++;
192 /* Chop off final newline */
193 eol = PL_strchr(buf, '\r');
194 if (!eol) {
195 eol = PL_strchr(buf, '\n');
197 if (eol)
198 *eol = '\0';
200 equals = PL_strchr(buf, '=');
201 if (!equals) {
202 continue;
205 *equals = '\0';
206 equals++;
208 /* Now buf points to the attribute, and equals points to the value. */
210 /* This is pretty straightforward, just deal with whatever attribute
211 * this is */
212 if (!PL_strcasecmp(buf, "basename")) {
213 type = BASE_OPT;
214 } else if (!PL_strcasecmp(buf, "compression")) {
215 type = COMPRESSION_OPT;
216 } else if (!PL_strcasecmp(buf, "certdir")) {
217 type = CERT_DIR_OPT;
218 } else if (!PL_strcasecmp(buf, "extension")) {
219 type = EXTENSION_OPT;
220 } else if (!PL_strcasecmp(buf, "generate")) {
221 type = GENKEY_OPT;
222 } else if (!PL_strcasecmp(buf, "installScript")) {
223 type = INSTALL_SCRIPT_OPT;
224 } else if (!PL_strcasecmp(buf, "javascriptdir")) {
225 type = SCRIPTDIR_OPT;
226 } else if (!PL_strcasecmp(buf, "htmldir")) {
227 type = JAVASCRIPT_OPT;
228 if (jartree) {
229 PR_fprintf(errorFD,
230 "warning: directory to be signed specified more than once."
231 " Only last specification will be used.\n");
232 warningCount++;
233 PR_Free(jartree);
234 jartree = NULL;
236 jartree = PL_strdup(equals);
237 } else if (!PL_strcasecmp(buf, "certname")) {
238 type = CERTNAME_OPT;
239 } else if (!PL_strcasecmp(buf, "signdir")) {
240 type = SIGNDIR_OPT;
241 } else if (!PL_strcasecmp(buf, "list")) {
242 type = LIST_OBJSIGN_CERTS_OPT;
243 } else if (!PL_strcasecmp(buf, "listall")) {
244 type = LIST_ALL_CERTS_OPT;
245 } else if (!PL_strcasecmp(buf, "metafile")) {
246 type = METAFILE_OPT;
247 } else if (!PL_strcasecmp(buf, "modules")) {
248 type = MODULES_OPT;
249 } else if (!PL_strcasecmp(buf, "optimize")) {
250 type = OPTIMIZE_OPT;
251 } else if (!PL_strcasecmp(buf, "ocsp")) {
252 type = ENABLE_OCSP_OPT;
253 } else if (!PL_strcasecmp(buf, "password")) {
254 type = PASSWORD_OPT;
255 } else if (!PL_strcasecmp(buf, "verify")) {
256 type = VERIFY_OPT;
257 } else if (!PL_strcasecmp(buf, "who")) {
258 type = WHO_OPT;
259 } else if (!PL_strcasecmp(buf, "exclude")) {
260 type = EXCLUDE_OPT;
261 } else if (!PL_strcasecmp(buf, "notime")) {
262 type = NO_TIME_OPT;
263 } else if (!PL_strcasecmp(buf, "jarfile")) {
264 type = ZIPFILE_OPT;
265 } else if (!PL_strcasecmp(buf, "outfile")) {
266 type = OUTFILE_OPT;
267 } else if (!PL_strcasecmp(buf, "leavearc")) {
268 type = LEAVE_ARC_OPT;
269 } else if (!PL_strcasecmp(buf, "verbosity")) {
270 type = VERBOSITY_OPT;
271 } else if (!PL_strcasecmp(buf, "keysize")) {
272 type = KEYSIZE_OPT;
273 } else if (!PL_strcasecmp(buf, "token")) {
274 type = TOKEN_OPT;
275 } else if (!PL_strcasecmp(buf, "xpi")) {
276 type = XPI_ARC_OPT;
277 } else {
278 PR_fprintf(errorFD,
279 "warning: unknown attribute \"%s\" in command file, line %d.\n",
280 buf, linenum);
281 warningCount++;
282 type = UNKNOWN_OPT;
285 /* Process the option, whatever it is */
286 if (type != UNKNOWN_OPT) {
287 if (ProcessOneOpt(type, equals) == -1) {
288 goto finish;
293 retval = 0;
295 finish:
296 PR_Close(fd);
297 return retval;
301 /*********************************************************************
303 * p a r s e _ a r g s
305 static int
306 parse_args(int argc, char *argv[])
308 char *opt;
309 char *arg;
310 int needsInc = 0;
311 int i;
312 OPT_TYPE type;
314 /* Loop over all arguments */
315 for (i = 1; i < argc; i++) {
316 opt = argv[i];
317 arg = NULL;
319 if (opt[0] == '-') {
320 if (opt[1] == '-') {
321 /* word option */
322 if (i < argc - 1) {
323 needsInc = 1;
324 arg = argv[i+1];
325 } else {
326 arg = NULL;
329 if ( !PL_strcasecmp(opt + 2, "norecurse")) {
330 type = NORECURSE_OPT;
331 } else if ( !PL_strcasecmp(opt + 2, "leavearc")) {
332 type = LEAVE_ARC_OPT;
333 } else if ( !PL_strcasecmp(opt + 2, "verbosity")) {
334 type = VERBOSITY_OPT;
335 } else if ( !PL_strcasecmp(opt + 2, "outfile")) {
336 type = OUTFILE_OPT;
337 } else if ( !PL_strcasecmp(opt + 2, "keysize")) {
338 type = KEYSIZE_OPT;
339 } else if ( !PL_strcasecmp(opt + 2, "token")) {
340 type = TOKEN_OPT;
341 } else {
342 PR_fprintf(errorFD, "warning: unknown option: %s\n",
343 opt);
344 warningCount++;
345 type = UNKNOWN_OPT;
347 } else {
348 /* char option */
349 if (opt[2] != '\0') {
350 arg = opt + 2;
351 } else if (i < argc - 1) {
352 needsInc = 1;
353 arg = argv[i+1];
354 } else {
355 arg = NULL;
358 switch (opt[1]) {
359 case 'b':
360 type = BASE_OPT;
361 break;
362 case 'c':
363 type = COMPRESSION_OPT;
364 break;
365 case 'd':
366 type = CERT_DIR_OPT;
367 break;
368 case 'e':
369 type = EXTENSION_OPT;
370 break;
371 case 'f':
372 type = COMMAND_FILE_OPT;
373 break;
374 case 'h':
375 type = HELP_OPT;
376 break;
377 case 'H':
378 type = LONG_HELP_OPT;
379 break;
380 case 'i':
381 type = INSTALL_SCRIPT_OPT;
382 break;
383 case 'j':
384 type = SCRIPTDIR_OPT;
385 break;
386 case 'k':
387 type = CERTNAME_OPT;
388 break;
389 case 'l':
390 type = LIST_OBJSIGN_CERTS_OPT;
391 break;
392 case 'L':
393 type = LIST_ALL_CERTS_OPT;
394 break;
395 case 'm':
396 type = METAFILE_OPT;
397 break;
398 case 'o':
399 type = OPTIMIZE_OPT;
400 break;
401 case 'O':
402 type = ENABLE_OCSP_OPT;
403 break;
404 case 'p':
405 type = PASSWORD_OPT;
406 break;
407 case 'v':
408 type = VERIFY_OPT;
409 break;
410 case 'w':
411 type = WHO_OPT;
412 break;
413 case 'x':
414 type = EXCLUDE_OPT;
415 break;
416 case 'X':
417 type = XPI_ARC_OPT;
418 break;
419 case 'z':
420 type = NO_TIME_OPT;
421 break;
422 case 'J':
423 type = JAVASCRIPT_OPT;
424 break;
425 case 'Z':
426 type = ZIPFILE_OPT;
427 break;
428 case 'G':
429 type = GENKEY_OPT;
430 break;
431 case 'M':
432 type = MODULES_OPT;
433 break;
434 case 's':
435 type = KEYSIZE_OPT;
436 break;
437 case 't':
438 type = TOKEN_OPT;
439 break;
440 default:
441 type = UNKNOWN_OPT;
442 PR_fprintf(errorFD, "warning: unrecognized option: -%c.\n",
444 opt[1]);
445 warningCount++;
446 break;
449 } else {
450 type = UNKNOWN_OPT;
451 if (i == argc - 1) {
452 if (jartree) {
453 PR_fprintf(errorFD,
454 "warning: directory to be signed specified more than once.\n"
455 " Only last specification will be used.\n");
456 warningCount++;
457 PR_Free(jartree);
458 jartree = NULL;
460 jartree = PL_strdup(opt);
461 } else {
462 PR_fprintf(errorFD, "warning: unrecognized option: %s\n", opt);
463 warningCount++;
467 if (type != UNKNOWN_OPT) {
468 short ateArg = ProcessOneOpt(type, arg);
469 if (ateArg == -1) {
470 /* error */
471 return - 1;
473 if (ateArg && needsInc) {
474 i++;
479 return 0;
483 /*********************************************************************
485 * P r o c e s s O n e O p t
487 * Since options can come from different places (command file, word options,
488 * char options), this is a central function that is called to deal with
489 * them no matter where they come from.
491 * type is the type of option.
492 * arg is the argument to the option, possibly NULL.
493 * Returns 1 if the argument was eaten, 0 if it wasn't, and -1 for error.
495 static int
496 ProcessOneOpt(OPT_TYPE type, char *arg)
498 int ate = 0;
500 switch (type) {
501 case HELP_OPT:
502 Usage();
503 break;
504 case LONG_HELP_OPT:
505 LongUsage();
506 break;
507 case BASE_OPT:
508 if (base) {
509 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-b");
510 warningCount++;
511 PR_Free(base);
512 base = NULL;
514 if (!arg) {
515 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-b");
516 errorCount++;
517 goto loser;
519 base = PL_strdup(arg);
520 ate = 1;
521 break;
522 case COMPRESSION_OPT:
523 if (compression_level_specified) {
524 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-c");
525 warningCount++;
527 if ( !arg ) {
528 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-c");
529 errorCount++;
530 goto loser;
532 compression_level = atoi(arg);
533 compression_level_specified = PR_TRUE;
534 ate = 1;
535 break;
536 case CERT_DIR_OPT:
537 if (cert_dir) {
538 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-d");
539 warningCount++;
540 PR_Free(cert_dir);
541 cert_dir = NULL;
543 if (!arg) {
544 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-d");
545 errorCount++;
546 goto loser;
548 cert_dir = PL_strdup(arg);
549 ate = 1;
550 break;
551 case EXTENSION_OPT:
552 if (!arg) {
553 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
554 "extension (-e)");
555 errorCount++;
556 goto loser;
558 PL_HashTableAdd(extensions, arg, arg);
559 extensionsGiven = PR_TRUE;
560 ate = 1;
561 break;
562 case INSTALL_SCRIPT_OPT:
563 if (install_script) {
564 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
565 "installScript (-i)");
566 warningCount++;
567 PR_Free(install_script);
568 install_script = NULL;
570 if (!arg) {
571 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
572 "installScript (-i)");
573 errorCount++;
574 goto loser;
576 install_script = PL_strdup(arg);
577 ate = 1;
578 break;
579 case SCRIPTDIR_OPT:
580 if (scriptdir) {
581 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
582 "javascriptdir (-j)");
583 warningCount++;
584 PR_Free(scriptdir);
585 scriptdir = NULL;
587 if (!arg) {
588 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
589 "javascriptdir (-j)");
590 errorCount++;
591 goto loser;
593 scriptdir = PL_strdup(arg);
594 ate = 1;
595 break;
596 case CERTNAME_OPT:
597 if (keyName) {
598 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
599 "keyName (-k)");
600 warningCount++;
601 PR_Free(keyName);
602 keyName = NULL;
604 if (!arg) {
605 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
606 "keyName (-k)");
607 errorCount++;
608 goto loser;
610 keyName = PL_strdup(arg);
611 ate = 1;
612 break;
613 case LIST_OBJSIGN_CERTS_OPT:
614 case LIST_ALL_CERTS_OPT:
615 if (list_certs != 0) {
616 PR_fprintf(errorFD,
617 "warning: only one of -l and -L may be specified.\n");
618 warningCount++;
620 list_certs = (type == LIST_OBJSIGN_CERTS_OPT ? 1 : 2);
621 break;
622 case METAFILE_OPT:
623 if (metafile) {
624 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
625 "metafile (-m)");
626 warningCount++;
627 PR_Free(metafile);
628 metafile = NULL;
630 if (!arg) {
631 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
632 "metafile (-m)");
633 errorCount++;
634 goto loser;
636 metafile = PL_strdup(arg);
637 ate = 1;
638 break;
639 case OPTIMIZE_OPT:
640 optimize = 1;
641 break;
642 case ENABLE_OCSP_OPT:
643 enableOCSP = 1;
644 break;
645 case PASSWORD_OPT:
646 if (password) {
647 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
648 "password (-p)");
649 warningCount++;
650 PR_Free(password);
651 password = NULL;
653 if (!arg) {
654 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
655 "password (-p)");
656 errorCount++;
657 goto loser;
659 password = PL_strdup(arg);
660 ate = 1;
661 break;
662 case VERIFY_OPT:
663 if (verify) {
664 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
665 "verify (-v)");
666 warningCount++;
667 PR_Free(verify);
668 verify = NULL;
670 if (!arg) {
671 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
672 "verify (-v)");
673 errorCount++;
674 goto loser;
676 verify = PL_strdup(arg);
677 ate = 1;
678 break;
679 case WHO_OPT:
680 if (tell_who) {
681 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
682 "who (-v)");
683 warningCount++;
684 PR_Free(tell_who);
685 tell_who = NULL;
687 if (!arg) {
688 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
689 "who (-w)");
690 errorCount++;
691 goto loser;
693 tell_who = PL_strdup(arg);
694 ate = 1;
695 break;
696 case EXCLUDE_OPT:
697 if (!arg) {
698 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
699 "exclude (-x)");
700 errorCount++;
701 goto loser;
703 PL_HashTableAdd(excludeDirs, arg, arg);
704 exclusionsGiven = PR_TRUE;
705 ate = 1;
706 break;
707 case NO_TIME_OPT:
708 no_time = 1;
709 break;
710 case JAVASCRIPT_OPT:
711 javascript++;
712 break;
713 case ZIPFILE_OPT:
714 if (zipfile) {
715 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
716 "jarfile (-Z)");
717 warningCount++;
718 PR_Free(zipfile);
719 zipfile = NULL;
721 if (!arg) {
722 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
723 "jarfile (-Z)");
724 errorCount++;
725 goto loser;
727 zipfile = PL_strdup(arg);
728 ate = 1;
729 break;
730 case GENKEY_OPT:
731 if (genkey) {
732 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
733 "generate (-G)");
734 warningCount++;
735 PR_Free(zipfile);
736 zipfile = NULL;
738 if (!arg) {
739 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
740 "generate (-G)");
741 errorCount++;
742 goto loser;
744 genkey = PL_strdup(arg);
745 ate = 1;
746 break;
747 case MODULES_OPT:
748 list_modules++;
749 break;
750 case SIGNDIR_OPT:
751 if (jartree) {
752 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
753 "signdir");
754 warningCount++;
755 PR_Free(jartree);
756 jartree = NULL;
758 if (!arg) {
759 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
760 "signdir");
761 errorCount++;
762 goto loser;
764 jartree = PL_strdup(arg);
765 ate = 1;
766 break;
767 case OUTFILE_OPT:
768 if (outfile) {
769 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
770 "outfile");
771 warningCount++;
772 PR_Free(outfile);
773 outfile = NULL;
775 if (!arg) {
776 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
777 "outfile");
778 errorCount++;
779 goto loser;
781 outfile = PL_strdup(arg);
782 ate = 1;
783 break;
784 case COMMAND_FILE_OPT:
785 if (cmdFile) {
786 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
787 "-f");
788 warningCount++;
789 PR_Free(cmdFile);
790 cmdFile = NULL;
792 if (!arg) {
793 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
794 "-f");
795 errorCount++;
796 goto loser;
798 cmdFile = PL_strdup(arg);
799 ate = 1;
800 break;
801 case NORECURSE_OPT:
802 noRecurse = PR_TRUE;
803 break;
804 case LEAVE_ARC_OPT:
805 leaveArc = PR_TRUE;
806 break;
807 case VERBOSITY_OPT:
808 if (!arg) {
809 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
810 "--verbosity");
811 errorCount++;
812 goto loser;
814 verbosity = atoi(arg);
815 ate = 1;
816 break;
817 case KEYSIZE_OPT:
818 if ( keySize != -1 ) {
819 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-s");
820 warningCount++;
822 keySize = atoi(arg);
823 ate = 1;
824 if ( keySize < 1 || keySize > MAX_RSA_KEY_SIZE ) {
825 PR_fprintf(errorFD, "Invalid key size: %d.\n", keySize);
826 errorCount++;
827 goto loser;
829 break;
830 case TOKEN_OPT:
831 if ( token ) {
832 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-t");
833 PR_Free(token);
834 token = NULL;
836 if ( !arg ) {
837 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-t");
838 errorCount++;
839 goto loser;
841 token = PL_strdup(arg);
842 ate = 1;
843 break;
844 case XPI_ARC_OPT:
845 xpi_arc = 1;
846 break;
847 default:
848 PR_fprintf(errorFD, "warning: unknown option\n");
849 warningCount++;
850 break;
853 return ate;
854 loser:
855 return - 1;
859 /*********************************************************************
861 * m a i n
864 main(int argc, char *argv[])
866 PRBool readOnly;
867 int retval = 0;
869 outputFD = PR_STDOUT;
870 errorFD = PR_STDERR;
872 progName = argv[0];
874 if (argc < 2) {
875 Usage();
878 excludeDirs = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
879 PL_CompareStrings, NULL, NULL);
880 extensions = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
881 PL_CompareStrings, NULL, NULL);
883 if (parse_args(argc, argv)) {
884 retval = -1;
885 goto cleanup;
888 /* Parse the command file if one was given */
889 if (cmdFile) {
890 if (ProcessCommandFile()) {
891 retval = -1;
892 goto cleanup;
896 /* Set up output redirection */
897 if (outfile) {
898 if (PR_Access(outfile, PR_ACCESS_EXISTS) == PR_SUCCESS) {
899 /* delete the file if it is already present */
900 PR_fprintf(errorFD,
901 "warning: %s already exists and will be overwritten.\n",
902 outfile);
903 warningCount++;
904 if (PR_Delete(outfile) != PR_SUCCESS) {
905 PR_fprintf(errorFD, "ERROR: unable to delete %s.\n", outfile);
906 errorCount++;
907 exit(ERRX);
910 outputFD = PR_Open(outfile,
911 PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777);
912 if (!outputFD) {
913 PR_fprintf(errorFD, "ERROR: Unable to create %s.\n",
914 outfile);
915 errorCount++;
916 exit(ERRX);
918 errorFD = outputFD;
921 /* This seems to be a fairly common user error */
923 if (verify && list_certs > 0) {
924 PR_fprintf (errorFD, "%s: Can't use -l and -v at the same time\n",
925 PROGRAM_NAME);
926 errorCount++;
927 retval = -1;
928 goto cleanup;
931 /* -J assumes -Z now */
933 if (javascript && zipfile) {
934 PR_fprintf (errorFD, "%s: Can't use -J and -Z at the same time\n",
935 PROGRAM_NAME);
936 PR_fprintf (errorFD, "%s: -J option will create the jar files for you\n",
937 PROGRAM_NAME);
938 errorCount++;
939 retval = -1;
940 goto cleanup;
943 /* -X needs -Z */
945 if (xpi_arc && !zipfile) {
946 PR_fprintf (errorFD, "%s: option XPI (-X) requires option jarfile (-Z)\n",
947 PROGRAM_NAME);
948 errorCount++;
949 retval = -1;
950 goto cleanup;
953 /* Less common mixing of -L with various options */
955 if (list_certs > 0 &&
956 (tell_who || zipfile || javascript ||
957 scriptdir || extensionsGiven || exclusionsGiven || install_script)) {
958 PR_fprintf(errorFD, "%s: Can't use -l or -L with that option\n",
959 PROGRAM_NAME);
960 errorCount++;
961 retval = -1;
962 goto cleanup;
966 if (!cert_dir)
967 cert_dir = get_default_cert_dir();
969 VerifyCertDir(cert_dir, keyName);
972 if ( compression_level < MIN_COMPRESSION_LEVEL ||
973 compression_level > MAX_COMPRESSION_LEVEL) {
974 PR_fprintf(errorFD, "Compression level must be between %d and %d.\n",
975 MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL);
976 errorCount++;
977 retval = -1;
978 goto cleanup;
981 if (jartree && !keyName) {
982 PR_fprintf(errorFD, "You must specify a key with which to sign.\n");
983 errorCount++;
984 retval = -1;
985 goto cleanup;
988 readOnly = (genkey == NULL); /* only key generation requires write */
989 if (InitCrypto(cert_dir, readOnly)) {
990 PR_fprintf(errorFD, "ERROR: Cryptographic initialization failed.\n");
991 errorCount++;
992 retval = -1;
993 goto cleanup;
996 if (enableOCSP) {
997 SECStatus rv = CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
998 if (rv != SECSuccess) {
999 PR_fprintf(errorFD, "ERROR: Attempt to enable OCSP Checking failed.\n");
1000 errorCount++;
1001 retval = -1;
1005 if (verify) {
1006 if (VerifyJar(verify)) {
1007 errorCount++;
1008 retval = -1;
1009 goto cleanup;
1011 } else if (list_certs) {
1012 if (ListCerts(keyName, list_certs)) {
1013 errorCount++;
1014 retval = -1;
1015 goto cleanup;
1017 } else if (list_modules) {
1018 JarListModules();
1019 } else if (genkey) {
1020 if (GenerateCert(genkey, keySize, token)) {
1021 errorCount++;
1022 retval = -1;
1023 goto cleanup;
1025 } else if (tell_who) {
1026 if (JarWho(tell_who)) {
1027 errorCount++;
1028 retval = -1;
1029 goto cleanup;
1031 } else if (javascript && jartree) {
1032 /* make sure directory exists */
1033 PRDir * dir;
1034 dir = PR_OpenDir(jartree);
1035 if (!dir) {
1036 PR_fprintf(errorFD, "ERROR: unable to open directory %s.\n",
1037 jartree);
1038 errorCount++;
1039 retval = -1;
1040 goto cleanup;
1041 } else {
1042 PR_CloseDir(dir);
1045 /* undo junk from prior runs of signtool*/
1046 if (RemoveAllArc(jartree)) {
1047 PR_fprintf(errorFD, "Error removing archive directories under %s\n",
1048 jartree);
1049 errorCount++;
1050 retval = -1;
1051 goto cleanup;
1054 /* traverse all the htm|html files in the directory */
1055 if (InlineJavaScript(jartree, !noRecurse)) {
1056 retval = -1;
1057 goto cleanup;
1060 /* sign any resultant .arc directories created in above step */
1061 if (SignAllArc(jartree, keyName, javascript, metafile, install_script,
1062 optimize, !noRecurse)) {
1063 retval = -1;
1064 goto cleanup;
1067 if (!leaveArc) {
1068 RemoveAllArc(jartree);
1071 if (errorCount > 0 || warningCount > 0) {
1072 PR_fprintf(outputFD, "%d error%s, %d warning%s.\n",
1073 errorCount,
1074 errorCount == 1 ? "" : "s", warningCount, warningCount
1075 == 1 ? "" : "s");
1076 } else {
1077 PR_fprintf(outputFD, "Directory %s signed successfully.\n",
1078 jartree);
1080 } else if (jartree) {
1081 SignArchive(jartree, keyName, zipfile, javascript, metafile,
1082 install_script, optimize, !noRecurse);
1083 } else
1084 Usage();
1086 cleanup:
1087 if (extensions) {
1088 PL_HashTableDestroy(extensions);
1089 extensions = NULL;
1091 if (excludeDirs) {
1092 PL_HashTableDestroy(excludeDirs);
1093 excludeDirs = NULL;
1095 if (outputFD != PR_STDOUT) {
1096 PR_Close(outputFD);
1098 rm_dash_r(TMP_OUTPUT);
1099 if (retval == 0) {
1100 if (NSS_Shutdown() != SECSuccess) {
1101 exit(1);
1104 return retval;