Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * SIGNTOOL
7 *
8 * A command line tool to create manifest files
9 * from a directory hierarchy. It is assumed that
10 * the tree will be equivalent to what resides
11 * or will reside in an archive.
12 *
13 *
14 */
16 #include "nss.h"
17 #include "signtool.h"
18 #include "prmem.h"
19 #include "prio.h"
21 /***********************************************************************
22 * Global Variable Definitions
23 */
24 char *progName; /* argv[0] */
26 /* password data */
27 secuPWData pwdata = { PW_NONE, 0 };
29 /* directories or files to exclude in descent */
30 PLHashTable *excludeDirs = NULL;
31 static PRBool exclusionsGiven = PR_FALSE;
33 /* zatharus is the man who knows no time, dies tragic death */
34 int no_time = 0;
36 /* -b basename of .rsa, .sf files */
37 char *base = DEFAULT_BASE_NAME;
39 /* Only sign files with this extension */
40 PLHashTable *extensions = NULL;
41 PRBool extensionsGiven = PR_FALSE;
43 char *scriptdir = NULL;
45 int verbosity = 0;
47 PRFileDesc *outputFD = NULL, *errorFD = NULL;
49 int errorCount = 0, warningCount = 0;
51 int compression_level = DEFAULT_COMPRESSION_LEVEL;
52 PRBool compression_level_specified = PR_FALSE;
54 int xpi_arc = 0;
56 /* Command-line arguments */
57 static char *genkey = NULL;
58 static char *verify = NULL;
59 static char *zipfile = NULL;
60 static char *cert_dir = NULL;
61 static int javascript = 0;
62 static char *jartree = NULL;
63 static char *keyName = NULL;
64 static char *metafile = NULL;
65 static char *install_script = NULL;
66 static int list_certs = 0;
67 static int list_modules = 0;
68 static int optimize = 0;
69 static int enableOCSP = 0;
70 static char *tell_who = NULL;
71 static char *outfile = NULL;
72 static char *cmdFile = NULL;
73 static PRBool noRecurse = PR_FALSE;
74 static PRBool leaveArc = PR_FALSE;
75 static int keySize = -1;
76 static char *token = NULL;
78 typedef enum {
79 UNKNOWN_OPT,
80 HELP_OPT,
81 LONG_HELP_OPT,
82 BASE_OPT,
83 COMPRESSION_OPT,
84 CERT_DIR_OPT,
85 EXTENSION_OPT,
86 INSTALL_SCRIPT_OPT,
87 SCRIPTDIR_OPT,
88 CERTNAME_OPT,
89 LIST_OBJSIGN_CERTS_OPT,
90 LIST_ALL_CERTS_OPT,
91 METAFILE_OPT,
92 OPTIMIZE_OPT,
93 ENABLE_OCSP_OPT,
94 PASSWORD_OPT,
95 VERIFY_OPT,
96 WHO_OPT,
97 EXCLUDE_OPT,
98 NO_TIME_OPT,
99 JAVASCRIPT_OPT,
100 ZIPFILE_OPT,
101 GENKEY_OPT,
102 MODULES_OPT,
103 NORECURSE_OPT,
104 SIGNDIR_OPT,
105 OUTFILE_OPT,
106 COMMAND_FILE_OPT,
107 LEAVE_ARC_OPT,
108 VERBOSITY_OPT,
109 KEYSIZE_OPT,
110 TOKEN_OPT,
111 XPI_ARC_OPT
112 }
115 OPT_TYPE;
117 typedef enum {
118 DUPLICATE_OPTION_ERR = 0,
119 OPTION_NEEDS_ARG_ERR
120 }
123 Error;
125 static char *errStrings[] = {
126 "warning: %s option specified more than once.\n"
127 "Only last specification will be used.\n",
128 "ERROR: option \"%s\" requires an argument.\n"
129 };
132 static int ProcessOneOpt(OPT_TYPE type, char *arg);
134 /*********************************************************************
135 *
136 * P r o c e s s C o m m a n d F i l e
137 */
138 int
139 ProcessCommandFile()
140 {
141 PRFileDesc * fd;
142 #define CMD_FILE_BUFSIZE 1024
143 char buf[CMD_FILE_BUFSIZE];
144 char *equals;
145 int linenum = 0;
146 int retval = -1;
147 OPT_TYPE type;
149 fd = PR_Open(cmdFile, PR_RDONLY, 0777);
150 if (!fd) {
151 PR_fprintf(errorFD, "ERROR: Unable to open command file %s.\n");
152 errorCount++;
153 return - 1;
154 }
156 while (pr_fgets(buf, CMD_FILE_BUFSIZE, fd)) {
157 char *eol;
158 linenum++;
160 /* Chop off final newline */
161 eol = PL_strchr(buf, '\r');
162 if (!eol) {
163 eol = PL_strchr(buf, '\n');
164 }
165 if (eol)
166 *eol = '\0';
168 equals = PL_strchr(buf, '=');
169 if (!equals) {
170 continue;
171 }
173 *equals = '\0';
174 equals++;
176 /* Now buf points to the attribute, and equals points to the value. */
178 /* This is pretty straightforward, just deal with whatever attribute
179 * this is */
180 if (!PL_strcasecmp(buf, "basename")) {
181 type = BASE_OPT;
182 } else if (!PL_strcasecmp(buf, "compression")) {
183 type = COMPRESSION_OPT;
184 } else if (!PL_strcasecmp(buf, "certdir")) {
185 type = CERT_DIR_OPT;
186 } else if (!PL_strcasecmp(buf, "extension")) {
187 type = EXTENSION_OPT;
188 } else if (!PL_strcasecmp(buf, "generate")) {
189 type = GENKEY_OPT;
190 } else if (!PL_strcasecmp(buf, "installScript")) {
191 type = INSTALL_SCRIPT_OPT;
192 } else if (!PL_strcasecmp(buf, "javascriptdir")) {
193 type = SCRIPTDIR_OPT;
194 } else if (!PL_strcasecmp(buf, "htmldir")) {
195 type = JAVASCRIPT_OPT;
196 if (jartree) {
197 PR_fprintf(errorFD,
198 "warning: directory to be signed specified more than once."
199 " Only last specification will be used.\n");
200 warningCount++;
201 PR_Free(jartree);
202 jartree = NULL;
203 }
204 jartree = PL_strdup(equals);
205 } else if (!PL_strcasecmp(buf, "certname")) {
206 type = CERTNAME_OPT;
207 } else if (!PL_strcasecmp(buf, "signdir")) {
208 type = SIGNDIR_OPT;
209 } else if (!PL_strcasecmp(buf, "list")) {
210 type = LIST_OBJSIGN_CERTS_OPT;
211 } else if (!PL_strcasecmp(buf, "listall")) {
212 type = LIST_ALL_CERTS_OPT;
213 } else if (!PL_strcasecmp(buf, "metafile")) {
214 type = METAFILE_OPT;
215 } else if (!PL_strcasecmp(buf, "modules")) {
216 type = MODULES_OPT;
217 } else if (!PL_strcasecmp(buf, "optimize")) {
218 type = OPTIMIZE_OPT;
219 } else if (!PL_strcasecmp(buf, "ocsp")) {
220 type = ENABLE_OCSP_OPT;
221 } else if (!PL_strcasecmp(buf, "password")) {
222 type = PASSWORD_OPT;
223 } else if (!PL_strcasecmp(buf, "verify")) {
224 type = VERIFY_OPT;
225 } else if (!PL_strcasecmp(buf, "who")) {
226 type = WHO_OPT;
227 } else if (!PL_strcasecmp(buf, "exclude")) {
228 type = EXCLUDE_OPT;
229 } else if (!PL_strcasecmp(buf, "notime")) {
230 type = NO_TIME_OPT;
231 } else if (!PL_strcasecmp(buf, "jarfile")) {
232 type = ZIPFILE_OPT;
233 } else if (!PL_strcasecmp(buf, "outfile")) {
234 type = OUTFILE_OPT;
235 } else if (!PL_strcasecmp(buf, "leavearc")) {
236 type = LEAVE_ARC_OPT;
237 } else if (!PL_strcasecmp(buf, "verbosity")) {
238 type = VERBOSITY_OPT;
239 } else if (!PL_strcasecmp(buf, "keysize")) {
240 type = KEYSIZE_OPT;
241 } else if (!PL_strcasecmp(buf, "token")) {
242 type = TOKEN_OPT;
243 } else if (!PL_strcasecmp(buf, "xpi")) {
244 type = XPI_ARC_OPT;
245 } else {
246 PR_fprintf(errorFD,
247 "warning: unknown attribute \"%s\" in command file, line %d.\n",
248 buf, linenum);
249 warningCount++;
250 type = UNKNOWN_OPT;
251 }
253 /* Process the option, whatever it is */
254 if (type != UNKNOWN_OPT) {
255 if (ProcessOneOpt(type, equals) == -1) {
256 goto finish;
257 }
258 }
259 }
261 retval = 0;
263 finish:
264 PR_Close(fd);
265 return retval;
266 }
269 /*********************************************************************
270 *
271 * p a r s e _ a r g s
272 */
273 static int
274 parse_args(int argc, char *argv[])
275 {
276 char *opt;
277 char *arg;
278 int needsInc = 0;
279 int i;
280 OPT_TYPE type;
282 /* Loop over all arguments */
283 for (i = 1; i < argc; i++) {
284 opt = argv[i];
285 arg = NULL;
287 if (opt[0] == '-') {
288 if (opt[1] == '-') {
289 /* word option */
290 if (i < argc - 1) {
291 needsInc = 1;
292 arg = argv[i+1];
293 } else {
294 arg = NULL;
295 }
297 if ( !PL_strcasecmp(opt + 2, "norecurse")) {
298 type = NORECURSE_OPT;
299 } else if ( !PL_strcasecmp(opt + 2, "leavearc")) {
300 type = LEAVE_ARC_OPT;
301 } else if ( !PL_strcasecmp(opt + 2, "verbosity")) {
302 type = VERBOSITY_OPT;
303 } else if ( !PL_strcasecmp(opt + 2, "outfile")) {
304 type = OUTFILE_OPT;
305 } else if ( !PL_strcasecmp(opt + 2, "keysize")) {
306 type = KEYSIZE_OPT;
307 } else if ( !PL_strcasecmp(opt + 2, "token")) {
308 type = TOKEN_OPT;
309 } else {
310 PR_fprintf(errorFD, "warning: unknown option: %s\n",
311 opt);
312 warningCount++;
313 type = UNKNOWN_OPT;
314 }
315 } else {
316 /* char option */
317 if (opt[2] != '\0') {
318 arg = opt + 2;
319 } else if (i < argc - 1) {
320 needsInc = 1;
321 arg = argv[i+1];
322 } else {
323 arg = NULL;
324 }
326 switch (opt[1]) {
327 case 'b':
328 type = BASE_OPT;
329 break;
330 case 'c':
331 type = COMPRESSION_OPT;
332 break;
333 case 'd':
334 type = CERT_DIR_OPT;
335 break;
336 case 'e':
337 type = EXTENSION_OPT;
338 break;
339 case 'f':
340 type = COMMAND_FILE_OPT;
341 break;
342 case 'h':
343 type = HELP_OPT;
344 break;
345 case 'H':
346 type = LONG_HELP_OPT;
347 break;
348 case 'i':
349 type = INSTALL_SCRIPT_OPT;
350 break;
351 case 'j':
352 type = SCRIPTDIR_OPT;
353 break;
354 case 'k':
355 type = CERTNAME_OPT;
356 break;
357 case 'l':
358 type = LIST_OBJSIGN_CERTS_OPT;
359 break;
360 case 'L':
361 type = LIST_ALL_CERTS_OPT;
362 break;
363 case 'm':
364 type = METAFILE_OPT;
365 break;
366 case 'o':
367 type = OPTIMIZE_OPT;
368 break;
369 case 'O':
370 type = ENABLE_OCSP_OPT;
371 break;
372 case 'p':
373 type = PASSWORD_OPT;
374 break;
375 case 'v':
376 type = VERIFY_OPT;
377 break;
378 case 'w':
379 type = WHO_OPT;
380 break;
381 case 'x':
382 type = EXCLUDE_OPT;
383 break;
384 case 'X':
385 type = XPI_ARC_OPT;
386 break;
387 case 'z':
388 type = NO_TIME_OPT;
389 break;
390 case 'J':
391 type = JAVASCRIPT_OPT;
392 break;
393 case 'Z':
394 type = ZIPFILE_OPT;
395 break;
396 case 'G':
397 type = GENKEY_OPT;
398 break;
399 case 'M':
400 type = MODULES_OPT;
401 break;
402 case 's':
403 type = KEYSIZE_OPT;
404 break;
405 case 't':
406 type = TOKEN_OPT;
407 break;
408 default:
409 type = UNKNOWN_OPT;
410 PR_fprintf(errorFD, "warning: unrecognized option: -%c.\n",
412 opt[1]);
413 warningCount++;
414 break;
415 }
416 }
417 } else {
418 type = UNKNOWN_OPT;
419 if (i == argc - 1) {
420 if (jartree) {
421 PR_fprintf(errorFD,
422 "warning: directory to be signed specified more than once.\n"
423 " Only last specification will be used.\n");
424 warningCount++;
425 PR_Free(jartree);
426 jartree = NULL;
427 }
428 jartree = PL_strdup(opt);
429 } else {
430 PR_fprintf(errorFD, "warning: unrecognized option: %s\n", opt);
431 warningCount++;
432 }
433 }
435 if (type != UNKNOWN_OPT) {
436 short ateArg = ProcessOneOpt(type, arg);
437 if (ateArg == -1) {
438 /* error */
439 return - 1;
440 }
441 if (ateArg && needsInc) {
442 i++;
443 }
444 }
445 }
447 return 0;
448 }
451 /*********************************************************************
452 *
453 * P r o c e s s O n e O p t
454 *
455 * Since options can come from different places (command file, word options,
456 * char options), this is a central function that is called to deal with
457 * them no matter where they come from.
458 *
459 * type is the type of option.
460 * arg is the argument to the option, possibly NULL.
461 * Returns 1 if the argument was eaten, 0 if it wasn't, and -1 for error.
462 */
463 static int
464 ProcessOneOpt(OPT_TYPE type, char *arg)
465 {
466 int ate = 0;
468 switch (type) {
469 case HELP_OPT:
470 Usage();
471 break;
472 case LONG_HELP_OPT:
473 LongUsage();
474 break;
475 case BASE_OPT:
476 if (base) {
477 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-b");
478 warningCount++;
479 PR_Free(base);
480 base = NULL;
481 }
482 if (!arg) {
483 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-b");
484 errorCount++;
485 goto loser;
486 }
487 base = PL_strdup(arg);
488 ate = 1;
489 break;
490 case COMPRESSION_OPT:
491 if (compression_level_specified) {
492 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-c");
493 warningCount++;
494 }
495 if ( !arg ) {
496 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-c");
497 errorCount++;
498 goto loser;
499 }
500 compression_level = atoi(arg);
501 compression_level_specified = PR_TRUE;
502 ate = 1;
503 break;
504 case CERT_DIR_OPT:
505 if (cert_dir) {
506 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-d");
507 warningCount++;
508 PR_Free(cert_dir);
509 cert_dir = NULL;
510 }
511 if (!arg) {
512 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-d");
513 errorCount++;
514 goto loser;
515 }
516 cert_dir = PL_strdup(arg);
517 ate = 1;
518 break;
519 case EXTENSION_OPT:
520 if (!arg) {
521 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
522 "extension (-e)");
523 errorCount++;
524 goto loser;
525 }
526 PL_HashTableAdd(extensions, arg, arg);
527 extensionsGiven = PR_TRUE;
528 ate = 1;
529 break;
530 case INSTALL_SCRIPT_OPT:
531 if (install_script) {
532 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
533 "installScript (-i)");
534 warningCount++;
535 PR_Free(install_script);
536 install_script = NULL;
537 }
538 if (!arg) {
539 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
540 "installScript (-i)");
541 errorCount++;
542 goto loser;
543 }
544 install_script = PL_strdup(arg);
545 ate = 1;
546 break;
547 case SCRIPTDIR_OPT:
548 if (scriptdir) {
549 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
550 "javascriptdir (-j)");
551 warningCount++;
552 PR_Free(scriptdir);
553 scriptdir = NULL;
554 }
555 if (!arg) {
556 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
557 "javascriptdir (-j)");
558 errorCount++;
559 goto loser;
560 }
561 scriptdir = PL_strdup(arg);
562 ate = 1;
563 break;
564 case CERTNAME_OPT:
565 if (keyName) {
566 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
567 "keyName (-k)");
568 warningCount++;
569 PR_Free(keyName);
570 keyName = NULL;
571 }
572 if (!arg) {
573 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
574 "keyName (-k)");
575 errorCount++;
576 goto loser;
577 }
578 keyName = PL_strdup(arg);
579 ate = 1;
580 break;
581 case LIST_OBJSIGN_CERTS_OPT:
582 case LIST_ALL_CERTS_OPT:
583 if (list_certs != 0) {
584 PR_fprintf(errorFD,
585 "warning: only one of -l and -L may be specified.\n");
586 warningCount++;
587 }
588 list_certs = (type == LIST_OBJSIGN_CERTS_OPT ? 1 : 2);
589 break;
590 case METAFILE_OPT:
591 if (metafile) {
592 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
593 "metafile (-m)");
594 warningCount++;
595 PR_Free(metafile);
596 metafile = NULL;
597 }
598 if (!arg) {
599 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
600 "metafile (-m)");
601 errorCount++;
602 goto loser;
603 }
604 metafile = PL_strdup(arg);
605 ate = 1;
606 break;
607 case OPTIMIZE_OPT:
608 optimize = 1;
609 break;
610 case ENABLE_OCSP_OPT:
611 enableOCSP = 1;
612 break;
613 case PASSWORD_OPT:
614 if (pwdata.data) {
615 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
616 "password (-p)");
617 warningCount++;
618 PR_Free(pwdata.data);
619 pwdata.data = NULL;
620 }
621 if (!arg) {
622 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
623 "password (-p)");
624 errorCount++;
625 goto loser;
626 }
627 pwdata.source = PW_PLAINTEXT;
628 pwdata.data = PL_strdup(arg);
629 ate = 1;
630 break;
631 case VERIFY_OPT:
632 if (verify) {
633 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
634 "verify (-v)");
635 warningCount++;
636 PR_Free(verify);
637 verify = NULL;
638 }
639 if (!arg) {
640 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
641 "verify (-v)");
642 errorCount++;
643 goto loser;
644 }
645 verify = PL_strdup(arg);
646 ate = 1;
647 break;
648 case WHO_OPT:
649 if (tell_who) {
650 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
651 "who (-v)");
652 warningCount++;
653 PR_Free(tell_who);
654 tell_who = NULL;
655 }
656 if (!arg) {
657 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
658 "who (-w)");
659 errorCount++;
660 goto loser;
661 }
662 tell_who = PL_strdup(arg);
663 ate = 1;
664 break;
665 case EXCLUDE_OPT:
666 if (!arg) {
667 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
668 "exclude (-x)");
669 errorCount++;
670 goto loser;
671 }
672 PL_HashTableAdd(excludeDirs, arg, arg);
673 exclusionsGiven = PR_TRUE;
674 ate = 1;
675 break;
676 case NO_TIME_OPT:
677 no_time = 1;
678 break;
679 case JAVASCRIPT_OPT:
680 javascript++;
681 break;
682 case ZIPFILE_OPT:
683 if (zipfile) {
684 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
685 "jarfile (-Z)");
686 warningCount++;
687 PR_Free(zipfile);
688 zipfile = NULL;
689 }
690 if (!arg) {
691 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
692 "jarfile (-Z)");
693 errorCount++;
694 goto loser;
695 }
696 zipfile = PL_strdup(arg);
697 ate = 1;
698 break;
699 case GENKEY_OPT:
700 if (genkey) {
701 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
702 "generate (-G)");
703 warningCount++;
704 PR_Free(genkey);
705 genkey = NULL;
706 }
707 if (!arg) {
708 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
709 "generate (-G)");
710 errorCount++;
711 goto loser;
712 }
713 genkey = PL_strdup(arg);
714 ate = 1;
715 break;
716 case MODULES_OPT:
717 list_modules++;
718 break;
719 case SIGNDIR_OPT:
720 if (jartree) {
721 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
722 "signdir");
723 warningCount++;
724 PR_Free(jartree);
725 jartree = NULL;
726 }
727 if (!arg) {
728 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
729 "signdir");
730 errorCount++;
731 goto loser;
732 }
733 jartree = PL_strdup(arg);
734 ate = 1;
735 break;
736 case OUTFILE_OPT:
737 if (outfile) {
738 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
739 "outfile");
740 warningCount++;
741 PR_Free(outfile);
742 outfile = NULL;
743 }
744 if (!arg) {
745 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
746 "outfile");
747 errorCount++;
748 goto loser;
749 }
750 outfile = PL_strdup(arg);
751 ate = 1;
752 break;
753 case COMMAND_FILE_OPT:
754 if (cmdFile) {
755 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
756 "-f");
757 warningCount++;
758 PR_Free(cmdFile);
759 cmdFile = NULL;
760 }
761 if (!arg) {
762 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
763 "-f");
764 errorCount++;
765 goto loser;
766 }
767 cmdFile = PL_strdup(arg);
768 ate = 1;
769 break;
770 case NORECURSE_OPT:
771 noRecurse = PR_TRUE;
772 break;
773 case LEAVE_ARC_OPT:
774 leaveArc = PR_TRUE;
775 break;
776 case VERBOSITY_OPT:
777 if (!arg) {
778 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
779 "--verbosity");
780 errorCount++;
781 goto loser;
782 }
783 verbosity = atoi(arg);
784 ate = 1;
785 break;
786 case KEYSIZE_OPT:
787 if ( keySize != -1 ) {
788 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-s");
789 warningCount++;
790 }
791 keySize = atoi(arg);
792 ate = 1;
793 if ( keySize < 1 || keySize > MAX_RSA_KEY_SIZE ) {
794 PR_fprintf(errorFD, "Invalid key size: %d.\n", keySize);
795 errorCount++;
796 goto loser;
797 }
798 break;
799 case TOKEN_OPT:
800 if ( token ) {
801 PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-t");
802 PR_Free(token);
803 token = NULL;
804 }
805 if ( !arg ) {
806 PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-t");
807 errorCount++;
808 goto loser;
809 }
810 token = PL_strdup(arg);
811 ate = 1;
812 break;
813 case XPI_ARC_OPT:
814 xpi_arc = 1;
815 break;
816 default:
817 PR_fprintf(errorFD, "warning: unknown option\n");
818 warningCount++;
819 break;
820 }
822 return ate;
823 loser:
824 return - 1;
825 }
828 /*********************************************************************
829 *
830 * m a i n
831 */
832 int
833 main(int argc, char *argv[])
834 {
835 PRBool readOnly;
836 int retval = 0;
838 outputFD = PR_STDOUT;
839 errorFD = PR_STDERR;
841 progName = argv[0];
843 if (argc < 2) {
844 Usage();
845 }
847 excludeDirs = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
848 PL_CompareStrings, NULL, NULL);
849 extensions = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
850 PL_CompareStrings, NULL, NULL);
852 if (parse_args(argc, argv)) {
853 retval = -1;
854 goto cleanup;
855 }
857 /* Parse the command file if one was given */
858 if (cmdFile) {
859 if (ProcessCommandFile()) {
860 retval = -1;
861 goto cleanup;
862 }
863 }
865 /* Set up output redirection */
866 if (outfile) {
867 if (PR_Access(outfile, PR_ACCESS_EXISTS) == PR_SUCCESS) {
868 /* delete the file if it is already present */
869 PR_fprintf(errorFD,
870 "warning: %s already exists and will be overwritten.\n",
871 outfile);
872 warningCount++;
873 if (PR_Delete(outfile) != PR_SUCCESS) {
874 PR_fprintf(errorFD, "ERROR: unable to delete %s.\n", outfile);
875 errorCount++;
876 exit(ERRX);
877 }
878 }
879 outputFD = PR_Open(outfile,
880 PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777);
881 if (!outputFD) {
882 PR_fprintf(errorFD, "ERROR: Unable to create %s.\n",
883 outfile);
884 errorCount++;
885 exit(ERRX);
886 }
887 errorFD = outputFD;
888 }
890 /* This seems to be a fairly common user error */
892 if (verify && list_certs > 0) {
893 PR_fprintf (errorFD, "%s: Can't use -l and -v at the same time\n",
894 PROGRAM_NAME);
895 errorCount++;
896 retval = -1;
897 goto cleanup;
898 }
900 /* -J assumes -Z now */
902 if (javascript && zipfile) {
903 PR_fprintf (errorFD, "%s: Can't use -J and -Z at the same time\n",
904 PROGRAM_NAME);
905 PR_fprintf (errorFD, "%s: -J option will create the jar files for you\n",
906 PROGRAM_NAME);
907 errorCount++;
908 retval = -1;
909 goto cleanup;
910 }
912 /* -X needs -Z */
914 if (xpi_arc && !zipfile) {
915 PR_fprintf (errorFD, "%s: option XPI (-X) requires option jarfile (-Z)\n",
916 PROGRAM_NAME);
917 errorCount++;
918 retval = -1;
919 goto cleanup;
920 }
922 /* Less common mixing of -L with various options */
924 if (list_certs > 0 &&
925 (tell_who || zipfile || javascript ||
926 scriptdir || extensionsGiven || exclusionsGiven || install_script)) {
927 PR_fprintf(errorFD, "%s: Can't use -l or -L with that option\n",
928 PROGRAM_NAME);
929 errorCount++;
930 retval = -1;
931 goto cleanup;
932 }
935 if (!cert_dir)
936 cert_dir = get_default_cert_dir();
938 VerifyCertDir(cert_dir, keyName);
941 if ( compression_level < MIN_COMPRESSION_LEVEL ||
942 compression_level > MAX_COMPRESSION_LEVEL) {
943 PR_fprintf(errorFD, "Compression level must be between %d and %d.\n",
944 MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL);
945 errorCount++;
946 retval = -1;
947 goto cleanup;
948 }
950 if (jartree && !keyName) {
951 PR_fprintf(errorFD, "You must specify a key with which to sign.\n");
952 errorCount++;
953 retval = -1;
954 goto cleanup;
955 }
957 readOnly = (genkey == NULL); /* only key generation requires write */
958 if (InitCrypto(cert_dir, readOnly)) {
959 PR_fprintf(errorFD, "ERROR: Cryptographic initialization failed.\n");
960 errorCount++;
961 retval = -1;
962 goto cleanup;
963 }
965 if (enableOCSP) {
966 SECStatus rv = CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
967 if (rv != SECSuccess) {
968 PR_fprintf(errorFD, "ERROR: Attempt to enable OCSP Checking failed.\n");
969 errorCount++;
970 retval = -1;
971 }
972 }
974 if (verify) {
975 if (VerifyJar(verify)) {
976 errorCount++;
977 retval = -1;
978 goto cleanup;
979 }
980 } else if (list_certs) {
981 if (ListCerts(keyName, list_certs)) {
982 errorCount++;
983 retval = -1;
984 goto cleanup;
985 }
986 } else if (list_modules) {
987 JarListModules();
988 } else if (genkey) {
989 if (GenerateCert(genkey, keySize, token)) {
990 errorCount++;
991 retval = -1;
992 goto cleanup;
993 }
994 } else if (tell_who) {
995 if (JarWho(tell_who)) {
996 errorCount++;
997 retval = -1;
998 goto cleanup;
999 }
1000 } else if (javascript && jartree) {
1001 /* make sure directory exists */
1002 PRDir * dir;
1003 dir = PR_OpenDir(jartree);
1004 if (!dir) {
1005 PR_fprintf(errorFD, "ERROR: unable to open directory %s.\n",
1006 jartree);
1007 errorCount++;
1008 retval = -1;
1009 goto cleanup;
1010 } else {
1011 PR_CloseDir(dir);
1012 }
1014 /* undo junk from prior runs of signtool*/
1015 if (RemoveAllArc(jartree)) {
1016 PR_fprintf(errorFD, "Error removing archive directories under %s\n",
1017 jartree);
1018 errorCount++;
1019 retval = -1;
1020 goto cleanup;
1021 }
1023 /* traverse all the htm|html files in the directory */
1024 if (InlineJavaScript(jartree, !noRecurse)) {
1025 retval = -1;
1026 goto cleanup;
1027 }
1029 /* sign any resultant .arc directories created in above step */
1030 if (SignAllArc(jartree, keyName, javascript, metafile, install_script,
1031 optimize, !noRecurse)) {
1032 retval = -1;
1033 goto cleanup;
1034 }
1036 if (!leaveArc) {
1037 RemoveAllArc(jartree);
1038 }
1040 if (errorCount > 0 || warningCount > 0) {
1041 PR_fprintf(outputFD, "%d error%s, %d warning%s.\n",
1042 errorCount,
1043 errorCount == 1 ? "" : "s", warningCount, warningCount
1044 == 1 ? "" : "s");
1045 } else {
1046 PR_fprintf(outputFD, "Directory %s signed successfully.\n",
1047 jartree);
1048 }
1049 } else if (jartree) {
1050 SignArchive(jartree, keyName, zipfile, javascript, metafile,
1051 install_script, optimize, !noRecurse);
1052 } else
1053 Usage();
1055 cleanup:
1056 if (extensions) {
1057 PL_HashTableDestroy(extensions);
1058 extensions = NULL;
1059 }
1060 if (excludeDirs) {
1061 PL_HashTableDestroy(excludeDirs);
1062 excludeDirs = NULL;
1063 }
1064 if (outputFD != PR_STDOUT) {
1065 PR_Close(outputFD);
1066 }
1067 rm_dash_r(TMP_OUTPUT);
1068 if (retval == 0) {
1069 if (NSS_Shutdown() != SECSuccess) {
1070 exit(1);
1071 }
1072 }
1073 return retval;
1074 }