|
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/. */ |
|
4 |
|
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 */ |
|
15 |
|
16 #include "nss.h" |
|
17 #include "signtool.h" |
|
18 #include "prmem.h" |
|
19 #include "prio.h" |
|
20 |
|
21 /*********************************************************************** |
|
22 * Global Variable Definitions |
|
23 */ |
|
24 char *progName; /* argv[0] */ |
|
25 |
|
26 /* password data */ |
|
27 secuPWData pwdata = { PW_NONE, 0 }; |
|
28 |
|
29 /* directories or files to exclude in descent */ |
|
30 PLHashTable *excludeDirs = NULL; |
|
31 static PRBool exclusionsGiven = PR_FALSE; |
|
32 |
|
33 /* zatharus is the man who knows no time, dies tragic death */ |
|
34 int no_time = 0; |
|
35 |
|
36 /* -b basename of .rsa, .sf files */ |
|
37 char *base = DEFAULT_BASE_NAME; |
|
38 |
|
39 /* Only sign files with this extension */ |
|
40 PLHashTable *extensions = NULL; |
|
41 PRBool extensionsGiven = PR_FALSE; |
|
42 |
|
43 char *scriptdir = NULL; |
|
44 |
|
45 int verbosity = 0; |
|
46 |
|
47 PRFileDesc *outputFD = NULL, *errorFD = NULL; |
|
48 |
|
49 int errorCount = 0, warningCount = 0; |
|
50 |
|
51 int compression_level = DEFAULT_COMPRESSION_LEVEL; |
|
52 PRBool compression_level_specified = PR_FALSE; |
|
53 |
|
54 int xpi_arc = 0; |
|
55 |
|
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; |
|
77 |
|
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 } |
|
113 |
|
114 |
|
115 OPT_TYPE; |
|
116 |
|
117 typedef enum { |
|
118 DUPLICATE_OPTION_ERR = 0, |
|
119 OPTION_NEEDS_ARG_ERR |
|
120 } |
|
121 |
|
122 |
|
123 Error; |
|
124 |
|
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 }; |
|
130 |
|
131 |
|
132 static int ProcessOneOpt(OPT_TYPE type, char *arg); |
|
133 |
|
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; |
|
148 |
|
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 } |
|
155 |
|
156 while (pr_fgets(buf, CMD_FILE_BUFSIZE, fd)) { |
|
157 char *eol; |
|
158 linenum++; |
|
159 |
|
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'; |
|
167 |
|
168 equals = PL_strchr(buf, '='); |
|
169 if (!equals) { |
|
170 continue; |
|
171 } |
|
172 |
|
173 *equals = '\0'; |
|
174 equals++; |
|
175 |
|
176 /* Now buf points to the attribute, and equals points to the value. */ |
|
177 |
|
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 } |
|
252 |
|
253 /* Process the option, whatever it is */ |
|
254 if (type != UNKNOWN_OPT) { |
|
255 if (ProcessOneOpt(type, equals) == -1) { |
|
256 goto finish; |
|
257 } |
|
258 } |
|
259 } |
|
260 |
|
261 retval = 0; |
|
262 |
|
263 finish: |
|
264 PR_Close(fd); |
|
265 return retval; |
|
266 } |
|
267 |
|
268 |
|
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; |
|
281 |
|
282 /* Loop over all arguments */ |
|
283 for (i = 1; i < argc; i++) { |
|
284 opt = argv[i]; |
|
285 arg = NULL; |
|
286 |
|
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 } |
|
296 |
|
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 } |
|
325 |
|
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", |
|
411 |
|
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 } |
|
434 |
|
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 } |
|
446 |
|
447 return 0; |
|
448 } |
|
449 |
|
450 |
|
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; |
|
467 |
|
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 } |
|
821 |
|
822 return ate; |
|
823 loser: |
|
824 return - 1; |
|
825 } |
|
826 |
|
827 |
|
828 /********************************************************************* |
|
829 * |
|
830 * m a i n |
|
831 */ |
|
832 int |
|
833 main(int argc, char *argv[]) |
|
834 { |
|
835 PRBool readOnly; |
|
836 int retval = 0; |
|
837 |
|
838 outputFD = PR_STDOUT; |
|
839 errorFD = PR_STDERR; |
|
840 |
|
841 progName = argv[0]; |
|
842 |
|
843 if (argc < 2) { |
|
844 Usage(); |
|
845 } |
|
846 |
|
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); |
|
851 |
|
852 if (parse_args(argc, argv)) { |
|
853 retval = -1; |
|
854 goto cleanup; |
|
855 } |
|
856 |
|
857 /* Parse the command file if one was given */ |
|
858 if (cmdFile) { |
|
859 if (ProcessCommandFile()) { |
|
860 retval = -1; |
|
861 goto cleanup; |
|
862 } |
|
863 } |
|
864 |
|
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 } |
|
889 |
|
890 /* This seems to be a fairly common user error */ |
|
891 |
|
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 } |
|
899 |
|
900 /* -J assumes -Z now */ |
|
901 |
|
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 } |
|
911 |
|
912 /* -X needs -Z */ |
|
913 |
|
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 } |
|
921 |
|
922 /* Less common mixing of -L with various options */ |
|
923 |
|
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 } |
|
933 |
|
934 |
|
935 if (!cert_dir) |
|
936 cert_dir = get_default_cert_dir(); |
|
937 |
|
938 VerifyCertDir(cert_dir, keyName); |
|
939 |
|
940 |
|
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 } |
|
949 |
|
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 } |
|
956 |
|
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 } |
|
964 |
|
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 } |
|
973 |
|
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 } |
|
1013 |
|
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 } |
|
1022 |
|
1023 /* traverse all the htm|html files in the directory */ |
|
1024 if (InlineJavaScript(jartree, !noRecurse)) { |
|
1025 retval = -1; |
|
1026 goto cleanup; |
|
1027 } |
|
1028 |
|
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 } |
|
1035 |
|
1036 if (!leaveArc) { |
|
1037 RemoveAllArc(jartree); |
|
1038 } |
|
1039 |
|
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(); |
|
1054 |
|
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 } |
|
1075 |
|
1076 |