Back to index

lightning-sunbird  0.9+nobinonly
signtool.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  *  SIGNTOOL
00039  *
00040  *  A command line tool to create manifest files
00041  *  from a directory hierarchy. It is assumed that
00042  *  the tree will be equivalent to what resides
00043  *  or will reside in an archive. 
00044  *
00045  * 
00046  */
00047 
00048 #include "nss.h"
00049 #include "signtool.h"
00050 #include "prmem.h"
00051 #include "prio.h"
00052 
00053 /***********************************************************************
00054  * Global Variable Definitions
00055  */
00056 char   *progName; /* argv[0] */
00057 
00058 /* password on command line. Use for build testing only */
00059 char   *password = NULL;
00060 
00061 /* directories or files to exclude in descent */
00062 PLHashTable *excludeDirs = NULL;
00063 static PRBool exclusionsGiven = PR_FALSE;
00064 
00065 /* zatharus is the man who knows no time, dies tragic death */
00066 int    no_time = 0;
00067 
00068 /* -b basename of .rsa, .sf files */
00069 char   *base = DEFAULT_BASE_NAME;
00070 
00071 /* Only sign files with this extension */
00072 PLHashTable *extensions = NULL;
00073 PRBool extensionsGiven = PR_FALSE;
00074 
00075 char   *scriptdir = NULL;
00076 
00077 int    verbosity = 0;
00078 
00079 PRFileDesc *outputFD = NULL, *errorFD = NULL;
00080 
00081 int    errorCount = 0, warningCount = 0;
00082 
00083 int    compression_level = DEFAULT_COMPRESSION_LEVEL;
00084 PRBool compression_level_specified = PR_FALSE;
00085 
00086 int    xpi_arc = 0;
00087 
00088 /* Command-line arguments */
00089 static char   *genkey = NULL;
00090 static char   *verify = NULL;
00091 static char   *zipfile = NULL;
00092 static char   *cert_dir = NULL;
00093 static int    javascript = 0;
00094 static char   *jartree = NULL;
00095 static char   *keyName = NULL;
00096 static char   *metafile = NULL;
00097 static char   *install_script = NULL;
00098 static int    list_certs = 0;
00099 static int    list_modules = 0;
00100 static int    optimize = 0;
00101 static int    enableOCSP = 0;
00102 static char   *tell_who = NULL;
00103 static char   *outfile = NULL;
00104 static char   *cmdFile = NULL;
00105 static PRBool noRecurse = PR_FALSE;
00106 static PRBool leaveArc = PR_FALSE;
00107 static int    keySize = -1;
00108 static char   *token = NULL;
00109 
00110 typedef enum {
00111     UNKNOWN_OPT,
00112     QUESTION_OPT,
00113     BASE_OPT,
00114     COMPRESSION_OPT,
00115     CERT_DIR_OPT,
00116     EXTENSION_OPT,
00117     INSTALL_SCRIPT_OPT,
00118     SCRIPTDIR_OPT,
00119     CERTNAME_OPT,
00120     LIST_OBJSIGN_CERTS_OPT,
00121     LIST_ALL_CERTS_OPT,
00122     METAFILE_OPT,
00123     OPTIMIZE_OPT,
00124     ENABLE_OCSP_OPT,
00125     PASSWORD_OPT,
00126     VERIFY_OPT,
00127     WHO_OPT,
00128     EXCLUDE_OPT,
00129     NO_TIME_OPT,
00130     JAVASCRIPT_OPT,
00131     ZIPFILE_OPT,
00132     GENKEY_OPT,
00133     MODULES_OPT,
00134     NORECURSE_OPT,
00135     SIGNDIR_OPT,
00136     OUTFILE_OPT,
00137     COMMAND_FILE_OPT,
00138     LEAVE_ARC_OPT,
00139     VERBOSITY_OPT,
00140     KEYSIZE_OPT,
00141     TOKEN_OPT,
00142     XPI_ARC_OPT
00143 } 
00144 
00145 
00146 OPT_TYPE;
00147 
00148 typedef enum {
00149     DUPLICATE_OPTION_ERR = 0,
00150     OPTION_NEEDS_ARG_ERR
00151 } 
00152 
00153 
00154 Error;
00155 
00156 static char   *errStrings[] = {
00157     "warning: %s option specified more than once.\n"
00158     "Only last specification will be used.\n",
00159     "ERROR: option \"%s\" requires an argument.\n"
00160 };
00161 
00162 
00163 static int    ProcessOneOpt(OPT_TYPE type, char *arg);
00164 
00165 /*********************************************************************
00166  *
00167  * P r o c e s s C o m m a n d F i l e
00168  */
00169 int
00170 ProcessCommandFile()
00171 {
00172     PRFileDesc * fd;
00173 #define CMD_FILE_BUFSIZE 1024
00174     char      buf[CMD_FILE_BUFSIZE];
00175     char      *equals;
00176     int       linenum = 0;
00177     int       retval = -1;
00178     OPT_TYPE type;
00179 
00180     fd = PR_Open(cmdFile, PR_RDONLY, 0777);
00181     if (!fd) {
00182        PR_fprintf(errorFD, "ERROR: Unable to open command file %s.\n");
00183        errorCount++;
00184        return - 1;
00185     }
00186 
00187     while (pr_fgets(buf, CMD_FILE_BUFSIZE, fd), buf && *buf != '\0') {
00188        char   *eol;
00189        linenum++;
00190 
00191        /* Chop off final newline */
00192        eol = PL_strchr(buf, '\r');
00193        if (!eol) {
00194            eol = PL_strchr(buf, '\n');
00195        }
00196        if (eol) 
00197            *eol = '\0';
00198 
00199        equals = PL_strchr(buf, '=');
00200        if (!equals) {
00201            continue;
00202        }
00203 
00204        *equals = '\0';
00205        equals++;
00206 
00207        /* Now buf points to the attribute, and equals points to the value. */
00208 
00209        /* This is pretty straightforward, just deal with whatever attribute
00210                * this is */
00211        if (!PL_strcasecmp(buf, "basename")) {
00212            type = BASE_OPT;
00213        } else if (!PL_strcasecmp(buf, "compression")) {
00214            type = COMPRESSION_OPT;
00215        } else if (!PL_strcasecmp(buf, "certdir")) {
00216            type = CERT_DIR_OPT;
00217        } else if (!PL_strcasecmp(buf, "extension")) {
00218            type = EXTENSION_OPT;
00219        } else if (!PL_strcasecmp(buf, "generate")) {
00220            type = GENKEY_OPT;
00221        } else if (!PL_strcasecmp(buf, "installScript")) {
00222            type = INSTALL_SCRIPT_OPT;
00223        } else if (!PL_strcasecmp(buf, "javascriptdir")) {
00224            type = SCRIPTDIR_OPT;
00225        } else if (!PL_strcasecmp(buf, "htmldir")) {
00226            type = JAVASCRIPT_OPT;
00227            if (jartree) {
00228               PR_fprintf(errorFD,
00229                   "warning: directory to be signed specified more than once."
00230                   " Only last specification will be used.\n");
00231               warningCount++;
00232               PR_Free(jartree); 
00233               jartree = NULL;
00234            }
00235            jartree = PL_strdup(equals);
00236        } else if (!PL_strcasecmp(buf, "certname")) {
00237            type = CERTNAME_OPT;
00238        } else if (!PL_strcasecmp(buf, "signdir")) {
00239            type = SIGNDIR_OPT;
00240        } else if (!PL_strcasecmp(buf, "list")) {
00241            type = LIST_OBJSIGN_CERTS_OPT;
00242        } else if (!PL_strcasecmp(buf, "listall")) {
00243            type = LIST_ALL_CERTS_OPT;
00244        } else if (!PL_strcasecmp(buf, "metafile")) {
00245            type = METAFILE_OPT;
00246        } else if (!PL_strcasecmp(buf, "modules")) {
00247            type = MODULES_OPT;
00248        } else if (!PL_strcasecmp(buf, "optimize")) {
00249            type = OPTIMIZE_OPT;
00250        } else if (!PL_strcasecmp(buf, "ocsp")) {
00251            type = ENABLE_OCSP_OPT;
00252        } else if (!PL_strcasecmp(buf, "password")) {
00253            type = PASSWORD_OPT;
00254        } else if (!PL_strcasecmp(buf, "verify")) {
00255            type = VERIFY_OPT;
00256        } else if (!PL_strcasecmp(buf, "who")) {
00257            type = WHO_OPT;
00258        } else if (!PL_strcasecmp(buf, "exclude")) {
00259            type = EXCLUDE_OPT;
00260        } else if (!PL_strcasecmp(buf, "notime")) {
00261            type = NO_TIME_OPT;
00262        } else if (!PL_strcasecmp(buf, "jarfile")) {
00263            type = ZIPFILE_OPT;
00264        } else if (!PL_strcasecmp(buf, "outfile")) {
00265            type = OUTFILE_OPT;
00266        } else if (!PL_strcasecmp(buf, "leavearc")) {
00267            type = LEAVE_ARC_OPT;
00268        } else if (!PL_strcasecmp(buf, "verbosity")) {
00269            type = VERBOSITY_OPT;
00270        } else if (!PL_strcasecmp(buf, "keysize")) {
00271            type = KEYSIZE_OPT;
00272        } else if (!PL_strcasecmp(buf, "token")) {
00273            type = TOKEN_OPT;
00274        } else if (!PL_strcasecmp(buf, "xpi")) {
00275            type = XPI_ARC_OPT;
00276        } else {
00277            PR_fprintf(errorFD,
00278                "warning: unknown attribute \"%s\" in command file, line %d.\n",
00279                                                  buf, linenum);
00280            warningCount++;
00281            type = UNKNOWN_OPT;
00282        }
00283 
00284        /* Process the option, whatever it is */
00285        if (type != UNKNOWN_OPT) {
00286            if (ProcessOneOpt(type, equals) == -1) {
00287               goto finish;
00288            }
00289        }
00290     }
00291 
00292     retval = 0;
00293 
00294 finish:
00295     PR_Close(fd);
00296     return retval;
00297 }
00298 
00299 
00300 /*********************************************************************
00301  *
00302  * p a r s e _ a r g s
00303  */
00304 static int    
00305 parse_args(int argc, char *argv[])
00306 {
00307     char      *opt;
00308     char      *arg;
00309     int       needsInc = 0;
00310     int       i;
00311     OPT_TYPE type;
00312 
00313     /* Loop over all arguments */
00314     for (i = 1; i < argc; i++) {
00315        opt = argv[i];
00316        arg = NULL;
00317 
00318        if (opt[0] == '-') {
00319            if (opt[1] == '-') {
00320               /* word option */
00321               if (i < argc - 1) {
00322                   needsInc = 1;
00323                   arg = argv[i+1];
00324               } else {
00325                   arg = NULL;
00326               }
00327 
00328               if ( !PL_strcasecmp(opt + 2, "norecurse")) {
00329                   type = NORECURSE_OPT;
00330               } else if ( !PL_strcasecmp(opt + 2, "leavearc")) {
00331                   type = LEAVE_ARC_OPT;
00332               } else if ( !PL_strcasecmp(opt + 2, "verbosity")) {
00333                   type = VERBOSITY_OPT;
00334               } else if ( !PL_strcasecmp(opt + 2, "outfile")) {
00335                   type = OUTFILE_OPT;
00336               } else if ( !PL_strcasecmp(opt + 2, "keysize")) {
00337                   type = KEYSIZE_OPT;
00338               } else if ( !PL_strcasecmp(opt + 2, "token")) {
00339                   type = TOKEN_OPT;
00340               } else {
00341                   PR_fprintf(errorFD, "warning: unknown option: %s\n",
00342                        opt);
00343                   warningCount++;
00344                   type = UNKNOWN_OPT;
00345               }
00346            } else {
00347               /* char option */
00348               if (opt[2] != '\0') {
00349                   arg = opt + 2;
00350               } else if (i < argc - 1) {
00351                   needsInc = 1;
00352                   arg = argv[i+1];
00353               } else {
00354                   arg = NULL;
00355               }
00356 
00357               switch (opt[1]) {
00358               case '?':
00359                   type = QUESTION_OPT;
00360                   break;
00361               case 'b':
00362                   type = BASE_OPT;
00363                   break;
00364               case 'c':
00365                   type = COMPRESSION_OPT;
00366                   break;
00367               case 'd':
00368                   type = CERT_DIR_OPT;
00369                   break;
00370               case 'e':
00371                   type = EXTENSION_OPT;
00372                   break;
00373               case 'f':
00374                   type = COMMAND_FILE_OPT;
00375                   break;
00376               case 'i':
00377                   type = INSTALL_SCRIPT_OPT;
00378                   break;
00379               case 'j':
00380                   type = SCRIPTDIR_OPT;
00381                   break;
00382               case 'k':
00383                   type = CERTNAME_OPT;
00384                   break;
00385               case 'l':
00386                   type = LIST_OBJSIGN_CERTS_OPT;
00387                   break;
00388               case 'L':
00389                   type = LIST_ALL_CERTS_OPT;
00390                   break;
00391               case 'm':
00392                   type = METAFILE_OPT;
00393                   break;
00394               case 'o':
00395                   type = OPTIMIZE_OPT;
00396                   break;
00397               case 'O':
00398                   type = ENABLE_OCSP_OPT;
00399                   break;
00400               case 'p':
00401                   type = PASSWORD_OPT;
00402                   break;
00403               case 'v':
00404                   type = VERIFY_OPT;
00405                   break;
00406               case 'w':
00407                   type = WHO_OPT;
00408                   break;
00409               case 'x':
00410                   type = EXCLUDE_OPT;
00411                   break;
00412               case 'X':
00413                   type = XPI_ARC_OPT;
00414                   break;
00415               case 'z':
00416                   type = NO_TIME_OPT;
00417                   break;
00418               case 'J':
00419                   type = JAVASCRIPT_OPT;
00420                   break;
00421               case 'Z':
00422                   type = ZIPFILE_OPT;
00423                   break;
00424               case 'G':
00425                   type = GENKEY_OPT;
00426                   break;
00427               case 'M':
00428                   type = MODULES_OPT;
00429                   break;
00430               case 's':
00431                   type = KEYSIZE_OPT;
00432                   break;
00433               case 't':
00434                   type = TOKEN_OPT;
00435                   break;
00436               default:
00437                   type = UNKNOWN_OPT;
00438                   PR_fprintf(errorFD, "warning: unrecognized option: -%c.\n",
00439                        
00440                       opt[1]);
00441                   warningCount++;
00442                   break;
00443               }
00444            }
00445        } else {
00446            type = UNKNOWN_OPT;
00447            if (i == argc - 1) {
00448               if (jartree) {
00449                   PR_fprintf(errorFD,
00450                       "warning: directory to be signed specified more than once.\n"
00451                       " Only last specification will be used.\n");
00452                   warningCount++;
00453                   PR_Free(jartree); 
00454                   jartree = NULL;
00455               }
00456               jartree = PL_strdup(opt);
00457            } else {
00458               PR_fprintf(errorFD, "warning: unrecognized option: %s\n", opt);
00459               warningCount++;
00460            }
00461        }
00462 
00463        if (type != UNKNOWN_OPT) {
00464            short     ateArg = ProcessOneOpt(type, arg);
00465            if (ateArg == -1) {
00466               /* error */
00467               return - 1;
00468            } 
00469            if (ateArg && needsInc) {
00470               i++;
00471            }
00472        }
00473     }
00474 
00475     return 0;
00476 }
00477 
00478 
00479 /*********************************************************************
00480  *
00481  * P r o c e s s O n e O p t
00482  *
00483  * Since options can come from different places (command file, word options,
00484  * char options), this is a central function that is called to deal with
00485  * them no matter where they come from.
00486  *
00487  * type is the type of option.
00488  * arg is the argument to the option, possibly NULL.
00489  * Returns 1 if the argument was eaten, 0 if it wasn't, and -1 for error.
00490  */
00491 static int    
00492 ProcessOneOpt(OPT_TYPE type, char *arg)
00493 {
00494     int       ate = 0;
00495 
00496     switch (type) {
00497     case QUESTION_OPT:
00498        usage();
00499        break;
00500     case BASE_OPT:
00501        if (base) {
00502            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-b");
00503            warningCount++;
00504            PR_Free(base); 
00505            base = NULL;
00506        }
00507        if (!arg) {
00508            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-b");
00509            errorCount++;
00510            goto loser;
00511        }
00512        base = PL_strdup(arg);
00513        ate = 1;
00514        break;
00515     case COMPRESSION_OPT:
00516        if (compression_level_specified) {
00517            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-c");
00518            warningCount++;
00519        }
00520        if ( !arg ) {
00521            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-c");
00522            errorCount++;
00523            goto loser;
00524        }
00525        compression_level = atoi(arg);
00526        compression_level_specified = PR_TRUE;
00527        ate = 1;
00528        break;
00529     case CERT_DIR_OPT:
00530        if (cert_dir) {
00531            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-d");
00532            warningCount++;
00533            PR_Free(cert_dir); 
00534            cert_dir = NULL;
00535        }
00536        if (!arg) {
00537            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-d");
00538            errorCount++;
00539            goto loser;
00540        }
00541        cert_dir = PL_strdup(arg);
00542        ate = 1;
00543        break;
00544     case EXTENSION_OPT:
00545        if (!arg) {
00546            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00547                                           "extension (-e)");
00548            errorCount++;
00549            goto loser;
00550        }
00551        PL_HashTableAdd(extensions, arg, arg);
00552        extensionsGiven = PR_TRUE;
00553        ate = 1;
00554        break;
00555     case INSTALL_SCRIPT_OPT:
00556        if (install_script) {
00557            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00558                                           "installScript (-i)");
00559            warningCount++;
00560            PR_Free(install_script); 
00561            install_script = NULL;
00562        }
00563        if (!arg) {
00564            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00565                                           "installScript (-i)");
00566            errorCount++;
00567            goto loser;
00568        }
00569        install_script = PL_strdup(arg);
00570        ate = 1;
00571        break;
00572     case SCRIPTDIR_OPT:
00573        if (scriptdir) {
00574            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00575                                           "javascriptdir (-j)");
00576            warningCount++;
00577            PR_Free(scriptdir); 
00578            scriptdir = NULL;
00579        }
00580        if (!arg) {
00581            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00582                                           "javascriptdir (-j)");
00583            errorCount++;
00584            goto loser;
00585        }
00586        scriptdir = PL_strdup(arg);
00587        ate = 1;
00588        break;
00589     case CERTNAME_OPT:
00590        if (keyName) {
00591            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00592                                           "keyName (-k)");
00593            warningCount++;
00594            PR_Free(keyName); 
00595            keyName = NULL;
00596        }
00597        if (!arg) {
00598            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00599                                           "keyName (-k)");
00600            errorCount++;
00601            goto loser;
00602        }
00603        keyName = PL_strdup(arg);
00604        ate = 1;
00605        break;
00606     case LIST_OBJSIGN_CERTS_OPT:
00607     case LIST_ALL_CERTS_OPT:
00608        if (list_certs != 0) {
00609            PR_fprintf(errorFD,
00610                "warning: only one of -l and -L may be specified.\n");
00611            warningCount++;
00612        }
00613        list_certs = (type == LIST_OBJSIGN_CERTS_OPT ? 1 : 2);
00614        break;
00615     case METAFILE_OPT:
00616        if (metafile) {
00617            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00618                                           "metafile (-m)");
00619            warningCount++;
00620            PR_Free(metafile); 
00621            metafile = NULL;
00622        }
00623        if (!arg) {
00624            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00625                                           "metafile (-m)");
00626            errorCount++;
00627            goto loser;
00628        }
00629        metafile = PL_strdup(arg);
00630        ate = 1;
00631        break;
00632     case OPTIMIZE_OPT:
00633        optimize = 1;
00634        break;
00635     case ENABLE_OCSP_OPT:
00636        enableOCSP = 1;
00637        break;
00638     case PASSWORD_OPT:
00639        if (password) {
00640            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00641                                           "password (-p)");
00642            warningCount++;
00643            PR_Free(password); 
00644            password = NULL;
00645        }
00646        if (!arg) {
00647            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00648                                           "password (-p)");
00649            errorCount++;
00650            goto loser;
00651        }
00652        password = PL_strdup(arg);
00653        ate = 1;
00654        break;
00655     case VERIFY_OPT:
00656        if (verify) {
00657            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00658                                           "verify (-v)");
00659            warningCount++;
00660            PR_Free(verify); 
00661            verify = NULL;
00662        }
00663        if (!arg) {
00664            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00665                                           "verify (-v)");
00666            errorCount++;
00667            goto loser;
00668        }
00669        verify = PL_strdup(arg);
00670        ate = 1;
00671        break;
00672     case WHO_OPT:
00673        if (tell_who) {
00674            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00675                                           "who (-v)");
00676            warningCount++;
00677            PR_Free(tell_who); 
00678            tell_who = NULL;
00679        }
00680        if (!arg) {
00681            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00682                                           "who (-w)");
00683            errorCount++;
00684            goto loser;
00685        }
00686        tell_who = PL_strdup(arg);
00687        ate = 1;
00688        break;
00689     case EXCLUDE_OPT:
00690        if (!arg) {
00691            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00692                                           "exclude (-x)");
00693            errorCount++;
00694            goto loser;
00695        }
00696        PL_HashTableAdd(excludeDirs, arg, arg);
00697        exclusionsGiven = PR_TRUE;
00698        ate = 1;
00699        break;
00700     case NO_TIME_OPT:
00701        no_time = 1;
00702        break;
00703     case JAVASCRIPT_OPT:
00704        javascript++;
00705        break;
00706     case ZIPFILE_OPT:
00707        if (zipfile) {
00708            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00709                                           "jarfile (-Z)");
00710            warningCount++;
00711            PR_Free(zipfile); 
00712            zipfile = NULL;
00713        }
00714        if (!arg) {
00715            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00716                                           "jarfile (-Z)");
00717            errorCount++;
00718            goto loser;
00719        }
00720        zipfile = PL_strdup(arg);
00721        ate = 1;
00722        break;
00723     case GENKEY_OPT:
00724        if (genkey) {
00725            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00726                                           "generate (-G)");
00727            warningCount++;
00728            PR_Free(zipfile); 
00729            zipfile = NULL;
00730        }
00731        if (!arg) {
00732            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00733                                           "generate (-G)");
00734            errorCount++;
00735            goto loser;
00736        }
00737        genkey = PL_strdup(arg);
00738        ate = 1;
00739        break;
00740     case MODULES_OPT:
00741        list_modules++;
00742        break;
00743     case SIGNDIR_OPT:
00744        if (jartree) {
00745            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00746                                           "signdir");
00747            warningCount++;
00748            PR_Free(jartree); 
00749            jartree = NULL;
00750        }
00751        if (!arg) {
00752            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00753                 "signdir");
00754            errorCount++;
00755            goto loser;
00756        }
00757        jartree = PL_strdup(arg);
00758        ate = 1;
00759        break;
00760     case OUTFILE_OPT:
00761        if (outfile) {
00762            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00763                                           "outfile");
00764            warningCount++;
00765            PR_Free(outfile); 
00766            outfile = NULL;
00767        }
00768        if (!arg) {
00769            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00770                 "outfile");
00771            errorCount++;
00772            goto loser;
00773        }
00774        outfile = PL_strdup(arg);
00775        ate = 1;
00776        break;
00777     case COMMAND_FILE_OPT:
00778        if (cmdFile) {
00779            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR],
00780                 "-f");
00781            warningCount++;
00782            PR_Free(cmdFile); 
00783            cmdFile = NULL;
00784        }
00785        if (!arg) {
00786            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00787                 "-f");
00788            errorCount++;
00789            goto loser;
00790        }
00791        cmdFile = PL_strdup(arg);
00792        ate = 1;
00793        break;
00794     case NORECURSE_OPT:
00795        noRecurse = PR_TRUE;
00796        break;
00797     case LEAVE_ARC_OPT:
00798        leaveArc = PR_TRUE;
00799        break;
00800     case VERBOSITY_OPT:
00801        if (!arg) {
00802            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR],
00803                                      "--verbosity");
00804            errorCount++;
00805            goto loser;
00806        }
00807        verbosity = atoi(arg);
00808        ate = 1;
00809        break;
00810     case KEYSIZE_OPT:
00811        if ( keySize != -1 ) {
00812            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-s");
00813            warningCount++;
00814        }
00815        keySize = atoi(arg);
00816        ate = 1;
00817        if ( keySize < 1 || keySize > MAX_RSA_KEY_SIZE ) {
00818            PR_fprintf(errorFD, "Invalid key size: %d.\n", keySize);
00819            errorCount++;
00820            goto loser;
00821        }
00822        break;
00823     case TOKEN_OPT:
00824        if ( token ) {
00825            PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-t");
00826            PR_Free(token); 
00827            token = NULL;
00828        }
00829        if ( !arg ) {
00830            PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-t");
00831            errorCount++;
00832            goto loser;
00833        }
00834        token = PL_strdup(arg);
00835        ate = 1;
00836        break;
00837     case XPI_ARC_OPT:
00838        xpi_arc = 1;
00839        break;
00840     default:
00841        PR_fprintf(errorFD, "warning: unknown option\n");
00842        warningCount++;
00843        break;
00844     }
00845 
00846     return ate;
00847 loser:
00848     return - 1;
00849 }
00850 
00851 
00852 /*********************************************************************
00853  *
00854  * m a i n
00855  */
00856 int
00857 main(int argc, char *argv[])
00858 {
00859     PRBool readOnly;
00860     int       retval = 0;
00861 
00862     outputFD = PR_STDOUT;
00863     errorFD = PR_STDERR;
00864 
00865     progName = argv[0];
00866 
00867     if (argc < 2) {
00868        usage();
00869     }
00870 
00871     excludeDirs = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
00872                                           PL_CompareStrings, NULL, NULL);
00873     extensions = PL_NewHashTable(10, PL_HashString, PL_CompareStrings,
00874                                           PL_CompareStrings, NULL, NULL);
00875 
00876     if (parse_args(argc, argv)) {
00877        retval = -1;
00878        goto cleanup;
00879     }
00880 
00881     /* Parse the command file if one was given */
00882     if (cmdFile) {
00883        if (ProcessCommandFile()) {
00884            retval = -1;
00885            goto cleanup;
00886        }
00887     }
00888 
00889     /* Set up output redirection */
00890     if (outfile) {
00891        if (PR_Access(outfile, PR_ACCESS_EXISTS) == PR_SUCCESS) {
00892            /* delete the file if it is already present */
00893            PR_fprintf(errorFD,
00894                "warning: %s already exists and will be overwritten.\n",
00895                                           outfile);
00896            warningCount++;
00897            if (PR_Delete(outfile) != PR_SUCCESS) {
00898               PR_fprintf(errorFD, "ERROR: unable to delete %s.\n", outfile);
00899               errorCount++;
00900               exit(ERRX);
00901            }
00902        }
00903        outputFD = PR_Open(outfile,
00904            PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777);
00905        if (!outputFD) {
00906            PR_fprintf(errorFD, "ERROR: Unable to create %s.\n",
00907                 outfile);
00908            errorCount++;
00909            exit(ERRX);
00910        }
00911        errorFD = outputFD;
00912     }
00913 
00914     /* This seems to be a fairly common user error */
00915 
00916     if (verify && list_certs > 0) {
00917        PR_fprintf (errorFD, "%s: Can't use -l and -v at the same time\n",
00918                      PROGRAM_NAME);
00919        errorCount++;
00920        retval = -1;
00921        goto cleanup;
00922     }
00923 
00924     /* -J assumes -Z now */
00925 
00926     if (javascript && zipfile) {
00927        PR_fprintf (errorFD, "%s: Can't use -J and -Z at the same time\n",
00928                      PROGRAM_NAME);
00929        PR_fprintf (errorFD, "%s: -J option will create the jar files for you\n",
00930                      PROGRAM_NAME);
00931        errorCount++;
00932        retval = -1;
00933        goto cleanup;
00934     }
00935 
00936     /* -X needs -Z */
00937 
00938     if (xpi_arc && !zipfile) {
00939        PR_fprintf (errorFD, "%s: option XPI (-X) requires option jarfile (-Z)\n",
00940                      PROGRAM_NAME);
00941        errorCount++;
00942        retval = -1;
00943        goto cleanup;
00944     }
00945 
00946     /* Less common mixing of -L with various options */
00947 
00948     if (list_certs > 0 && 
00949         (tell_who || zipfile || javascript || 
00950         scriptdir || extensionsGiven || exclusionsGiven || install_script)) {
00951        PR_fprintf(errorFD, "%s: Can't use -l or -L with that option\n",
00952                             PROGRAM_NAME);
00953        errorCount++;
00954        retval = -1;
00955        goto cleanup;
00956     }
00957 
00958 
00959     if (!cert_dir)
00960        cert_dir = get_default_cert_dir();
00961 
00962     VerifyCertDir(cert_dir, keyName);
00963 
00964 
00965     if (      compression_level < MIN_COMPRESSION_LEVEL || 
00966         compression_level > MAX_COMPRESSION_LEVEL) {
00967        PR_fprintf(errorFD, "Compression level must be between %d and %d.\n",
00968                       MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL);
00969        errorCount++;
00970        retval = -1;
00971        goto cleanup;
00972     }
00973 
00974     if (jartree && !keyName) {
00975        PR_fprintf(errorFD, "You must specify a key with which to sign.\n");
00976        errorCount++;
00977        retval = -1;
00978        goto cleanup;
00979     }
00980 
00981     readOnly = (genkey == NULL); /* only key generation requires write */
00982     if (InitCrypto(cert_dir, readOnly)) {
00983        PR_fprintf(errorFD, "ERROR: Cryptographic initialization failed.\n");
00984        errorCount++;
00985        retval = -1;
00986        goto cleanup;
00987     }
00988 
00989     if (enableOCSP) {
00990        SECStatus rv = CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
00991        if (rv != SECSuccess) {
00992            PR_fprintf(errorFD, "ERROR: Attempt to enable OCSP Checking failed.\n");
00993            errorCount++;
00994            retval = -1;
00995        }
00996     }
00997 
00998     if (verify) {
00999        if (VerifyJar(verify)) {
01000            errorCount++;
01001            retval = -1;
01002            goto cleanup;
01003        }
01004     } else if (list_certs) {
01005        if (ListCerts(keyName, list_certs)) {
01006            errorCount++;
01007            retval = -1;
01008            goto cleanup;
01009        }
01010     } else if (list_modules) {
01011        JarListModules();
01012     } else if (genkey) {
01013        if (GenerateCert(genkey, keySize, token)) {
01014            errorCount++;
01015            retval = -1;
01016            goto cleanup;
01017        }
01018     } else if (tell_who) {
01019        if (JarWho(tell_who)) {
01020            errorCount++;
01021            retval = -1;
01022            goto cleanup;
01023        }
01024     } else if (javascript && jartree) {
01025        /* make sure directory exists */
01026        PRDir * dir;
01027        dir = PR_OpenDir(jartree);
01028        if (!dir) {
01029            PR_fprintf(errorFD, "ERROR: unable to open directory %s.\n",
01030                 jartree);
01031            errorCount++;
01032            retval = -1;
01033            goto cleanup;
01034        } else {
01035            PR_CloseDir(dir);
01036        }
01037 
01038        /* undo junk from prior runs of signtool*/
01039        if (RemoveAllArc(jartree)) {
01040            PR_fprintf(errorFD, "Error removing archive directories under %s\n",
01041                 jartree);
01042            errorCount++;
01043            retval = -1;
01044            goto cleanup;
01045        }
01046 
01047        /* traverse all the htm|html files in the directory */
01048        if (InlineJavaScript(jartree, !noRecurse)) {
01049            retval = -1;
01050            goto cleanup;
01051        }
01052 
01053        /* sign any resultant .arc directories created in above step */
01054        if (SignAllArc(jartree, keyName, javascript, metafile, install_script,
01055                      optimize, !noRecurse)) {
01056            retval = -1;
01057            goto cleanup;
01058        }
01059 
01060        if (!leaveArc) {
01061            RemoveAllArc(jartree);
01062        }
01063 
01064        if (errorCount > 0 || warningCount > 0) {
01065            PR_fprintf(outputFD, "%d error%s, %d warning%s.\n",
01066                 errorCount,
01067                errorCount == 1 ? "" : "s", warningCount, warningCount
01068                == 1 ? "" : "s");
01069        } else {
01070            PR_fprintf(outputFD, "Directory %s signed successfully.\n",
01071                 jartree);
01072        }
01073     } else if (jartree) {
01074        SignArchive(jartree, keyName, zipfile, javascript, metafile,
01075                      install_script, optimize, !noRecurse);
01076     } else
01077        usage();
01078 
01079 cleanup:
01080     if (extensions) {
01081        PL_HashTableDestroy(extensions); 
01082        extensions = NULL;
01083     }
01084     if (excludeDirs) {
01085        PL_HashTableDestroy(excludeDirs); 
01086        excludeDirs = NULL;
01087     }
01088     if (outputFD != PR_STDOUT) {
01089        PR_Close(outputFD);
01090     }
01091     rm_dash_r(TMP_OUTPUT);
01092     if (retval == 0) {
01093        if (NSS_Shutdown() != SECSuccess) {
01094            exit(1);
01095        }
01096     }
01097     return retval;
01098 }
01099 
01100