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