Back to index

lightning-sunbird  0.9+nobinonly
util.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 #include "signtool.h"
00038 #include "prio.h"
00039 #include "prmem.h"
00040 #include "nss.h"
00041 
00042 static int    is_dir (char *filename);
00043 
00044 /***********************************************************
00045  * Nasty hackish function definitions
00046  */
00047 
00048 long   *mozilla_event_queue = 0;
00049 
00050 #ifndef XP_WIN
00051 char   *XP_GetString (int i)
00052 {
00053     return SECU_ErrorStringRaw ((int16) i);
00054 }
00055 #endif
00056 
00057 void   FE_SetPasswordEnabled()
00058 {
00059 }
00060 
00061 
00062 void   /*MWContext*/ *FE_GetInitContext (void)
00063 {
00064     return 0;
00065 }
00066 
00067 
00068 void   /*MWContext*/ *XP_FindSomeContext()
00069 {
00070     /* No windows context in command tools */
00071     return NULL;
00072 }
00073 
00074 
00075 void   ET_moz_CallFunction()
00076 {
00077 }
00078 
00079 
00080 /*
00081  *  R e m o v e A l l A r c
00082  *
00083  *  Remove .arc directories that are lingering
00084  *  from a previous run of signtool.
00085  *
00086  */
00087 int
00088 RemoveAllArc(char *tree)
00089 {
00090     PRDir * dir;
00091     PRDirEntry * entry;
00092     char      *archive = NULL;
00093     int       retval = 0;
00094 
00095     dir = PR_OpenDir (tree);
00096     if (!dir) 
00097        return - 1;
00098 
00099     for (entry = PR_ReadDir (dir, 0); entry; entry = PR_ReadDir (dir,
00100          0)) {
00101 
00102        if (entry->name[0] == '.') {
00103            continue;
00104        }
00105 
00106        if (archive) 
00107            PR_Free(archive);
00108        archive = PR_smprintf("%s/%s", tree, entry->name);
00109 
00110        if (PL_strcaserstr (entry->name, ".arc")
00111             == (entry->name + strlen(entry->name) - 4) ) {
00112 
00113            if (verbosity >= 0) {
00114               PR_fprintf(outputFD, "removing: %s\n", archive);
00115            }
00116 
00117            if (rm_dash_r(archive)) {
00118               PR_fprintf(errorFD, "Error removing %s\n", archive);
00119               errorCount++;
00120               retval = -1;
00121               goto finish;
00122            }
00123        } else if (is_dir(archive)) {
00124            if (RemoveAllArc(archive)) {
00125               retval = -1;
00126               goto finish;
00127            }
00128        }
00129     }
00130 
00131 finish:
00132     PR_CloseDir (dir);
00133     if (archive) 
00134        PR_Free(archive);
00135 
00136     return retval;
00137 }
00138 
00139 
00140 /*
00141  *  r m _ d a s h _ r
00142  *
00143  *  Remove a file, or a directory recursively.
00144  *
00145  */
00146 int    rm_dash_r (char *path)
00147 {
00148     PRDir      * dir;
00149     PRDirEntry * entry;
00150     PRFileInfo fileinfo;
00151     char      filename[FNSIZE];
00152 
00153     if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
00154        /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
00155        return - 1;
00156     }
00157     if (fileinfo.type == PR_FILE_DIRECTORY) {
00158 
00159        dir = PR_OpenDir(path);
00160        if (!dir) {
00161            PR_fprintf(errorFD, "Error: Unable to open directory %s.\n", path);
00162            errorCount++;
00163            return - 1;
00164        }
00165 
00166        /* Recursively delete all entries in the directory */
00167        while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
00168            sprintf(filename, "%s/%s", path, entry->name);
00169            if (rm_dash_r(filename)) 
00170               return - 1;
00171        }
00172 
00173        if (PR_CloseDir(dir) != PR_SUCCESS) {
00174            PR_fprintf(errorFD, "Error: Could not close %s.\n", path);
00175            errorCount++;
00176            return - 1;
00177        }
00178 
00179        /* Delete the directory itself */
00180        if (PR_RmDir(path) != PR_SUCCESS) {
00181            PR_fprintf(errorFD, "Error: Unable to delete %s\n", path);
00182            errorCount++;
00183            return - 1;
00184        }
00185     } else {
00186        if (PR_Delete(path) != PR_SUCCESS) {
00187            PR_fprintf(errorFD, "Error: Unable to delete %s\n", path);
00188            errorCount++;
00189            return - 1;
00190        }
00191     }
00192     return 0;
00193 }
00194 
00195 
00196 /*
00197  *  u s a g e 
00198  * 
00199  *  Print some useful help information
00200  *
00201  */
00202 void
00203 usage (void)
00204 {
00205     PR_fprintf(outputFD, "\n");
00206     PR_fprintf(outputFD, "%s %s - a signing tool for jar files\n", LONG_PROGRAM_NAME,
00207          NSS_VERSION);
00208     PR_fprintf(outputFD, "\n");
00209     PR_fprintf(outputFD, "Usage:  %s [options] directory-tree \n\n",
00210         PROGRAM_NAME);
00211     PR_fprintf(outputFD, "    -b \"basename\"\t\tbasename of .sf, .rsa files for signing\n");
00212     PR_fprintf(outputFD, "    -c#\t\t\t\tCompression level, 0-9, 0=none\n");
00213     PR_fprintf(outputFD, "    -d \"certificate directory\"\tcontains cert*.db and key*.db\n");
00214     PR_fprintf(outputFD, "    -e \".ext\"\t\t\tsign only files with this extension\n");
00215     PR_fprintf(outputFD, "    -f \"filename\"\t\t\tread commands from file\n");
00216     PR_fprintf(outputFD, "    -G \"nickname\"\t\tcreate object-signing cert with this nickname\n");
00217     PR_fprintf(outputFD, "    -i \"installer script\"\tassign installer javascript\n");
00218     PR_fprintf(outputFD, "    -j \"javascript directory\"\tsign javascript files in this subtree\n");
00219     PR_fprintf(outputFD, "    -J\t\t\t\tdirectory contains HTML files. Javascript will\n"
00220         "\t\t\t\tbe extracted and signed.\n");
00221     PR_fprintf(outputFD, "    -k \"cert nickname\"\t\tsign with this certificate\n");
00222     PR_fprintf(outputFD, "    --leavearc\t\t\tdo not delete .arc directories created\n"
00223         "\t\t\t\tby -J option\n");
00224     PR_fprintf(outputFD, "    -m \"metafile\"\t\tinclude custom meta-information\n");
00225     PR_fprintf(outputFD, "    --norecurse\t\t\tdo not operate on subdirectories\n");
00226     PR_fprintf(outputFD, "    -o\t\t\t\toptimize - omit optional headers\n");
00227     PR_fprintf(outputFD, "    -O\t\t\t\tenableOCSP - enable OCSP checking\n");
00228     PR_fprintf(outputFD, "    --outfile \"filename\"\tredirect output to file\n");
00229     PR_fprintf(outputFD, "    -p \"password\"\t\tfor password on command line (insecure)\n");
00230     PR_fprintf(outputFD, "    -s keysize\t\t\tkeysize in bits of generated cert\n");
00231     PR_fprintf(outputFD, "    -t token\t\t\tname of token on which to generate cert\n");
00232     PR_fprintf(outputFD, "    --verbosity #\t\tSet amount of debugging information to generate.\n"
00233         "\t\t\t\tLower number means less output, 0 is default.\n");
00234     PR_fprintf(outputFD, "    -x \"name\"\t\t\tdirectory or filename to exclude\n");
00235     PR_fprintf(outputFD, "    -X\t\t\t\tCreate XPI Compatible Archive\n"
00236         "\t\t\t\t(used in conjunction with the -Z)\n");
00237     PR_fprintf(outputFD, "    -z\t\t\t\tomit signing time from signature\n");
00238     PR_fprintf(outputFD, "    -Z \"jarfile\"\t\tcreate JAR file with the given name.\n"
00239         "\t\t\t\t(Default compression level is 6.)\n");
00240     PR_fprintf(outputFD, "\n");
00241     PR_fprintf(outputFD, "%s -l\n", PROGRAM_NAME);
00242     PR_fprintf(outputFD, "  lists the signing certificates in your database\n");
00243     PR_fprintf(outputFD, "\n");
00244     PR_fprintf(outputFD, "%s -L\n", PROGRAM_NAME);
00245     PR_fprintf(outputFD, "  lists all certificates in your database, marks object-signing certificates\n");
00246     PR_fprintf(outputFD, "\n");
00247     PR_fprintf(outputFD, "%s -M\n", PROGRAM_NAME);
00248     PR_fprintf(outputFD, "  lists the PKCS #11 modules available to %s\n",
00249          PROGRAM_NAME);
00250     PR_fprintf(outputFD, "\n");
00251     PR_fprintf(outputFD, "%s -v file.jar\n", PROGRAM_NAME);
00252     PR_fprintf(outputFD, "  show the contents of the specified jar file\n");
00253     PR_fprintf(outputFD, "\n");
00254     PR_fprintf(outputFD, "%s -w file.jar\n", PROGRAM_NAME);
00255     PR_fprintf(outputFD, "  if valid, tries to tell you who signed the jar file\n");
00256     PR_fprintf(outputFD, "\n");
00257     PR_fprintf(outputFD, "%s -d \"certificate directory\" -K -k \"cert nickname\" -p \"password\" -X -Z \"file.xpi\" directory-tree\n",
00258          PROGRAM_NAME);
00259     PR_fprintf(outputFD, "  Common syntax to create a XPInstall compatible signed archive\n\n");
00260     PR_fprintf(outputFD, "For more details, visit\n");
00261     PR_fprintf(outputFD, 
00262         "  http://developer.netscape.com/library/documentation/signedobj/signtool/\n");
00263 
00264     exit (ERRX);
00265 }
00266 
00267 
00268 /*
00269  *  p r i n t _ e r r o r
00270  *
00271  *  For the undocumented -E function. If an older version
00272  *  of communicator gives you a numeric error, we can see what
00273  *  really happened without doing hex math.
00274  *
00275  */
00276 
00277 void
00278 print_error (int err)
00279 {
00280     PR_fprintf(errorFD, "Error %d: %s\n", err, JAR_get_error (err));
00281     errorCount++;
00282     give_help (err);
00283 }
00284 
00285 
00286 /*
00287  *  o u t _ o f _ m e m o r y
00288  *
00289  *  Out of memory, exit Signtool.
00290  * 
00291  */
00292 void
00293 out_of_memory (void)
00294 {
00295     PR_fprintf(errorFD, "%s: out of memory\n", PROGRAM_NAME);
00296     errorCount++;
00297     exit (ERRX);
00298 }
00299 
00300 
00301 /*
00302  *  V e r i f y C e r t D i r
00303  *
00304  *  Validate that the specified directory
00305  *  contains a certificate database
00306  *
00307  */
00308 void
00309 VerifyCertDir(char *dir, char *keyName)
00310 {
00311     char      fn [FNSIZE];
00312 
00313     /* don't try verifying if we don't have a local directory */
00314     if (strncmp(dir, "multiaccess:", sizeof("multiaccess:") - 1) == 0) {
00315        return;
00316     }
00317 
00318     /* This code is really broken because it makes underlying assumptions about
00319    * how the NSS profile directory is laid out, but these names can change
00320    * from release to release. */
00321     sprintf (fn, "%s/cert8.db", dir);
00322 
00323     if (PR_Access (fn, PR_ACCESS_EXISTS)) {
00324        PR_fprintf(errorFD, "%s: No certificate database in \"%s\"\n",
00325                       PROGRAM_NAME, dir);
00326        PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n",
00327                      PROGRAM_NAME);
00328        errorCount++;
00329        exit (ERRX);
00330     }
00331 
00332     if (verbosity >= 0) {
00333        PR_fprintf(outputFD, "using certificate directory: %s\n", dir);
00334     }
00335 
00336     if (keyName == NULL)
00337        return;
00338 
00339     /* if the user gave the -k key argument, verify that 
00340      a key database already exists */
00341 
00342     sprintf (fn, "%s/key3.db", dir);
00343 
00344     if (PR_Access (fn, PR_ACCESS_EXISTS)) {
00345        PR_fprintf(errorFD, "%s: No private key database in \"%s\"\n",
00346             PROGRAM_NAME,
00347            dir);
00348        PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n",
00349                      PROGRAM_NAME);
00350        errorCount++;
00351        exit (ERRX);
00352     }
00353 }
00354 
00355 
00356 /*
00357  *  f o r e a c h 
00358  * 
00359  *  A recursive function to loop through all names in
00360  *  the specified directory, as well as all subdirectories.
00361  *
00362  *  FIX: Need to see if all platforms allow multiple
00363  *  opendir's to be called.
00364  *
00365  */
00366 
00367 int
00368 foreach(char *dirname, char *prefix, 
00369 int (*fn)(char *relpath, char *basedir, char *reldir, char *filename,
00370 void*arg),
00371 PRBool recurse, PRBool includeDirs, void *arg) 
00372 {
00373     char      newdir [FNSIZE];
00374     int       retval = 0;
00375 
00376     PRDir * dir;
00377     PRDirEntry * entry;
00378 
00379     strcpy (newdir, dirname);
00380     if (*prefix) {
00381        strcat (newdir, "/");
00382        strcat (newdir, prefix);
00383     }
00384 
00385     dir = PR_OpenDir (newdir);
00386     if (!dir) 
00387        return - 1;
00388 
00389     for (entry = PR_ReadDir (dir, 0); entry; entry = PR_ReadDir (dir, 0)) {
00390        if ( strcmp(entry->name, ".") == 0   || 
00391            strcmp(entry->name, "..") == 0 ) {
00392            /* no infinite recursion, please */
00393            continue;
00394        }
00395 
00396        /* can't sign self */
00397        if (!strcmp (entry->name, "META-INF"))
00398            continue;
00399 
00400        /* -x option */
00401        if (PL_HashTableLookup(excludeDirs, entry->name))
00402            continue;
00403 
00404        strcpy (newdir, dirname);
00405        if (*dirname)
00406            strcat (newdir, "/");
00407 
00408        if (*prefix) {
00409            strcat (newdir, prefix);
00410            strcat (newdir, "/");
00411        }
00412        strcat (newdir, entry->name);
00413 
00414        if (!is_dir(newdir) || includeDirs) {
00415            char      newpath [FNSIZE];
00416 
00417            strcpy (newpath, prefix);
00418            if (*newpath)
00419               strcat (newpath, "/");
00420            strcat (newpath, entry->name);
00421 
00422            if ( (*fn) (newpath, dirname, prefix, (char *) entry->name,
00423                 arg)) {
00424               retval = -1;
00425               break;
00426            }
00427        }
00428 
00429        if (is_dir (newdir)) {
00430            if (recurse) {
00431               char   newprefix [FNSIZE];
00432 
00433               strcpy (newprefix, prefix);
00434               if (*newprefix) {
00435                   strcat (newprefix, "/");
00436               }
00437               strcat (newprefix, entry->name);
00438 
00439               if (foreach (dirname, newprefix, fn, recurse,
00440                    includeDirs, arg)) {
00441                   retval = -1;
00442                   break;
00443               }
00444            }
00445        }
00446 
00447     }
00448 
00449     PR_CloseDir (dir);
00450 
00451     return retval;
00452 }
00453 
00454 
00455 /*
00456  *  i s _ d i r
00457  *
00458  *  Return 1 if file is a directory.
00459  *  Wonder if this runs on a mac, trust not.
00460  *
00461  */
00462 static int    is_dir (char *filename)
00463 {
00464     PRFileInfo       finfo;
00465 
00466     if ( PR_GetFileInfo(filename, &finfo) != PR_SUCCESS ) {
00467        printf("Unable to get information about %s\n", filename);
00468        return 0;
00469     }
00470 
00471     return ( finfo.type == PR_FILE_DIRECTORY );
00472 }
00473 
00474 
00475 /*
00476  *  p a s s w o r d _ h a r d c o d e 
00477  *
00478  *  A function to use the password passed in the -p(password) argument
00479  *  of the command line. This is only to be used for build & testing purposes,
00480  *  as it's extraordinarily insecure. 
00481  *
00482  *  After use once, null it out otherwise PKCS11 calls us forever.
00483  *
00484  */
00485 SECItem *
00486 password_hardcode(void *arg, void *handle)
00487 {
00488     SECItem * pw = NULL;
00489     if (password) {
00490        pw = SECITEM_AllocItem(NULL, NULL, PL_strlen(password));
00491        pw->data = (unsigned char *)PL_strdup(password);
00492        password = NULL;
00493     }
00494     return pw;
00495 }
00496 
00497 
00498 char   *
00499 pk11_password_hardcode(PK11SlotInfo *slot, PRBool retry, void *arg)
00500 {
00501     char      *pw;
00502     if (retry) {
00503        return NULL; /* the password is incorrect, fail */
00504     }
00505     pw = password ? PORT_Strdup (password) : NULL;
00506     /* XXX don't do this, or FIPS won't work */
00507     /*password = NULL;*/
00508     return pw;
00509 }
00510 
00511 
00512 /***************************************************************
00513  *
00514  * s e c E r r o r S t r i n g
00515  *
00516  * Returns an error string corresponding to the given error code.
00517  * Doesn't cover all errors; returns a default for many.
00518  * Returned string is only valid until the next call of this function.
00519  */
00520 const char    *
00521 secErrorString(long code)
00522 {
00523     static char      errstring[80]; /* dynamically constructed error string */
00524     char      *c; /* the returned string */
00525 
00526     switch (code) {
00527     case SEC_ERROR_IO: 
00528        c = "io error";
00529        break;
00530     case SEC_ERROR_LIBRARY_FAILURE: 
00531        c = "security library failure";
00532        break;
00533     case SEC_ERROR_BAD_DATA: 
00534        c = "bad data";
00535        break;
00536     case SEC_ERROR_OUTPUT_LEN: 
00537        c = "output length";
00538        break;
00539     case SEC_ERROR_INPUT_LEN: 
00540        c = "input length";
00541        break;
00542     case SEC_ERROR_INVALID_ARGS: 
00543        c = "invalid args";
00544        break;
00545     case SEC_ERROR_EXPIRED_CERTIFICATE: 
00546        c = "expired certificate";
00547        break;
00548     case SEC_ERROR_REVOKED_CERTIFICATE: 
00549        c = "revoked certificate";
00550        break;
00551     case SEC_ERROR_INADEQUATE_KEY_USAGE: 
00552        c = "inadequate key usage";
00553        break;
00554     case SEC_ERROR_INADEQUATE_CERT_TYPE: 
00555        c = "inadequate certificate type";
00556        break;
00557     case SEC_ERROR_UNTRUSTED_CERT: 
00558        c = "untrusted cert";
00559        break;
00560     case SEC_ERROR_NO_KRL: 
00561        c = "no key revocation list";
00562        break;
00563     case SEC_ERROR_KRL_BAD_SIGNATURE: 
00564        c = "key revocation list: bad signature";
00565        break;
00566     case SEC_ERROR_KRL_EXPIRED: 
00567        c = "key revocation list expired";
00568        break;
00569     case SEC_ERROR_REVOKED_KEY: 
00570        c = "revoked key";
00571        break;
00572     case SEC_ERROR_CRL_BAD_SIGNATURE:
00573        c = "certificate revocation list: bad signature";
00574        break;
00575     case SEC_ERROR_CRL_EXPIRED: 
00576        c = "certificate revocation list expired";
00577        break;
00578     case SEC_ERROR_CRL_NOT_YET_VALID:
00579        c = "certificate revocation list not yet valid";
00580        break;
00581     case SEC_ERROR_UNKNOWN_ISSUER: 
00582        c = "unknown issuer";
00583        break;
00584     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: 
00585        c = "expired issuer certificate";
00586        break;
00587     case SEC_ERROR_BAD_SIGNATURE: 
00588        c = "bad signature";
00589        break;
00590     case SEC_ERROR_BAD_KEY: 
00591        c = "bad key";
00592        break;
00593     case SEC_ERROR_NOT_FORTEZZA_ISSUER: 
00594        c = "not fortezza issuer";
00595        break;
00596     case SEC_ERROR_CA_CERT_INVALID:
00597        c = "Certificate Authority certificate invalid";
00598        break;
00599     case SEC_ERROR_EXTENSION_NOT_FOUND: 
00600        c = "extension not found";
00601        break;
00602     case SEC_ERROR_CERT_NOT_IN_NAME_SPACE: 
00603        c = "certificate not in name space";
00604        break;
00605     case SEC_ERROR_UNTRUSTED_ISSUER: 
00606        c = "untrusted issuer";
00607        break;
00608     default:
00609        sprintf(errstring, "security error %ld", code);
00610        c = errstring;
00611        break;
00612     }
00613 
00614     return c;
00615 }
00616 
00617 
00618 /***************************************************************
00619  *
00620  * d i s p l a y V e r i f y L o g
00621  *
00622  * Prints the log of a cert verification.
00623  */
00624 void
00625 displayVerifyLog(CERTVerifyLog *log)
00626 {
00627     CERTVerifyLogNode        * node;
00628     CERTCertificate          * cert;
00629     char      *name;
00630 
00631     if ( !log  || (log->count <= 0) ) {
00632        return;
00633     }
00634 
00635     for (node = log->head; node != NULL; node = node->next) {
00636 
00637        if ( !(cert = node->cert) ) {
00638            continue;
00639        }
00640 
00641        /* Get a name for this cert */
00642        if (cert->nickname != NULL) {
00643            name = cert->nickname;
00644        } else if (cert->emailAddr && cert->emailAddr[0]) {
00645            name = cert->emailAddr;
00646        } else {
00647            name = cert->subjectName;
00648        }
00649 
00650        printf( "%s%s:\n", name,
00651            (node->depth > 0) ? " [Certificate Authority]" : "");
00652 
00653        printf("\t%s\n", secErrorString(node->error));
00654 
00655     }
00656 }
00657 
00658 
00659 /*
00660  *  J a r L i s t M o d u l e s
00661  *
00662  *  Print a list of the PKCS11 modules that are
00663  *  available. This is useful for smartcard people to
00664  *  make sure they have the drivers loaded.
00665  *
00666  */
00667 void
00668 JarListModules(void)
00669 {
00670     int       i;
00671     int       count = 0;
00672 
00673     SECMODModuleList * modules = NULL;
00674     static SECMODListLock *moduleLock = NULL;
00675 
00676     SECMODModuleList * mlp;
00677 
00678     modules = SECMOD_GetDefaultModuleList();
00679 
00680     if (modules == NULL) {
00681        PR_fprintf(errorFD, "%s: Can't get module list\n", PROGRAM_NAME);
00682        errorCount++;
00683        exit (ERRX);
00684     }
00685 
00686     if ((moduleLock = SECMOD_NewListLock()) == NULL) {
00687        /* this is the wrong text */
00688        PR_fprintf(errorFD, "%s: unable to acquire lock on module list\n",
00689                      PROGRAM_NAME);
00690        errorCount++;
00691        exit (ERRX);
00692     }
00693 
00694     SECMOD_GetReadLock (moduleLock);
00695 
00696     PR_fprintf(outputFD, "\nListing of PKCS11 modules\n");
00697     PR_fprintf(outputFD, "-----------------------------------------------\n");
00698 
00699     for (mlp = modules; mlp != NULL; mlp = mlp->next) {
00700        count++;
00701        PR_fprintf(outputFD, "%3d. %s\n", count, mlp->module->commonName);
00702 
00703        if (mlp->module->internal)
00704            PR_fprintf(outputFD, "          (this module is internally loaded)\n");
00705        else
00706            PR_fprintf(outputFD, "          (this is an external module)\n");
00707 
00708        if (mlp->module->dllName)
00709            PR_fprintf(outputFD, "          DLL name: %s\n",
00710                mlp->module->dllName);
00711 
00712        if (mlp->module->slotCount == 0)
00713            PR_fprintf(outputFD, "          slots: There are no slots attached to this module\n");
00714        else
00715            PR_fprintf(outputFD, "          slots: %d slots attached\n",
00716                 mlp->module->slotCount);
00717 
00718        if (mlp->module->loaded == 0)
00719            PR_fprintf(outputFD, "          status: Not loaded\n");
00720        else
00721            PR_fprintf(outputFD, "          status: loaded\n");
00722 
00723        for (i = 0; i < mlp->module->slotCount; i++) {
00724            PK11SlotInfo * slot = mlp->module->slots[i];
00725 
00726            PR_fprintf(outputFD, "\n");
00727            PR_fprintf(outputFD, "    slot: %s\n", PK11_GetSlotName(slot));
00728            PR_fprintf(outputFD, "   token: %s\n", PK11_GetTokenName(slot));
00729        }
00730     }
00731 
00732     PR_fprintf(outputFD, "-----------------------------------------------\n");
00733 
00734     if (count == 0)
00735        PR_fprintf(outputFD,
00736            "Warning: no modules were found (should have at least one)\n");
00737 
00738     SECMOD_ReleaseReadLock (moduleLock);
00739 }
00740 
00741 
00742 /**********************************************************************
00743  * c h o p
00744  *
00745  * Eliminates leading and trailing whitespace.  Returns a pointer to the 
00746  * beginning of non-whitespace, or an empty string if it's all whitespace.
00747  */
00748 char*
00749 chop(char *str)
00750 {
00751     char      *start, *end;
00752 
00753     if (str) {
00754        start = str;
00755 
00756        /* Nip leading whitespace */
00757        while (isspace(*start)) {
00758            start++;
00759        }
00760 
00761        /* Nip trailing whitespace */
00762        if (*start) {
00763            end = start + strlen(start) - 1;
00764            while (isspace(*end) && end > start) {
00765               end--;
00766            }
00767            *(end + 1) = '\0';
00768        }
00769 
00770        return start;
00771     } else {
00772        return NULL;
00773     }
00774 }
00775 
00776 
00777 /***********************************************************************
00778  *
00779  * F a t a l E r r o r
00780  *
00781  * Outputs an error message and bails out of the program.
00782  */
00783 void
00784 FatalError(char *msg)
00785 {
00786     if (!msg) 
00787        msg = "";
00788 
00789     PR_fprintf(errorFD, "FATAL ERROR: %s\n", msg);
00790     errorCount++;
00791     exit(ERRX);
00792 }
00793 
00794 
00795 /*************************************************************************
00796  *
00797  * I n i t C r y p t o
00798  */
00799 int
00800 InitCrypto(char *cert_dir, PRBool readOnly)
00801 {
00802     SECStatus rv;
00803     static int       prior = 0;
00804     PK11SlotInfo * slotinfo;
00805 
00806     if (prior == 0) {
00807        /* some functions such as OpenKeyDB expect this path to be
00808         * implicitly set prior to calling */
00809        if (readOnly) {
00810            rv = NSS_Init(cert_dir);
00811        } else {
00812            rv = NSS_InitReadWrite(cert_dir);
00813        }
00814        if (rv != SECSuccess) {
00815            SECU_PrintPRandOSError(PROGRAM_NAME);
00816            exit(-1);
00817        }
00818 
00819        SECU_ConfigDirectory (cert_dir);
00820 
00821        /* Been there done that */
00822        prior++;
00823 
00824        if (password) {
00825            PK11_SetPasswordFunc(pk11_password_hardcode);
00826        } else {
00827            PK11_SetPasswordFunc(SECU_GetModulePassword);
00828        }
00829 
00830        /* Must login to FIPS before you do anything else */
00831        if (PK11_IsFIPS()) {
00832            slotinfo = PK11_GetInternalSlot();
00833            if (!slotinfo) {
00834               fprintf(stderr, "%s: Unable to get PKCS #11 Internal Slot."
00835                                 "\n", PROGRAM_NAME);
00836               return - 1;
00837            }
00838            if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/,
00839                                      NULL /*wincx*/) != SECSuccess) {
00840               fprintf(stderr, "%s: Unable to authenticate to %s.\n",
00841                                 PROGRAM_NAME, PK11_GetSlotName(slotinfo));
00842               PK11_FreeSlot(slotinfo);
00843               return - 1;
00844            }
00845            PK11_FreeSlot(slotinfo);
00846        }
00847 
00848        /* Make sure there is a password set on the internal key slot */
00849        slotinfo = PK11_GetInternalKeySlot();
00850        if (!slotinfo) {
00851            fprintf(stderr, "%s: Unable to get PKCS #11 Internal Key Slot."
00852                "\n", PROGRAM_NAME);
00853            return - 1;
00854        }
00855        if (PK11_NeedUserInit(slotinfo)) {
00856            PR_fprintf(errorFD,
00857                "\nWARNING: No password set on internal key database.  Most operations will fail."
00858                "\nYou must create a password.\n");
00859            warningCount++;
00860        }
00861 
00862        /* Make sure we can authenticate to the key slot in FIPS mode */
00863        if (PK11_IsFIPS()) {
00864            if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/,
00865                                      NULL /*wincx*/) != SECSuccess) {
00866               fprintf(stderr, "%s: Unable to authenticate to %s.\n",
00867                             PROGRAM_NAME, PK11_GetSlotName(slotinfo));
00868               PK11_FreeSlot(slotinfo);
00869               return - 1;
00870            }
00871        }
00872        PK11_FreeSlot(slotinfo);
00873     }
00874 
00875     return 0;
00876 }
00877 
00878 
00879 /* Windows foolishness is now in the secutil lib */
00880 
00881 /*****************************************************************
00882  *  g e t _ d e f a u l t _ c e r t _ d i r
00883  *
00884  *  Attempt to locate a certificate directory.
00885  *  Failing that, complain that the user needs to
00886  *  use the -d(irectory) parameter.
00887  *
00888  */
00889 char   *get_default_cert_dir (void)
00890 {
00891     char      *home;
00892 
00893     char      *cd = NULL;
00894     static char      db [FNSIZE];
00895 
00896 #ifdef XP_UNIX
00897     home = getenv ("HOME");
00898 
00899     if (home && *home) {
00900        sprintf (db, "%s/.netscape", home);
00901        cd = db;
00902     }
00903 #endif
00904 
00905 #ifdef XP_PC
00906     FILE * fp;
00907 
00908     /* first check the environment override */
00909 
00910     home = getenv ("JAR_HOME");
00911 
00912     if (home && *home) {
00913        sprintf (db, "%s/cert7.db", home);
00914 
00915        if ((fp = fopen (db, "r")) != NULL) {
00916            fclose (fp);
00917            cd = home;
00918        }
00919     }
00920 
00921     /* try the old navigator directory */
00922 
00923     if (cd == NULL) {
00924        home = "c:/Program Files/Netscape/Navigator";
00925 
00926        sprintf (db, "%s/cert7.db", home);
00927 
00928        if ((fp = fopen (db, "r")) != NULL) {
00929            fclose (fp);
00930            cd = home;
00931        }
00932     }
00933 
00934     /* Try the current directory, I wonder if this
00935      is really a good idea. Remember, Windows only.. */
00936 
00937     if (cd == NULL) {
00938        home = ".";
00939 
00940        sprintf (db, "%s/cert7.db", home);
00941 
00942        if ((fp = fopen (db, "r")) != NULL) {
00943            fclose (fp);
00944            cd = home;
00945        }
00946     }
00947 
00948 #endif
00949 
00950     if (!cd) {
00951        PR_fprintf(errorFD,
00952            "You must specify the location of your certificate directory\n");
00953        PR_fprintf(errorFD,
00954            "with the -d option. Example: -d ~/.netscape in many cases with Unix.\n");
00955        errorCount++;
00956        exit (ERRX);
00957     }
00958 
00959     return cd;
00960 }
00961 
00962 
00963 /************************************************************************
00964  * g i v e _ h e l p
00965  */
00966 void   give_help (int status)
00967 {
00968     if (status == SEC_ERROR_UNKNOWN_ISSUER) {
00969        PR_fprintf(errorFD,
00970            "The Certificate Authority (CA) for this certificate\n");
00971        PR_fprintf(errorFD,
00972            "does not appear to be in your database. You should contact\n");
00973        PR_fprintf(errorFD,
00974            "the organization which issued this certificate to obtain\n");
00975        PR_fprintf(errorFD, "a copy of its CA Certificate.\n");
00976     }
00977 }
00978 
00979 
00980 /**************************************************************************
00981  *
00982  * p r _ f g e t s
00983  *
00984  * fgets implemented with NSPR.
00985  */
00986 char*
00987 pr_fgets(char *buf, int size, PRFileDesc *file)
00988 {
00989     int       i;
00990     int       status;
00991     char      c;
00992 
00993     i = 0;
00994     while (i < size - 1) {
00995        status = PR_Read(file, (void * ) &c, 1);
00996        if (status == -1) {
00997            return NULL;
00998        } else if (status == 0) {
00999            break;
01000        }
01001        buf[i++] = c;
01002        if (c == '\n') {
01003            break;
01004        }
01005     }
01006     buf[i] = '\0';
01007 
01008     return buf;
01009 }
01010 
01011