Annotation of pgp/src/pgp.c, revision 1.1.1.8

1.1.1.8 ! root        1: /* #define TEMP_VERSION / * if defined, temporary experimental
        !             2:                            version of PGP */
        !             3: /* pgp.c -- main module for PGP.
        !             4:    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
        !             5: 
        !             6:    Synopsis:  PGP uses public-key encryption to protect E-mail. 
        !             7:    Communicate securely with people you've never met, with no secure
        !             8:    channels needed for prior exchange of keys.  PGP is well featured and
        !             9:    fast, with sophisticated key management, digital signatures, data
        !            10:    compression, and good ergonomic design.
        !            11: 
        !            12:    The original PGP version 1.0 was written by Philip Zimmermann, of
        !            13:    Phil's Pretty Good(tm) Software.  Many parts of later versions of 
        !            14:    PGP were developed by an international collaborative effort, 
        !            15:    involving a number of contributors, including major efforts by:
        !            16:    Branko Lankester <[email protected]>
        !            17:    Hal Finney <[email protected]>
        !            18:    Peter Gutmann <[email protected]>
        !            19:    Other contributors who ported or translated or otherwise helped include:
        !            20:    Jean-loup Gailly in France
        !            21:    Hugh Kennedy in Germany
        !            22:    Lutz Frank in Germany
        !            23:    Cor Bosman in The Netherlands
        !            24:    Felipe Rodriquez Svensson in The Netherlands
        !            25:    Armando Ramos in Spain
        !            26:    Miguel Angel Gallardo Ortiz in Spain
        !            27:    Harry Bush and Maris Gabalins in Latvia
        !            28:    Zygimantas Cepaitis in Lithuania
        !            29:    Alexander Smishlajev
        !            30:    Peter Suchkow and Andrew Chernov in Russia
        !            31:    David Vincenzetti in Italy
        !            32:    ...and others.
        !            33: 
        !            34: 
        !            35:    (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
        !            36:    The author assumes no liability for damages resulting from the use
        !            37:    of this software, even if the damage results from defects in this
        !            38:    software.  No warranty is expressed or implied.
        !            39: 
        !            40:    Note that while most PGP source modules bear Philip Zimmermann's
        !            41:    copyright notice, many of them have been revised or entirely written
        !            42:    by contributors who frequently failed to put their names in their
        !            43:    code.  Code that has been incorporated into PGP from other authors
        !            44:    was either originally published in the public domain or is used with
        !            45:    permission from the various authors.
        !            46: 
        !            47:    PGP is available for free to the public under certain restrictions.
        !            48:    See the PGP User's Guide (included in the release package) for
        !            49:    important information about licensing, patent restrictions on
        !            50:    certain algorithms, trademarks, copyrights, and export controls.
        !            51: 
        !            52: 
        !            53:    Philip Zimmermann may be reached at:
        !            54:    Boulder Software Engineering
        !            55:    3021 Eleventh Street
        !            56:    Boulder, Colorado 80304  USA
        !            57:    (303) 541-0140  (voice or FAX)
        !            58:    email:  [email protected]
        !            59: 
        !            60: 
        !            61:    PGP will run on MSDOS, Sun Unix, VAX/VMS, Ultrix, Atari ST, 
        !            62:    Commodore Amiga, and OS/2.  Note:  Don't try to do anything with 
        !            63:    this source code without looking at the PGP User's Guide.
        !            64: 
        !            65:    PGP combines the convenience of the Rivest-Shamir-Adleman (RSA)
        !            66:    public key cryptosystem with the speed of fast conventional
        !            67:    cryptographic algorithms, fast message digest algorithms, data
        !            68:    compression, and sophisticated key management.  And PGP performs 
        !            69:    the RSA functions faster than most other software implementations.  
        !            70:    PGP is RSA public key cryptography for the masses.
        !            71: 
        !            72:    Uses RSA Data Security, Inc. MD5 Message Digest Algorithm
        !            73:    as a hash for signatures.  Uses the ZIP algorithm for compression.
        !            74:    Uses the ETH IPES/IDEA algorithm for conventional encryption.
        !            75: 
        !            76:    PGP generally zeroes its used stack and memory areas before exiting.
        !            77:    This avoids leaving sensitive information in RAM where other users
        !            78:    could find it later.  The RSA library and keygen routines also
        !            79:    sanitize their own stack areas.  This stack sanitizing has not been
        !            80:    checked out under all the error exit conditions, when routines exit
        !            81:    abnormally.  Also, we must find a way to clear the C I/O library
        !            82:    file buffers, the disk buffers, and and cache buffers.
        !            83: 
        !            84:    Revisions:
        !            85:    Version 1.0 -  5 Jun 91
        !            86:    Version 1.4 - 19 Jan 92
        !            87:    Version 1.5 - 12 Feb 92
        !            88:    Version 1.6 - 24 Feb 92
        !            89:    Version 1.7 - 29 Mar 92
        !            90:    Version 1.8 - 23 May 92
        !            91:    Version 2.0 -  2 Sep 92
        !            92:    Version 2.1 -  6 Dec 92
        !            93:    Version 2.2 -  6 Mar 93
        !            94:    Version 2.3 - 13 Jun 93
        !            95:    Version 2.3a-  1 Jul 93
        !            96:    Version 2.4 -  6 Nov 93
        !            97:    Version 2.5 -  5 May 94
        !            98:    Version 2.6 - 22 May 94
        !            99: 
        !           100:    Modified: 12-Nov-92 HAJK
        !           101:    Add FDL stuff for VAX/VMS local mode. 
        !           102:  */
1.1.1.7   root      103: 
                    104: 
                    105: #include <ctype.h>
                    106: #ifndef AMIGA
                    107: #include <signal.h>
                    108: #endif
                    109: #include <stdio.h>
                    110: #include <stdlib.h>
                    111: #include <string.h>
1.1.1.8 ! root      112: 
        !           113: #ifdef __QNX__
        !           114: #include <sys/stat.h>
        !           115: #endif
        !           116: 
1.1.1.7   root      117: #include "system.h"
                    118: #include "mpilib.h"
                    119: #include "random.h"
                    120: #include "crypto.h"
                    121: #include "fileio.h"
                    122: #include "keymgmt.h"
                    123: #include "language.h"
                    124: #include "pgp.h"
                    125: #include "exitpgp.h"
                    126: #include "charset.h"
                    127: #include "getopt.h"
                    128: #include "config.h"
                    129: #include "keymaint.h"
                    130: #include "keyadd.h"
                    131: #include "rsaglue.h"
                    132: #ifdef  M_XENIX
                    133: char *strstr();
                    134: long time();
                    135: #endif
                    136: 
                    137: #ifdef MSDOS
1.1.1.8 ! root      138: #ifdef __ZTC__                 /* Extend stack for Zortech C */
        !           139: unsigned _stack_ = 24 * 1024;
1.1.1.7   root      140: #endif
                    141: #ifdef __TURBOC__
1.1.1.8 ! root      142: unsigned _stklen = 24 * 1024;
1.1.1.7   root      143: #endif
                    144: #endif
                    145: #define        STACK_WIPE      4096
                    146: 
                    147: /* Global filenames and system-wide file extensions... */
1.1.1.8 ! root      148: char rel_version[] = _LANG("2.6.1");   /* release version */
        !           149: static char rel_date[] = "29 Aug 94";  /* release date */
1.1.1.7   root      150: char PGP_EXTENSION[] = ".pgp";
                    151: char ASC_EXTENSION[] = ".asc";
                    152: char SIG_EXTENSION[] = ".sig";
                    153: char BAK_EXTENSION[] = ".bak";
                    154: static char HLP_EXTENSION[] = ".hlp";
                    155: char CONSOLE_FILENAME[] = "_CONSOLE";
                    156: static char HELP_FILENAME[] = "pgp.hlp";
                    157: 
                    158: /* These files use the environmental variable PGPPATH as a default path: */
                    159: char globalPubringName[MAX_PATH];
                    160: char globalSecringName[MAX_PATH];
                    161: char globalRandseedName[MAX_PATH];
                    162: char globalCommentString[128];
                    163: 
                    164: /* Flags which are global across the driver code files */
                    165: boolean verbose = FALSE;       /* -l option: display maximum information */
1.1.1.8 ! root      166: FILE *pgpout;                  /* Place for routine messages */
1.1.1.7   root      167: 
                    168: static void usage(void);
                    169: static void key_usage(void);
                    170: static void arg_error(void);
                    171: static void initsigs(void);
                    172: static int do_keyopt(char);
                    173: static int do_decrypt(char *);
                    174: static void do_armorfile(char *);
                    175: 
                    176: 
1.1.1.8 ! root      177: /* Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK.
        !           178:    Lha(rc) is handled specially in the code; it is missing from the
        !           179:    compressSig structure intentionally.  If more formats are added,
        !           180:    put them before lharc to keep the code consistent.
        !           181:  */
        !           182: static char *compressSig[] =
        !           183: {"PK\03\04", "ZOO ", "GIF8", "\352\140",
        !           184:  "HPAK", "\037\213", "\037\235", "\032\013", "\032HP%"
1.1.1.7   root      185:        /* lharc is special, must be last */ };
1.1.1.8 ! root      186: static char *compressName[] =
        !           187: {"PKZIP", "Zoo", "GIF", "Arj",
        !           188:  "Hpack", "gzip", "compressed", "PAK", "Hyper",
        !           189:  "LHarc"};
        !           190: static char *compressExt[] =
        !           191: {".zip", ".zoo", ".gif", ".arj",
        !           192:  ".hpk", ".z", ".Z", ".pak", ".hyp",
        !           193:  ".lzh"};
1.1.1.7   root      194: 
                    195: /* "\032\0??", "ARC", ".arc" */
                    196: 
                    197: /* Returns file signature type from a number of popular compression formats
                    198:    or -1 if no match */
1.1.1.8 ! root      199: int compressSignature(byte * header)
1.1.1.7   root      200: {
1.1.1.8 ! root      201:     int i;
1.1.1.7   root      202: 
1.1.1.8 ! root      203:     for (i = 0; i < sizeof(compressSig) / sizeof(*compressSig); i++)
        !           204:        if (!strncmp((char *) header, compressSig[i], strlen(compressSig[i])))
        !           205:            return i;
        !           206:     /* Special check for lharc files */
        !           207:     if (header[2] == '-' && header[3] == 'l' &&
        !           208:        (header[4] == 'z' || header[4] == 'h') &&
        !           209:        header[6] == '-')
        !           210:        return i;
        !           211:     return -1;
        !           212: }                              /* compressSignature */
1.1.1.7   root      213: 
                    214: /* returns TRUE iff file is likely to be compressible */
1.1.1.8 ! root      215: static boolean file_compressible(char *filename)
1.1.1.7   root      216: {
1.1.1.8 ! root      217:     byte header[8];
        !           218:     get_header_info_from_file(filename, header, 8);
        !           219:     if (compressSignature(header) >= 0)
        !           220:        return FALSE;           /* probably not compressible */
        !           221:     return TRUE;               /* possibly compressible */
        !           222: }                              /* compressible */
1.1.1.7   root      223: 
                    224: 
                    225: /* Possible error exit codes - not all of these are used.  Note that we
                    226:    don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE.  To make things
                    227:    easier for compilers which don't support enum we use #defines */
                    228: 
                    229: #define EXIT_OK                                0
                    230: #define INVALID_FILE_ERROR             1
                    231: #define FILE_NOT_FOUND_ERROR           2
                    232: #define UNKNOWN_FILE_ERROR             3
                    233: #define NO_BATCH                       4
                    234: #define BAD_ARG_ERROR                  5
                    235: #define INTERRUPT                      6
                    236: #define OUT_OF_MEM                     7
                    237: 
                    238: /* Keyring errors: Base value = 10 */
                    239: #define KEYGEN_ERROR                   10
                    240: #define NONEXIST_KEY_ERROR             11
                    241: #define KEYRING_ADD_ERROR              12
                    242: #define KEYRING_EXTRACT_ERROR          13
                    243: #define KEYRING_EDIT_ERROR             14
                    244: #define KEYRING_VIEW_ERROR             15
                    245: #define KEYRING_REMOVE_ERROR           16
                    246: #define KEYRING_CHECK_ERROR            17
                    247: #define KEY_SIGNATURE_ERROR            18
                    248: #define KEYSIG_REMOVE_ERROR            19
                    249: 
                    250: /* Encode errors: Base value = 20 */
                    251: #define SIGNATURE_ERROR                        20
                    252: #define RSA_ENCR_ERROR                 21
                    253: #define ENCR_ERROR                     22
                    254: #define COMPRESS_ERROR                 23
                    255: 
                    256: /* Decode errors: Base value = 30 */
                    257: #define SIGNATURE_CHECK_ERROR          30
                    258: #define RSA_DECR_ERROR                 31
                    259: #define DECR_ERROR                     32
                    260: #define DECOMPRESS_ERROR               33
                    261: 
                    262: 
                    263: #ifdef SIGINT
1.1.1.8 ! root      264: 
1.1.1.7   root      265: /* This function is called if a BREAK signal is sent to the program.  In this
                    266:    case we zap the temporary files.
1.1.1.8 ! root      267:  */
        !           268: void breakHandler(int sig)
1.1.1.7   root      269: {
                    270: #ifdef UNIX
1.1.1.8 ! root      271:     if (sig == SIGPIPE) {
        !           272:        signal(SIGPIPE, SIG_IGN);
1.1.1.7   root      273:        exitPGP(INTERRUPT);
1.1.1.8 ! root      274:     }
        !           275:     if (sig != SIGINT)
        !           276:        fprintf(stderr, "\nreceived signal %d\n", sig);
        !           277:     else
        !           278: #endif
        !           279:        fprintf(pgpout, LANG("\nStopped at user request\n"));
        !           280:     exitPGP(INTERRUPT);
1.1.1.7   root      281: }
                    282: #endif
                    283: 
1.1.1.8 ! root      284: /* Clears screen and homes the cursor. */
1.1.1.7   root      285: static void clearscreen(void)
1.1.1.8 ! root      286: {
        !           287:     fprintf(pgpout, "\n\033[0;0H\033[J\r           \r");  /* ANSI sequence. */
        !           288:     fflush(pgpout);
1.1.1.7   root      289: }
                    290: 
1.1.1.8 ! root      291: /* We had to process the config file first to possibly select the 
        !           292:    foreign language to translate the sign-on line that follows... */
1.1.1.7   root      293: static void signon_msg(void)
1.1.1.8 ! root      294: {    
        !           295:     word32 tstamp;
        !           296:     /* display message only once to allow calling multiple times */
        !           297:     static boolean printed = FALSE;
        !           298: 
        !           299:     if (quietmode || printed)
        !           300:        return;
        !           301:     printed = TRUE;
        !           302:     fprintf(stderr,
        !           303: LANG("Pretty Good Privacy(tm) %s - Public-key encryption for the masses.\n"),
        !           304:            rel_version);
1.1.1.7   root      305: #ifdef TEMP_VERSION
1.1.1.8 ! root      306:     fputs(
        !           307: "Internal development version only - not for general release.\n", stderr);
1.1.1.7   root      308: #endif
1.1.1.8 ! root      309:     fprintf(stderr,
        !           310: LANG("(c) 1990-1994 Philip Zimmermann, Phil's Pretty Good Software. %s\n"),
        !           311:            rel_date);
        !           312:     fputs(LANG(signon_legalese), stderr);
        !           313:     fputs(
        !           314: LANG("Export of this software may be restricted by the U.S. government.\n"),
        !           315:          stderr);
1.1.1.7   root      316: 
1.1.1.8 ! root      317:     get_timestamp((byte *) & tstamp);  /* timestamp points to tstamp */
        !           318:     fprintf(pgpout, "Current time: %s\n", ctdate(&tstamp));
1.1.1.7   root      319: }
                    320: 
                    321: 
1.1.1.8 ! root      322: #ifdef TEMP_VERSION            /* temporary experimental version of PGP */
1.1.1.7   root      323: #include <time.h>
                    324: #define CREATION_DATE 0x2DC079A4ul
1.1.1.8 ! root      325:                                /* CREATION_DATE is
        !           326:                                   Fri Apr 29 03:06:12 1994 UTC */
1.1.1.7   root      327: #define LIFESPAN       ((unsigned long) 60L * (unsigned long) 86400L)
1.1.1.8 ! root      328:                                /* LIFESPAN is 60 days */
        !           329: 
1.1.1.7   root      330: /* If this is an experimental version of PGP, cut its life short */
1.1.1.8 ! root      331: void check_expiration_date(void)
1.1.1.7   root      332: {
1.1.1.8 ! root      333:     if (get_timestamp(NULL) > (CREATION_DATE + LIFESPAN)) {
        !           334:        fprintf(stderr,
        !           335:                "\n\007This experimental version of PGP has expired.\n");
        !           336:        exit(-1);               /* error exit */
        !           337:     }
        !           338: }                              /* check_expiration_date */
        !           339: #else                          /* no expiration date */
        !           340: #define check_expiration_date()        /* null statement */
        !           341: #endif                         /* TEMP_VERSION */
1.1.1.7   root      342: 
                    343: /* -f means act as a unix-style filter */
                    344: /* -i means internalize extended file attribute information, only supported
                    345:  *          between like (or very compatible) operating systems. */
                    346: /* -l means show longer more descriptive diagnostic messages */
                    347: /* -m means display plaintext output on screen, like unix "more" */
                    348: /* -d means decrypt only, leaving inner signature wrapping intact */
                    349: /* -t means treat as pure text and convert to canonical text format */
                    350: 
                    351: /* Used by getopt function... */
                    352: #define OPTIONS "abcdefghiklmo:prstu:vwxz:ABCDEFGHIKLMO:PRSTU:VWX?"
                    353: extern int optind;
                    354: extern char *optarg;
                    355: 
1.1.1.8 ! root      356: boolean emit_radix_64 = FALSE; /* set by config file */
1.1.1.7   root      357: static boolean sign_flag = FALSE;
                    358: boolean moreflag = FALSE;
                    359: boolean filter_mode = FALSE;
                    360: static boolean preserve_filename = FALSE;
                    361: static boolean decrypt_only_flag = FALSE;
                    362: static boolean de_armor_only = FALSE;
                    363: static boolean strip_sig_flag = FALSE;
                    364: boolean clear_signatures = TRUE;
                    365: boolean strip_spaces;
                    366: static boolean c_flag = FALSE;
                    367: boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? */
                    368: boolean batchmode = FALSE;     /* if TRUE: don't ask questions */
                    369: boolean quietmode = FALSE;
                    370: boolean force_flag = FALSE;    /* overwrite existing file without asking */
                    371: boolean pkcs_compat = 1;
1.1.1.8 ! root      372: #ifdef VMS                     /* kludge for those stupid VMS variable-length
        !           373:                                   text records */
        !           374: char literal_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal
        !           375:                                   packet */
        !           376: #else                          /* not VMS */
        !           377: char literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal
        !           378:                                    packet */
        !           379: #endif                         /* not VMS */
1.1.1.7   root      380: /* my_name is substring of default userid for secret key to make signatures */
1.1.1.8 ! root      381: char my_name[256] = "\0";      /* null my_name means take first userid
        !           382:                                   in ring */
1.1.1.7   root      383: boolean keepctx = FALSE;       /* TRUE means keep .ctx file on decrypt */
                    384: /* Ask for each key separately if it should be added to the keyring */
                    385: boolean interactive_add = FALSE;
1.1.1.8 ! root      386: boolean compress_enabled = TRUE; /* attempt compression before encryption */
        !           387: long timeshift = 0L;           /* seconds from GMT timezone */
1.1.1.7   root      388: boolean legal_kludge;
                    389: int version_byte = VERSION_BYTE_OLD;
                    390: boolean nomanual = 0;
                    391: 
                    392: 
                    393: static boolean attempt_compression; /* attempt compression before encryption */
                    394: static char *outputfile = NULL;
                    395: static int errorLvl = EXIT_OK;
1.1.1.8 ! root      396: static char mcguffin[256];     /* userid search tag */
1.1.1.7   root      397: boolean signature_checked = FALSE;
                    398: char plainfile[MAX_PATH];
                    399: int myArgc = 2;
                    400: char **myArgv;
                    401: struct hashedpw *passwds = 0, *keypasswds = 0;
                    402: static struct hashedpw **passwdstail = &passwds;
                    403: 
                    404: int main(int argc, char *argv[])
                    405: {
1.1.1.8 ! root      406:     int status, opt;
        !           407:     char *inputfile = NULL;
        !           408:     char **recipient = NULL;
        !           409:     char **mcguffins;
        !           410:     char *workfile, *tempf;
        !           411:     boolean nestflag = FALSE;
        !           412:     boolean decrypt_mode = FALSE;
        !           413:     boolean wipeflag = FALSE;
        !           414:     boolean armor_flag = FALSE;        /* -a option */
        !           415:     boolean separate_signature = FALSE;
        !           416:     boolean keyflag = FALSE;
        !           417:     boolean encrypt_flag = FALSE;
        !           418:     boolean conventional_flag = FALSE;
        !           419:     char *clearfile = NULL;
        !           420:     char *literal_file = NULL;
        !           421:     char literal_file_name[MAX_PATH];
        !           422:     char cipherfile[MAX_PATH];
        !           423:     char keychar = '\0';
1.1.1.7   root      424:     char *p;
1.1.1.8 ! root      425:     byte ctb;
        !           426:     struct hashedpw *hpw;
1.1.1.7   root      427: 
1.1.1.8 ! root      428:     /* Initial messages to stderr */
        !           429:     pgpout = stderr;
1.1.1.7   root      430: 
                    431: #ifdef DEBUG1
1.1.1.8 ! root      432:     verbose = TRUE;
1.1.1.7   root      433: #endif
1.1.1.8 ! root      434:     /* The various places one can get passwords from.
        !           435:      * We accumulate them all into two lists.  One is
        !           436:      * to try on keys only, and is stored in no particular
        !           437:      * order, while the other is of unknown purpose so
        !           438:      * far (they may be used for conventional encryption
        !           439:      * or decryption as well), and are kept in a specific
        !           440:      * order.  If any password in the general list is found
        !           441:      * to decode a key, it is moved to the key list.
        !           442:      * The general list is not grown after initialization,
        !           443:      * so the tail pointer is not used after this.
        !           444:      */
        !           445: 
        !           446:     if ((p = getenv("PGPPASS")) != NULL) {
        !           447:        hpw = xmalloc(sizeof(struct hashedpw));
        !           448:        hashpass(p, strlen(p), hpw->hash);
        !           449:        /* Add to linked list of key passwords */
        !           450:        hpw->next = keypasswds;
        !           451:        keypasswds = hpw;
        !           452:     }
        !           453:     /* The -z "password" option should be used instead of PGPPASS if
        !           454:      * the environment can be displayed with the ps command (eg. BSD).
        !           455:      * If the system does not allow overwriting of the command line
        !           456:      * argument list but if it has a "hidden" environment, PGPPASS
        !           457:      * should be used.
        !           458:      */
        !           459:     for (opt = 1; opt < argc; ++opt) {
        !           460:        p = argv[opt];
        !           461:        if (p[0] != '-' || p[1] != 'z')
        !           462:            continue;
        !           463:        /* Accept either "-zpassword" or "-z password" */
        !           464:        p += 2;
        !           465:        if (!*p)
        !           466:            p = argv[++opt];
        !           467:        /* p now points to password */
        !           468:        if (!p)
        !           469:            break;              /* End of arg list - ignore */
        !           470:        hpw = xmalloc(sizeof(struct hashedpw));
        !           471:        hashpass(p, strlen(p), hpw->hash);
        !           472:        /* Wipe password */
        !           473:        while (*p)
        !           474:            *p++ = ' ';
        !           475:        /* Add to tail of linked list of passwords */
        !           476:        hpw->next = 0;
        !           477:        *passwdstail = hpw;
        !           478:        passwdstail = &hpw->next;
        !           479:     }
        !           480:     /*
        !           481:      * If PGPPASSFD is set in the environment try to read the password
        !           482:      * from this file descriptor.  If you set PGPPASSFD to 0 pgp will
        !           483:      * use the first line read from stdin as password.
        !           484:      */
        !           485:     if ((p = getenv("PGPPASSFD")) != NULL) {
        !           486:        int passfd;
        !           487:        if (*p && (passfd = atoi(p)) >= 0) {
        !           488:            char pwbuf[256];
        !           489:            p = pwbuf;
        !           490:            while (read(passfd, p, 1) == 1 && *p != '\n')
        !           491:                ++p;
        !           492:            hpw = xmalloc(sizeof(struct hashedpw));
        !           493:            hashpass(pwbuf, p - pwbuf, hpw->hash);
        !           494:            memset(pwbuf, 0, p - pwbuf);
        !           495:            /* Add to tail of linked list of passwords */
        !           496:            hpw->next = 0;
        !           497:            *passwdstail = hpw;
        !           498:            passwdstail = &hpw->next;
        !           499:        }
        !           500:     }
        !           501:     /* Process the config file.  The following override each other:
        !           502:        - Hard-coded defualts
        !           503:        - The system config file
        !           504:        - Hard-coded defaults for security-critical things
        !           505:        - The user's config file
        !           506:        - Environment variables
        !           507:        - Command-line options.
        !           508:      */
        !           509:     opt = 0;                   /* Number of config files read */
        !           510: #ifdef PGP_SYSTEM_DIR
        !           511:     strcpy(mcguffin, PGP_SYSTEM_DIR);
        !           512:     strcat(mcguffin, "config.txt");
        !           513:     if (access(mcguffin, 0) == 0) {
        !           514:        opt++;
1.1.1.7   root      515:        /*
1.1.1.8 ! root      516:         * Note: errors here are NOT fatal, so that people
        !           517:         * can use PGP with a corrputed system file.
1.1.1.7   root      518:         */
1.1.1.8 ! root      519:        processConfigFile(mcguffin);
        !           520:     }
1.1.1.7   root      521: #endif
                    522: 
1.1.1.8 ! root      523:     /*
        !           524:      * These must be personal; the system config file may not
        !           525:      * influence them.
        !           526:      */
        !           527:     buildfilename(globalPubringName, "pubring.pgp");
        !           528:     buildfilename(globalSecringName, "secring.pgp");
        !           529:     buildfilename(globalRandseedName, "randseed.bin");
        !           530:     my_name[0] = '\0';
        !           531: 
        !           532:     /* Process the config file first.  Any command-line arguments will
        !           533:        override the config file settings */
        !           534:     buildfilename(mcguffin, "config.txt");
        !           535:     if (access(mcguffin, 0) == 0) {
        !           536:        opt++;
        !           537:        if (processConfigFile(mcguffin) < 0)
        !           538:            exit(BAD_ARG_ERROR);
        !           539:     }
        !           540:     if (!opt)
        !           541:        fprintf(pgpout, LANG("\007No configuration file found.\n"));
        !           542: 
        !           543:     init_charset();
        !           544: 
        !           545: #ifdef MSDOS                   /* only on MSDOS systems */
        !           546:     if ((p = getenv("TZ")) == NULL || *p == '\0') {
        !           547:        fprintf(pgpout,LANG("\007WARNING: Environmental variable TZ is not \
        !           548: defined, so GMT timestamps\n\
1.1.1.7   root      549: may be wrong.  See the PGP User's Guide to properly define TZ\n\
                    550: in AUTOEXEC.BAT file.\n"));
1.1.1.8 ! root      551:     }
        !           552: #endif                         /* MSDOS */
1.1.1.7   root      553: 
                    554: #ifdef VMS
                    555: #define TEMP "SYS$SCRATCH"
                    556: #else
                    557: #define TEMP "TMP"
1.1.1.8 ! root      558: #endif                         /* VMS */
        !           559:     if ((p = getenv(TEMP)) != NULL && *p != '\0')
        !           560:        settmpdir(p);
        !           561: 
        !           562:     /* Turn on incompatibility as of 1 September 1994 (GMT) */
        !           563:     legal_kludge = (get_timestamp(NULL) >= 0x2e651980);
        !           564: 
        !           565:     if ((myArgv = (char **) malloc((argc + 2) * sizeof(char **))) == NULL) {
        !           566:        fprintf(stderr, LANG("\n\007Out of memory.\n"));
        !           567:        exitPGP(7);
        !           568:     }
        !           569:     myArgv[0] = NULL;
        !           570:     myArgv[1] = NULL;
        !           571: 
        !           572:     /* Process all the command-line option switches: */
        !           573:     while (optind < argc) {
        !           574:        /*
        !           575:         * Allow random order of options and arguments (like GNU getopt)
        !           576:         * NOTE: this does not work with GNU getopt, use getopt.c from
        !           577:         * the PGP distribution.
        !           578:         */
        !           579:        if ((opt = pgp_getopt(argc, argv, OPTIONS)) == EOF) {
        !           580:            if (optind == argc) /* -- at end */
        !           581:                break;
        !           582:            myArgv[myArgc++] = argv[optind++];
        !           583:            continue;
        !           584:        }
        !           585:        opt = to_lower(opt);
        !           586:        if (keyflag && (keychar == '\0' || (keychar == 'v' && opt == 'v'))) {
        !           587:            if (keychar == 'v')
        !           588:                keychar = 'V';
        !           589:            else
        !           590:                keychar = opt;
        !           591:            continue;
        !           592:        }
        !           593:        switch (opt) {
        !           594:        case 'a':
        !           595:            armor_flag = TRUE;
        !           596:            emit_radix_64 = 1;
        !           597:            break;
        !           598:        case 'b':
        !           599:            separate_signature = strip_sig_flag = TRUE;
        !           600:            break;
        !           601:        case 'c':
        !           602:            encrypt_flag = conventional_flag = TRUE;
        !           603:            c_flag = TRUE;
        !           604:            break;
        !           605:        case 'd':
        !           606:            decrypt_only_flag = TRUE;
        !           607:            break;
        !           608:        case 'e':
        !           609:            encrypt_flag = TRUE;
        !           610:            break;
        !           611:        case 'f':
        !           612:            filter_mode = TRUE;
        !           613:            break;
        !           614:        case '?':
        !           615:        case 'h':
        !           616:            usage();
        !           617:            break;
1.1.1.7   root      618: #ifdef VMS
1.1.1.8 ! root      619:        case 'i':
        !           620:            literal_mode = MODE_LOCAL;
        !           621:            break;
        !           622: #endif                         /* VMS */
        !           623:        case 'k':
        !           624:            keyflag = TRUE;
        !           625:            break;
        !           626:        case 'l':
        !           627:            verbose = TRUE;
        !           628:            break;
        !           629:        case 'm':
        !           630:            moreflag = TRUE;
        !           631:            break;
        !           632:        case 'p':
        !           633:            preserve_filename = TRUE;
        !           634:            break;
        !           635:        case 'o':
        !           636:            outputfile = optarg;
        !           637:            break;
        !           638:        case 's':
        !           639:            sign_flag = TRUE;
        !           640:            break;
        !           641:        case 't':
        !           642:            literal_mode = MODE_TEXT;
        !           643:            break;
        !           644:        case 'u':
        !           645:            strncpy(my_name, optarg, sizeof(my_name) - 1);
        !           646:            CONVERT_TO_CANONICAL_CHARSET(my_name);
        !           647:            break;
        !           648:        case 'w':
        !           649:            wipeflag = TRUE;
        !           650:            break;
        !           651:        case 'z':
        !           652:            break;
        !           653:            /* '+' special option: does not require - */
        !           654:        case '+':
        !           655:            if (processConfigLine(optarg) == 0)
        !           656:                break;
        !           657:            fprintf(stderr, "\n");
        !           658:            /* fallthrough */
        !           659:        default:
        !           660:            arg_error();
1.1.1.7   root      661:        }
1.1.1.8 ! root      662:     }
        !           663:     myArgv[myArgc] = NULL;     /* Just to make it NULL terminated */
1.1.1.7   root      664: 
1.1.1.8 ! root      665:     if (keyflag && keychar == '\0')
        !           666:        key_usage();
1.1.1.7   root      667: 
1.1.1.8 ! root      668:     signon_msg();
        !           669:     check_expiration_date();   /* hobble any experimental version */
1.1.1.7   root      670: 
1.1.1.8 ! root      671:     if (legal_kludge)
        !           672:        version_byte = VERSION_BYTE_KLUDGE;
1.1.1.7   root      673: 
                    674: #if 1
1.1.1.8 ! root      675:     /* At request of Peter Simons, use stderr always. Sounds reasonable. */
        !           676:     /* JIS: Put this code back in... removing it broke too many things */
        !           677:     if (!filter_mode && (outputfile == NULL || strcmp(outputfile, "-")))
        !           678:        pgpout = stdout;
1.1.1.7   root      679: #endif
                    680: 
                    681: #if 0
1.1.1.8 ! root      682:     /* Check for the existence of the manual */
        !           683:     /* Commented out to make PGP less facist */
        !           684:     if (manuals_missing()) {
        !           685:        fputs(
        !           686: LANG("\nWARNING: PGP User's Guide not found.  PGP should not be\n\
1.1.1.7   root      687: distributed without the User's Guide.\n"), pgpout);
1.1.1.8 ! root      688:     }
1.1.1.7   root      689: #endif
1.1.1.8 ! root      690: 
1.1.1.7   root      691: 
                    692: #if defined(UNIX) || defined(VMS)
1.1.1.8 ! root      693:     umask(077);                        /* Make files default to private */
1.1.1.7   root      694: #endif
                    695: 
1.1.1.8 ! root      696:     initsigs();                        /* Catch signals */
        !           697:     noise();                   /* Start random number generation */
1.1.1.7   root      698: 
1.1.1.8 ! root      699:     if (keyflag) {
        !           700:        status = do_keyopt(keychar);
        !           701:        if (status < 0)
        !           702:            user_error();
        !           703:        exitPGP(status);
        !           704:     }
        !           705:     /* -db means break off signature certificate into separate file */
        !           706:     if (decrypt_only_flag && strip_sig_flag)
        !           707:        decrypt_only_flag = FALSE;
        !           708: 
        !           709:     if (decrypt_only_flag && armor_flag)
        !           710:        decrypt_mode = de_armor_only = TRUE;
        !           711: 
        !           712:     if (outputfile != NULL)
        !           713:        preserve_filename = FALSE;
        !           714: 
        !           715:     if (!sign_flag && !encrypt_flag && !conventional_flag && !armor_flag) {
        !           716:        if (wipeflag) {         /* wipe only */
        !           717:            if (myArgc != 3)
        !           718:                arg_error();    /* need one argument */
        !           719:            if (wipefile(myArgv[2]) == 0 && remove(myArgv[2]) == 0) {
        !           720:                fprintf(pgpout,
        !           721:                        LANG("\nFile %s wiped and deleted. "), myArgv[2]);
        !           722:                fprintf(pgpout, "\n");
        !           723:                exitPGP(EXIT_OK);
        !           724:            }
        !           725:            exitPGP(UNKNOWN_FILE_ERROR);
        !           726:        }
        !           727:        /* decrypt if none of the -s -e -c -a -w options are specified */
        !           728:        decrypt_mode = TRUE;
        !           729:     }
        !           730:     if (myArgc == 2) {         /* no arguments */
1.1.1.7   root      731: #ifdef UNIX
1.1.1.8 ! root      732:        if (!filter_mode && !isatty(fileno(stdin))) {
        !           733:            /* piping to pgp without arguments and no -f:
        !           734:             * switch to filter mode but don't write output to stdout
        !           735:             * if it's a tty, use the preserved filename */
        !           736:            if (!moreflag)
        !           737:                pgpout = stderr;
        !           738:            filter_mode = TRUE;
        !           739:            if (isatty(fileno(stdout)) && !moreflag)
        !           740:                preserve_filename = TRUE;
        !           741:        }
        !           742: #endif
        !           743:        if (!filter_mode) {
        !           744:            if (quietmode) {
        !           745:                quietmode = FALSE;
        !           746:                signon_msg();
        !           747:            }
        !           748:            fprintf(pgpout,
        !           749: LANG("\nFor details on licensing and distribution, see the PGP User's Guide.\
1.1.1.7   root      750: \nFor other cryptography products and custom development services, contact:\
1.1.1.8 ! root      751: \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, \
        !           752: phone +1 303 541-0140\n"));
        !           753:            if (strcmp((p = LANG("@translator@")), "@translator@"))
        !           754:                fprintf(pgpout, p);
        !           755:            fprintf(pgpout, LANG("\nFor a usage summary, type:  pgp -h\n"));
        !           756:            exit(BAD_ARG_ERROR);        /* error exit */
1.1.1.7   root      757:        }
1.1.1.8 ! root      758:     } else {
1.1.1.7   root      759:        if (filter_mode) {
1.1.1.8 ! root      760:            recipient = &myArgv[2];
1.1.1.7   root      761:        } else {
1.1.1.8 ! root      762:            inputfile = myArgv[2];
        !           763:            recipient = &myArgv[3];
1.1.1.7   root      764:        }
1.1.1.8 ! root      765:     }
1.1.1.7   root      766: 
                    767: 
1.1.1.8 ! root      768:     if (filter_mode) {
        !           769:        inputfile = "stdin";
        !           770:     } else {
        !           771:        if (decrypt_mode && no_extension(inputfile)) {
        !           772:            strcpy(cipherfile, inputfile);
        !           773:            force_extension(cipherfile, ASC_EXTENSION);
        !           774:            if (file_exists(cipherfile)) {
        !           775:                inputfile = cipherfile;
        !           776:            } else {
        !           777:                force_extension(cipherfile, PGP_EXTENSION);
        !           778:                if (file_exists(cipherfile)) {
        !           779:                    inputfile = cipherfile;
        !           780:                } else {
        !           781:                    force_extension(cipherfile, SIG_EXTENSION);
        !           782:                    if (file_exists(cipherfile))
        !           783:                        inputfile = cipherfile;
        !           784:                }
        !           785:            }
        !           786:        }
        !           787:        if (!file_exists(inputfile)) {
        !           788:            fprintf(pgpout,
        !           789:                    LANG("\007File [%s] does not exist.\n"), inputfile);
        !           790:            errorLvl = FILE_NOT_FOUND_ERROR;
        !           791:            user_error();
        !           792:        }
        !           793:     }
        !           794: 
        !           795:     if (strlen(inputfile) >= (unsigned) MAX_PATH - 4) {
        !           796:        fprintf(pgpout, 
        !           797:                LANG("\007Invalid filename: [%s] too long\n"), inputfile);
        !           798:        errorLvl = INVALID_FILE_ERROR;
        !           799:        user_error();
        !           800:     }
        !           801:     strcpy(plainfile, inputfile);
1.1.1.7   root      802: 
1.1.1.8 ! root      803:     if (filter_mode) {
        !           804:        setoutdir(NULL);        /* NULL means use tmpdir */
        !           805:     } else {
        !           806:        if (outputfile)
        !           807:            setoutdir(outputfile);
1.1.1.7   root      808:        else
1.1.1.8 ! root      809:            setoutdir(inputfile);
        !           810:     }
1.1.1.7   root      811: 
1.1.1.8 ! root      812:     if (filter_mode) {
        !           813:        workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !           814:        readPhantomInput(workfile);
        !           815:     } else {
        !           816:        workfile = inputfile;
        !           817:     }
        !           818: 
        !           819:     get_header_info_from_file(workfile, &ctb, 1);
        !           820:     if (decrypt_mode) {
        !           821:        strip_spaces = FALSE;
        !           822:        if (!is_ctb(ctb) && is_armor_file(workfile, 0L))
        !           823:            do_armorfile(workfile);
        !           824:        else if (do_decrypt(workfile) < 0)
        !           825:            user_error();
        !           826:        if (batchmode && !signature_checked)
        !           827:            exitPGP(1);         /* alternate success, file did not have sig. */
        !           828:        else
        !           829:            exitPGP(EXIT_OK);
        !           830:     }
        !           831:     /*
        !           832:      * See if plaintext input file was actually created by PGP earlier--
        !           833:      * If it was, maybe we should NOT encapsulate it in a literal packet.
        !           834:      * Otherwise, always encapsulate it.
        !           835:      */
        !           836:     if (force_flag)            /* for use with batchmode, force nesting */
        !           837:        nestflag = legal_ctb(ctb);
        !           838:     else
        !           839:        nestflag = FALSE;       /* First assume we will encapsulate it. */
        !           840: 
        !           841:     if (!batchmode && !filter_mode && legal_ctb(ctb)) {
        !           842:        /*      Special case--may be a PGP-created packet, so
        !           843:           do we inhibit encapsulation in literal packet? */
        !           844:        fprintf(pgpout,
        !           845: LANG("\n\007Input file '%s' looks like it may have been created by PGP. "),
        !           846:                inputfile);
        !           847:        fprintf(pgpout,
        !           848: LANG("\nIs it safe to assume that it was created by PGP (y/N)? "));
        !           849:        nestflag = getyesno('n');
        !           850:     }                          /* Possible ciphertext input file */
        !           851:     if (moreflag) {            /* special name to cause printout on decrypt */
        !           852:        strcpy(literal_file_name, CONSOLE_FILENAME);
        !           853:        literal_mode = MODE_TEXT;       /* will check for text file later */
        !           854:     } else {
        !           855:        strcpy(literal_file_name, inputfile);
1.1.1.7   root      856: #ifdef MSDOS
1.1.1.8 ! root      857:        strlwr(literal_file_name);
1.1.1.7   root      858: #endif
1.1.1.8 ! root      859:     }
        !           860:     literal_file = literal_file_name;
1.1.1.7   root      861: 
1.1.1.8 ! root      862:     /*      Make sure non-text files are not accidentally converted 
        !           863:        to canonical text.  This precaution should only be followed 
        !           864:        for US ASCII text files, since European text files may have 
        !           865:        8-bit character codes and still be legitimate text files 
        !           866:        suitable for conversion to canonical (CR/LF-terminated) 
        !           867:        text format. */
        !           868:     if (literal_mode == MODE_TEXT && !is_text_file(workfile)) {
        !           869:        fprintf(pgpout,
        !           870: LANG("\nNote: '%s' is not a pure text file.\n\
        !           871: File will be treated as binary data.\n"),
        !           872:                workfile);
        !           873:        literal_mode = MODE_BINARY;     /* now expect straight binary */
        !           874:     }
        !           875:     if (moreflag && literal_mode == MODE_BINARY) {     /* For eyes only?
        !           876:                                                           Can't display
        !           877:                                                           binary file. */
        !           878:        fprintf(pgpout,
        !           879: LANG("\n\007Error: Only text files may be sent as display-only.\n"));
        !           880:        errorLvl = INVALID_FILE_ERROR;
        !           881:        user_error();
        !           882:     }
        !           883:     /*      See if plainfile looks like it might be incompressible, 
        !           884:        by examining its contents for compression headers for 
        !           885:        commonly-used compressed file formats like PKZIP, etc.
        !           886:        Remember this information for later, when we are deciding
        !           887:        whether to attempt compression before encryption.
        !           888:      */
        !           889:     attempt_compression = compress_enabled && file_compressible(plainfile);
        !           890: 
        !           891: 
        !           892:     if (sign_flag) {
        !           893:        if (!filter_mode && !quietmode)
        !           894:            fprintf(pgpout,
        !           895: LANG("\nA secret key is required to make a signature. "));
        !           896:        if (!quietmode && my_name[0] == '\0') {
        !           897:            fprintf(pgpout,
        !           898: LANG("\nYou specified no user ID to select your secret key,\n\
1.1.1.7   root      899: so the default user ID and key will be the most recently\n\
                    900: added key on your secret keyring.\n"));
                    901:        }
1.1.1.8 ! root      902:        strip_spaces = FALSE;
        !           903:        clearfile = NULL;
        !           904:        if (literal_mode == MODE_TEXT) {
        !           905:            /* Text mode requires becoming canonical */
        !           906:            tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
        !           907:            /* +clear means output file with signature in the clear,
        !           908:               only in combination with -t and -a, not with -e or -b */
        !           909:            if (!encrypt_flag && !separate_signature &&
        !           910:                emit_radix_64 && clear_signatures) {
        !           911:                clearfile = workfile;
        !           912:                strip_spaces = TRUE;
        !           913:            }
        !           914:            make_canonical(workfile, tempf);
        !           915:            if (!clearfile)
1.1.1.7   root      916:                rmtemp(workfile);
1.1.1.8 ! root      917:            workfile = tempf;
        !           918:        }
        !           919:        if ((emit_radix_64 || encrypt_flag) && !separate_signature)
        !           920:            tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
        !           921:        else
        !           922:            tempf = tempfile(TMP_WIPE);
        !           923:        /* for clear signatures we create a separate signature */
        !           924:        status = signfile(nestflag, separate_signature || (clearfile != NULL),
        !           925:                   my_name, workfile, tempf, literal_mode, literal_file);
        !           926:        rmtemp(workfile);
        !           927:        workfile = tempf;
        !           928: 
        !           929:        if (status < 0) {       /* signfile failed */
        !           930:            fprintf(pgpout, LANG("\007Signature error\n"));
        !           931:            errorLvl = SIGNATURE_ERROR;
        !           932:            user_error();
        !           933:        }
        !           934:        /*
        !           935:         *  We used to compress signed files only if they were also
        !           936:         * armored.  Now that we have clear signatures it makes more
        !           937:         * sense to always compress signature files.
        !           938:         */
        !           939:        if (attempt_compression && !separate_signature && !encrypt_flag
        !           940:            && !clearfile) {
        !           941:            tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
        !           942:            squish_file(workfile, tempf);
        !           943:            rmtemp(workfile);
        !           944:            workfile = tempf;
        !           945:        }
        !           946:     } else if (!nestflag) {    /* !sign_file */
        !           947:        /*      Prepend CTB_LITERAL byte to plaintext file.
        !           948:           --sure wish this pass could be optimized away. */
        !           949:        tempf = tempfile(TMP_WIPE);
        !           950:        status = make_literal(workfile, tempf, literal_mode, literal_file);
        !           951:        rmtemp(workfile);
        !           952:        workfile = tempf;
        !           953:     }
        !           954:     if (encrypt_flag) {
        !           955:        tempf = tempfile(TMP_WIPE);
        !           956:        if (!conventional_flag) {
        !           957:            if (!filter_mode && !quietmode)
        !           958:                fprintf(pgpout,
        !           959: LANG("\n\nRecipients' public key(s) will be used to encrypt. "));
        !           960:            if (recipient == NULL || *recipient == NULL ||
        !           961:                **recipient == '\0') {
        !           962:                /* no recipient specified on command line */
        !           963:                fprintf(pgpout,
        !           964: LANG("\nA user ID is required to select the recipient's public key. "));
        !           965:                fprintf(pgpout, LANG("\nEnter the recipient's user ID: "));
        !           966:                getstring(mcguffin, 255, TRUE);         /* echo keyboard */
        !           967:                if ((mcguffins = (char **) malloc(2 * sizeof(char *)))
        !           968:                    == NULL) {
        !           969:                    fprintf(stderr, LANG("\n\007Out of memory.\n"));
        !           970:                    exitPGP(7);
        !           971:                }
        !           972:                mcguffins[0] = mcguffin;
        !           973:                mcguffins[1] = "";
        !           974:            } else {
        !           975:                /* recipient specified on command line */
        !           976:                mcguffins = recipient;
        !           977:            }
        !           978:            for (recipient = mcguffins; *recipient != NULL &&
        !           979:                 **recipient != '\0'; recipient++) {
        !           980:                CONVERT_TO_CANONICAL_CHARSET(*recipient);
        !           981:            }
        !           982:            status = encryptfile(mcguffins, workfile, tempf,
        !           983:                                 attempt_compression);
        !           984:        } else {
        !           985:            status = idea_encryptfile(workfile, tempf, attempt_compression);
        !           986:        }
1.1.1.7   root      987: 
1.1.1.8 ! root      988:        rmtemp(workfile);
        !           989:        workfile = tempf;
1.1.1.7   root      990: 
1.1.1.8 ! root      991:        if (status < 0) {
        !           992:            fprintf(pgpout, LANG("\007Encryption error\n"));
        !           993:            errorLvl = (conventional_flag ? ENCR_ERROR : RSA_ENCR_ERROR);
        !           994:            user_error();
        !           995:        }
        !           996:     }                          /* encrypt file */
        !           997:     if (outputfile)            /* explicit output file overrides
        !           998:                                   filter mode */
        !           999:        filter_mode = (strcmp(outputfile, "-") == 0);
        !          1000: 
        !          1001:     if (filter_mode) {
        !          1002:        if (emit_radix_64) {
        !          1003:            /* NULL for outputfile means write to stdout */
        !          1004:            if (armor_file(workfile, NULL, inputfile, clearfile) != 0) {
        !          1005:                errorLvl = UNKNOWN_FILE_ERROR;
        !          1006:                user_error();
        !          1007:            }
        !          1008:            if (clearfile)
        !          1009:                rmtemp(clearfile);
1.1.1.7   root     1010:        } else {
1.1.1.8 ! root     1011:            if (writePhantomOutput(workfile) < 0) {
        !          1012:                errorLvl = UNKNOWN_FILE_ERROR;
        !          1013:                user_error();
        !          1014:            }
1.1.1.7   root     1015:        }
1.1.1.8 ! root     1016:        rmtemp(workfile);
        !          1017:     } else {
        !          1018:        char name[MAX_PATH];
        !          1019:        if (outputfile) {
        !          1020:            strcpy(name, outputfile);
        !          1021:        } else {
        !          1022:            strcpy(name, inputfile);
        !          1023:            drop_extension(name);
1.1.1.7   root     1024:        }
1.1.1.8 ! root     1025:        if (no_extension(name)) {
        !          1026:            if (emit_radix_64)
        !          1027:                force_extension(name, ASC_EXTENSION);
        !          1028:            else if (sign_flag && separate_signature)
        !          1029:                force_extension(name, SIG_EXTENSION);
        !          1030:            else
        !          1031:                force_extension(name, PGP_EXTENSION);
        !          1032:        }
        !          1033:        if (emit_radix_64) {
        !          1034:            if (armor_file(workfile, name, inputfile, clearfile) != 0) {
        !          1035:                errorLvl = UNKNOWN_FILE_ERROR;
        !          1036:                user_error();
        !          1037:            }
        !          1038:            if (clearfile)
        !          1039:                rmtemp(clearfile);
        !          1040:        } else {
        !          1041:            if ((outputfile = savetemp(workfile, name)) == NULL) {
        !          1042:                errorLvl = UNKNOWN_FILE_ERROR;
        !          1043:                user_error();
        !          1044:            }
        !          1045:            if (!quietmode) {
        !          1046:                if (encrypt_flag)
        !          1047:                    fprintf(pgpout,
        !          1048:                            LANG("\nCiphertext file: %s\n"), outputfile);
        !          1049:                else if (sign_flag)
        !          1050:                    fprintf(pgpout,
        !          1051:                            LANG("\nSignature file: %s\n"), outputfile);
        !          1052:            }
        !          1053:        }
        !          1054:     }
        !          1055: 
        !          1056:     if (wipeflag) {
        !          1057:        /* destroy every trace of plaintext */
        !          1058:        if (wipefile(inputfile) == 0) {
        !          1059:            remove(inputfile);
        !          1060:            fprintf(pgpout, LANG("\nFile %s wiped and deleted. "), inputfile);
        !          1061:            fprintf(pgpout, "\n");
        !          1062:        }
        !          1063:     }
        !          1064:     exitPGP(EXIT_OK);
        !          1065:     return 0;                  /* to shut up lint and some compilers */
        !          1066: }                              /* main */
1.1.1.7   root     1067: 
                   1068: #ifdef MSDOS
                   1069: #include <dos.h>
1.1.1.8 ! root     1070: static char *dos_errlst[] =
        !          1071: {
        !          1072:     "Write protect error",     /* LANG ("Write protect error") */
        !          1073:     "Unknown unit",
        !          1074:     "Drive not ready",         /* LANG ("Drive not ready") */
        !          1075:     "3", "4", "5", "6", "7", "8", "9",
        !          1076:     "Write error",             /* LANG ("Write error") */
        !          1077:     "Read error",              /* LANG ("Read error") */
        !          1078:     "General failure",
1.1.1.7   root     1079: };
                   1080: 
                   1081: /* handler for msdos 'harderrors' */
                   1082: #ifndef OS2
1.1.1.8 ! root     1083: #ifdef __TURBOC__              /* Turbo C 2.0 */
1.1.1.7   root     1084: static int dostrap(int errval)
                   1085: #else
                   1086: static void dostrap(unsigned deverr, unsigned errval)
                   1087: #endif
                   1088: {
1.1.1.8 ! root     1089:     char errbuf[64];
        !          1090:     int i;
        !          1091:     sprintf(errbuf, "\r\nDOS error: %s\r\n", dos_errlst[errval]);
        !          1092:     i = 0;
        !          1093:     do
        !          1094:        bdos(2, (unsigned int) errbuf[i], 0);
        !          1095:     while (errbuf[++i]);
1.1.1.7   root     1096: #ifdef __TURBOC__
1.1.1.8 ! root     1097:     return 0;                  /* ignore (fopen will return NULL) */
1.1.1.7   root     1098: #else
1.1.1.8 ! root     1099:     return;
1.1.1.7   root     1100: #endif
                   1101: }
1.1.1.8 ! root     1102: #endif                         /* MSDOS */
1.1.1.7   root     1103: #endif
                   1104: 
                   1105: static void initsigs()
                   1106: {
                   1107: #ifdef MSDOS
                   1108: #ifndef OS2
                   1109: #ifdef __TURBOC__
1.1.1.8 ! root     1110:     harderr(dostrap);
        !          1111: #else                          /* MSC */
        !          1112: #ifndef __GNUC__               /* DJGPP's not MSC */
        !          1113:     _harderr(dostrap);
1.1.1.7   root     1114: #endif
                   1115: #endif
                   1116: #endif
1.1.1.8 ! root     1117: #endif                         /* MSDOS */
1.1.1.7   root     1118: #ifdef SIGINT
                   1119: #ifdef ATARI
1.1.1.8 ! root     1120:     signal(SIGINT, (sigfunc_t) breakHandler);
1.1.1.7   root     1121: #else
1.1.1.8 ! root     1122:     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
        !          1123:        signal(SIGINT, breakHandler);
1.1.1.7   root     1124: #if defined(UNIX) || defined(VMS)
1.1.1.8 ! root     1125:     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
        !          1126:        signal(SIGHUP, breakHandler);
        !          1127:     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
        !          1128:        signal(SIGQUIT, breakHandler);
1.1.1.7   root     1129: #ifdef UNIX
1.1.1.8 ! root     1130:     signal(SIGPIPE, breakHandler);
1.1.1.7   root     1131: #endif
1.1.1.8 ! root     1132:     signal(SIGTERM, breakHandler);
1.1.1.7   root     1133: #ifndef DEBUG
1.1.1.8 ! root     1134:     signal(SIGTRAP, breakHandler);
        !          1135:     signal(SIGSEGV, breakHandler);
        !          1136:     signal(SIGILL, breakHandler);
1.1.1.7   root     1137: #ifdef SIGBUS
1.1.1.8 ! root     1138:     signal(SIGBUS, breakHandler);
1.1.1.7   root     1139: #endif
1.1.1.8 ! root     1140: #endif                         /* DEBUG */
        !          1141: #endif                         /* UNIX */
        !          1142: #endif                         /* not Atari */
        !          1143: #endif                         /* SIGINT */
        !          1144: }                              /* initsigs */
1.1.1.7   root     1145: 
                   1146: 
                   1147: static void do_armorfile(char *armorfile)
                   1148: {
1.1.1.8 ! root     1149:     char *tempf;
        !          1150:     char cipherfile[MAX_PATH];
        !          1151:     long linepos = 0;
        !          1152:     int status;
        !          1153:     int success = 0;
        !          1154: 
        !          1155:     for (;;) {
        !          1156:        /* Handle transport armor stripping */
        !          1157:        tempf = tempfile(0);
        !          1158:        strip_spaces = FALSE;   /* de_armor_file() sets
        !          1159:                                   this for clear signature files */
        !          1160:        status = de_armor_file(armorfile, tempf, &linepos);
        !          1161:        if (status) {
        !          1162:            fprintf(pgpout,
        !          1163: LANG("\n\007Error: Transport armor stripping failed for file %s\n"),
        !          1164:                    armorfile);
        !          1165:            errorLvl = INVALID_FILE_ERROR;
        !          1166:            user_error();       /* Bad file */
        !          1167:        }
        !          1168:        if (keepctx || de_armor_only) {
        !          1169:            if (outputfile && de_armor_only) {
        !          1170:                if (strcmp(outputfile, "-") == 0) {
        !          1171:                    writePhantomOutput(tempf);
        !          1172:                    rmtemp(tempf);
        !          1173:                    return;
        !          1174:                }
        !          1175:                strcpy(cipherfile, outputfile);
        !          1176:            } else {
        !          1177:                strcpy(cipherfile, file_tail(armorfile));
        !          1178:                force_extension(cipherfile, PGP_EXTENSION);
        !          1179:            }
        !          1180:            if ((tempf = savetemp(tempf, cipherfile)) == NULL) {
        !          1181:                errorLvl = UNKNOWN_FILE_ERROR;
        !          1182:                user_error();
        !          1183:            }
        !          1184:            if (!quietmode)
        !          1185:                fprintf(pgpout,
        !          1186: LANG("Stripped transport armor from '%s', producing '%s'.\n"),
        !          1187:                        armorfile, tempf);
        !          1188:            /* -da flag: don't decrypt */
        !          1189:            if (de_armor_only || do_decrypt(tempf) >= 0)
        !          1190:                ++success;
        !          1191:        } else {
        !          1192:            if (do_decrypt(tempf) >= 0)
        !          1193:                ++success;
        !          1194:            rmtemp(tempf);
        !          1195:        }
1.1.1.7   root     1196: 
1.1.1.8 ! root     1197:        if (!is_armor_file(armorfile, linepos)) {
        !          1198:            if (!success)       /* print error msg if we didn't
        !          1199:                                   decrypt anything */
        !          1200:                user_error();
        !          1201:            return;
1.1.1.7   root     1202:        }
1.1.1.8 ! root     1203:        fprintf(pgpout,
        !          1204:                LANG("\nLooking for next packet in '%s'...\n"), armorfile);
        !          1205:     }
        !          1206: }                              /* do_armorfile */
1.1.1.7   root     1207: 
                   1208: 
                   1209: static int do_decrypt(char *cipherfile)
                   1210: {
1.1.1.8 ! root     1211:     char *outfile = NULL;
        !          1212:     int status, i;
        !          1213:     boolean nested_info = FALSE;
        !          1214:     char ringfile[MAX_PATH];
        !          1215:     byte ctb;
        !          1216:     byte header[8];            /* used to classify file type at the end. */
        !          1217:     char preserved_name[MAX_PATH];
        !          1218:     char *newname;
        !          1219: 
        !          1220:     /* will be set to the original file name after processing a
        !          1221:        literal packet */
        !          1222:     preserved_name[0] = '\0';
        !          1223: 
        !          1224:     do {                       /* while nested parsable info present */
        !          1225:        if (nested_info) {
        !          1226:            rmtemp(cipherfile); /* never executed on first pass */
        !          1227:            cipherfile = outfile;
        !          1228:        }
        !          1229:        if (get_header_info_from_file(cipherfile, &ctb, 1) < 0) {
        !          1230:            fprintf(pgpout,
        !          1231: LANG("\n\007Can't open ciphertext file '%s'\n"), cipherfile);
        !          1232:            errorLvl = FILE_NOT_FOUND_ERROR;
        !          1233:            return -1;
        !          1234:        }
        !          1235:        if (!is_ctb(ctb))       /* not a real CTB -- complain */
        !          1236:            break;
1.1.1.7   root     1237: 
1.1.1.8 ! root     1238:        if (moreflag)
        !          1239:            outfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !          1240:        else
        !          1241:            outfile = tempfile(TMP_WIPE);
1.1.1.7   root     1242: 
1.1.1.8 ! root     1243:        /* PKE is Public Key Encryption */
        !          1244:        if (is_ctb_type(ctb, CTB_PKE_TYPE)) {
1.1.1.7   root     1245: 
1.1.1.8 ! root     1246:            if (!quietmode)
        !          1247:                fprintf(pgpout,
        !          1248: LANG("\nFile is encrypted.  Secret key is required to read it. "));
1.1.1.7   root     1249: 
1.1.1.8 ! root     1250:            /* Decrypt to scratch file since we may have a LITERAL2 */
        !          1251:            status = decryptfile(cipherfile, outfile);
1.1.1.7   root     1252: 
1.1.1.8 ! root     1253:            if (status < 0) {   /* error return */
        !          1254:                errorLvl = RSA_DECR_ERROR;
        !          1255:                return -1;
        !          1256:            }
        !          1257:            nested_info = (status > 0);
1.1.1.7   root     1258: 
1.1.1.8 ! root     1259:        } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
1.1.1.7   root     1260: 
1.1.1.8 ! root     1261:            if (decrypt_only_flag) {
        !          1262:                /* swap file names instead of just copying the file */
        !          1263:                rmtemp(outfile);
        !          1264:                outfile = cipherfile;
        !          1265:                cipherfile = NULL;
        !          1266:                if (!quietmode)
        !          1267:                    fprintf(pgpout,
        !          1268: LANG("\nThis file has a signature, which will be left in place.\n"));
        !          1269:                nested_info = FALSE;
        !          1270:                break;          /* Do no more */
        !          1271:            }
        !          1272:            if (!quietmode)
        !          1273:                fprintf(pgpout,
        !          1274: LANG("\nFile has signature.  Public key is required to check signature. "));
1.1.1.7   root     1275: 
1.1.1.8 ! root     1276:            status = check_signaturefile(cipherfile, outfile,
        !          1277:                                         strip_sig_flag, preserved_name);
1.1.1.7   root     1278: 
1.1.1.8 ! root     1279:            if (status < 0) {   /* error return */
        !          1280:                errorLvl = SIGNATURE_CHECK_ERROR;
1.1.1.7   root     1281:                return -1;
1.1.1.8 ! root     1282:            }
        !          1283:            nested_info = (status > 0);
1.1.1.7   root     1284: 
1.1.1.8 ! root     1285:            if (strcmp(preserved_name, "/dev/null") == 0) {
1.1.1.7   root     1286:                rmtemp(outfile);
1.1.1.8 ! root     1287:                fprintf(pgpout, "\n");
1.1.1.7   root     1288:                return 0;
1.1.1.8 ! root     1289:            }
        !          1290:        } else if (is_ctb_type(ctb, CTB_CKE_TYPE)) {
1.1.1.7   root     1291: 
1.1.1.8 ! root     1292:            /* Conventional Key Encrypted ciphertext. */
        !          1293:            /* Tell user it's encrypted here, and prompt for
        !          1294:               password in subroutine. */
        !          1295:            if (!quietmode)
        !          1296:                fprintf(pgpout, LANG("\nFile is conventionally encrypted.  "));
        !          1297:            /* Decrypt to scratch file since it may be a LITERAL2 */
        !          1298:            status = idea_decryptfile(cipherfile, outfile);
        !          1299:            if (status < 0) {   /* error return */
        !          1300:                errorLvl = DECR_ERROR;
        !          1301:                return -1;      /* error exit status */
        !          1302:            }
        !          1303:            nested_info = (status > 0);
        !          1304: 
        !          1305:        } else if (is_ctb_type(ctb, CTB_COMPRESSED_TYPE)) {
        !          1306: 
        !          1307:            /* Compressed text. */
        !          1308:            status = decompress_file(cipherfile, outfile);
        !          1309:            if (status < 0) {   /* error return */
        !          1310:                errorLvl = DECOMPRESS_ERROR;
        !          1311:                return -1;
        !          1312:            }
        !          1313:            /* Always assume nested information... */
        !          1314:            nested_info = TRUE;
        !          1315: 
        !          1316:        } else if (is_ctb_type(ctb, CTB_LITERAL_TYPE) ||
        !          1317:                   is_ctb_type(ctb, CTB_LITERAL2_TYPE)) { /* Raw plaintext.
        !          1318:                                                             Just copy it.
        !          1319:                                                             No more nesting.
        !          1320:                                                           */
        !          1321: 
        !          1322:            /* Strip off CTB_LITERAL prefix byte from file: */
        !          1323:            /* strip_literal may alter plainfile; will set mode */
        !          1324:            status = strip_literal(cipherfile, outfile,
        !          1325:                                   preserved_name, &literal_mode);
        !          1326:            if (status < 0) {   /* error return */
        !          1327:                errorLvl = UNKNOWN_FILE_ERROR;
        !          1328:                return -1;
        !          1329:            }
        !          1330:            nested_info = FALSE;
        !          1331:        } else if (ctb == CTB_CERT_SECKEY || ctb == CTB_CERT_PUBKEY) {
        !          1332: 
        !          1333:            rmtemp(outfile);
        !          1334:            if (decrypt_only_flag) {
        !          1335:                /* swap file names instead of just copying the file */
        !          1336:                outfile = cipherfile;
        !          1337:                cipherfile = NULL;
        !          1338:                break;          /* no further processing */
        !          1339:            }
        !          1340:            /* Key ring.  View it. */
        !          1341:            fprintf(pgpout,
        !          1342: LANG("\nFile contains key(s).  Contents follow..."));
        !          1343:            if (view_keyring(NULL, cipherfile, TRUE, FALSE) < 0) {
        !          1344:                errorLvl = KEYRING_VIEW_ERROR;
        !          1345:                return -1;
        !          1346:            }
        !          1347:            /* filter mode explicit requested with -f */
        !          1348:            if (filter_mode && !preserve_filename)
        !          1349:                return 0;       /*    No output file */
        !          1350:            if (batchmode)
        !          1351:                return 0;
        !          1352:            if (ctb == CTB_CERT_SECKEY)
        !          1353:                strcpy(ringfile, globalSecringName);
        !          1354:            else
        !          1355:                strcpy(ringfile, globalPubringName);
        !          1356:            /*      Ask if it should be put on key ring */
        !          1357:            fprintf(pgpout,
        !          1358: LANG("\nDo you want to add this keyfile to keyring '%s' (y/N)? "), ringfile);
        !          1359:            if (!getyesno('n'))
        !          1360:                return 0;
        !          1361:            status = addto_keyring(cipherfile, ringfile);
        !          1362:            if (status < 0) {
        !          1363:                fprintf(pgpout, LANG("\007Keyring add error. "));
        !          1364:                errorLvl = KEYRING_ADD_ERROR;
        !          1365:                return -1;
        !          1366:            }
        !          1367:            return 0;           /*    No output file */
        !          1368: 
        !          1369:        } else {                /* Unrecognized CTB */
        !          1370:            break;
1.1.1.7   root     1371:        }
                   1372: 
1.1.1.8 ! root     1373:     } while (nested_info);
        !          1374:     /* No more nested parsable information */
        !          1375: 
        !          1376:     /* Stopped early due to error */
        !          1377:     if (nested_info) {
        !          1378:        fprintf(pgpout,
        !          1379: "\7\nERROR: Nested data has unexpected format.  CTB=0x%02X\n", ctb);
        !          1380:        if (outfile)
        !          1381:            rmtemp(outfile);
        !          1382:        if (cipherfile)
        !          1383:            rmtemp(cipherfile);
        !          1384:        errorLvl = UNKNOWN_FILE_ERROR;
        !          1385:        return -1;
        !          1386:     }
        !          1387:     if (outfile == NULL) {     /* file was not encrypted */
        !          1388:        if (!filter_mode && !moreflag) {
        !          1389:            fprintf(pgpout,
        !          1390: LANG("\007\nError: '%s' is not a ciphertext, signature, or key file.\n"),
        !          1391:                    cipherfile);
        !          1392:            errorLvl = UNKNOWN_FILE_ERROR;
        !          1393:            return -1;
        !          1394:        }
        !          1395:        outfile = cipherfile;
        !          1396:     } else {
        !          1397:        if (cipherfile)
        !          1398:            rmtemp(cipherfile);
        !          1399:     }
        !          1400: 
        !          1401:     if (moreflag || (strcmp(preserved_name, CONSOLE_FILENAME) == 0)) {
        !          1402:        /* blort to screen */
        !          1403:        if (strcmp(preserved_name, CONSOLE_FILENAME) == 0) {
        !          1404:            fprintf(pgpout,
        !          1405: LANG("\n\nThis message is marked \"For your eyes only\".  Display now \
        !          1406: (Y/n)? "));
        !          1407:            if (batchmode || !getyesno('y')) {
        !          1408:                /* no -- abort display, and clean up */
1.1.1.7   root     1409:                rmtemp(outfile);
                   1410:                return 0;
1.1.1.8 ! root     1411:            }
1.1.1.7   root     1412:        }
1.1.1.8 ! root     1413:        if (!quietmode)
        !          1414:            fprintf(pgpout, LANG("\n\nPlaintext message follows...\n"));
        !          1415:        else
        !          1416:            putc('\n', pgpout);
        !          1417:        fprintf(pgpout, "------------------------------\n");
        !          1418:        more_file(outfile);
        !          1419:        /* Disallow saving to disk if outfile is console-only: */
        !          1420:        if (strcmp(preserved_name, CONSOLE_FILENAME) == 0) {
        !          1421:            clearscreen();      /* remove all evidence */
        !          1422:        } else if (!quietmode && !batchmode) {
        !          1423:            fprintf(pgpout, LANG("Save this file permanently (y/N)? "));
        !          1424:            if (getyesno('n')) {
        !          1425:                char moreFilename[256];
        !          1426:                fprintf(pgpout, LANG("Enter filename to save file as: "));
        !          1427:                if (preserved_name[0])
        !          1428:                    fprintf(pgpout, "[%s]: ", file_tail(preserved_name));
        !          1429:                getstring(moreFilename, 255, TRUE);
        !          1430:                if (*moreFilename == '\0') {
        !          1431:                    if (*preserved_name != '\0')
        !          1432:                        savetemp(outfile, file_tail(preserved_name));
        !          1433:                    else
        !          1434:                        rmtemp(outfile);
        !          1435:                } else
        !          1436:                    savetemp(outfile, moreFilename);
1.1.1.7   root     1437:                return 0;
1.1.1.8 ! root     1438:            }
1.1.1.7   root     1439:        }
1.1.1.8 ! root     1440:        rmtemp(outfile);
        !          1441:        return 0;
        !          1442:     }                          /* blort to screen */
        !          1443:     if (outputfile) {
        !          1444:        if (!strcmp(outputfile, "/dev/null")) {
        !          1445:            rmtemp(outfile);
        !          1446:            return 0;
        !          1447:        }
        !          1448:        filter_mode = (strcmp(outputfile, "-") == 0);
        !          1449:        strcpy(plainfile, outputfile);
        !          1450:     } else {
        !          1451: #ifdef VMS
        !          1452:        /* VMS null extension has to be ".", not "" */
        !          1453:        force_extension(plainfile, ".");
        !          1454: #else                          /* not VMS */
        !          1455:        drop_extension(plainfile);
        !          1456: #endif                         /* not VMS */
        !          1457:     }
        !          1458: 
        !          1459:     if (!preserve_filename && filter_mode) {
        !          1460:        if (writePhantomOutput(outfile) < 0) {
        !          1461:            errorLvl = UNKNOWN_FILE_ERROR;
        !          1462:            return -1;
1.1.1.7   root     1463:        }
1.1.1.8 ! root     1464:        rmtemp(outfile);
1.1.1.7   root     1465:        return 0;
1.1.1.8 ! root     1466:     }
        !          1467:     if (preserve_filename && preserved_name[0] != '\0')
        !          1468:        strcpy(plainfile, file_tail(preserved_name));
        !          1469: 
        !          1470:     if (quietmode) {
        !          1471:        if (savetemp(outfile, plainfile) == NULL) {
        !          1472:            errorLvl = UNKNOWN_FILE_ERROR;
        !          1473:            return -1;
        !          1474:        }
        !          1475:        return 0;
        !          1476:     }
        !          1477:     if (!verbose)             /* if other filename messages were suppressed */
        !          1478:        fprintf(pgpout, LANG("\nPlaintext filename: %s"), plainfile);
        !          1479: 
        !          1480: 
        !          1481: /*---------------------------------------------------------*/
        !          1482: 
        !          1483:     /*      One last thing-- let's attempt to classify some of the more
        !          1484:        frequently occurring cases of plaintext output files, as an
        !          1485:        aid to the user.
        !          1486: 
        !          1487:        For example, if output file is a public key, it should have
        !          1488:        the right extension on the filename.
        !          1489: 
        !          1490:        Also, it will likely be common to encrypt files created by
        !          1491:        various archivers, so they should be renamed with the archiver
        !          1492:        extension.
        !          1493:      */
        !          1494:     get_header_info_from_file(outfile, header, 8);
        !          1495: 
        !          1496:     newname = NULL;
        !          1497:     if (header[0] == CTB_CERT_PUBKEY) {
        !          1498:        /* Special case--may be public key, worth renaming */
        !          1499:        fprintf(pgpout,
        !          1500: LANG("\nPlaintext file '%s' looks like it contains a public key."),
        !          1501:                plainfile);
        !          1502:        newname = maybe_force_extension(plainfile, PGP_EXTENSION);
        !          1503:     }
        !          1504:     /* Possible public key output file */ 
        !          1505:     else if ((i = compressSignature(header)) >= 0) {
        !          1506:        /*      Special case--may be an archived/compressed file,
        !          1507:                worth renaming
        !          1508:        */
        !          1509:        fprintf(pgpout, LANG("\nPlaintext file '%s' looks like a %s file."),
        !          1510:                plainfile, compressName[i]);
        !          1511:        newname = maybe_force_extension(plainfile, compressExt[i]);
        !          1512:     } else if (is_ctb(header[0]) &&
        !          1513:               (is_ctb_type(header[0], CTB_PKE_TYPE)
        !          1514:                || is_ctb_type(header[0], CTB_SKE_TYPE)
        !          1515:                || is_ctb_type(header[0], CTB_CKE_TYPE))) {
        !          1516:        /* Special case--may be another ciphertext file, worth renaming */
        !          1517:        fprintf(pgpout,
        !          1518: LANG("\n\007Output file '%s' may contain more ciphertext or signature."),
        !          1519:                plainfile);
        !          1520:        newname = maybe_force_extension(plainfile, PGP_EXTENSION);
        !          1521:     }                          /* Possible ciphertext output file */
        !          1522:     if (savetemp(outfile, (newname ? newname : plainfile)) == NULL) {
        !          1523:        errorLvl = UNKNOWN_FILE_ERROR;
        !          1524:        return -1;
        !          1525:     }
        !          1526:     fprintf(pgpout, "\n");
        !          1527:     return 0;
        !          1528: }                              /* do_decrypt */
1.1.1.7   root     1529: 
                   1530: static int do_keyopt(char keychar)
                   1531: {
1.1.1.8 ! root     1532:     char keyfile[MAX_PATH];
        !          1533:     char ringfile[MAX_PATH];
        !          1534:     char *workfile;
        !          1535:     int status;
        !          1536: 
        !          1537:     if ((filter_mode || batchmode)
        !          1538:        && (keychar == 'g' || keychar == 'e' || keychar == 'd'
        !          1539:            || (keychar == 'r' && sign_flag))) {
        !          1540:        errorLvl = NO_BATCH;
        !          1541:        arg_error();            /* interactive process, no go in batch mode */
        !          1542:     }
        !          1543:     /*
        !          1544:      * If we're not doing anything that uses stdout, produce output there,
        !          1545:      * in case user wants to redirect it.
        !          1546:      */
        !          1547:     if (!filter_mode)
        !          1548:        pgpout = stdout;
        !          1549: 
        !          1550:     switch (keychar) {
        !          1551: 
        !          1552: /*-------------------------------------------------------*/
        !          1553:     case 'g':
        !          1554:        {                       /*      Key generation
        !          1555:                                   Arguments: bitcount, bitcount
        !          1556:                                 */
        !          1557:            char keybits[6], ebits[6];
        !          1558: 
        !          1559:            /* 
        !          1560:             * Why all this code?
        !          1561:             *
        !          1562:             * Some dimwits have been distributing versions of
        !          1563:             * PGP (especially on MS-DOS) without the manuals.
        !          1564:             * This frustrates users (who call Philip Zimmermann
        !          1565:             * at all hours of the day and night), and in
        !          1566:             * addition to depriving them of instructions on how
        !          1567:             * to operate the program, also deprives them of
        !          1568:             * IMPORTANT legal notices.  This is a Bad Thing, so
        !          1569:             * we've gone to the trouble of being fascist and
        !          1570:             * *forcing* the manuals to be there.  The +nomanual
        !          1571:             * flag (documented only in the manual) lets you
        !          1572:             * overrride this if desired.
        !          1573:             */
1.1.1.7   root     1574: 
1.1.1.8 ! root     1575:            if (!nomanual && manuals_missing()) {
        !          1576:                char const *const *dir;
1.1.1.7   root     1577: 
1.1.1.8 ! root     1578:                fputs(LANG("\a\nError: PGP User's Guide not found.\n\
1.1.1.7   root     1579: PGP looked for it in the following directories:\n"), pgpout);
1.1.1.8 ! root     1580:                for (dir = manual_dirs; *dir; dir++)
        !          1581:                    fprintf(pgpout, "\t\"%s\"\n", *dir);
        !          1582:                fputs(
        !          1583: LANG("and the doc subdirectory of each of the above.  Please put a copy of\n\
1.1.1.7   root     1584: both volumes of the User's Guide in one of these directories.\n\
                   1585: \n\
                   1586: Under NO CIRCUMSTANCES should PGP ever be distributed without the PGP\n\
                   1587: User's Guide, which is included in the standard distribution package.\n\
                   1588: If you got a copy of PGP without the manual, please inform whomever you\n\
                   1589: got it from that this is an incomplete package that should not be\n\
                   1590: distributed further.\n\
                   1591: \n\
                   1592: PGP will not generate a key without finding the User's Guide.\n\
                   1593: \n"), pgpout);
1.1.1.8 ! root     1594:                return KEYGEN_ERROR;
        !          1595:            }
        !          1596:            if (myArgc > 2)
        !          1597:                strncpy(keybits, myArgv[2], sizeof(keybits) - 1);
        !          1598:            else
        !          1599:                keybits[0] = '\0';
        !          1600: 
        !          1601:            if (myArgc > 3)
        !          1602:                strncpy(ebits, myArgv[3], sizeof(ebits) - 1);
        !          1603:            else
        !          1604:                ebits[0] = '\0';
        !          1605: 
        !          1606:            /* dokeygen writes the keys out to the key rings... */
        !          1607:            status = dokeygen(keybits, ebits);
        !          1608: 
        !          1609:            if (status < 0) {
        !          1610:                fprintf(pgpout, LANG("\007Keygen error. "));
        !          1611:                errorLvl = KEYGEN_ERROR;
        !          1612:            }
        !          1613:            return status;
        !          1614:        }                       /* Key generation */
        !          1615: 
        !          1616: /*-------------------------------------------------------*/
        !          1617:     case 'c':
        !          1618:        {                       /*      Key checking
        !          1619:                                   Arguments: userid, ringfile
        !          1620:                                 */
        !          1621: 
        !          1622:            if (myArgc < 3) {   /* Default to all user ID's */
        !          1623:                mcguffin[0] = '\0';
        !          1624:            } else {
        !          1625:                strcpy(mcguffin, myArgv[2]);
        !          1626:                if (strcmp(mcguffin, "*") == 0)
        !          1627:                    mcguffin[0] = '\0';
        !          1628:            }
        !          1629:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
        !          1630: 
        !          1631:            if (myArgc < 4)     /* default key ring filename */
        !          1632:                strcpy(ringfile, globalPubringName);
        !          1633:            else
        !          1634:                strncpy(ringfile, myArgv[3], sizeof(ringfile) - 1);
        !          1635: 
        !          1636:            if ((myArgc < 4 && myArgc > 2)     /* Allow just key file as arg */
        !          1637:                &&has_extension(myArgv[2], PGP_EXTENSION)) {
        !          1638:                strcpy(ringfile, myArgv[2]);
        !          1639:                mcguffin[0] = '\0';
        !          1640:            }
        !          1641:            status = dokeycheck(mcguffin, ringfile, CHECK_ALL);
        !          1642: 
        !          1643:            if (status < 0) {
        !          1644:                fprintf(pgpout, LANG("\007Keyring check error.\n"));
        !          1645:                errorLvl = KEYRING_CHECK_ERROR;
        !          1646:            }
        !          1647:            if (status >= 0 && mcguffin[0] != '\0')
        !          1648:                return status;  /* just checking a single user,
        !          1649:                                   dont do maintenance */
        !          1650: 
        !          1651:            if ((status = maint_check(ringfile, 0)) < 0 && status != -7) {
        !          1652:                fprintf(pgpout, LANG("\007Maintenance pass error. "));
        !          1653:                errorLvl = KEYRING_CHECK_ERROR;
        !          1654:            }
        !          1655:            return status == -7 ? 0 : status;
        !          1656:        }                       /* Key check */
        !          1657: 
        !          1658: /*-------------------------------------------------------*/
        !          1659:     case 'm':
        !          1660:        {                       /*      Maintenance pass
        !          1661:                                   Arguments: ringfile
        !          1662:                                 */
        !          1663: 
        !          1664:            if (myArgc < 3)     /* default key ring filename */
        !          1665:                strcpy(ringfile, globalPubringName);
        !          1666:            else
        !          1667:                strcpy(ringfile, myArgv[2]);
1.1.1.7   root     1668: 
                   1669: #ifdef MSDOS
1.1.1.8 ! root     1670:            strlwr(ringfile);
1.1.1.7   root     1671: #endif
1.1.1.8 ! root     1672:            if (!file_exists(ringfile))
        !          1673:                default_extension(ringfile, PGP_EXTENSION);
1.1.1.7   root     1674: 
1.1.1.8 ! root     1675:            if ((status = maint_check(ringfile,
        !          1676:                      MAINT_VERBOSE | (c_flag ? MAINT_CHECK : 0))) < 0) {
        !          1677:                if (status == -7)
        !          1678:                    fprintf(pgpout,
        !          1679:                            LANG("File '%s' is not a public keyring\n"),
        !          1680:                            ringfile);
        !          1681:                fprintf(pgpout, LANG("\007Maintenance pass error. "));
        !          1682:                errorLvl = KEYRING_CHECK_ERROR;
        !          1683:            }
        !          1684:            return status;
        !          1685:        }                       /* Maintenance pass */
        !          1686: 
        !          1687: /*-------------------------------------------------------*/
        !          1688:     case 's':
        !          1689:        {                       /*      Key signing
        !          1690:                                   Arguments: her_id, keyfile
        !          1691:                                 */
        !          1692: 
        !          1693:            if (myArgc >= 4)
        !          1694:                strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
        !          1695:            else
        !          1696:                strcpy(keyfile, globalPubringName);
        !          1697: 
        !          1698:            if (myArgc >= 3) {
        !          1699:                strcpy(mcguffin, myArgv[2]);    /* Userid to sign */
        !          1700:            } else {
        !          1701:                fprintf(pgpout,
        !          1702: LANG("\nA user ID is required to select the public key you want to sign. "));
        !          1703:                if (batchmode)  /* not interactive, userid
        !          1704:                                   must be on command line */
        !          1705:                    return -1;
        !          1706:                fprintf(pgpout, LANG("\nEnter the public key's user ID: "));
        !          1707:                getstring(mcguffin, 255, TRUE);         /* echo keyboard */
        !          1708:            }
        !          1709:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
        !          1710: 
        !          1711:            if (my_name[0] == '\0') {
        !          1712:                fprintf(pgpout,
        !          1713: LANG("\nA secret key is required to make a signature. "));
        !          1714:                fprintf(pgpout,
        !          1715: LANG("\nYou specified no user ID to select your secret key,\n\
1.1.1.7   root     1716: so the default user ID and key will be the most recently\n\
                   1717: added key on your secret keyring.\n"));
1.1.1.8 ! root     1718:            }
        !          1719:            status = signkey(mcguffin, my_name, keyfile);
1.1.1.7   root     1720: 
1.1.1.8 ! root     1721:            if (status >= 0) {
        !          1722:                status = maint_update(keyfile, 0);
        !          1723:                if (status == -7) { /* ringfile is a keyfile or
        !          1724:                                       secret keyring */
        !          1725:                    fprintf(pgpout,
        !          1726:                            "Warning: '%s' is not a public keyring\n",
        !          1727:                            keyfile);
        !          1728:                    return 0;
1.1.1.7   root     1729:                }
                   1730:                if (status < 0)
1.1.1.8 ! root     1731:                    fprintf(pgpout, LANG("\007Maintenance pass error. "));
        !          1732:            }
        !          1733:            if (status < 0) {
        !          1734:                fprintf(pgpout, LANG("\007Key signature error. "));
        !          1735:                errorLvl = KEY_SIGNATURE_ERROR;
        !          1736:            }
        !          1737:            return status;
        !          1738:        }                       /* Key signing */
        !          1739: 
        !          1740: 
        !          1741: /*-------------------------------------------------------*/
        !          1742:     case 'd':
        !          1743:        {                       /*      disable/revoke key
        !          1744:                                   Arguments: userid, keyfile
        !          1745:                                 */
        !          1746: 
        !          1747:            if (myArgc >= 4)
        !          1748:                strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
        !          1749:            else
        !          1750:                strcpy(keyfile, globalPubringName);
        !          1751: 
        !          1752:            if (myArgc >= 3) {
        !          1753:                strcpy(mcguffin, myArgv[2]);    /* Userid to sign */
        !          1754:            } else {
        !          1755:                fprintf(pgpout,
        !          1756: LANG("\nA user ID is required to select the key you want to revoke or \
        !          1757: disable. "));
        !          1758:                fprintf(pgpout, LANG("\nEnter user ID: "));
        !          1759:                getstring(mcguffin, 255, TRUE);         /* echo keyboard */
        !          1760:            }
        !          1761:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
        !          1762: 
        !          1763:            status = disable_key(mcguffin, keyfile);
        !          1764: 
        !          1765:            if (status >= 0) {
        !          1766:                status = maint_update(keyfile, 0);
        !          1767:                if (status == -7) { /* ringfile is a keyfile or
        !          1768:                                       secret keyring */
        !          1769:                    fprintf(pgpout, "Warning: '%s' is not a public keyring\n",
        !          1770:                            keyfile);
        !          1771:                    return 0;
1.1.1.7   root     1772:                }
1.1.1.8 ! root     1773:                if (status < 0)
        !          1774:                    fprintf(pgpout, LANG("\007Maintenance pass error. "));
        !          1775:            }
        !          1776:            if (status < 0)
        !          1777:                errorLvl = KEY_SIGNATURE_ERROR;
        !          1778:            return status;
        !          1779:        }                       /* Key compromise */
        !          1780: 
        !          1781: /*-------------------------------------------------------*/
        !          1782:     case 'e':
        !          1783:        {                       /*      Key editing
        !          1784:                                   Arguments: userid, ringfile
        !          1785:                                 */
        !          1786: 
        !          1787:            if (myArgc >= 4)
        !          1788:                strncpy(ringfile, myArgv[3], sizeof(ringfile) - 1);
        !          1789:            else                /* default key ring filename */
        !          1790:                strcpy(ringfile, globalPubringName);
        !          1791: 
        !          1792:            if (myArgc >= 3) {
        !          1793:                strcpy(mcguffin, myArgv[2]);    /* Userid to edit */
        !          1794:            } else {
        !          1795:                fprintf(pgpout,
        !          1796: LANG("\nA user ID is required to select the key you want to edit. "));
        !          1797:                fprintf(pgpout, LANG("\nEnter the key's user ID: "));
        !          1798:                getstring(mcguffin, 255, TRUE);         /* echo keyboard */
        !          1799:            }
        !          1800:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
        !          1801: 
        !          1802:            status = dokeyedit(mcguffin, ringfile);
        !          1803: 
        !          1804:            if (status >= 0) {
        !          1805:                status = maint_update(ringfile, 0);
        !          1806:                if (status == -7)
        !          1807:                    status = 0; /* ignore "not a public keyring" error */
        !          1808:                if (status < 0)
        !          1809:                    fprintf(pgpout, LANG("\007Maintenance pass error. "));
        !          1810:            }
        !          1811:            if (status < 0) {
        !          1812:                fprintf(pgpout, LANG("\007Keyring edit error. "));
        !          1813:                errorLvl = KEYRING_EDIT_ERROR;
        !          1814:            }
        !          1815:            return status;
        !          1816:        }                       /* Key edit */
        !          1817: 
        !          1818: /*-------------------------------------------------------*/
        !          1819:     case 'a':
        !          1820:        {                       /*      Add key to key ring
        !          1821:                                   Arguments: keyfile, ringfile
        !          1822:                                 */
1.1.1.7   root     1823: 
1.1.1.8 ! root     1824:            if (myArgc < 3 && !filter_mode)
        !          1825:                arg_error();
1.1.1.7   root     1826: 
1.1.1.8 ! root     1827:            if (!filter_mode) { /* Get the keyfile from args */
        !          1828:                strncpy(keyfile, myArgv[2], sizeof(keyfile) - 1);
1.1.1.7   root     1829: 
                   1830: #ifdef MSDOS
1.1.1.8 ! root     1831:                strlwr(keyfile);
1.1.1.7   root     1832: #endif
1.1.1.8 ! root     1833:                if (!file_exists(keyfile))
        !          1834:                    default_extension(keyfile, PGP_EXTENSION);
1.1.1.7   root     1835: 
1.1.1.8 ! root     1836:                if (!file_exists(keyfile)) {
        !          1837:                    fprintf(pgpout,
        !          1838:                            LANG("\n\007Key file '%s' does not exist.\n"),
        !          1839:                            keyfile);
        !          1840:                    errorLvl = NONEXIST_KEY_ERROR;
        !          1841:                    return -1;
1.1.1.7   root     1842:                }
1.1.1.8 ! root     1843:                workfile = keyfile;
1.1.1.7   root     1844: 
1.1.1.8 ! root     1845:            } else {
        !          1846:                workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !          1847:                readPhantomInput(workfile);
        !          1848:            }
        !          1849: 
        !          1850:            if (myArgc < (filter_mode ? 3 : 4)) { /* default key ring
        !          1851:                                                     filename */
        !          1852:                byte ctb;
        !          1853:                get_header_info_from_file(workfile, &ctb, 1);
        !          1854:                if (ctb == CTB_CERT_SECKEY)
        !          1855:                    strcpy(ringfile, globalSecringName);
        !          1856:                else
        !          1857:                    strcpy(ringfile, globalPubringName);
        !          1858:            } else {
        !          1859:                strncpy(ringfile, myArgv[(filter_mode ? 2 : 3)],
        !          1860:                        sizeof(ringfile) - 1);
        !          1861:                default_extension(ringfile, PGP_EXTENSION);
        !          1862:            }
1.1.1.7   root     1863: #ifdef MSDOS
1.1.1.8 ! root     1864:            strlwr(ringfile);
1.1.1.7   root     1865: #endif
                   1866: 
1.1.1.8 ! root     1867:            status = addto_keyring(workfile, ringfile);
1.1.1.7   root     1868: 
1.1.1.8 ! root     1869:            if (filter_mode)
        !          1870:                rmtemp(workfile);
1.1.1.7   root     1871: 
1.1.1.8 ! root     1872:            if (status < 0) {
        !          1873:                fprintf(pgpout, LANG("\007Keyring add error. "));
        !          1874:                errorLvl = KEYRING_ADD_ERROR;
        !          1875:            }
        !          1876:            return status;
        !          1877:        }                       /* Add key to key ring */
        !          1878: 
        !          1879: /*-------------------------------------------------------*/
        !          1880:     case 'x':
        !          1881:        {                       /*      Extract key from key ring
        !          1882:                                   Arguments: mcguffin, keyfile, ringfile
        !          1883:                                 */
        !          1884: 
        !          1885:            if (myArgc >= (filter_mode ? 4 : 5)) /* default key ring
        !          1886:                                                    filename */
        !          1887:                strncpy(ringfile, myArgv[(filter_mode ? 3 : 4)],
        !          1888:                        sizeof(ringfile) - 1);
        !          1889:            else
        !          1890:                strcpy(ringfile, globalPubringName);
        !          1891: 
        !          1892:            if (myArgc >= (filter_mode ? 2 : 3)) {
        !          1893:                if (myArgv[2])
        !          1894:                    /* Userid to extract */
        !          1895:                    strcpy(mcguffin, myArgv[2]);
1.1.1.7   root     1896:                else
1.1.1.8 ! root     1897:                    strcpy(mcguffin, "");
        !          1898:            } else {
        !          1899:                fprintf(pgpout,
        !          1900: LANG("\nA user ID is required to select the key you want to extract. "));
        !          1901:                if (batchmode)  /* not interactive, userid
        !          1902:                                   must be on command line */
        !          1903:                    return -1;
        !          1904:                fprintf(pgpout, LANG("\nEnter the key's user ID: "));
        !          1905:                getstring(mcguffin, 255, TRUE);         /* echo keyboard */
        !          1906:            }
        !          1907:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
1.1.1.7   root     1908: 
1.1.1.8 ! root     1909:            if (!filter_mode) {
        !          1910:                if (myArgc >= 4)
        !          1911:                    strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
        !          1912:                else
        !          1913:                    keyfile[0] = '\0';
1.1.1.7   root     1914: 
1.1.1.8 ! root     1915:                workfile = keyfile;
        !          1916:            } else {
        !          1917:                workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !          1918:            }
1.1.1.7   root     1919: 
                   1920: #ifdef MSDOS
1.1.1.8 ! root     1921:            strlwr(workfile);
        !          1922:            strlwr(ringfile);
1.1.1.7   root     1923: #endif
                   1924: 
1.1.1.8 ! root     1925:            default_extension(ringfile, PGP_EXTENSION);
1.1.1.7   root     1926: 
1.1.1.8 ! root     1927:            status = extract_from_keyring(mcguffin, workfile,
        !          1928:                                          ringfile, (filter_mode ? FALSE :
        !          1929:                                                     emit_radix_64));
1.1.1.7   root     1930: 
1.1.1.8 ! root     1931:            if (status < 0) {
        !          1932:                fprintf(pgpout, LANG("\007Keyring extract error. "));
        !          1933:                errorLvl = KEYRING_EXTRACT_ERROR;
        !          1934:                if (filter_mode)
        !          1935:                    rmtemp(workfile);
        !          1936:                return status;
        !          1937:            }
        !          1938:            if (filter_mode && !status) {
        !          1939:                if (emit_radix_64) {
        !          1940:                    /* NULL for outputfile means write to stdout */
        !          1941:                    if (armor_file(workfile, NULL, NULL, NULL) != 0) {
        !          1942:                        errorLvl = UNKNOWN_FILE_ERROR;
        !          1943:                        return -1;
        !          1944:                    }
        !          1945:                } else {
        !          1946:                    if (writePhantomOutput(workfile) < 0) {
        !          1947:                        errorLvl = UNKNOWN_FILE_ERROR;
        !          1948:                        return -1;
        !          1949:                    }
1.1.1.7   root     1950:                }
1.1.1.8 ! root     1951:                rmtemp(workfile);
        !          1952:            }
        !          1953:            return 0;
        !          1954:        }                       /* Extract key from key ring */
        !          1955: 
        !          1956: /*-------------------------------------------------------*/
        !          1957:     case 'r':
        !          1958:        {       /*      Remove keys or selected key signatures from userid keys
1.1.1.7   root     1959:                        Arguments: userid, ringfile
1.1.1.8 ! root     1960:                 */
1.1.1.7   root     1961: 
1.1.1.8 ! root     1962:            if (myArgc >= 4)
        !          1963:                strcpy(ringfile, myArgv[3]);
        !          1964:            else                /* default key ring filename */
        !          1965:                strcpy(ringfile, globalPubringName);
        !          1966: 
        !          1967:            if (myArgc >= 3) {
        !          1968:                strcpy(mcguffin, myArgv[2]);    /* Userid to work on */
        !          1969:            } else {
        !          1970:                if (sign_flag) {
        !          1971:                    fprintf(pgpout,
        !          1972: LANG("\nA user ID is required to select the public key you want to\n\
1.1.1.7   root     1973: remove certifying signatures from. "));
1.1.1.8 ! root     1974:                } else {
        !          1975:                    fprintf(pgpout,
        !          1976: LANG("\nA user ID is required to select the key you want to remove. "));
1.1.1.7   root     1977:                }
1.1.1.8 ! root     1978:                if (batchmode)  /* not interactive, userid must be on
        !          1979:                                   command line */
        !          1980:                    return -1;
        !          1981:                fprintf(pgpout, LANG("\nEnter the key's user ID: "));
        !          1982:                getstring(mcguffin, 255, TRUE);         /* echo keyboard */
        !          1983:            }
        !          1984:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
1.1.1.7   root     1985: 
                   1986: #ifdef MSDOS
1.1.1.8 ! root     1987:            strlwr(ringfile);
1.1.1.7   root     1988: #endif
1.1.1.8 ! root     1989:            if (!file_exists(ringfile))
        !          1990:                default_extension(ringfile, PGP_EXTENSION);
1.1.1.7   root     1991: 
1.1.1.8 ! root     1992:            if (sign_flag) {    /* Remove signatures */
        !          1993:                if (remove_sigs(mcguffin, ringfile) < 0) {
        !          1994:                    fprintf(pgpout, LANG("\007Key signature remove error. "));
        !          1995:                    errorLvl = KEYSIG_REMOVE_ERROR;
        !          1996:                    return -1;
        !          1997:                }
        !          1998:            } else {            /* Remove keyring */
        !          1999:                if (remove_from_keyring(NULL, mcguffin, ringfile,
        !          2000:                                        (boolean) (myArgc < 4)) < 0) {
        !          2001:                    fprintf(pgpout, LANG("\007Keyring remove error. "));
        !          2002:                    errorLvl = KEYRING_REMOVE_ERROR;
        !          2003:                    return -1;
        !          2004:                }
        !          2005:            }
        !          2006:            return 0;
        !          2007:        }                       /* remove key signatures from userid */
        !          2008: 
        !          2009: /*-------------------------------------------------------*/
        !          2010:     case 'v':
        !          2011:     case 'V':                  /* -kvv */
        !          2012:        {                       /* View or remove key ring entries,
        !          2013:                                   with userid match
        !          2014:                                   Arguments: userid, ringfile
        !          2015:                                 */
        !          2016: 
        !          2017:            if (myArgc < 4)     /* default key ring filename */
        !          2018:                strcpy(ringfile, globalPubringName);
        !          2019:            else
        !          2020:                strcpy(ringfile, myArgv[3]);
        !          2021: 
        !          2022:            if (myArgc > 2) {
        !          2023:                strcpy(mcguffin, myArgv[2]);
        !          2024:                if (strcmp(mcguffin, "*") == 0)
        !          2025:                    mcguffin[0] = '\0';
        !          2026:            } else {
        !          2027:                *mcguffin = '\0';
        !          2028:            }
        !          2029: 
        !          2030:            if ((myArgc == 3) && has_extension(myArgv[2], PGP_EXTENSION)) {
        !          2031:                strcpy(ringfile, myArgv[2]);
        !          2032:                mcguffin[0] = '\0';
        !          2033:            }
        !          2034:            CONVERT_TO_CANONICAL_CHARSET(mcguffin);
1.1.1.7   root     2035: 
                   2036: #ifdef MSDOS
1.1.1.8 ! root     2037:            strlwr(ringfile);
1.1.1.7   root     2038: #endif
1.1.1.8 ! root     2039:            if (!file_exists(ringfile))
        !          2040:                default_extension(ringfile, PGP_EXTENSION);
1.1.1.7   root     2041: 
1.1.1.8 ! root     2042:            /* If a second 'v' (keychar = V), show signatures too */
        !          2043:            status = view_keyring(mcguffin, ringfile,
        !          2044:                                  (boolean) (keychar == 'V'), c_flag);
        !          2045:            if (status < 0) {
        !          2046:                fprintf(pgpout, LANG("\007Keyring view error. "));
        !          2047:                errorLvl = KEYRING_VIEW_ERROR;
        !          2048:            }
        !          2049:            return status;
        !          2050:        }                       /* view key ring entries, with userid match */
        !          2051: 
        !          2052:     default:
        !          2053:        arg_error();
        !          2054:     }
        !          2055:     return 0;
        !          2056: }                              /* do_keyopt */
1.1.1.7   root     2057: 
1.1.1.8 ! root     2058: /* comes here if user made a boo-boo. */
        !          2059: void user_error()
1.1.1.7   root     2060: {
1.1.1.8 ! root     2061:     fprintf(pgpout, LANG("\nFor a usage summary, type:  pgp -h\n"));
        !          2062:     fprintf(pgpout,
        !          2063:            LANG("For more detailed help, consult the PGP User's Guide.\n"));
        !          2064:     exitPGP(errorLvl ? errorLvl : 127);                /* error exit */
1.1.1.7   root     2065: }
                   2066: 
                   2067: #if defined(DEBUG) && defined(linux)
                   2068: #include <malloc.h>
                   2069: #endif
1.1.1.8 ! root     2070: 
1.1.1.7   root     2071: /*
                   2072:  * exitPGP: wipes and removes temporary files, also tries to wipe
                   2073:  * the stack.
                   2074:  */
                   2075: void exitPGP(int returnval)
                   2076: {
1.1.1.8 ! root     2077:     char buf[STACK_WIPE];
        !          2078:     struct hashedpw *hpw;
1.1.1.7   root     2079: 
1.1.1.8 ! root     2080:     if (verbose)
        !          2081:        fprintf(pgpout, "exitPGP: exitcode = %d\n", returnval);
        !          2082:     for (hpw = passwds; hpw; hpw = hpw->next)
        !          2083:        memset(hpw->hash, 0, sizeof(hpw->hash));
        !          2084:     for (hpw = keypasswds; hpw; hpw = hpw->next)
        !          2085:        memset(hpw->hash, 0, sizeof(hpw->hash));
        !          2086:     cleanup_tmpf();
1.1.1.7   root     2087: #if defined(DEBUG) && defined(linux)
1.1.1.8 ! root     2088:     if (verbose) {
        !          2089:        struct mstats mstat;
        !          2090:        mstat = mstats();
        !          2091:        printf("%d chunks used (%d bytes)  %d bytes total\n",
        !          2092:               mstat.chunks_used, mstat.bytes_used, mstat.bytes_total);
        !          2093:     }
1.1.1.7   root     2094: #endif
1.1.1.8 ! root     2095:     memset(buf, 0, sizeof(buf));       /* wipe stack */
1.1.1.7   root     2096: #ifdef VMS
                   2097: /*
                   2098:  * Fake VMS style error returns with severity in bottom 3 bits
                   2099:  */
1.1.1.8 ! root     2100:     if (returnval)
        !          2101:        returnval = (returnval << 3) | 0x10000002;
        !          2102:     else
        !          2103:        returnval = 0x10000001;
        !          2104: #endif                         /* VMS */
        !          2105:     exit(returnval);
1.1.1.7   root     2106: }
                   2107: 
                   2108: static void arg_error()
                   2109: {
1.1.1.8 ! root     2110:     signon_msg();
        !          2111:     fprintf(pgpout, LANG("\nInvalid arguments.\n"));
        !          2112:     errorLvl = BAD_ARG_ERROR;
        !          2113:     user_error();
1.1.1.7   root     2114: }
                   2115: 
                   2116: /*
                   2117:  * Check for language specific help files in PGPPATH, then the system
                   2118:  * directory.  If that fails, check for the default pgp.hlp, again
                   2119:  * firat a private copy, then the system-wide one.
                   2120:  *
                   2121:  * System-wide copies currently only exist on Unix.
                   2122:  */
1.1.1.8 ! root     2123: static void build_helpfile(char *helpfile, char const *extra)
1.1.1.7   root     2124: {
1.1.1.8 ! root     2125:     if (strcmp(language, "en")) {
        !          2126:        buildfilename(helpfile, language);
1.1.1.7   root     2127:        strcat(helpfile, extra);
                   2128:        force_extension(helpfile, HLP_EXTENSION);
                   2129:        if (file_exists(helpfile))
1.1.1.8 ! root     2130:            return;
        !          2131: #ifdef PGP_SYSTEM_DIR
1.1.1.7   root     2132:        strcpy(helpfile, PGP_SYSTEM_DIR);
1.1.1.8 ! root     2133:        strcat(helpfile, language);
1.1.1.7   root     2134:        strcat(helpfile, extra);
                   2135:        force_extension(helpfile, HLP_EXTENSION);
1.1.1.8 ! root     2136:        if (file_exists(helpfile))
        !          2137:            return;
        !          2138: #endif
        !          2139:     }
        !          2140:     buildfilename(helpfile, "pgp");
        !          2141:     strcat(helpfile, extra);
        !          2142:     force_extension(helpfile, HLP_EXTENSION);
        !          2143: #ifdef PGP_SYSTEM_DIR
        !          2144:     if (file_exists(helpfile))
        !          2145:        return;
        !          2146:     strcpy(helpfile, PGP_SYSTEM_DIR);
        !          2147:     strcat(helpfile, "pgp");
        !          2148:     strcat(helpfile, extra);
        !          2149:     force_extension(helpfile, HLP_EXTENSION);
1.1.1.7   root     2150: #endif
                   2151: }
                   2152: 
                   2153: static void usage()
                   2154: {
1.1.1.8 ! root     2155:     char helpfile[MAX_PATH];
        !          2156:     char *tmphelp = helpfile;
        !          2157:     extern unsigned char *ext_c_ptr;
        !          2158: 
        !          2159:     signon_msg();
        !          2160:     build_helpfile(helpfile, "");
        !          2161: 
        !          2162:     if (ext_c_ptr) {
        !          2163:        /* conversion to external format necessary */
        !          2164:        tmphelp = tempfile(TMP_TMPDIR);
        !          2165:        CONVERSION = EXT_CONV;
        !          2166:        if (copyfiles_by_name(helpfile, tmphelp) < 0) {
        !          2167:            rmtemp(tmphelp);
        !          2168:            tmphelp = helpfile;
        !          2169:        }
        !          2170:        CONVERSION = NO_CONV;
        !          2171:     }
        !          2172:     /* built-in help if pgp.hlp is not available */
        !          2173:     if (more_file(tmphelp) < 0)
        !          2174:        fprintf(pgpout, LANG("\nUsage summary:\
1.1.1.7   root     2175: \nTo encrypt a plaintext file with recipent's public key, type:\
                   2176: \n   pgp -e textfile her_userid [other userids] (produces textfile.pgp)\
                   2177: \nTo sign a plaintext file with your secret key:\
                   2178: \n   pgp -s textfile [-u your_userid]           (produces textfile.pgp)\
                   2179: \nTo sign a plaintext file with your secret key, and then encrypt it\
                   2180: \n   with recipent's public key, producing a .pgp file:\
                   2181: \n   pgp -es textfile her_userid [other userids] [-u your_userid]\
                   2182: \nTo encrypt with conventional encryption only:\
                   2183: \n   pgp -c textfile\
                   2184: \nTo decrypt or check a signature for a ciphertext (.pgp) file:\
                   2185: \n   pgp ciphertextfile [plaintextfile]\
                   2186: \nTo produce output in ASCII for email, add the -a option to other options.\
                   2187: \nTo generate your own unique public/secret key pair:  pgp -kg\
                   2188: \nFor help on other key management functions, type:   pgp -k\n"));
1.1.1.8 ! root     2189:     if (ext_c_ptr)
        !          2190:        rmtemp(tmphelp);
        !          2191:     exit(BAD_ARG_ERROR);       /* error exit */
1.1.1.7   root     2192: }
                   2193: 
                   2194: static void key_usage()
                   2195: {
1.1.1.8 ! root     2196:     char helpfile[MAX_PATH];
        !          2197:     char *tmphelp = helpfile;
        !          2198:     extern unsigned char *ext_c_ptr;
        !          2199: 
        !          2200:     signon_msg();
        !          2201:     build_helpfile(helpfile, "key");
        !          2202: 
        !          2203:     if (ext_c_ptr) {
        !          2204:        /* conversion to external format necessary */
        !          2205:        tmphelp = tempfile(TMP_TMPDIR);
        !          2206:        CONVERSION = EXT_CONV;
        !          2207:        if (copyfiles_by_name(helpfile, tmphelp) < 0) {
        !          2208:            rmtemp(tmphelp);
        !          2209:            tmphelp = helpfile;
        !          2210:        }
        !          2211:        CONVERSION = NO_CONV;
        !          2212:     }
        !          2213:     /* built-in help if pgp.hlp is not available */
        !          2214:     if (more_file(tmphelp) < 0)
        !          2215:        /* only use built-in help if there is no helpfile */
        !          2216:        fprintf(pgpout, LANG("\nKey management functions:\
1.1.1.7   root     2217: \nTo generate your own unique public/secret key pair:\
                   2218: \n   pgp -kg\
                   2219: \nTo add a key file's contents to your public or secret key ring:\
                   2220: \n   pgp -ka keyfile [keyring]\
                   2221: \nTo remove a key or a user ID from your public or secret key ring:\
                   2222: \n   pgp -kr userid [keyring]\
                   2223: \nTo edit your user ID or pass phrase:\
                   2224: \n   pgp -ke your_userid [keyring]\
                   2225: \nTo extract (copy) a key from your public or secret key ring:\
                   2226: \n   pgp -kx userid keyfile [keyring]\
                   2227: \nTo view the contents of your public key ring:\
                   2228: \n   pgp -kv[v] [userid] [keyring]\
                   2229: \nTo check signatures on your public key ring:\
                   2230: \n   pgp -kc [userid] [keyring]\
                   2231: \nTo sign someone else's public key on your public key ring:\
                   2232: \n   pgp -ks her_userid [-u your_userid] [keyring]\
                   2233: \nTo remove selected signatures from a userid on a keyring:\
                   2234: \n   pgp -krs userid [keyring]\
                   2235: \n"));
1.1.1.8 ! root     2236: 
        !          2237:     exit(BAD_ARG_ERROR);       /* error exit */
1.1.1.7   root     2238: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.