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

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

unix.superglobalmegacorp.com

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