--- pgp/src/pgp.c 2018/04/24 16:38:58 1.1.1.3 +++ pgp/src/pgp.c 2018/04/24 16:39:42 1.1.1.4 @@ -44,8 +44,9 @@ Version 1.8 - 23 May 92 Version 2.0 - 2 Sep 92 Version 2.1 - 6 Dec 92 + Version 2.2 - 6 Mar 92 - (c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved. + (c) Copyright 1990-1993 by Philip Zimmermann. All rights reserved. The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. @@ -108,6 +109,7 @@ #include #include #include +#include "system.h" #include "mpilib.h" #include "random.h" #include "crypto.h" @@ -115,8 +117,12 @@ #include "keymgmt.h" #include "language.h" #include "pgp.h" -int maintenance(char *ringfile, int options); /* from keymaint.c */ -int processConfigLine( char *option ); /* From config.c */ +#include "exitpgp.h" +#include "charset.h" +#include "getopt.h" +#include "config.h" +#include "keymaint.h" +#include "keyadd.h" #ifdef M_XENIX char *strstr(); long time(); @@ -124,28 +130,27 @@ long time(); #ifdef MSDOS #ifdef __ZTC__ /* Extend stack for Zortech C */ -unsigned _stack_ = 12*1024; +unsigned _stack_ = 24*1024; #endif #ifdef __TURBOC__ -unsigned _stklen = 12*1024; +unsigned _stklen = 24*1024; #endif #endif #define STACK_WIPE 4096 /* Global filenames and system-wide file extensions... */ -char rel_version[] = "2.1"; /* release version */ -char rel_date[] = "6 Dec 92"; /* release date */ -char CTX_EXTENSION[] = ".pgp"; +char rel_version[] = "2.2"; /* release version */ +static char rel_date[] = "6 Mar 93"; /* release date */ char PGP_EXTENSION[] = ".pgp"; char ASC_EXTENSION[] = ".asc"; char SIG_EXTENSION[] = ".sig"; char BAK_EXTENSION[] = ".bak"; -char HLP_EXTENSION[] = ".hlp"; +static char HLP_EXTENSION[] = ".hlp"; char CONSOLE_FILENAME[] = "_CONSOLE"; -char HELP_FILENAME[] = "pgp.hlp"; +static char HELP_FILENAME[] = "pgp.hlp"; /* These files use the environmental variable PGPPATH as a default path: */ -char CONFIG_FILENAME[] = "config.txt"; +static char CONFIG_FILENAME[] = "config.txt"; char PUBLIC_KEYRING_FILENAME[32] = "pubring.pgp"; char SECRET_KEYRING_FILENAME[32] = "secring.pgp"; char RANDSEED_FILENAME[32] = "randseed.bin"; @@ -154,53 +159,13 @@ char RANDSEED_FILENAME[32] = "randseed.b boolean verbose = FALSE; /* -l option: display maximum information */ FILE *pgpout; /* Place for routine messages */ -/* Prototype for function in config.c */ - -int processConfigFile( char *configFileName ); - -static void usage(); -static void key_usage(); -static void arg_error(); -static void initsigs(); -static void do_keyopt(char); -static void do_decrypt(char *); +static void usage(void); +static void key_usage(void); +static void arg_error(void); +static void initsigs(void); +static int do_keyopt(char); +static int do_decrypt(char *); static void do_armorfile(char *); -void user_error(); -void exitPGP(int); - - -#if 0 /* unused */ -boolean strcontains( char *s1, char *s2 ) -{ /* - ** Searches s1 for s2, without case sensitivity. - ** Return TRUE if found. - ** - ** If s2 is an empty string then return TRUE. This is because, - ** at least in the world of mathematics, the empty set is contained - ** in all other sets. The Microsoft C version 6.0 strstr function - ** behaves this way but version 5.1 does not, so we need to - ** explicitly test for the situation. -- ALH 91/2/17 - */ - - if (s2 != NULL && s2[0] != '\0') - { - char buf1[256], buf2[256]; /* scratch buffers */ - - if (s1 != NULL) - { - strncpy( buf1, s1, 256 ); - strlwr( buf1 ); /* converts to lower case */ - } - else - buf1[0] = '\0'; - strncpy( buf2, s2, 256 ); strlwr( buf2 ); /* converts to lower case */ - - if (strstr( buf1, buf2 ) == NULL) - return( FALSE ); /* string not found */ - } - return(TRUE); -} /* strcontains */ -#endif /* Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK. @@ -208,9 +173,17 @@ boolean strcontains( char *s1, char *s2 compressSig structure intentionally. If more formats are added, put them before lharc to keep the code consistent. */ -char *compressSig[] = { "PK\03\04", "ZOO ", "GIF8", "\352\140", "HPAK" }; -char *compressName[] = { "PKZIP", "Zoo", "GIF", "Arj", "Hpack", "LHarc" }; -char *compressExt[] = { ".zip", ".zoo", ".gif", ".arj", ".hpk", ".lzh" }; +static char *compressSig[] = { "PK\03\04", "ZOO ", "GIF8", "\352\140", + "HPAK", "\037\213", "\037\235", "\032\013", "\032HP%" + /* lharc is special, must be last */ }; +static char *compressName[] = { "PKZIP", "Zoo", "GIF", "Arj", + "Hpack", "gzip", "compressed", "PAK", "Hyper", + "LHarc" }; +static char *compressExt[] = { ".zip", ".zoo", ".gif", ".arj", + ".hpk", ".z", ".Z", ".pak", ".hyp", + ".lzh" }; + +/* "\032\0??", "ARC", ".arc" */ int compressSignature(byte *header) /* Returns file signature type from a number of popular compression formats @@ -228,7 +201,7 @@ int compressSignature(byte *header) } /* compressSignature */ -boolean file_compressible(char *filename) +static boolean file_compressible(char *filename) { /* returns TRUE iff file is likely to be compressible */ byte header[8]; get_header_info_from_file( filename, header, 8 ); @@ -297,20 +270,20 @@ void breakHandler(int sig) #endif -void clearscreen(void) +static void clearscreen(void) { /* Clears screen and homes the cursor. */ fprintf(pgpout,"\n\033[0;0H\033[J\r \r"); /* ANSI sequence. */ fflush(pgpout); } -void signon_msg() +static void signon_msg(void) { /* We had to process the config file first to possibly select the foreign language to translate the sign-on line that follows... */ word32 tstamp; /* display message only once to allow calling multiple times */ static boolean printed = FALSE; - if (filter_mode || printed) + if (quietmode || printed) return; printed = TRUE; fprintf(stderr,PSTR("Pretty Good Privacy %s - Public-key encryption for the masses.\n"), @@ -318,7 +291,7 @@ void signon_msg() #ifdef TEMP_VERSION fprintf(stderr, "Internal development version only - not for general release.\n"); #endif - fprintf(stderr, PSTR("(c) 1990-1992 Philip Zimmermann, Phil's Pretty Good Software. %s\n"), + fprintf(stderr, PSTR("(c) 1990-1993 Philip Zimmermann, Phil's Pretty Good Software. %s\n"), rel_date); get_timestamp((byte *)&tstamp); /* timestamp points to tstamp */ @@ -349,7 +322,7 @@ void check_expiration_date(void) /* -f means act as a unix-style filter */ /* -i means internalize extended file attribute information, only supported - * between like (or very compatible) operating systems. + * between like (or very compatible) operating systems. */ /* -l means show longer more descriptive diagnostic messages */ /* -m means display plaintext output on screen, like unix "more" */ /* -d means decrypt only, leaving inner signature wrapping intact */ @@ -361,41 +334,48 @@ extern int optind; extern char *optarg; boolean emit_radix_64 = FALSE; /* set by config file */ -boolean sign_flag = FALSE; +static boolean sign_flag = FALSE; boolean moreflag = FALSE; boolean filter_mode = FALSE; -boolean preserve_filename = FALSE; -boolean decrypt_only_flag = FALSE; -boolean de_armor_only = FALSE; -boolean strip_sig_flag = FALSE; +static boolean preserve_filename = FALSE; +static boolean decrypt_only_flag = FALSE; +static boolean de_armor_only = FALSE; +static boolean strip_sig_flag = FALSE; boolean clear_signatures = FALSE; -boolean c_flag = FALSE; +boolean strip_spaces; +static boolean c_flag = FALSE; +boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? */ +boolean batchmode = FALSE; /* if TRUE: don't ask questions */ +boolean quietmode = FALSE; +boolean force_flag = FALSE; /* overwrite existing file without asking */ #ifdef VMS /* kludge for those stupid VMS variable-length text records */ -char lit_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal packet */ +char literal_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal packet */ #else /* not VMS */ -char lit_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal packet */ +char literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal packet */ #endif /* not VMS */ /* my_name is substring of default userid for secret key to make signatures */ char my_name[256] = "\0"; /* null my_name means take first userid in ring */ boolean keepctx = FALSE; /* TRUE means keep .ctx file on decrypt */ +/* Ask for each key separately if it should be added to the keyring */ +boolean interactive_add = FALSE; boolean compress_enabled = TRUE; /* attempt compression before encryption */ long timeshift = 0L; /* seconds from GMT timezone */ -boolean attempt_compression; /* attempt compression before encryption */ -char *outputfile = NULL; -int errorLvl = EXIT_OK; -char mcguffin[256]; /* userid search tag */ +static boolean attempt_compression; /* attempt compression before encryption */ +static char *outputfile = NULL; +static int errorLvl = EXIT_OK; +static char mcguffin[256]; /* userid search tag */ +boolean signature_checked = FALSE; char plainfile[MAX_PATH]; -#define MAXARGC 8 int myArgc = 2; -char *myArgv[MAXARGC] = { NULL, }; +char **myArgv; char password[256] = ""; - int main(int argc, char *argv[]) { int status, opt; char *inputfile = NULL; - char *recipient = NULL; + char **recipient = NULL; + char **mcguffins; char *workfile, *tempf; boolean nestflag = FALSE; boolean decrypt_mode = FALSE; @@ -420,10 +400,15 @@ int main(int argc, char *argv[]) verbose = TRUE; #endif -#ifndef UNIX if ((p = getenv("PGPPASS")) != NULL) strcpy(password, p); -#else + + /* The -z "password" option should be used instead of PGPPASS if + * the environment can be displayed with the ps command (eg. BSD). + * If the system does not allow overwriting of the command line + * argument list but if it has a "hidden" environment, PGPPASS + * should be used. + */ for (opt = 1; opt < argc; ++opt) { if (strcmp(argv[opt], "-z") == 0 && ++opt < argc) { strcpy(password, argv[opt]); @@ -431,7 +416,22 @@ int main(int argc, char *argv[]) *p = ' '; } } -#endif + /* + * If PGPPASSFD is set in the environment try to read the password + * from this file descriptor. If you set PGPPASSFD to 0 pgp will + * use the first line read from stdin as password. + */ + if (*password == '\0' && (p = getenv("PGPPASSFD")) != NULL) + { + int passfd; + if (*p && (passfd = atoi(p)) >= 0) + { + p = password; + while (read(passfd, p, 1) == 1 && *p != '\n') + ++p; + *p = '\0'; + } + } /* Process the config file first. Any command-line arguments will override the config file settings */ @@ -448,7 +448,7 @@ in AUTOEXEC.BAT file.\n")); } #endif /* MSDOS */ -#ifdef XVMS /* When we can trust FILEIO.C, change this to VMS, HAJK */ +#ifdef VMS #define TEMP "SYS$SCRATCH" #else #define TEMP "TMP" @@ -456,6 +456,13 @@ in AUTOEXEC.BAT file.\n")); if ((p = getenv(TEMP)) != NULL && *p != '\0') settmpdir(p); + if ((myArgv = (char **) malloc((argc + 2) * sizeof(char **))) == NULL) { + fprintf(stderr, PSTR("\n\007Out of memory.\n")); + exitPGP(7); + } + myArgv[0] = NULL; + myArgv[1] = NULL; + /* Process all the command-line option switches: */ while (optind < argc) { /* @@ -466,12 +473,6 @@ in AUTOEXEC.BAT file.\n")); if ((opt = getopt(argc, argv, OPTIONS)) == EOF) { if (optind == argc) /* -- at end */ break; - if (myArgc == MAXARGC) - { signon_msg(); - fprintf(pgpout, PSTR("\007Too many arguments.\n")); - errorLvl = BAD_ARG_ERROR; - user_error(); - } myArgv[myArgc++] = argv[optind++]; continue; } @@ -496,7 +497,7 @@ in AUTOEXEC.BAT file.\n")); case '?': case 'h': usage(); break; #ifdef VMS - case 'i': lit_mode = MODE_LOCAL; break; + case 'i': literal_mode = MODE_LOCAL; break; #endif /* VMS */ case 'k': keyflag = TRUE; break; case 'l': verbose = TRUE; break; @@ -504,7 +505,7 @@ in AUTOEXEC.BAT file.\n")); case 'p': preserve_filename = TRUE; break; case 'o': outputfile = optarg; break; case 's': sign_flag = TRUE; break; - case 't': lit_mode = MODE_TEXT; break; + case 't': literal_mode = MODE_TEXT; break; case 'u': strncpy(my_name, optarg, sizeof(my_name)-1); CONVERT_TO_CANONICAL_CHARSET(my_name); break; @@ -520,16 +521,16 @@ in AUTOEXEC.BAT file.\n")); arg_error(); } } + myArgv[myArgc] = NULL; /* Just to make it NULL terminated */ + if (keyflag && keychar == '\0') key_usage(); signon_msg(); check_expiration_date(); /* hobble any experimental version */ -#ifndef UNIX - if (!filter_mode) + if (!filter_mode && (outputfile == NULL || strcmp(outputfile, "-"))) pgpout = stdout; -#endif #if defined(UNIX) || defined(VMS) umask(077); /* Make files default to private */ @@ -538,8 +539,10 @@ in AUTOEXEC.BAT file.\n")); initsigs(); if (keyflag) - { do_keyopt(keychar); - exitPGP(EXIT_OK); + { status = do_keyopt(keychar); + if (status < 0) + user_error(); + exitPGP(status); } /* -db means break off signature certificate into separate file */ @@ -574,13 +577,21 @@ in AUTOEXEC.BAT file.\n")); { /* piping to pgp without arguments and no -f: * switch to filter mode but don't write output to stdout * if it's a tty, use the preserved filename */ + if (!moreflag) + pgpout = stderr; filter_mode = TRUE; if (isatty(fileno(stdout)) && !moreflag) preserve_filename = TRUE; } #endif if (!filter_mode) - { fprintf(pgpout,PSTR("\nFor details on licensing and distribution, see the PGP User's Guide.\ + { + if (quietmode) + { + quietmode = FALSE; + signon_msg(); + } + fprintf(pgpout,PSTR("\nFor details on licensing and distribution, see the PGP User's Guide.\ \nFor other cryptography products and custom development services, contact:\ \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, phone (303)541-0140\n")); if (strcmp((p = PSTR("@translator@")), "@translator@")) @@ -591,18 +602,16 @@ in AUTOEXEC.BAT file.\n")); } else { if (filter_mode) - recipient = myArgv[2]; + recipient = &myArgv[2]; else { inputfile = myArgv[2]; - recipient = myArgv[3]; + recipient = &myArgv[3]; } } if (filter_mode) - { inputfile = "stdin"; - filter_mode = TRUE; - } + inputfile = "stdin"; else { if (decrypt_mode && no_extension(inputfile)) { strcpy(cipherfile, inputfile); @@ -610,7 +619,7 @@ in AUTOEXEC.BAT file.\n")); if (file_exists (cipherfile)) inputfile = cipherfile; else - { force_extension( cipherfile, CTX_EXTENSION ); + { force_extension( cipherfile, PGP_EXTENSION ); if (file_exists (cipherfile)) inputfile = cipherfile; else @@ -625,7 +634,6 @@ in AUTOEXEC.BAT file.\n")); errorLvl = FILE_NOT_FOUND_ERROR; user_error(); } - workfile = inputfile; } if (strlen(inputfile) >= (unsigned) MAX_PATH-4) @@ -648,16 +656,23 @@ in AUTOEXEC.BAT file.\n")); { workfile = tempfile(TMP_WIPE|TMP_TMPDIR); readPhantomInput(workfile); } + else + workfile = inputfile; get_header_info_from_file( workfile, &ctb, 1 ); if (decrypt_mode) - { if (!outputfile) + { if (!outputfile && myArgc > 3) outputfile = myArgv[3]; + strip_spaces = FALSE; if (!is_ctb(ctb) && is_armor_file(workfile, 0L)) do_armorfile(workfile); else - do_decrypt(workfile); - exitPGP(EXIT_OK); + if (do_decrypt(workfile) < 0) + user_error(); + if (batchmode && !signature_checked) + exitPGP(1); /* alternate success, file did not have sig. */ + else + exitPGP(EXIT_OK); } @@ -665,20 +680,22 @@ in AUTOEXEC.BAT file.\n")); If it was, maybe we should NOT encapsulate it in a literal packet. Otherwise, always encapsulate it. */ - nestflag = FALSE; /* First assume we will encapsulate it. */ - if (!filter_mode && legal_ctb(ctb)) + if (force_flag) /* for use with batchmode, force nesting */ + nestflag = legal_ctb(ctb); + else + nestflag = FALSE; /* First assume we will encapsulate it. */ + if (!batchmode && !filter_mode && legal_ctb(ctb)) { /* Special case--may be a PGP-created packet, so do we inhibit encapsulation in literal packet? */ fprintf(pgpout, PSTR("\n\007Input file '%s' looks like it may have been created by PGP. "), inputfile ); fprintf(pgpout, PSTR("\nIs it safe to assume that it was created by PGP (y/N)? ")); - if (getyesno('n')) - nestflag = TRUE; /* don't re-encapsulate PGP packet */ + nestflag = getyesno('n'); } /* Possible ciphertext input file */ if (moreflag) /* special name to cause printout on decrypt */ { strcpy (literal_file_name, CONSOLE_FILENAME); - lit_mode = MODE_TEXT; /* will check for text file later */ + literal_mode = MODE_TEXT; /* will check for text file later */ } else { strcpy (literal_file_name, inputfile); @@ -694,14 +711,14 @@ in AUTOEXEC.BAT file.\n")); 8-bit character codes and still be legitimate text files suitable for conversion to canonical (CR/LF-terminated) text format. */ - if (lit_mode==MODE_TEXT && !is_text_file(workfile)) + if (literal_mode==MODE_TEXT && !is_text_file(workfile)) { fprintf(pgpout, PSTR("\n\007Warning: '%s' is not a pure text file.\nFile will be treated as binary data.\n"), workfile); - lit_mode = MODE_BINARY; /* now expect straight binary */ + literal_mode = MODE_BINARY; /* now expect straight binary */ } - if (moreflag && lit_mode==MODE_BINARY) /* For eyes only? Can't display binary file. */ + if (moreflag && literal_mode==MODE_BINARY) /* For eyes only? Can't display binary file. */ { fprintf(pgpout, PSTR("\n\007Error: Only text files may be sent as display-only.\n")); errorLvl = INVALID_FILE_ERROR; @@ -720,27 +737,30 @@ PSTR("\n\007Warning: '%s' is not a pure if (sign_flag) { - if (!filter_mode) + if (!filter_mode && !quietmode) fprintf(pgpout, PSTR("\nA secret key is required to make a signature. ")); - if (my_name[0] == '\0') + if (!quietmode && my_name[0] == '\0') { fprintf(pgpout, PSTR("\nYou specified no user ID to select your secret key,\n\ so the default user ID and key will be the most recently\n\ added key on your secret keyring.\n")); } - if (lit_mode==MODE_TEXT) + strip_spaces = FALSE; + clearfile = NULL; + if (literal_mode==MODE_TEXT) { /* Text mode requires becoming canonical */ tempf = tempfile(TMP_WIPE|TMP_TMPDIR); - make_canonical( workfile, tempf ); /* +clear means output file with signature in the clear, only in combination with -t and -a, not with -e or -b */ if (!encrypt_flag && !separate_signature && emit_radix_64 && clear_signatures) { clearfile = workfile; - } else { - rmtemp(workfile); + strip_spaces = TRUE; } + make_canonical( workfile, tempf ); + if (!clearfile) + rmtemp(workfile); workfile = tempf; } if ((emit_radix_64 || encrypt_flag) && !separate_signature) @@ -749,7 +769,7 @@ added key on your secret keyring.\n")); tempf = tempfile(TMP_WIPE); /* for clear signatures we create a separate signature */ status = signfile(nestflag, separate_signature || (clearfile != NULL), - my_name, workfile, tempf, lit_mode, literal_file ); + my_name, workfile, tempf, literal_mode, literal_file ); rmtemp(workfile); workfile = tempf; @@ -759,10 +779,10 @@ added key on your secret keyring.\n")); user_error(); } - /* If we just sign it without encryption, and we want radix-64 - output, we may as well compress it before converting to - radix-64 format. */ - if (attempt_compression && emit_radix_64 && !encrypt_flag && + /* We used to compress signed files only if they were also armored. + Now that we have clear signatures it makes more sense to always + compress signature files. */ + if (attempt_compression && !separate_signature && !encrypt_flag && !clearfile) { tempf = tempfile(TMP_WIPE|TMP_TMPDIR); squish_file(workfile, tempf); @@ -775,35 +795,42 @@ added key on your secret keyring.\n")); { /* Prepend CTB_LITERAL byte to plaintext file. --sure wish this pass could be optimized away. */ tempf = tempfile(TMP_WIPE); - status = make_literal( workfile, tempf, lit_mode, literal_file ); + status = make_literal( workfile, tempf, literal_mode, literal_file ); rmtemp(workfile); workfile = tempf; } if (encrypt_flag) { + tempf = tempfile(TMP_WIPE); if (!conventional_flag) { - if (!filter_mode) - fprintf(pgpout, PSTR("\n\nRecipient's public key will be used to encrypt. ")); - if (recipient == NULL) + if (!filter_mode && !quietmode) + fprintf(pgpout, PSTR("\n\nRecipients' public key(s) will be used to encrypt. ")); + if (recipient == NULL || *recipient == NULL || **recipient == '\0') { /* no recipient specified on command line */ fprintf(pgpout, PSTR("\nA user ID is required to select the recipient's public key. ")); fprintf(pgpout, PSTR("\nEnter the recipient's user ID: ")); getstring( mcguffin, 255, TRUE ); /* echo keyboard */ + if ((mcguffins = (char **) malloc (2 * sizeof(char *))) == NULL) { + fprintf(stderr, PSTR("\n\007Out of memory.\n")); + exitPGP(7); + } + mcguffins[0] = mcguffin; + mcguffins[1] = ""; } else { /* recipient specified on command line */ - strcpy( mcguffin, recipient ); /* Userid of recipient */ + mcguffins = recipient; } - CONVERT_TO_CANONICAL_CHARSET(mcguffin); + for (recipient = mcguffins; *recipient != NULL && + **recipient != '\0'; recipient++) { + CONVERT_TO_CANONICAL_CHARSET(*recipient); + } + status = encryptfile( mcguffins, workfile, tempf, attempt_compression); } - - tempf = tempfile(TMP_WIPE); - if (conventional_flag) - status = idea_encryptfile( workfile, tempf, attempt_compression); else - status = encryptfile( mcguffin, workfile, tempf, attempt_compression); + status = idea_encryptfile( workfile, tempf, attempt_compression); rmtemp(workfile); workfile = tempf; @@ -849,7 +876,7 @@ added key on your secret keyring.\n")); else if (sign_flag && separate_signature) force_extension(name, SIG_EXTENSION); else - force_extension(name, CTX_EXTENSION); + force_extension(name, PGP_EXTENSION); } if (emit_radix_64) { @@ -865,10 +892,13 @@ added key on your secret keyring.\n")); { errorLvl = UNKNOWN_FILE_ERROR; user_error(); } - if (!verbose && encrypt_flag) - fprintf(pgpout, PSTR("\nCiphertext file: %s\n"), outputfile); - else if (!verbose && sign_flag) - fprintf(pgpout, PSTR("\nSignature file: %s\n"), outputfile); + if (!quietmode) + { + if (encrypt_flag) + fprintf(pgpout, PSTR("\nCiphertext file: %s\n"), outputfile); + else if (sign_flag) + fprintf(pgpout, PSTR("\nSignature file: %s\n"), outputfile); + } } } @@ -882,6 +912,7 @@ added key on your secret keyring.\n")); } exitPGP(EXIT_OK); + return(0); /* to shut up lint and some compilers */ } /* main */ #ifdef MSDOS @@ -927,9 +958,11 @@ static void initsigs() #ifdef __TURBOC__ harderr(dostrap); #else /* MSC */ +#ifndef __GNUC__ /* DJGPP's not MSC */ _harderr(dostrap); #endif #endif +#endif #endif /* MSDOS */ #ifdef SIGINT #ifdef ATARI @@ -944,6 +977,7 @@ static void initsigs() #endif signal(SIGTERM,breakHandler); #ifndef DEBUG + signal(SIGTRAP,breakHandler); signal(SIGSEGV,breakHandler); signal(SIGILL,breakHandler); #ifdef SIGBUS @@ -962,10 +996,12 @@ static void do_armorfile(char *armorfile char cipherfile[MAX_PATH]; long linepos = 0; int status; + int success = 0; while (TRUE) { /* Handle transport armor stripping */ tempf = tempfile(0); + strip_spaces = FALSE; /* de_armor_file() sets this for clear signature files */ status = de_armor_file(armorfile,tempf,&linepos); if (status) { fprintf(pgpout,PSTR("\n\007Error: Transport armor stripping failed for file %s\n"),armorfile); @@ -973,35 +1009,48 @@ static void do_armorfile(char *armorfile user_error(); /* Bad file */ } if (keepctx || de_armor_only) - { if (outputfile) + { if (outputfile && de_armor_only) + { if (strcmp(outputfile, "-") == 0) + { writePhantomOutput(tempf); + rmtemp(tempf); + return; + } strcpy(cipherfile, outputfile); + } else { strcpy(cipherfile, file_tail(armorfile)); - force_extension(cipherfile, CTX_EXTENSION); + force_extension(cipherfile, PGP_EXTENSION); } if ((tempf = savetemp(tempf, cipherfile)) == NULL) { errorLvl = UNKNOWN_FILE_ERROR; user_error(); } - fprintf(pgpout,PSTR("Stripped transport armor from '%s', producing '%s'.\n"), - armorfile, tempf); - if (!de_armor_only) - do_decrypt(tempf); + if (!quietmode) + fprintf(pgpout,PSTR("Stripped transport armor from '%s', producing '%s'.\n"), + armorfile, tempf); + /* -da flag: don't decrypt */ + if (de_armor_only || do_decrypt(tempf) >= 0) + ++success; } else - { do_decrypt(tempf); + { if (do_decrypt(tempf) >= 0) + ++success; rmtemp(tempf); } if (!is_armor_file(armorfile, linepos)) - break; + { + if (!success) /* print error msg if we didn't decrypt anything */ + user_error(); + return; + } fprintf (pgpout, PSTR("\nLooking for next packet in '%s'...\n"), armorfile); } } /* do_armorfile */ -static void do_decrypt(char *cipherfile) +static int do_decrypt(char *cipherfile) { char *outfile = NULL; int status, i; @@ -1024,7 +1073,7 @@ static void do_decrypt(char *cipherfile) if (get_header_info_from_file( cipherfile, &ctb, 1) < 0) { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),cipherfile); errorLvl = FILE_NOT_FOUND_ERROR; - user_error(); + return -1; } if (!is_ctb(ctb)) /* not a real CTB -- complain */ @@ -1035,7 +1084,7 @@ static void do_decrypt(char *cipherfile) /* PKE is Public Key Encryption */ if (is_ctb_type( ctb, CTB_PKE_TYPE )) { - if (!filter_mode) + if (!quietmode) fprintf(pgpout,PSTR("\nFile is encrypted. Secret key is required to read it. ")); /* Decrypt to scratch file since we may have a LITERAL2 */ @@ -1043,7 +1092,7 @@ static void do_decrypt(char *cipherfile) if (status < 0) /* error return */ { errorLvl = RSA_DECR_ERROR; - user_error(); + return -1; } nested_info = (status > 0); } /* outer CTB is PKE type */ @@ -1055,23 +1104,25 @@ static void do_decrypt(char *cipherfile) rmtemp(outfile); outfile = cipherfile; cipherfile = NULL; - fprintf(pgpout,PSTR("\nThis file has a signature, which will be left in place.\n")); + if (!quietmode) + fprintf(pgpout,PSTR("\nThis file has a signature, which will be left in place.\n")); break; /* Do no more */ } - fprintf(pgpout,PSTR("\nFile has signature. Public key is required to check signature. ")); + if (!quietmode) + fprintf(pgpout,PSTR("\nFile has signature. Public key is required to check signature. ")); status = check_signaturefile( cipherfile, outfile, strip_sig_flag, preserved_name ); if (status < 0) /* error return */ { errorLvl = SIGNATURE_CHECK_ERROR; - user_error(); + return -1; } nested_info = (status > 0); if (strcmp(preserved_name, "/dev/null") == 0) { rmtemp(outfile); fprintf(pgpout, "\n"); - return; + return 0; } } /* outer CTB is SKE type */ @@ -1079,13 +1130,13 @@ static void do_decrypt(char *cipherfile) if (is_ctb_type( ctb, CTB_CKE_TYPE )) { /* Conventional Key Encrypted ciphertext. */ /* Tell user it's encrypted here, and prompt for password in subroutine. */ - if (!filter_mode) + if (!quietmode) fprintf(pgpout,PSTR("\nFile is conventionally encrypted. ")); /* Decrypt to scratch file since it may be a LITERAL2 */ status = idea_decryptfile( cipherfile, outfile ); if (status < 0) /* error return */ { errorLvl = DECR_ERROR; - user_error(); /* error exit status */ + return -1; /* error exit status */ } nested_info = (status > 0); } /* CTB is CKE type */ @@ -1096,7 +1147,7 @@ static void do_decrypt(char *cipherfile) status = decompress_file( cipherfile, outfile ); if (status < 0) /* error return */ { errorLvl = DECOMPRESS_ERROR; - user_error(); + return -1; } /* Always assume nested information... */ nested_info = TRUE; @@ -1108,10 +1159,10 @@ static void do_decrypt(char *cipherfile) /* Strip off CTB_LITERAL prefix byte from file: */ /* strip_literal may alter plainfile; will set mode */ status = strip_literal( cipherfile, outfile, - preserved_name, &lit_mode); + preserved_name, &literal_mode); if (status < 0) /* error return */ { errorLvl = UNKNOWN_FILE_ERROR; - user_error(); + return -1; } nested_info = FALSE; } /* CTB is LITERAL type */ @@ -1127,26 +1178,30 @@ static void do_decrypt(char *cipherfile) } /* Key ring. View it. */ fprintf(pgpout, PSTR("\nFile contains key(s). Contents follow...") ); - if (filter_mode && !preserve_filename) - { /* filter mode explicit requested with -f */ - if (view_keyring( NULL, cipherfile, TRUE, FALSE ) < 0) - { errorLvl = KEYRING_VIEW_ERROR; - user_error(); - } - return; /* No output file */ + if (view_keyring( NULL, cipherfile, TRUE, FALSE ) < 0) + { errorLvl = KEYRING_VIEW_ERROR; + return -1; } + /* filter mode explicit requested with -f */ + if (filter_mode && !preserve_filename) + return 0; /* No output file */ + if (batchmode) + return 0; if (ctb == CTB_CERT_SECKEY) buildfilename(ringfile,SECRET_KEYRING_FILENAME); else buildfilename(ringfile,PUBLIC_KEYRING_FILENAME); /* Ask if it should be put on key ring */ - status = addto_keyring(cipherfile,ringfile,TRUE); + fprintf(pgpout, PSTR("\nDo you want to add this keyfile to keyring '%s' (y/N)? "), ringfile); + if (!getyesno('n')) + return 0; + status = addto_keyring(cipherfile,ringfile); if (status < 0) { fprintf(pgpout, PSTR("\007Keyring add error. ") ); errorLvl = KEYRING_ADD_ERROR; - user_error(); + return -1; } - return; /* No output file */ + return 0; /* No output file */ } /* key ring. view it. */ } while (nested_info); @@ -1157,7 +1212,7 @@ static void do_decrypt(char *cipherfile) { fprintf(pgpout,PSTR("\007\nError: '%s' is not a ciphertext, signature, or key file.\n"), cipherfile); errorLvl = UNKNOWN_FILE_ERROR; - user_error(); + return -1; } outfile = cipherfile; } @@ -1170,19 +1225,24 @@ static void do_decrypt(char *cipherfile) if (strcmp(preserved_name,CONSOLE_FILENAME) == 0) { fprintf(pgpout, PSTR("\n\nThis message is marked \"For your eyes only\". Display now (Y/n)? ")); - if (!getyesno('y')) + if (batchmode || !getyesno('y')) { /* no -- abort display, and clean up */ rmtemp(outfile); - return; + return 0; } } - fprintf(pgpout, PSTR("\n\nPlaintext message follows...\n")); + if (!quietmode) + fprintf(pgpout, PSTR("\n\nPlaintext message follows...\n")); + else + putc('\n', pgpout); + fprintf(pgpout, "------------------------------\n"); more_file(outfile); /* Disallow saving to disk if outfile is console-only: */ if (strcmp(preserved_name,CONSOLE_FILENAME) == 0) clearscreen(); /* remove all evidence */ - else - { fprintf(pgpout, PSTR("Save this file permanently (y/N)? ")); + else if (!quietmode && !batchmode) + { + fprintf(pgpout, PSTR("Save this file permanently (y/N)? ")); if (getyesno('n')) { char moreFilename[256]; fprintf(pgpout,PSTR("Enter filename to save file as: ")); @@ -1197,17 +1257,17 @@ static void do_decrypt(char *cipherfile) } else savetemp (outfile, moreFilename); - return; + return 0; } } rmtemp(outfile); - return; + return 0; } /* blort to screen */ if (outputfile) { if (!strcmp(outputfile, "/dev/null")) { rmtemp(outfile); - return; + return 0; } filter_mode = (strcmp(outputfile, "-") == 0); strcpy(plainfile, outputfile); @@ -1223,15 +1283,22 @@ static void do_decrypt(char *cipherfile) if (!preserve_filename && filter_mode) { if (writePhantomOutput(outfile) < 0) { errorLvl = UNKNOWN_FILE_ERROR; - user_error(); + return -1; } rmtemp(outfile); - return; + return 0; } if (preserve_filename && preserved_name[0] != '\0') strcpy(plainfile, file_tail(preserved_name)); + if (quietmode) + { if (savetemp(outfile, plainfile) == NULL) + { errorLvl = UNKNOWN_FILE_ERROR; + return -1; + } + return 0; + } if (!verbose) /* if other filename messages were suppressed */ fprintf(pgpout,PSTR("\nPlaintext filename: %s"), plainfile); @@ -1275,26 +1342,29 @@ static void do_decrypt(char *cipherfile) { /* Special case--may be another ciphertext file, worth renaming */ fprintf(pgpout, PSTR("\n\007Output file '%s' may contain more ciphertext or signature."), plainfile ); - newname = maybe_force_extension( plainfile, CTX_EXTENSION ); + newname = maybe_force_extension( plainfile, PGP_EXTENSION ); } /* Possible ciphertext output file */ if (savetemp(outfile, (newname ? newname : plainfile)) == NULL) { errorLvl = UNKNOWN_FILE_ERROR; - user_error(); + return -1; } fprintf (pgpout, "\n"); - + return 0; } /* do_decrypt */ -static void do_keyopt(char keychar) +static int do_keyopt(char keychar) { char keyfile[MAX_PATH]; char ringfile[MAX_PATH]; + char *workfile; int status; - if (filter_mode && keychar != 'r') + if ((filter_mode || batchmode) + && (keychar == 'g' || keychar == 'e' || keychar == 'd' + || (keychar == 'r' && sign_flag))) { errorLvl = NO_BATCH; arg_error(); /* interactive process, no go in batch mode */ } @@ -1325,9 +1395,8 @@ static void do_keyopt(char keychar) if (status < 0) { fprintf(pgpout, PSTR("\007Keygen error. ") ); errorLvl = KEYGEN_ERROR; - user_error(); } - return; + return status; } /* Key generation */ /*-------------------------------------------------------*/ @@ -1356,24 +1425,21 @@ static void do_keyopt(char keychar) mcguffin[0] = '\0'; } - status = dokeycheck( mcguffin, ringfile, NULL ); + status = dokeycheck( mcguffin, ringfile, CHECK_ALL ); - errorLvl = 0; if (status < 0) { fprintf(pgpout, PSTR("\007Keyring check error. ") ); errorLvl = KEYRING_CHECK_ERROR; } - if (errorLvl == 0 && mcguffin[0] != '\0') - return; /* just checking a single user, dont do maintenance */ + if (status >= 0 && mcguffin[0] != '\0') + return status; /* just checking a single user, dont do maintenance */ - if ((status = maintenance(ringfile, 0)) < 0 && status != -7) + if ((status = maint_check(ringfile, 0)) < 0 && status != -7) { fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); errorLvl = KEYRING_CHECK_ERROR; } - if (errorLvl) - user_error(); - return; + return (status == -7 ? 0 : status); } /* Key check */ /*-------------------------------------------------------*/ @@ -1393,15 +1459,14 @@ static void do_keyopt(char keychar) if (! file_exists( ringfile )) default_extension( ringfile, PGP_EXTENSION ); - if ((status = maintenance(ringfile, + if ((status = maint_check(ringfile, MAINT_VERBOSE|(c_flag ? MAINT_CHECK : 0))) < 0) { if (status == -7) fprintf(pgpout, PSTR("File '%s' is not a public keyring\n"), ringfile); fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); errorLvl = KEYRING_CHECK_ERROR; - user_error(); } - return; + return status; } /* Maintenance pass */ /*-------------------------------------------------------*/ @@ -1420,6 +1485,8 @@ static void do_keyopt(char keychar) else { fprintf(pgpout, PSTR("\nA user ID is required to select the public key you want to sign. ")); + if (batchmode) /* not interactive, userid must be on command line */ + return -1; fprintf(pgpout, PSTR("\nEnter the public key's user ID: ")); getstring( mcguffin, 255, TRUE ); /* echo keyboard */ } @@ -1436,10 +1503,10 @@ added key on your secret keyring.\n")); status = signkey ( mcguffin, my_name, keyfile ); if (status >= 0) { - status = maintenance(keyfile, MAINT_SILENT); + status = maint_update(keyfile); if (status == -7) /* ringfile is a keyfile or secret keyring */ { fprintf(pgpout, "Warning: '%s' is not a public keyring\n", keyfile); - return; + return 0; } if (status < 0) fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); @@ -1448,15 +1515,14 @@ added key on your secret keyring.\n")); if (status < 0) { fprintf(pgpout, PSTR("\007Key signature error. ") ); errorLvl = KEY_SIGNATURE_ERROR; - user_error(); } - return; + return status; } /* Key signing */ /*-------------------------------------------------------*/ case 'd': - { /* Key compromise + { /* disable/revoke key Arguments: userid, keyfile */ @@ -1469,30 +1535,27 @@ added key on your secret keyring.\n")); strcpy( mcguffin, myArgv[2] ); /* Userid to sign */ else { - fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to revoke. ")); + fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to revoke or disable. ")); fprintf(pgpout, PSTR("\nEnter user ID: ")); getstring( mcguffin, 255, TRUE ); /* echo keyboard */ } CONVERT_TO_CANONICAL_CHARSET(mcguffin); - status = compromise ( mcguffin, keyfile ); + status = disable_key ( mcguffin, keyfile ); if (status >= 0) { - status = maintenance(keyfile, MAINT_SILENT); + status = maint_update(keyfile); if (status == -7) /* ringfile is a keyfile or secret keyring */ { fprintf(pgpout, "Warning: '%s' is not a public keyring\n", keyfile); - return; + return 0; } if (status < 0) fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); } if (status < 0) - { errorLvl = KEY_SIGNATURE_ERROR; - user_error(); - } - return; + return status; } /* Key compromise */ /*-------------------------------------------------------*/ @@ -1519,17 +1582,18 @@ added key on your secret keyring.\n")); status = dokeyedit( mcguffin, ringfile ); if (status >= 0) { - status = maintenance(ringfile, MAINT_SILENT); - if (status < 0 && status != -7) + status = maint_update(ringfile); + if (status == -7) + status = 0; /* ignore "not a public keyring" error */ + if (status < 0) fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); } - if (status < 0 && status != -7) + if (status < 0) { fprintf(pgpout, PSTR("\007Keyring edit error. ") ); errorLvl = KEYRING_EDIT_ERROR; - user_error(); } - return; + return status; } /* Key edit */ /*-------------------------------------------------------*/ @@ -1538,47 +1602,57 @@ added key on your secret keyring.\n")); Arguments: keyfile, ringfile */ - if (myArgc < 3) + if (myArgc < 3 && !filter_mode) arg_error(); - strncpy( keyfile, myArgv[2], sizeof(keyfile)-1 ); - + if (!filter_mode) { /* Get the keyfile from args */ + strncpy( keyfile, myArgv[2], sizeof(keyfile)-1 ); + #ifdef MSDOS - strlwr( keyfile ); + strlwr( keyfile ); #endif - if (! file_exists( keyfile )) - default_extension( keyfile, PGP_EXTENSION ); + if (! file_exists( keyfile )) + default_extension( keyfile, PGP_EXTENSION ); - if (! file_exists( keyfile )) - { fprintf(pgpout, PSTR("\n\007Key file '%s' does not exist.\n"), keyfile ); - errorLvl = NONEXIST_KEY_ERROR; - user_error(); + if (! file_exists( keyfile )) + { fprintf(pgpout, PSTR("\n\007Key file '%s' does not exist.\n"), keyfile ); + errorLvl = NONEXIST_KEY_ERROR; + return -1; + } + + workfile = keyfile; + + } else { + workfile = tempfile(TMP_WIPE|TMP_TMPDIR); + readPhantomInput(workfile); } - if (myArgc < 4) /* default key ring filename */ + if (myArgc < (filter_mode ? 3 : 4)) /* default key ring filename */ { byte ctb; - get_header_info_from_file(keyfile, &ctb, 1); + get_header_info_from_file(workfile, &ctb, 1); if (ctb == CTB_CERT_SECKEY) buildfilename(ringfile,SECRET_KEYRING_FILENAME); else buildfilename(ringfile,PUBLIC_KEYRING_FILENAME); } else - { strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 ); + { strncpy( ringfile, myArgv[(filter_mode ? 2 : 3)], sizeof(ringfile)-1 ); default_extension( ringfile, PGP_EXTENSION ); } #ifdef MSDOS strlwr( ringfile ); #endif - status = addto_keyring( keyfile, ringfile, FALSE ); + status = addto_keyring( workfile, ringfile); + + if (filter_mode) + rmtemp(workfile); if (status < 0) { fprintf(pgpout, PSTR("\007Keyring add error. ") ); errorLvl = KEYRING_ADD_ERROR; - user_error(); } - return; + return status; } /* Add key to key ring */ /*-------------------------------------------------------*/ @@ -1587,43 +1661,77 @@ added key on your secret keyring.\n")); Arguments: mcguffin, keyfile, ringfile */ - if (myArgc >= 5) /* default key ring filename */ - strncpy( ringfile, myArgv[4], sizeof(ringfile)-1 ); + if (myArgc >= (filter_mode ? 4 : 5)) /* default key ring filename */ + strncpy( ringfile, myArgv[(filter_mode ? 3 : 4)], sizeof(ringfile)-1 ); else buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); - if (myArgc >= 3) - strcpy( mcguffin, myArgv[2] ); /* Userid to extract */ + if (myArgc >= (filter_mode ? 2 : 3)) + { if (myArgv[2]) + /* Userid to extract */ + strcpy( mcguffin, myArgv[2] ); + else + strcpy( mcguffin, "" ); + } else { fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to extract. ")); + if (batchmode) /* not interactive, userid must be on command line */ + return -1; fprintf(pgpout, PSTR("\nEnter the key's user ID: ")); getstring( mcguffin, 255, TRUE ); /* echo keyboard */ } CONVERT_TO_CANONICAL_CHARSET(mcguffin); - if (myArgc >= 4) - { strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 ); + if (!filter_mode) { + if (myArgc >= 4) + { strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 ); + } + else + keyfile[0] = '\0'; + + workfile = keyfile; + } else { + workfile = tempfile(TMP_WIPE|TMP_TMPDIR); } - else - keyfile[0] = '\0'; #ifdef MSDOS - strlwr( keyfile ); + strlwr( workfile ); strlwr( ringfile ); #endif default_extension( ringfile, PGP_EXTENSION ); - status = extract_from_keyring( mcguffin, keyfile, - ringfile, emit_radix_64 ); + status = extract_from_keyring( mcguffin, workfile, + ringfile, (filter_mode ? FALSE : + emit_radix_64) ); if (status < 0) { fprintf(pgpout, PSTR("\007Keyring extract error. ") ); errorLvl = KEYRING_EXTRACT_ERROR; - user_error(); + if (filter_mode) + rmtemp(workfile); + return status; } - return; + + + if (filter_mode && !status) { + if (emit_radix_64) + { /* NULL for outputfile means write to stdout */ + if (armor_file(workfile, NULL, NULL, NULL) != 0) + { errorLvl = UNKNOWN_FILE_ERROR; + return -1; + } + } + else + if (writePhantomOutput(workfile) < 0) + { errorLvl = UNKNOWN_FILE_ERROR; + return -1; + } + rmtemp(workfile); + } + + return 0; } /* Extract key from key ring */ /*-------------------------------------------------------*/ @@ -1649,6 +1757,8 @@ remove certifying signatures from. ")); { fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to remove. ")); } + if (batchmode) /* not interactive, userid must be on command line */ + return -1; fprintf(pgpout, PSTR("\nEnter the key's user ID: ")); getstring( mcguffin, 255, TRUE ); /* echo keyboard */ } @@ -1664,22 +1774,17 @@ remove certifying signatures from. ")); { if (remove_sigs( mcguffin, ringfile ) < 0) { fprintf(pgpout, PSTR("\007Key signature remove error. ") ); errorLvl = KEYSIG_REMOVE_ERROR; - user_error(); + return -1; } } else /* Remove keyring */ { if (remove_from_keyring( NULL, mcguffin, ringfile, (boolean) (myArgc < 4) ) < 0) { fprintf(pgpout, PSTR("\007Keyring remove error. ") ); errorLvl = KEYRING_REMOVE_ERROR; - user_error(); + return -1; } } - if ((status = maintenance(ringfile, MAINT_SILENT)) < 0 && status != -7) - { fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); - errorLvl = KEYRING_CHECK_ERROR; - user_error(); - } - return; + return 0; } /* remove key signatures from userid */ /*-------------------------------------------------------*/ @@ -1715,19 +1820,18 @@ remove certifying signatures from. ")); default_extension( ringfile, PGP_EXTENSION ); /* If a second 'v' (keychar = V), show signatures too */ - if (view_keyring(mcguffin, ringfile, (boolean) (keychar == 'V'), c_flag) < 0) + status = view_keyring(mcguffin, ringfile, (boolean) (keychar == 'V'), c_flag); + if (status < 0) { fprintf(pgpout, PSTR("\007Keyring view error. ") ); errorLvl = KEYRING_VIEW_ERROR; - user_error(); } - return; + return status; } /* view key ring entries, with userid match */ - default: arg_error(); } - + return 0; } /* do_keyopt */ @@ -1736,9 +1840,12 @@ void user_error() /* comes here if user { fprintf(pgpout,PSTR("\nFor a usage summary, type: pgp -h\n")); fprintf(pgpout,PSTR("For more detailed help, consult the PGP User's Guide.\n")); - exitPGP(errorLvl); /* error exit */ + exitPGP(errorLvl ? errorLvl : 127); /* error exit */ } +#if defined(DEBUG) && defined(linux) +#include +#endif /* * exitPGP: wipes and removes temporary files, also tries to wipe * the stack. @@ -1751,6 +1858,14 @@ void exitPGP(int returnval) fprintf(pgpout, "exitPGP: exitcode = %d\n", returnval); memset(password, 0, sizeof(password)); cleanup_tmpf(); +#if defined(DEBUG) && defined(linux) + if (verbose) + { struct mstats mstat; + mstat = mstats(); + printf("%d chunks used (%d bytes) %d bytes total\n", + mstat.chunks_used, mstat.bytes_used, mstat.bytes_total); + } +#endif memset(buf, 0, sizeof(buf)); /* wipe stack */ #ifdef VMS /* @@ -1807,12 +1922,12 @@ static void usage() if (more_file(tmphelp) < 0) fprintf(pgpout,PSTR("\nUsage summary:\ \nTo encrypt a plaintext file with recipent's public key, type:\ -\n pgp -e textfile her_userid (produces textfile.pgp)\ +\n pgp -e textfile her_userid [other userids] (produces textfile.pgp)\ \nTo sign a plaintext file with your secret key:\ \n pgp -s textfile [-u your_userid] (produces textfile.pgp)\ \nTo sign a plaintext file with your secret key, and then encrypt it\ \n with recipent's public key, producing a .pgp file:\ -\n pgp -es textfile her_userid [-u your_userid]\ +\n pgp -es textfile her_userid [other userids] [-u your_userid]\ \nTo encrypt with conventional encryption only:\ \n pgp -c textfile\ \nTo decrypt or check a signature for a ciphertext (.pgp) file:\ @@ -1836,7 +1951,7 @@ static void key_usage() { fprintf(pgpout,PSTR("\nFor a usage summary, type: pgp -h\n")); fprintf(pgpout,PSTR("For more detailed help, consult the PGP User's Guide.\n")); } - else + else /* only use built-in help if there is no helpfile */ fprintf(pgpout,PSTR("\nKey management functions:\ \nTo generate your own unique public/secret key pair:\ \n pgp -kg\