|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.