/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "signtool.h" #include "prio.h" #include "prmem.h" #include "prenv.h" #include "nss.h" static int is_dir(char *filename); /*********************************************************** * Nasty hackish function definitions */ long *mozilla_event_queue = 0; #ifndef XP_WIN char * XP_GetString(int i) { /* nasty hackish cast to avoid changing the signature of * JAR_init_callbacks() */ return (char *)SECU_Strerror(i); } #endif void FE_SetPasswordEnabled() { } void /*MWContext*/ * FE_GetInitContext(void) { return 0; } void /*MWContext*/ * XP_FindSomeContext() { /* No windows context in command tools */ return NULL; } void ET_moz_CallFunction() { } /* * R e m o v e A l l A r c * * Remove .arc directories that are lingering * from a previous run of signtool. * */ int RemoveAllArc(char *tree) { PRDir *dir; PRDirEntry *entry; char *archive = NULL; int retval = 0; dir = PR_OpenDir(tree); if (!dir) return -1; for (entry = PR_ReadDir(dir, 0); entry; entry = PR_ReadDir(dir, 0)) { if (entry->name[0] == '.') { continue; } if (archive) PR_Free(archive); archive = PR_smprintf("%s/%s", tree, entry->name); if (PL_strcaserstr(entry->name, ".arc") == (entry->name + strlen(entry->name) - 4)) { if (verbosity >= 0) { PR_fprintf(outputFD, "removing: %s\n", archive); } if (rm_dash_r(archive)) { PR_fprintf(errorFD, "Error removing %s\n", archive); errorCount++; retval = -1; goto finish; } } else if (is_dir(archive)) { if (RemoveAllArc(archive)) { retval = -1; goto finish; } } } finish: PR_CloseDir(dir); if (archive) PR_Free(archive); return retval; } /* * r m _ d a s h _ r * * Remove a file, or a directory recursively. * */ int rm_dash_r(char *path) { PRDir *dir; PRDirEntry *entry; PRFileInfo fileinfo; char filename[FNSIZE]; if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) { /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/ return -1; } if (fileinfo.type == PR_FILE_DIRECTORY) { dir = PR_OpenDir(path); if (!dir) { PR_fprintf(errorFD, "Error: Unable to open directory %s.\n", path); errorCount++; return -1; } /* Recursively delete all entries in the directory */ while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) { snprintf(filename, sizeof(filename), "%s/%s", path, entry->name); if (rm_dash_r(filename)) { PR_CloseDir(dir); return -1; } } if (PR_CloseDir(dir) != PR_SUCCESS) { PR_fprintf(errorFD, "Error: Could not close %s.\n", path); errorCount++; return -1; } /* Delete the directory itself */ if (PR_RmDir(path) != PR_SUCCESS) { PR_fprintf(errorFD, "Error: Unable to delete %s\n", path); errorCount++; return -1; } } else { if (PR_Delete(path) != PR_SUCCESS) { PR_fprintf(errorFD, "Error: Unable to delete %s\n", path); errorCount++; return -1; } } return 0; } /* * u s a g e * * Print some useful help information * */ void Usage(void) { #define FPS PR_fprintf(outputFD, FPS "%s %s -a signing tool for jar files\n", LONG_PROGRAM_NAME,NSS_VERSION); FPS "\n\nType %s -H for more detailed descriptions\n", PROGRAM_NAME); FPS "\nUsage: %s -k keyName [-b basename] [-c Compression Level]\n" "\t\t [-d cert-dir] [-i installer script] [-m metafile] [-x name]\n" "\t\t [-e extension] [-o] [-z] [-X] [--outfile] [--verbose value]\n" "\t\t [--norecurse] [--leavearc] [-j directory] [-Z jarfile] [-O]\n" "\t\t [-p password] directory-tree\n", PROGRAM_NAME); FPS "\t%s -J -k keyName [-b basename] [-c Compression Level]\n" "\t\t [-d cert-dir][-i installer script] [-m metafile] [-x name]\n" "\t\t [-e extension] [-o] [-z] [-X] [--outfile] [--verbose value]\n" "\t\t [--norecurse] [--leavearc] [-j directory] [-p password] [-O] \n" "\t\t directory-tree\n", PROGRAM_NAME); FPS "\t%s -h \n", PROGRAM_NAME); FPS "\t%s -H \n", PROGRAM_NAME); FPS "\t%s -l [-k keyName] [-d cert-dir] [--outfile] [-O] \n", PROGRAM_NAME); FPS "\t%s -L [-k keyName] [-d cert-dir] [--outfile] [-O] \n", PROGRAM_NAME); FPS "\t%s -M [--outfile] [-O] \n", PROGRAM_NAME); FPS "\t%s -v [-d cert-dir] [--outfile] [-O] archive\n", PROGRAM_NAME); FPS "\t%s -w [--outfile] [-O] archive\n" , PROGRAM_NAME); FPS "\t%s -G nickname [--keysize|-s size] [-t |--token tokenname]\n" "\t\t [--outfile] [-O] \n", PROGRAM_NAME); FPS "\t%s -f filename\n" , PROGRAM_NAME); exit(ERRX); } void LongUsage(void) { FPS "%s %s -a signing tool for jar files\n", LONG_PROGRAM_NAME,NSS_VERSION); FPS "\n%-20s Signs the directory-tree\n", "signtool directory-tree"); FPS "%-30s Nickname (key) of the certificate to sign with\n", " -k keyname"); FPS "%-30s Base filename for the .rsa and.sf files in the\n", " -b basename"); FPS "%-30s META-INF directory\n"," "); FPS "%-30s Set the compression level. 0-9, 0=none\n", " -c CompressionLevel"); FPS "%-30s Certificate database directory containing cert*db\n", " -d certificate directory"); FPS "%-30s and key*db\n"," "); FPS "%-30s Name of the installer script for SmartUpdate\n", " -i installer script"); FPS "%-30s Name of a metadata control file\n", " -m metafile"); FPS "%-30s For optimizing the archive for size.\n", " -o"); FPS "%-30s Omit Optional Headers\n"," "); FPS "%-30s Excludes the specified directory or file from\n", " -x directory or file name"); FPS "%-30s signing\n"," "); FPS "%-30s To not store the signing time in digital\n", " -z directory or file name"); FPS "%-30s signature\n"," "); FPS "%-30s Create XPI Compatible Archive. It requires -Z\n", " -X directory or file name"); FPS "%-30s option\n"," "); FPS "%-30s Sign only files with the given extension\n", " -e"); FPS "%-30s Causes the specified directory to be signed and\n", " -j"); FPS "%-30s tags its entries as inline JavaScript\n"," "); FPS "%-30s Creates a JAR file with the specified name.\n", " -Z"); FPS "%-30s -Z option cannot be used with -J option\n"," "); FPS "%-30s Specifies a password for the private-key database\n", " -p"); FPS "%-30s (insecure)\n"," "); FPS "%-30s File to receive redirected output\n", " --outfile filename"); FPS "%-30s Sets the quantity of information generated in\n", " --verbosity value"); FPS "%-30s operation\n"," "); FPS "%-30s Blocks recursion into subdirectories\n", " --norecurse"); FPS "%-30s Retains the temporary .arc (archive) directories\n", " --leavearc"); FPS "%-30s -J option creates\n"," "); FPS "\n%-20s Signs a directory of HTML files containing JavaScript and\n", "-J" ); FPS "%-20s creates as many archive files as are in the HTML tags.\n"," "); FPS "%-20s The options are same as without any command option given\n"," "); FPS "%-20s above. -Z and -J options are not allowed together\n"," "); FPS "\n%-20s Generates a new private-public key pair and corresponding\n", "-G nickname"); FPS "%-20s object-signing certificates with the given nickname\n"," "); FPS "%-30s Specifies the size of the key for generated \n", " --keysize|-s keysize"); FPS "%-30s certificate\n"," "); FPS "%-30s Specifies which available token should generate\n", " --token|-t token name "); FPS "%-30s the key and receive the certificate\n"," "); FPS "%-30s Specifies a file to receive redirected output\n", " --outfile filename "); FPS "\n%-20s Display signtool help\n", "-h "); FPS "\n%-20s Display signtool help(Detailed)\n", "-H "); FPS "\n%-20s Lists signing certificates, including issuing CAs\n", "-l "); FPS "%-30s Certificate database directory containing cert*db\n", " -d certificate directory"); FPS "%-30s and key*db\n"," "); FPS "%-30s Specifies a file to receive redirected output\n", " --outfile filename "); FPS "%-30s Specifies the nickname (key) of the certificate\n", " -k keyname"); FPS "\n%-20s Lists the certificates in your database\n", "-L "); FPS "%-30s Certificate database directory containing cert*db\n", " -d certificate directory"); FPS "%-30s and key*db\n"," "); FPS "%-30s Specifies a file to receive redirected output\n", " --outfile filename "); FPS "%-30s Specifies the nickname (key) of the certificate\n", " -k keyname"); FPS "\n%-20s Lists the PKCS #11 modules available to signtool\n", "-M "); FPS "\n%-20s Displays the contents of an archive and verifies\n", "-v archive"); FPS "%-20s cryptographic integrity\n"," "); FPS "%-30s Certificate database directory containing cert*db\n", " -d certificate directory"); FPS "%-30s and key*db\n"," "); FPS "%-30s Specifies a file to receive redirected output\n", " --outfile filename "); FPS "\n%-20s Displays the names of signers in the archive\n", "-w archive"); FPS "%-30s Specifies a file to receive redirected output\n", " --outfile filename "); FPS "\n%-30s Common option to all the above.\n", " -O"); FPS "%-30s Enable OCSP checking\n"," "); FPS "\n%-20s Specifies a text file containing options and arguments in\n", "-f command-file"); FPS "%-20s keyword=value format. Commands are taken from this file\n"," "); FPS "\n\n\n"); FPS "Example:\n"); FPS "%-10s -d \"certificate directory\" -k \"certnickname\" \\", PROGRAM_NAME); FPS "\n%-10s -p \"password\" -X -Z \"file.xpi\" directory-tree\n"," " ); FPS "Common syntax to create an XPInstall compatible" " signed archive\n\n"," "); FPS "\nCommand File Keywords and Example:\n"); FPS "\nKeyword\t\tValue\n"); FPS "basename\tSame as -b option\n"); FPS "compression\tSame as -c option\n"); FPS "certdir\t\tSame as -d option\n"); FPS "extension\tSame as -e option\n"); FPS "generate\tSame as -G option\n"); FPS "installscript\tSame as -i option\n"); FPS "javascriptdir\tSame as -j option\n"); FPS "htmldir\t\tSame as -J option\n"); FPS "certname\tNickname of certificate, as with -k option\n"); FPS "signdir\t\tThe directory to be signed, as with -k option\n"); FPS "list\t\tSame as -l option. Value is ignored,\n" " \t\tbut = sign must be present\n"); FPS "listall\t\tSame as -L option. Value is ignored\n" " \t\tbut = sign must be present\n"); FPS "metafile\tSame as -m option\n"); FPS "modules\t\tSame as -M option. Value is ignored,\n" " \t\tbut = sign must be present\n"); FPS "optimize\tSame as -o option. Value is ignored,\n" " \tbut = sign must be present\n"); FPS "ocsp\t\tSame as -O option\n"); FPS "password\tSame as -p option\n"); FPS "verify\t\tSame as -v option\n"); FPS "who\t\tSame as -w option\n"); FPS "exclude\t\tSame as -x option\n"); FPS "notime\t\tSame as -z option. Value is ignored,\n" " \t\tbut = sign must be present\n"); FPS "jarfile\t\tSame as -Z option\n"); FPS "outfile\t\tSame as --outfile option. The argument\n"); FPS " \t\tis the name of a file to which output\n"); FPS " \t\tof a file and error messages will be \n"); FPS " \t\tredirected\n"); FPS "leavearc\tSame as --leavearc option\n"); FPS "verbosity\tSame as --verbosity option\n"); FPS "keysize\t\tSame as -s option\n"); FPS "token\t\tSame as -t option\n"); FPS "xpi\t\tSame as -X option\n"); FPS "\n\n"); FPS "Here's an example of the use of the command file. The command\n\n"); FPS " signtool -d c:\\netscape\\users\\james -k mycert -Z myjar.jar \\\n" " signdir > output.txt\n\n"); FPS "becomes\n\n"); FPS " signtool -f somefile\n\n"); FPS "where somefile contains the following lines:\n\n"); FPS " certdir=c:\\netscape\\users\\james\n"," "); FPS " certname=mycert\n"," "); FPS " jarfile=myjar.jar\n"," "); FPS " signdir=signdir\n"," "); FPS " outfile=output.txt\n"," "); exit(ERRX); #undef FPS } /* * p r i n t _ e r r o r * * For the undocumented -E function. If an older version * of communicator gives you a numeric error, we can see what * really happened without doing hex math. * */ void print_error(int err) { PR_fprintf(errorFD, "Error %d: %s\n", err, JAR_get_error(err)); errorCount++; give_help(err); } /* * o u t _ o f _ m e m o r y * * Out of memory, exit Signtool. * */ void out_of_memory(void) { PR_fprintf(errorFD, "%s: out of memory\n", PROGRAM_NAME); errorCount++; exit(ERRX); } /* * V e r i f y C e r t D i r * * Validate that the specified directory * contains a certificate database * */ void VerifyCertDir(char *dir, char *keyName) { /* this function is truly evil. Tools and applications should not have * any knowledge of actual cert databases! */ return; } /* * f o r e a c h * * A recursive function to loop through all names in * the specified directory, as well as all subdirectories. * * FIX: Need to see if all platforms allow multiple * opendir's to be called. * */ int foreach (char *dirname, char *prefix, int (*fn)(char *relpath, char *basedir, char *reldir, char *filename, void *arg), PRBool recurse, PRBool includeDirs, void *arg) { char newdir[FNSIZE]; int retval = 0; PRDir *dir; PRDirEntry *entry; strcpy(newdir, dirname); if (*prefix) { strcat(newdir, "/"); strcat(newdir, prefix); } dir = PR_OpenDir(newdir); if (!dir) return -1; for (entry = PR_ReadDir(dir, 0); entry; entry = PR_ReadDir(dir, 0)) { if (strcmp(entry->name, ".") == 0 || strcmp(entry->name, "..") == 0) { /* no infinite recursion, please */ continue; } /* can't sign self */ if (!strcmp(entry->name, "META-INF")) continue; /* -x option */ if (PL_HashTableLookup(excludeDirs, entry->name)) continue; strcpy(newdir, dirname); if (*dirname) strcat(newdir, "/"); if (*prefix) { strcat(newdir, prefix); strcat(newdir, "/"); } strcat(newdir, entry->name); if (!is_dir(newdir) || includeDirs) { char newpath[FNSIZE]; strcpy(newpath, prefix); if (*newpath) strcat(newpath, "/"); strcat(newpath, entry->name); if ((*fn)(newpath, dirname, prefix, (char *)entry->name, arg)) { retval = -1; break; } } if (is_dir(newdir)) { if (recurse) { char newprefix[FNSIZE]; strcpy(newprefix, prefix); if (*newprefix) { strcat(newprefix, "/"); } strcat(newprefix, entry->name); if (foreach (dirname, newprefix, fn, recurse, includeDirs, arg)) { retval = -1; break; } } } } PR_CloseDir(dir); return retval; } /* * i s _ d i r * * Return 1 if file is a directory. * Wonder if this runs on a mac, trust not. * */ static int is_dir(char *filename) { PRFileInfo finfo; if (PR_GetFileInfo(filename, &finfo) != PR_SUCCESS) { printf("Unable to get information about %s\n", filename); return 0; } return (finfo.type == PR_FILE_DIRECTORY); } /*************************************************************** * * s e c E r r o r S t r i n g * * Returns an error string corresponding to the given error code. * Doesn't cover all errors; returns a default for many. * Returned string is only valid until the next call of this function. */ const char * secErrorString(long code) { static char errstring[80]; /* dynamically constructed error string */ char *c; /* the returned string */ switch (code) { case SEC_ERROR_IO: c = "io error"; break; case SEC_ERROR_LIBRARY_FAILURE: c = "security library failure"; break; case SEC_ERROR_BAD_DATA: c = "bad data"; break; case SEC_ERROR_OUTPUT_LEN: c = "output length"; break; case SEC_ERROR_INPUT_LEN: c = "input length"; break; case SEC_ERROR_INVALID_ARGS: c = "invalid args"; break; case SEC_ERROR_EXPIRED_CERTIFICATE: c = "expired certificate"; break; case SEC_ERROR_REVOKED_CERTIFICATE: c = "revoked certificate"; break; case SEC_ERROR_INADEQUATE_KEY_USAGE: c = "inadequate key usage"; break; case SEC_ERROR_INADEQUATE_CERT_TYPE: c = "inadequate certificate type"; break; case SEC_ERROR_UNTRUSTED_CERT: c = "untrusted cert"; break; case SEC_ERROR_NO_KRL: c = "no key revocation list"; break; case SEC_ERROR_KRL_BAD_SIGNATURE: c = "key revocation list: bad signature"; break; case SEC_ERROR_KRL_EXPIRED: c = "key revocation list expired"; break; case SEC_ERROR_REVOKED_KEY: c = "revoked key"; break; case SEC_ERROR_CRL_BAD_SIGNATURE: c = "certificate revocation list: bad signature"; break; case SEC_ERROR_CRL_EXPIRED: c = "certificate revocation list expired"; break; case SEC_ERROR_CRL_NOT_YET_VALID: c = "certificate revocation list not yet valid"; break; case SEC_ERROR_UNKNOWN_ISSUER: c = "unknown issuer"; break; case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: c = "expired issuer certificate"; break; case SEC_ERROR_BAD_SIGNATURE: c = "bad signature"; break; case SEC_ERROR_BAD_KEY: c = "bad key"; break; case SEC_ERROR_NOT_FORTEZZA_ISSUER: c = "not fortezza issuer"; break; case SEC_ERROR_CA_CERT_INVALID: c = "Certificate Authority certificate invalid"; break; case SEC_ERROR_EXTENSION_NOT_FOUND: c = "extension not found"; break; case SEC_ERROR_CERT_NOT_IN_NAME_SPACE: c = "certificate not in name space"; break; case SEC_ERROR_UNTRUSTED_ISSUER: c = "untrusted issuer"; break; default: snprintf(errstring, sizeof(errstring), "security error %ld", code); c = errstring; break; } return c; } /*************************************************************** * * d i s p l a y V e r i f y L o g * * Prints the log of a cert verification. */ void displayVerifyLog(CERTVerifyLog *log) { CERTVerifyLogNode *node; CERTCertificate *cert; char *name; if (!log || (log->count <= 0)) { return; } for (node = log->head; node != NULL; node = node->next) { if (!(cert = node->cert)) { continue; } /* Get a name for this cert */ if (cert->nickname != NULL) { name = cert->nickname; } else if (cert->emailAddr && cert->emailAddr[0]) { name = cert->emailAddr; } else { name = cert->subjectName; } printf("%s%s:\n", name, (node->depth > 0) ? " [Certificate Authority]" : ""); printf("\t%s\n", secErrorString(node->error)); } } /* * J a r L i s t M o d u l e s * * Print a list of the PKCS11 modules that are * available. This is useful for smartcard people to * make sure they have the drivers loaded. * */ void JarListModules(void) { int i; int count = 0; SECMODModuleList *modules = NULL; static SECMODListLock *moduleLock = NULL; SECMODModuleList *mlp; if ((moduleLock = SECMOD_GetDefaultModuleListLock()) == NULL) { /* this is the wrong text */ PR_fprintf(errorFD, "%s: unable to acquire lock on module list\n", PROGRAM_NAME); errorCount++; exit(ERRX); } SECMOD_GetReadLock(moduleLock); modules = SECMOD_GetDefaultModuleList(); if (modules == NULL) { SECMOD_ReleaseReadLock(moduleLock); PR_fprintf(errorFD, "%s: Can't get module list\n", PROGRAM_NAME); errorCount++; exit(ERRX); } PR_fprintf(outputFD, "\nListing of PKCS11 modules\n"); PR_fprintf(outputFD, "-----------------------------------------------\n"); for (mlp = modules; mlp != NULL; mlp = mlp->next) { count++; PR_fprintf(outputFD, "%3d. %s\n", count, mlp->module->commonName); if (mlp->module->internal) PR_fprintf(outputFD, " (this module is internally loaded)\n"); else PR_fprintf(outputFD, " (this is an external module)\n"); if (mlp->module->dllName) PR_fprintf(outputFD, " DLL name: %s\n", mlp->module->dllName); if (mlp->module->slotCount == 0) PR_fprintf(outputFD, " slots: There are no slots attached to this module\n"); else PR_fprintf(outputFD, " slots: %d slots attached\n", mlp->module->slotCount); if (mlp->module->loaded == 0) PR_fprintf(outputFD, " status: Not loaded\n"); else PR_fprintf(outputFD, " status: loaded\n"); for (i = 0; i < mlp->module->slotCount; i++) { PK11SlotInfo *slot = mlp->module->slots[i]; PR_fprintf(outputFD, "\n"); PR_fprintf(outputFD, " slot: %s\n", PK11_GetSlotName(slot)); PR_fprintf(outputFD, " token: %s\n", PK11_GetTokenName(slot)); } } PR_fprintf(outputFD, "-----------------------------------------------\n"); if (count == 0) PR_fprintf(outputFD, "Warning: no modules were found (should have at least one)\n"); SECMOD_ReleaseReadLock(moduleLock); } /********************************************************************** * c h o p * * Eliminates leading and trailing whitespace. Returns a pointer to the * beginning of non-whitespace, or an empty string if it's all whitespace. */ char * chop(char *str) { char *start, *end; if (str) { start = str; /* Nip leading whitespace */ while (isspace(*start)) { start++; } /* Nip trailing whitespace */ if (*start) { end = start + strlen(start) - 1; while (isspace(*end) && end > start) { end--; } *(end + 1) = '\0'; } return start; } else { return NULL; } } /*********************************************************************** * * F a t a l E r r o r * * Outputs an error message and bails out of the program. */ void FatalError(char *msg) { if (!msg) msg = ""; PR_fprintf(errorFD, "FATAL ERROR: %s\n", msg); errorCount++; exit(ERRX); } /************************************************************************* * * I n i t C r y p t o */ int InitCrypto(char *cert_dir, PRBool readOnly) { SECStatus rv; static int prior = 0; PK11SlotInfo *slotinfo; if (prior == 0) { /* some functions such as OpenKeyDB expect this path to be * implicitly set prior to calling */ if (readOnly) { rv = NSS_Init(cert_dir); } else { rv = NSS_InitReadWrite(cert_dir); } if (rv != SECSuccess) { SECU_PrintPRandOSError(PROGRAM_NAME); exit(-1); } SECU_ConfigDirectory(cert_dir); /* Been there done that */ prior++; PK11_SetPasswordFunc(SECU_GetModulePassword); /* Must login to FIPS before you do anything else */ if (PK11_IsFIPS()) { slotinfo = PK11_GetInternalSlot(); if (!slotinfo) { fprintf(stderr, "%s: Unable to get PKCS #11 Internal Slot." "\n", PROGRAM_NAME); return -1; } if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/, &pwdata) != SECSuccess) { fprintf(stderr, "%s: Unable to authenticate to %s.\n", PROGRAM_NAME, PK11_GetSlotName(slotinfo)); PK11_FreeSlot(slotinfo); return -1; } PK11_FreeSlot(slotinfo); } /* Make sure there is a password set on the internal key slot */ slotinfo = PK11_GetInternalKeySlot(); if (!slotinfo) { fprintf(stderr, "%s: Unable to get PKCS #11 Internal Key Slot." "\n", PROGRAM_NAME); return -1; } if (PK11_NeedUserInit(slotinfo)) { PR_fprintf(errorFD, "\nWARNING: No password set on internal key database. Most operations will fail." "\nYou must create a password.\n"); warningCount++; } /* Make sure we can authenticate to the key slot in FIPS mode */ if (PK11_IsFIPS()) { if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/, &pwdata) != SECSuccess) { fprintf(stderr, "%s: Unable to authenticate to %s.\n", PROGRAM_NAME, PK11_GetSlotName(slotinfo)); PK11_FreeSlot(slotinfo); return -1; } } PK11_FreeSlot(slotinfo); } return 0; } /* Windows foolishness is now in the secutil lib */ /***************************************************************** * g e t _ d e f a u l t _ c e r t _ d i r * * Attempt to locate a certificate directory. * Failing that, complain that the user needs to * use the -d(irectory) parameter. * */ char * get_default_cert_dir(void) { char *home; char *cd = NULL; static char db[FNSIZE]; #ifdef XP_UNIX home = PR_GetEnvSecure("HOME"); if (home && *home) { snprintf(db, sizeof(db), "%s/.netscape", home); cd = db; } #endif #ifdef XP_PC FILE *fp; /* first check the environment override */ home = PR_GetEnvSecure("JAR_HOME"); if (home && *home) { snprintf(db, sizeof(db), "%s/cert7.db", home); if ((fp = fopen(db, "r")) != NULL) { fclose(fp); cd = home; } } /* try the old navigator directory */ if (cd == NULL) { home = "c:/Program Files/Netscape/Navigator"; snprintf(db, sizeof(db), "%s/cert7.db", home); if ((fp = fopen(db, "r")) != NULL) { fclose(fp); cd = home; } } /* Try the current directory, I wonder if this is really a good idea. Remember, Windows only.. */ if (cd == NULL) { home = "."; snprintf(db, sizeof(db), "%s/cert7.db", home); if ((fp = fopen(db, "r")) != NULL) { fclose(fp); cd = home; } } #endif if (!cd) { PR_fprintf(errorFD, "You must specify the location of your certificate directory\n"); PR_fprintf(errorFD, "with the -d option. Example: -d ~/.netscape in many cases with Unix.\n"); errorCount++; exit(ERRX); } return cd; } /************************************************************************ * g i v e _ h e l p */ void give_help(int status) { if (status == SEC_ERROR_UNKNOWN_ISSUER) { PR_fprintf(errorFD, "The Certificate Authority (CA) for this certificate\n"); PR_fprintf(errorFD, "does not appear to be in your database. You should contact\n"); PR_fprintf(errorFD, "the organization which issued this certificate to obtain\n"); PR_fprintf(errorFD, "a copy of its CA Certificate.\n"); } } /************************************************************************** * * p r _ f g e t s * * fgets implemented with NSPR. */ char * pr_fgets(char *buf, int size, PRFileDesc *file) { int i; int status; char c; i = 0; while (i < size - 1) { status = PR_Read(file, &c, 1); if (status == -1) { return NULL; } else if (status == 0) { if (i == 0) { return NULL; } break; } buf[i++] = c; if (c == '\n') { break; } } buf[i] = '\0'; return buf; }