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