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 <branko@hacktic.nl>
17 Hal Finney <74076.1041@compuserve.com>
18 Peter Gutmann <pgut1@cs.aukuni.ac.nz>
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-1996 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: prz@acm.org
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 cache buffers.
83
84 Revisions:
85 Version 1.0 - 5 Jun 91
86 Version 1.4 - 19 Jan 92
87 Version 1.5 - 12 Feb 92
88 Version 1.6 - 24 Feb 92
89 Version 1.7 - 29 Mar 92
90 Version 1.8 - 23 May 92
91 Version 2.0 - 2 Sep 92
92 Version 2.1 - 6 Dec 92
93 Version 2.2 - 6 Mar 93
94 Version 2.3 - 13 Jun 93
95 Version 2.3a- 1 Jul 93
96 Version 2.4 - 6 Nov 93
97 Version 2.5 - 5 May 94
98 Version 2.6 - 22 May 94
99 Version 2.6.1 - 29 Aug 94
100 Version 2.6.2 - 11 Oct 94
101 Version 2.6.2i - 7 May 95
102 Version 2.6.3(i) - 18 Jan 96
103 Version 2.6.3(i)a - 4 Mar 96
104 Version 2.6.3(i)n - 2 Apr 1997
105 Version 2.6.3(i)n - 3 Apr 1997
106 Version 2.6.3(i)n - 4 Apr 1997
107 Version 2.6.3(i)n - 18 Apr 1997
108 Version 2.6.3(i)n - 12 May 1997
109 Version 2.6.3(i)n - 13 May 1997
110 Version 2.6.3(i)n - 29 May 1997
111 Version 2.6.3(i)n - 29 Jul 1997
112 Version 2.6.3(i)n - 28 Aug 1997
113 Version 2.6.3(i)n - 5 Sep 1997
114 Version 2.6.3(i)n - 6 Oct 1997
115 Version 2.6.3(i)n - 7 Oct 1997
116 Version 2.6.3(i)n - 2 Sep 1999
117 Version 2.6.3(i)n - 6 Oct 2000
118 Version 2.6.3(i)n - 22 Mar 2001
119 */
120
121
122 #include <ctype.h>
123 #ifndef AMIGA
124 #include <signal.h>
125 #endif
126 #include <stdio.h>
127 #include <stdlib.h>
128 #include <string.h>
129
130 #ifdef UNIX
131 #include <sys/types.h>
132 #include <sys/stat.h>
133 #endif
134
135 #include "system.h"
136 #include "mpilib.h"
137 #include "random.h"
138 #include "crypto.h"
139 #include "fileio.h"
140 #include "keymgmt.h"
141 #include "language.h"
142 #include "pgp.h"
143 #include "exitpgp.h"
144 #include "charset.h"
145 #include "getopt.h"
146 #include "config.h"
147 #include "keymaint.h"
148 #include "keyadd.h"
149 #include "rsaglue.h"
150 #include "noise.h"
151
152 #ifdef MACTC5
153 #include "Macutil.h"
154 #include "Macutil2.h"
155 #include "Macutil3.h"
156 #include "Macutil4.h"
157 #include "Macbinary.h"
158 #include "Binhex.h"
159 #include "MacPGP.h"
160 #include "mystr.h"
161 void AddOutputFiles(char *filepath);
162 void ReInitKeyMaint(void);
163 extern char appPathName[];
164 void ReInitGlobals(void);
165 extern int level,method;
166 extern Boolean explicit_plainfile;
167 extern long infile_line;
168 extern int eofonce;
169 extern boolean savedwashed;
170 extern char *special;
171 char *Outputfile = NULL;
172 void check_expiration_date(void);
173 #define BEST -1
174 #define exit Exit
175 void Exit(int x);
176 #endif
177
178 #ifdef M_XENIX
179 char *strstr();
180 long time();
181 #endif
182
183 #ifdef MSDOS
184 #ifdef __ZTC__ /* Extend stack for Zortech C */
185 unsigned _stack_ = 24 * 1024;
186 #endif
187 #ifdef __TURBOC__
188 unsigned _stklen = 24 * 1024;
189 #endif
190 #endif
191 #define STACK_WIPE 4096
192
193 #ifdef AMIGA
194 #ifdef __SASC_60
195 /* Let the compiler allocate us an appropriate stack. */
196 extern long __stack = 32768L;
197 #endif
198
199 /* Add the appropriate AmigaOS version string, depending on the
200 * compiler flags.
201 */
202 #ifdef USA
203 static const char __DOSVer[] = "$VER: PGP 2.6.3n (2001-03-23)"
204 # ifdef _M68020
205 " Amiga 68020 version by Rob Knop <rknop@mop.caltech.edu>";
206 # else
207 " Amiga 68000 version by Rob Knop <rknop@mop.caltech.edu>";
208 # endif
209 #else
210 static const char __DOSVer[] = "$VER: PGP 2.6.3in (2001-03-23)"
211 # ifdef _M68020
212 " Amiga 68020 version by Peter Simons <simons@peti.rhein.de>";
213 # else
214 " Amiga 68000 version by Peter Simons <simons@peti.rhein.de>";
215 # endif
216 #endif /* USA */
217 #endif /* AMIGA */
218
219 /* Global filenames and system-wide file extensions... */
220 #ifdef USA
221 char rel_version[] = _LANG("2.6.3n"); /* release version */
222 #else
223 char rel_version[] = _LANG("2.6.3in"); /* release version */
224 #endif
225 char rel_date[] = "2001-03-23"; /* release date */
226 char PGP_EXTENSION[] = ".pgp";
227 char ASC_EXTENSION[] = ".asc";
228 char SIG_EXTENSION[] = ".sig";
229 char BAK_EXTENSION[] = ".bak";
230 static char HLP_EXTENSION[] = ".hlp";
231 char CONSOLE_FILENAME[] = "_CONSOLE";
232 #ifdef MACTC5
233 char HELP_FILENAME[256] = "pgp.hlp";
234 #else
235 static char HELP_FILENAME[] = "pgp.hlp";
236 #endif
237
238 /* These files use the environmental variable PGPPATH as a default path: */
239 char globalPubringName[MAX_PATH];
240 char globalSecringName[MAX_PATH];
241 char globalRandseedName[MAX_PATH];
242 char globalCommentString[128];
243
244 /* Flags which are global across the driver code files */
245 boolean verbose = FALSE; /* -l option: display maximum information */
246 FILE *pgpout; /* Place for routine messages */
247
248 static void usage(void);
249 static void key_usage(void);
250 static void arg_error(void);
251 static void initsigs(void);
252 static int do_keyopt(char);
253 static int do_decrypt(char *);
254 static void do_armorfile(char *);
255 char ** ParseRecipients(char **);
256 void hashpass (char *keystring, int keylen, byte *hash);
257
258 /* Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK.
259 Lha(rc) is handled specially in the code; it is missing from the
260 compressSig structure intentionally. If more formats are added,
261 put them before lharc to keep the code consistent.
262
263 27-Jun-95 simons@peti.rhein.de (Peter Simons)
264 Added support for lh5 archive as generated by Lha. Unfortunately,
265 lh5 requires special treatment also. I inserted the check right
266 _before_ lharc, because lh5/lha is a special type of an lharc
267 archive.
268 */
269 static char *compressSig[] =
270 {"PK\03\04", "ZOO ", "GIF8", "\x60\xea", "Rar!",
271 "HPAK", "\037\213", "\037\235", "\032\013", "\032HP%"
272 /* lharc is special, must be last */ };
273 static char *compressName[] =
274 {"PKZIP", "Zoo", "GIF", "Arj", "RAR",
275 "Hpack", "gzip", "compressed", "PAK", "Hyper",
276 "Lha", "Lharc"};
277 static char *compressExt[] =
278 {".zip", ".zoo", ".gif", ".arj", ".rar",
279 ".hpk", ".gz", ".Z", ".pak", ".hyp",
280 ".lha", ".lzh"};
281
282 /* "\032\0??", "ARC", ".arc" */
283
284 /* Returns file signature type from a number of popular compression formats
285 or -1 if no match */
compressSignature(byte * header)286 int compressSignature(byte * header)
287 {
288 int i;
289
290 for (i = 0; i < sizeof(compressSig) / sizeof(*compressSig); i++)
291 if (!strncmp((char *) header, compressSig[i], strlen(compressSig[i])))
292 return i;
293
294 /* Special check for lha files */
295 if (!strncmp((char *)header+2, "-lh5-", 5))
296 return i;
297
298 /* Special check for lharc files */
299 if (header[2] == '-' && header[3] == 'l' &&
300 (header[4] == 'z' || header[4] == 'h') &&
301 header[6] == '-')
302 return i+1;
303 return -1;
304 } /* compressSignature */
305
306 /* returns TRUE if file is likely to be compressible */
file_compressible(char * filename)307 static boolean file_compressible(char *filename)
308 {
309 byte header[8];
310 get_header_info_from_file(filename, header, 8);
311 if (compressSignature(header) >= 0)
312 return FALSE; /* probably not compressible */
313 return TRUE; /* possibly compressible */
314 } /* compressible */
315
316
317 /* Possible error exit codes - not all of these are used. Note that we
318 don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE. To make things
319 easier for compilers which don't support enum we use #defines */
320
321 #define EXIT_OK 0
322 #define INVALID_FILE_ERROR 1
323 #define FILE_NOT_FOUND_ERROR 2
324 #define UNKNOWN_FILE_ERROR 3
325 #define NO_BATCH 4
326 #define BAD_ARG_ERROR 5
327 #define INTERRUPT 6
328 #define OUT_OF_MEM 7
329
330 /* Keyring errors: Base value = 10 */
331 #define KEYGEN_ERROR 10
332 #define NONEXIST_KEY_ERROR 11
333 #define KEYRING_ADD_ERROR 12
334 #define KEYRING_EXTRACT_ERROR 13
335 #define KEYRING_EDIT_ERROR 14
336 #define KEYRING_VIEW_ERROR 15
337 #define KEYRING_REMOVE_ERROR 16
338 #define KEYRING_CHECK_ERROR 17
339 #define KEY_SIGNATURE_ERROR 18
340 #define KEYSIG_REMOVE_ERROR 19
341
342 /* Encode errors: Base value = 20 */
343 #define SIGNATURE_ERROR 20
344 #define RSA_ENCR_ERROR 21
345 #define ENCR_ERROR 22
346 #define COMPRESS_ERROR 23
347
348 /* Decode errors: Base value = 30 */
349 #define SIGNATURE_CHECK_ERROR 30
350 #define RSA_DECR_ERROR 31
351 #define DECR_ERROR 32
352 #define DECOMPRESS_ERROR 33
353
354
355 #ifdef SIGINT
356
357 /* This function is called if a BREAK signal is sent to the program. In this
358 case we zap the temporary files.
359 */
breakHandler(int sig)360 void breakHandler(int sig)
361 {
362 #ifdef UNIX
363 if (sig == SIGPIPE) {
364 signal(SIGPIPE, SIG_IGN);
365 exitPGP(INTERRUPT);
366 }
367 if (sig != SIGINT)
368 fprintf(stderr, "\nreceived signal %d\n", sig);
369 else
370 #endif
371 fprintf(pgpout, LANG("\nStopped at user request\n"));
372 exitPGP(INTERRUPT);
373 }
374 #endif
375
376 /* Clears screen and homes the cursor. */
clearscreen(void)377 static void clearscreen(void)
378 {
379 fprintf(pgpout, "\n\033[0;0H\033[J\r \r"); /* ANSI sequence. */
380 fflush(pgpout);
381 }
382
383 /* We had to process the config file first to possibly select the
384 foreign language to translate the sign-on line that follows... */
signon_msg(void)385 static void signon_msg(void)
386 {
387 word32 tstamp;
388 /* display message only once to allow calling multiple times */
389 static boolean printed = FALSE;
390
391 if (quietmode || printed)
392 return;
393 printed = TRUE;
394 fprintf(stderr,
395 LANG("Pretty Good Privacy(tm) %s - Public-key encryption for the masses.\n"),
396 rel_version);
397 #ifdef TEMP_VERSION
398 fputs(
399 "Internal development version only - not for general release.\n", stderr);
400 #endif
401 fputs(LANG("(c) 1990-96 Philip Zimmermann, Phil's Pretty Good Software."),
402 stderr);
403 fprintf(stderr, " %s\n",LANG(rel_date));
404 #ifdef USA
405 fputs(LANG(signon_legalese), stderr);
406 #endif
407 fputs(
408 #ifdef USA
409 LANG("Export of this software may be restricted by the U.S. government.\n"),
410 #else
411 LANG("International version - not for use in the USA. Does not use RSAREF.\n"),
412 #endif
413 stderr);
414
415 get_timestamp((byte *) & tstamp); /* timestamp points to tstamp */
416 fprintf(pgpout, LANG("Current time: %s\n"), ctdate(&tstamp));
417 }
418
419
420 #ifdef TEMP_VERSION /* temporary experimental version of PGP */
421 #include <time.h>
422 #define CREATION_DATE 0x30FE3640ul
423 /* CREATION_DATE is
424 Thu Jan 18, 1996 1200 hours UTC */
425 #define LIFESPAN ((unsigned long) 60L * (unsigned long) 86400L)
426 /* LIFESPAN is 60 days */
427
428 /* If this is an experimental version of PGP, cut its life short */
check_expiration_date(void)429 void check_expiration_date(void)
430 {
431 if (get_timestamp(NULL) > (CREATION_DATE + LIFESPAN)) {
432 fprintf(stderr,
433 "\n\007This experimental version of PGP has expired.\n");
434 exit(-1); /* error exit */
435 }
436 } /* check_expiration_date */
437 #else /* no expiration date */
438 #define check_expiration_date() /* null statement */
439 #endif /* TEMP_VERSION */
440
441 /* -f means act as a unix-style filter */
442 /* -i means internalize extended file attribute information, only supported
443 * between like (or very compatible) operating systems. */
444 /* -l means show longer more descriptive diagnostic messages */
445 /* -m means display plaintext output on screen, like unix "more" */
446 /* -d means decrypt only, leaving inner signature wrapping intact */
447 /* -t means treat as pure text and convert to canonical text format */
448
449 /* Used by getopt function... */
450 #define OPTIONS "abcdefghiklmo:prstu:vwxz:ABCDEFGHIKLMO:PRSTU:VWX?"
451 extern int optind;
452 extern char *optarg;
453
454 #define INCLUDE_MARK "-@"
455 #define INCLUDE_MARK_LEN sizeof(INCLUDE_MARK)-1 /* skip the \0 */
456
457 boolean emit_radix_64 = FALSE; /* set by config file */
458 static boolean sign_flag = FALSE;
459 boolean moreflag = FALSE;
460 boolean filter_mode = FALSE;
461 static boolean preserve_filename = FALSE;
462 static boolean decrypt_only_flag = FALSE;
463 static boolean de_armor_only = FALSE;
464 static boolean strip_sig_flag = FALSE;
465 boolean clear_signatures = TRUE;
466 boolean strip_spaces;
467 static boolean c_flag = FALSE;
468 static boolean u_flag = FALSE; /* Did I get my_name from -u? */
469 boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? */
470 boolean sign_new_userids = TRUE;
471 boolean batchmode = FALSE; /* if TRUE: don't ask questions */
472 boolean quietmode = FALSE;
473 boolean force_flag = FALSE; /* overwrite existing file without asking */
474 #ifdef VMS /* kludge for those stupid VMS variable-length
475 text records */
476 char literal_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal
477 packet */
478 #else /* not VMS */
479 char literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal
480 packet */
481 #endif /* not VMS */
482 /* my_name is substring of default userid for secret key to make signatures */
483 char my_name[256] = "\0"; /* null my_name means take first userid
484 in ring */
485 char my_etsid[256] = "\0";
486 boolean keepctx = FALSE; /* TRUE means keep .ctx file on decrypt */
487 /* Ask for each key separately if it should be added to the keyring */
488 boolean interactive_add = FALSE;
489 boolean compress_enabled = TRUE; /* attempt compression before encryption */
490 long timeshift = 0L; /* seconds from GMT timezone */
491 int version_byte = VERSION_BYTE_NEW;
492 boolean nomanual = 0;
493 /* Show unknown certs in -kv[c][v], default: no, because it's useless */
494 boolean show_unknown_certs = FALSE;
495 /* If non-zero, initialize file to this many random bytes */
496 int makerandom = 0;
497
498
499 static char *outputfile = NULL;
500 #ifndef MACTC5
501 static int errorLvl = EXIT_OK;
502 #else
503 int errorLvl = EXIT_OK;
504 #endif
505 static char mcguffin[256]; /* userid search tag */
506 boolean signature_checked = FALSE;
507 int checksig_pass = 0;
508 boolean use_charset_header;
509 char charset_header[16] = "";
510 char plainfile[MAX_PATH];
511 int myArgc = 2;
512 char **myArgv;
513 struct hashedpw *passwds = 0, *keypasswds = 0;
514 static struct hashedpw **passwdstail = &passwds;
515
516 #ifdef MACTC5
517 extern unsigned long PGPStart, WNECalls;
518
ReInitGlobals()519 void ReInitGlobals()
520 {
521 int i;
522 char scratch[64];
523 WNECalls = 0;
524 if (verbose)
525 PGPStart = TickCount();
526 else
527 PGPStart = 0;
528 Abort = FALSE;
529 BreakCntl = 0;
530 pgpout = stderr;
531 optind = 1;
532 errorLvl = EXIT_OK;
533 myArgc = 2;
534 myArgv = nil;
535 emit_radix_64 = FALSE; /* set by config file */
536 sign_flag = FALSE;
537 moreflag = FALSE;
538 filter_mode = FALSE;
539 preserve_filename = FALSE;
540 decrypt_only_flag = FALSE;
541 de_armor_only = FALSE;
542 strip_sig_flag = FALSE;
543 u_flag = FALSE;
544 c_flag = FALSE;
545 signature_checked = FALSE;
546 literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal packet */
547 errorLvl = EXIT_OK;
548 outputfile = Outputfile;
549 method = BEST; /* one of BEST, DEFLATE (only), or STORE (only) */
550 level = 9; /* 0=fastest compression, 9=best compression */
551 special = NULL; /* List of special suffixes */
552 infile_line = 0;
553 eofonce = 0;
554 savedwashed = FALSE;
555 ReInitKeyMaint();
556 settmpdir(nil);
557 setoutdir(nil);
558 makerandom = 0;
559 if (xcli_opt[0]) {
560 if (argv[argc] == nil)
561 argv[argc] = malloc((size_t) 80);
562 if (argv[argc] == nil) {
563 BailoutAlert(LANG("Out of memory"));
564 ExitToShell();
565 }
566 strcpy(argv[argc], xcli_opt);
567 argc++;
568 fprintf(pgpout, " %s\n", xcli_opt);
569 }
570 for (i = 0; i <= 63; i++)
571 scratch[i] = to_upper(xcli_opt[i]);
572 if (strcmp(xcli_opt, "+NOMANUAL=ON")==0) nomanual = true;
573 else nomanual = false;
574 }
575
init_pgp()576 int init_pgp()
577 {
578 int err=0;
579 pgpout=stderr;
580 /* Process the config file first. Any command-line arguments will
581 override the config file settings */
582 buildfilename( mcguffin, "config.txt");
583 if ( processConfigFile( mcguffin ) < 0 )
584 err=BAD_ARG_ERROR;
585 init_charset();
586 signon_msg();
587 g_armor_flag=emit_radix_64;
588 g_text_mode=(literal_mode == MODE_TEXT);
589 g_clear_signatures=clear_signatures;
590 PGPSetFinfo(globalRandseedName,'RSed','MPGP');
591 set_precision(MAX_UNIT_PRECISION);
592 return err;
593 }
594
595
Exit(int x)596 void Exit(int x) {
597
598 errorLvl = x;
599 if (myArgv)
600 free(myArgv);
601 if (mcguffins)
602 free(mcguffins);
603 mac_cleanup_tmpf();
604 longjmp(jmp_env,5);
605 }
606
607
pgp_dispatch(int argc,char * argv[])608 int pgp_dispatch(int argc, char *argv[])
609 {
610 int status, opt;
611 char *inputfile = NULL;
612 char **recipient = NULL;
613 /* char **mcguffins; zigf made global so we can free */
614 boolean macbin_flag = FALSE;
615 #else
616
617 int main(int argc, char *argv[])
618 {
619 int status, opt;
620 char *inputfile = NULL;
621 char **recipient = NULL;
622 char **mcguffins;
623 #endif /* MACTC5 */
624 char *workfile, *tempf;
625 boolean nestflag = FALSE;
626 boolean decrypt_mode = FALSE;
627 boolean wipeflag = FALSE;
628 boolean armor_flag = FALSE; /* -a option */
629 boolean separate_signature = FALSE;
630 boolean keyflag = FALSE;
631 boolean encrypt_flag = FALSE;
632 boolean conventional_flag = FALSE;
633 boolean attempt_compression; /* attempt compression before encryption */
634 boolean output_stdout; /* Output goes to stdout */
635 char *clearfile = NULL;
636 char *literal_file = NULL;
637 char literal_file_name[MAX_PATH];
638 char cipherfile[MAX_PATH];
639 char keychar = '\0';
640 char *p;
641 byte ctb;
642 struct hashedpw *hpw;
643
644 /* Initial messages to stderr */
645 pgpout = stderr;
646
647 #ifdef MACTC5
648 ReInitGlobals();
649 #endif
650 #ifdef DEBUG1
651 verbose = TRUE;
652 #endif
653 /* The various places one can get passwords from.
654 * We accumulate them all into two lists. One is
655 * to try on keys only, and is stored in no particular
656 * order, while the other is of unknown purpose so
657 * far (they may be used for conventional encryption
658 * or decryption as well), and are kept in a specific
659 * order. If any password in the general list is found
660 * to decode a key, it is moved to the key list.
661 * The general list is not grown after initialization,
662 * so the tail pointer is not used after this.
663 */
664
665 #ifndef MACTC5
666 if ((p = getenv("PGPPASS")) != NULL) {
667 hpw = xmalloc(sizeof(struct hashedpw));
668 hashpass(p, strlen(p), hpw->hash);
669 /* Add to linked list of key passwords */
670 hpw->next = keypasswds;
671 keypasswds = hpw;
672 }
673 /* The -z "password" option should be used instead of PGPPASS if
674 * the environment can be displayed with the ps command (eg. BSD).
675 * If the system does not allow overwriting of the command line
676 * argument list but if it has a "hidden" environment, PGPPASS
677 * should be used.
678 */
679 for (opt = 1; opt < argc; ++opt) {
680 p = argv[opt];
681 if (p[0] != '-' || p[1] != 'z')
682 continue;
683 /* Accept either "-zpassword" or "-z password" */
684 p += 2;
685 if (!*p)
686 p = argv[++opt];
687 /* p now points to password */
688 if (!p)
689 break; /* End of arg list - ignore */
690 hpw = xmalloc(sizeof(struct hashedpw));
691 hashpass(p, strlen(p), hpw->hash);
692 /* Wipe password */
693 while (*p)
694 *p++ = ' ';
695 /* Add to tail of linked list of passwords */
696 hpw->next = 0;
697 *passwdstail = hpw;
698 passwdstail = &hpw->next;
699 }
700 /*
701 * If PGPPASSFD is set in the environment try to read the password
702 * from this file descriptor. If you set PGPPASSFD to 0 pgp will
703 * use the first line read from stdin as password.
704 */
705 if ((p = getenv("PGPPASSFD")) != NULL) {
706 int passfd;
707 if (*p && (passfd = atoi(p)) >= 0) {
708 char pwbuf[256];
709 p = pwbuf;
710 while (read(passfd, p, 1) == 1 && *p != '\n')
711 ++p;
712 hpw = xmalloc(sizeof(struct hashedpw));
713 hashpass(pwbuf, p - pwbuf, hpw->hash);
714 memset(pwbuf, 0, p - pwbuf);
715 /* Add to tail of linked list of passwords */
716 hpw->next = 0;
717 *passwdstail = hpw;
718 passwdstail = &hpw->next;
719 }
720 }
721 /* Process the config file. The following override each other:
722 - Hard-coded defaults
723 - The system config file
724 - Hard-coded defaults for security-critical things
725 - The user's config file
726 - Environment variables
727 - Command-line options.
728 */
729 opt = 0; /* Number of config files read */
730 #ifdef PGP_SYSTEM_DIR
731 #ifdef UNIX
732 buildsysfilename(mcguffin, ".pgprc");
733 if (access(mcguffin, 0) != 0)
734 #endif
735 buildsysfilename(mcguffin, "config.txt");
736 if (access(mcguffin, 0) == 0) {
737 opt++;
738 /*
739 * Note: errors here are NOT fatal, so that people
740 * can use PGP with a corrputed system file.
741 */
742 processConfigFile(mcguffin);
743 }
744 #endif
745
746 /*
747 * These must be personal; the system config file may not
748 * influence them.
749 */
750 buildfilename(globalPubringName, "pubring.pgp");
751 buildfilename(globalSecringName, "secring.pgp");
752 buildfilename(globalRandseedName, "randseed.bin");
753 my_name[0] = '\0';
754
755 /* Process the config file first. Any command-line arguments will
756 override the config file settings */
757 #if defined(UNIX) || defined(MSDOS) || defined(OS2) || defined (WIN32)
758 /* Try "pgp.ini" on MS-DOS or ".pgprc" on Unix */
759 #ifdef UNIX
760 buildfilename(mcguffin, ".pgprc");
761 #else
762 buildfilename(mcguffin, "pgp.ini");
763 #endif
764 if (access(mcguffin, 0) != 0)
765 buildfilename(mcguffin, "config.txt");
766 #else
767 buildfilename(mcguffin, "config.txt");
768 #endif
769 if (access(mcguffin, 0) == 0) {
770 opt++;
771 if (processConfigFile(mcguffin) < 0)
772 exit(BAD_ARG_ERROR);
773 }
774 if (!opt)
775 fprintf(pgpout, LANG("\007No configuration file found.\n"));
776
777 init_charset();
778 #endif /* MACTC5 */
779
780 #ifdef MSDOS /* only on MSDOS systems */
781 if ((p = getenv("TZ")) == NULL || *p == '\0') {
782 fprintf(pgpout,LANG("\007WARNING: Environmental variable TZ is not \
783 defined, so GMT timestamps\n\
784 may be wrong. See the PGP User's Guide to properly define TZ\n\
785 in AUTOEXEC.BAT file.\n"));
786 }
787 #endif /* MSDOS */
788
789 #ifdef VMS
790 #define TEMP "SYS$SCRATCH"
791 #else
792 #define TEMP "TMP"
793 #endif /* VMS */
794 if ((p = getenv(TEMP)) != NULL && *p != '\0')
795 settmpdir(p);
796
797 if ((myArgv = (char **) malloc((argc + 2) * sizeof(char **))) == NULL) {
798 fprintf(stderr, LANG("\n\007Out of memory.\n"));
799 exitPGP(7);
800 }
801 myArgv[0] = NULL;
802 myArgv[1] = NULL;
803
804 /* Process all the command-line option switches: */
805 while (optind < argc) {
806 /*
807 * Allow random order of options and arguments (like GNU getopt)
808 * NOTE: this does not work with GNU getopt, use getopt.c from
809 * the PGP distribution.
810 */
811 if ((!strncmp(argv[optind], INCLUDE_MARK, INCLUDE_MARK_LEN)) ||
812 ((opt = pgp_getopt(argc, argv, OPTIONS)) == EOF)) {
813 if (optind == argc) /* -- at end */
814 break;
815 myArgv[myArgc++] = argv[optind++];
816 continue;
817 }
818 opt = to_lower(opt);
819 if (keyflag && (keychar == '\0' || (keychar == 'v' && opt == 'v'))) {
820 if (keychar == 'v')
821 keychar = 'V';
822 else
823 keychar = opt;
824 continue;
825 }
826 switch (opt) {
827 case 'a':
828 armor_flag = TRUE;
829 emit_radix_64 = 1;
830 break;
831 case 'b':
832 separate_signature = strip_sig_flag = TRUE;
833 break;
834 case 'c':
835 encrypt_flag = conventional_flag = TRUE;
836 c_flag = TRUE;
837 break;
838 case 'd':
839 decrypt_only_flag = TRUE;
840 break;
841 case 'e':
842 encrypt_flag = TRUE;
843 break;
844 #ifdef MACTC5
845 case 'f':
846 if (macbin_flag == FALSE) filter_mode = TRUE;
847 break;
848 #else
849 case 'f':
850 filter_mode = TRUE;
851 break;
852 #endif
853 case '?':
854 case 'h':
855 usage();
856 break;
857 #ifdef VMS
858 case 'i':
859 literal_mode = MODE_LOCAL;
860 break;
861 #else
862 #ifdef MACTC5
863 case 'i':
864 macbin_flag = TRUE;
865 moreflag = FALSE;
866 literal_mode = MODE_BINARY;
867 filter_mode = FALSE;
868 break;
869 #endif /* MACTC5 */
870 #endif /* VMS */
871 case 'k':
872 keyflag = TRUE;
873 break;
874 case 'l':
875 verbose = TRUE;
876 break;
877 #ifdef MACTC5
878 case 'm':
879 if( macbin_flag == FALSE )
880 moreflag = TRUE;
881 break;
882 #else
883 case 'm':
884 moreflag = TRUE;
885 break;
886 #endif
887 case 'p':
888 preserve_filename = TRUE;
889 break;
890 case 'o':
891 outputfile = optarg;
892 break;
893 case 's':
894 sign_flag = TRUE;
895 break;
896 #ifdef MACTC5
897 case 't':
898 if( macbin_flag == FALSE )
899 literal_mode = MODE_TEXT;
900 break;
901 #else
902 case 't':
903 literal_mode = MODE_TEXT;
904 break;
905 #endif
906 case 'u':
907 strncpy(my_name, optarg, sizeof(my_name) - 1);
908 CONVERT_TO_CANONICAL_CHARSET(my_name);
909 u_flag = TRUE;
910 break;
911 case 'w':
912 wipeflag = TRUE;
913 break;
914 case 'z':
915 break;
916 /* '+' special option: does not require - */
917 case '+':
918 if (processConfigLine(optarg) == 0) {
919 if (!strncmp(optarg,"CH",2)) /* CHARSET */
920 init_charset();
921 break;
922 }
923 fprintf(stderr, "\n");
924 /* fallthrough */
925 default:
926 arg_error();
927 }
928 }
929 myArgv[myArgc] = NULL; /* Just to make it NULL terminated */
930
931 if (keyflag && keychar == '\0')
932 key_usage();
933
934 signon_msg();
935 check_expiration_date(); /* hobble any experimental version */
936
937 /*
938 * Write to stdout if explicitly asked to, or in filter mode and
939 * no explicit file name was given.
940 */
941 output_stdout = outputfile ? strcmp(outputfile, "-") == 0 : filter_mode;
942
943 #if 1
944 /* At request of Peter Simons, use stderr always. Sounds reasonable. */
945 /* JIS: Put this code back in... removing it broke too many things */
946 if (!output_stdout)
947 pgpout = stdout;
948 #endif
949
950
951 #if defined(UNIX) || defined(VMS)
952 umask(077); /* Make files default to private */
953 #endif
954
955 initsigs(); /* Catch signals */
956 noise(); /* Start random number generation */
957
958 if (keyflag) {
959 status = do_keyopt(keychar);
960 if (status < 0)
961 user_error();
962 exitPGP(status);
963 }
964 /* -db means break off signature certificate into separate file */
965 if (decrypt_only_flag && strip_sig_flag)
966 decrypt_only_flag = FALSE;
967
968 if (decrypt_only_flag && armor_flag)
969 decrypt_mode = de_armor_only = TRUE;
970
971 if (outputfile != NULL)
972 preserve_filename = FALSE;
973
974 if (!sign_flag && !encrypt_flag && !conventional_flag && !armor_flag) {
975 if (wipeflag) { /* wipe only */
976 if (myArgc != 3)
977 arg_error(); /* need one argument */
978 if (wipefile(myArgv[2]) == 0 && remove(myArgv[2]) == 0) {
979 fprintf(pgpout,
980 LANG("\nFile %s wiped and deleted. "), myArgv[2]);
981 fprintf(pgpout, "\n");
982 exitPGP(EXIT_OK);
983 } else if (file_exists(myArgv[2]))
984 fprintf(pgpout,
985 LANG("\n\007Error: Can't wipe out file '%s' - read only, maybe?\n"),
986 myArgv[2]);
987 else {
988 fprintf(pgpout,
989 LANG("\n\007File '%s' does not exist.\n"), myArgv[2]);
990 }
991 exitPGP(UNKNOWN_FILE_ERROR);
992 }
993 /* decrypt if none of the -s -e -c -a -w options are specified */
994 decrypt_mode = TRUE;
995 }
996 if (myArgc == 2) { /* no arguments */
997 #ifdef UNIX
998 if (!filter_mode && !isatty(fileno(stdin))) {
999 /* piping to pgp without arguments and no -f:
1000 * switch to filter mode but don't write output to stdout
1001 * if it's a tty, use the preserved filename */
1002 if (!moreflag)
1003 pgpout = stderr;
1004 filter_mode = TRUE;
1005 if (isatty(fileno(stdout)) && !moreflag)
1006 preserve_filename = TRUE;
1007 }
1008 #endif
1009 if (!filter_mode) {
1010 if (quietmode) {
1011 quietmode = FALSE;
1012 signon_msg();
1013 }
1014 fprintf(pgpout,
1015 LANG("\nFor details on licensing and distribution, see the PGP User's Guide.\
1016 \nFor other cryptography products and custom development services, contact:\
1017 \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, \
1018 phone +1 303 541-0140\n"));
1019 if (strcmp((p = LANG("@translator@")), "@translator@"))
1020 fprintf(pgpout, p);
1021 fprintf(pgpout, LANG("\nFor a usage summary, type: pgp -h\n"));
1022 #ifdef MACTC5
1023 exitPGP(BAD_ARG_ERROR);
1024 #else
1025 exit(BAD_ARG_ERROR); /* error exit */
1026 #endif
1027 }
1028 } else {
1029 if (filter_mode) {
1030 recipient = &myArgv[2];
1031 } else {
1032 inputfile = myArgv[2];
1033 recipient = &myArgv[3];
1034 }
1035 recipient = ParseRecipients(recipient);
1036 }
1037
1038
1039 if (filter_mode) {
1040 inputfile = "stdin";
1041 } else if (makerandom > 0) { /* Create the input file */
1042 /*
1043 * +makerandom=<bytes>: Create an input file consisting of <bytes>
1044 * cryptographically strong random bytes, before applying the
1045 * encryption options of PGP. This is an advanced option, so
1046 * assume the user knows what he's doing and don't bother about
1047 * overwriting questions. E.g.
1048 * pgp +makerandom=24 foofile
1049 * Create "foofile" with 24 random bytes in it.
1050 * pgp +makerandom=24 -ea foofile recipient
1051 * The same, but also encrypt it to "recipient", creating
1052 * foofile.asc as well.
1053 * This feature was created to allow PGP to create and send keys
1054 * around for other applications to use.
1055 */
1056 status = cryptRandWriteFile(inputfile, (struct IdeaCfbContext *)0,
1057 (unsigned)makerandom);
1058 if (status < 0) {
1059 fprintf(stderr,"Error writing file \"%s\"\n",inputfile);
1060 exitPGP(INVALID_FILE_ERROR);
1061 }
1062 fprintf(pgpout, LANG("File %s created containing %d random bytes.\n"),
1063 inputfile, makerandom);
1064 /* If we aren't encrypting, don't bother trying to decrypt this! */
1065 if (decrypt_mode)
1066 exitPGP(EXIT_OK);
1067
1068 /* This is obviously NOT a text file */
1069 literal_mode = MODE_BINARY;
1070 } else {
1071 if (decrypt_mode && no_extension(inputfile)) {
1072 strcpy(cipherfile, inputfile);
1073 force_extension(cipherfile, ASC_EXTENSION);
1074 if (file_exists(cipherfile)) {
1075 inputfile = cipherfile;
1076 } else {
1077 force_extension(cipherfile, PGP_EXTENSION);
1078 if (file_exists(cipherfile)) {
1079 inputfile = cipherfile;
1080 } else {
1081 force_extension(cipherfile, SIG_EXTENSION);
1082 if (file_exists(cipherfile))
1083 inputfile = cipherfile;
1084 }
1085 }
1086 }
1087 if (!file_exists(inputfile)) {
1088 fprintf(pgpout,
1089 LANG("\n\007File '%s' does not exist.\n"), inputfile);
1090 errorLvl = FILE_NOT_FOUND_ERROR;
1091 user_error();
1092 }
1093 }
1094
1095 if (strlen(inputfile) >= (unsigned) MAX_PATH - 4) {
1096 fprintf(pgpout,
1097 LANG("\007Invalid filename: '%s' too long\n"), inputfile);
1098 errorLvl = INVALID_FILE_ERROR;
1099 user_error();
1100 }
1101 strcpy(plainfile, inputfile);
1102
1103 if (filter_mode) {
1104 setoutdir(NULL); /* NULL means use tmpdir */
1105 } else {
1106 if (outputfile)
1107 setoutdir(outputfile);
1108 else
1109 setoutdir(inputfile);
1110 }
1111
1112 if (filter_mode) {
1113 workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
1114 readPhantomInput(workfile);
1115 } else {
1116 workfile = inputfile;
1117 }
1118
1119 get_header_info_from_file(workfile, &ctb, 1);
1120 if (decrypt_mode) {
1121 strip_spaces = FALSE;
1122 if (!is_ctb(ctb) && is_armor_file(workfile, 0L))
1123 do_armorfile(workfile);
1124 else if (do_decrypt(workfile) < 0)
1125 user_error();
1126 #ifdef MACTC5
1127 if (verbose) fprintf(stderr, "Final file = %s.\n", plainfile);
1128 /* Allow for overide of auto-unmacbin : 205b */
1129 if( (macbin_flag == FALSE) && is_macbin(plainfile) )
1130 bin2mac(plainfile,TRUE);
1131 else {
1132 AddOutputFiles(plainfile);
1133 PGPSetFinfo(plainfile,FType,FCreator);
1134 }
1135 if (use_clipboard) File2Scrap(plainfile);
1136 #endif
1137 if (batchmode && !signature_checked)
1138 exitPGP(1); /* alternate success, file did not have sig. */
1139 else
1140 exitPGP(EXIT_OK);
1141 }
1142 /*
1143 * See if plaintext input file was actually created by PGP earlier--
1144 * If it was, maybe we should NOT encapsulate it in a literal packet.
1145 * (nestflag = TRUE). Otherwise, always encapsulate it (default).
1146 * (Why test for filter_mode???)
1147 */
1148 if (!batchmode && !filter_mode && legal_ctb(ctb)) {
1149 /* Special case--may be a PGP-created packet, so
1150 do we inhibit encapsulation in literal packet? */
1151 fprintf(pgpout,
1152 LANG("\n\007Input file '%s' looks like it may have been created by PGP. "),
1153 inputfile);
1154 fprintf(pgpout,
1155 LANG("\nIs it safe to assume that it was created by PGP (y/N)? "));
1156 nestflag = getyesno('n');
1157 } else if (force_flag && makerandom == 0 && legal_ctb(ctb)) {
1158 nestflag = TRUE;
1159 }
1160
1161 if (moreflag && makerandom == 0) {
1162 /* special name to cause printout on decrypt */
1163 strcpy(literal_file_name, CONSOLE_FILENAME);
1164 literal_mode = MODE_TEXT; /* will check for text file later */
1165 } else {
1166 strcpy(literal_file_name, file_tail(inputfile));
1167 #ifdef MSDOS
1168 strlwr(literal_file_name);
1169 #endif
1170 }
1171 literal_file = literal_file_name;
1172
1173 /* Make sure non-text files are not accidentally converted
1174 to canonical text. This precaution should only be followed
1175 for US ASCII text files, since European text files may have
1176 8-bit character codes and still be legitimate text files
1177 suitable for conversion to canonical (CR/LF-terminated)
1178 text format. */
1179 if (literal_mode == MODE_TEXT && !is_text_file(workfile)) {
1180 fprintf(pgpout,
1181 LANG("\nNote: '%s' is not a pure text file.\n\
1182 File will be treated as binary data.\n"),
1183 workfile);
1184 literal_mode = MODE_BINARY; /* now expect straight binary */
1185 }
1186 if (moreflag && literal_mode == MODE_BINARY) {
1187 /* For eyes only? Can't display binary file. */
1188 fprintf(pgpout,
1189 LANG("\n\007Error: Only text files may be sent as display-only.\n"));
1190 errorLvl = INVALID_FILE_ERROR;
1191 user_error();
1192 }
1193
1194 /*
1195 * See if plainfile looks like it might be incompressible,
1196 * by examining its contents for compression headers for
1197 * commonly-used compressed file formats like PKZIP, etc.
1198 * Remember this information for later, when we are deciding
1199 * whether to attempt compression before encryption.
1200 *
1201 * Naturally, don't bother if we are making a separate signature or
1202 * clear-signed message. Also, don't bother trying to compress a
1203 * PGP message, as it's probably already compressed.
1204 */
1205 attempt_compression = compress_enabled && !separate_signature &&
1206 !nestflag && !clearfile && makerandom == 0 &&
1207 file_compressible(plainfile);
1208
1209 #ifdef MACTC5
1210 if(( macbin_flag == TRUE ) && (nestflag==FALSE)) {
1211 char *saveworkfile;
1212 nestflag = false;
1213 saveworkfile = workfile;
1214 workfile = tempfile(TMP_WIPE|TMP_TMPDIR);
1215 if (mac2bin(saveworkfile, workfile)!=0) {
1216 fprintf(pgpout, LANG("\n\007Error: MacBinary failed!\n"));
1217 errorLvl = INVALID_FILE_ERROR;
1218 rmtemp(workfile);
1219 exitPGP(errorLvl);
1220 }
1221 }
1222 #endif
1223 if (sign_flag) {
1224 if (!filter_mode && !quietmode)
1225 fprintf(pgpout,
1226 LANG("\nA secret key is required to make a signature. "));
1227 if (!quietmode && my_name[0] == '\0') {
1228 fprintf(pgpout,
1229 LANG("\nYou specified no user ID to select your secret key,\n\
1230 so the default user ID and key will be the most recently\n\
1231 added key on your secret keyring.\n"));
1232 }
1233 strip_spaces = FALSE;
1234 clearfile = NULL;
1235 if (literal_mode == MODE_TEXT) {
1236 /* Text mode requires becoming canonical */
1237 tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
1238 /* +clear means output file with signature in the clear,
1239 only in combination with -t and -a, not with -e or -b */
1240 if (!encrypt_flag && !separate_signature &&
1241 emit_radix_64 && clear_signatures) {
1242 clearfile = workfile;
1243 strip_spaces = TRUE;
1244 }
1245 make_canonical(workfile, tempf);
1246 if (!clearfile)
1247 rmtemp(workfile);
1248 workfile = tempf;
1249 }
1250 if (attempt_compression || encrypt_flag || emit_radix_64 ||
1251 output_stdout)
1252 tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
1253 else
1254 tempf = tempfile(TMP_WIPE);
1255 /* for clear signatures we create a separate signature */
1256 status = signfile(nestflag, separate_signature || (clearfile != NULL),
1257 my_name, workfile, tempf, literal_mode, literal_file);
1258 rmtemp(workfile);
1259 workfile = tempf;
1260
1261 if (status < 0) { /* signfile failed */
1262 fprintf(pgpout, LANG("\007Signature error\n"));
1263 errorLvl = SIGNATURE_ERROR;
1264 user_error();
1265 }
1266 } else if (!nestflag) { /* !sign_file */
1267 /* Prepend CTB_LITERAL byte to plaintext file.
1268 --sure wish this pass could be optimized away. */
1269 if (attempt_compression || encrypt_flag || emit_radix_64 ||
1270 output_stdout)
1271 tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
1272 else
1273 tempf = tempfile(TMP_WIPE);
1274 /* for clear signatures we create a separate signature */
1275 status = make_literal(workfile, tempf, literal_mode, literal_file);
1276 rmtemp(workfile);
1277 workfile = tempf;
1278 }
1279
1280 if (encrypt_flag) {
1281 if (emit_radix_64 || output_stdout)
1282 tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
1283 else
1284 tempf = tempfile(TMP_WIPE);
1285 if (!conventional_flag) {
1286 if (!filter_mode && !quietmode)
1287 fprintf(pgpout,
1288 LANG("\n\nRecipients' public key(s) will be used to encrypt. "));
1289 if (recipient == NULL || *recipient == NULL ||
1290 **recipient == '\0') {
1291 /* no recipient specified on command line */
1292 fprintf(pgpout,
1293 LANG("\nA user ID is required to select the recipient's public key. "));
1294 fprintf(pgpout, LANG("\nEnter the recipient's user ID: "));
1295 #ifdef AMIGA
1296 requesterdesc=LANG("\nEnter the recipient's user ID: ");
1297 #endif
1298 getstring(mcguffin, 255, TRUE); /* echo keyboard */
1299 if ((mcguffins = (char **) malloc(2 * sizeof(char *))) == NULL)
1300 {
1301 fprintf(stderr, LANG("\n\007Out of memory.\n"));
1302 exitPGP(7);
1303 }
1304 mcguffins[0] = mcguffin;
1305 mcguffins[1] = "";
1306 } else {
1307 /* recipient specified on command line */
1308 mcguffins = recipient;
1309 }
1310 for (recipient = mcguffins; *recipient != NULL &&
1311 **recipient != '\0'; recipient++) {
1312 CONVERT_TO_CANONICAL_CHARSET(*recipient);
1313 }
1314 status = encryptfile(mcguffins, workfile, tempf,
1315 attempt_compression);
1316 } else {
1317 status = idea_encryptfile(workfile, tempf, attempt_compression);
1318 }
1319
1320 rmtemp(workfile);
1321 workfile = tempf;
1322
1323 if (status < 0) {
1324 fprintf(pgpout, LANG("\007Encryption error\n"));
1325 errorLvl = (conventional_flag ? ENCR_ERROR : RSA_ENCR_ERROR);
1326 user_error();
1327 }
1328 } else if (attempt_compression && !separate_signature && !clearfile) {
1329 /*
1330 * PGP used to be parsimonious about compression; originally, it only
1331 * did it for files that were being encrypted (to reduce the
1332 * redundancy in the plaintext), but it should really do it for
1333 * anything where it's not a bad idea.
1334 */
1335 if (emit_radix_64 || output_stdout)
1336 tempf = tempfile(TMP_WIPE | TMP_TMPDIR);
1337 else
1338 tempf = tempfile(TMP_WIPE);
1339 squish_file(workfile, tempf);
1340 rmtemp(workfile);
1341 workfile = tempf;
1342 }
1343
1344 /*
1345 * Write to stdout if explicitly asked to, or in filter mode and
1346 * no explicit file name was given.
1347 */
1348 if (output_stdout) {
1349 if (emit_radix_64) {
1350 /* NULL for outputfile means write to stdout */
1351 if (armor_file(workfile, NULL, inputfile, clearfile, FALSE) != 0) {
1352 errorLvl = UNKNOWN_FILE_ERROR;
1353 user_error();
1354 }
1355 if (clearfile)
1356 rmtemp(clearfile);
1357 } else {
1358 if (writePhantomOutput(workfile) < 0) {
1359 errorLvl = UNKNOWN_FILE_ERROR;
1360 user_error();
1361 }
1362 }
1363 rmtemp(workfile);
1364 } else {
1365 char name[MAX_PATH];
1366 char *t;
1367 if (outputfile) {
1368 strcpy(name, outputfile);
1369 } else {
1370 strcpy(name, inputfile);
1371 drop_extension(name);
1372 }
1373 do {
1374 if (!outputfile && no_extension(name)) {
1375 if (emit_radix_64)
1376 force_extension(name, ASC_EXTENSION);
1377 else if (sign_flag && separate_signature)
1378 force_extension(name, SIG_EXTENSION);
1379 else
1380 force_extension(name, PGP_EXTENSION);
1381 #ifdef MACTC5
1382 if (addresfork) {
1383 drop_extension(name);
1384 force_extension(name, ".sdf");
1385 }
1386 #endif
1387 }
1388 if (!file_exists(name)) break;
1389 t=ck_dup_output(name, TRUE, !clearfile);
1390 if (t==NULL) user_error();
1391 if (clearfile && !strcmp(t,name)) break;
1392 strcpy(name,t);
1393 } while (TRUE);
1394 if (emit_radix_64) {
1395 if (armor_file(workfile, name, inputfile, clearfile, FALSE) != 0) {
1396 errorLvl = UNKNOWN_FILE_ERROR;
1397 user_error();
1398 }
1399 if (clearfile)
1400 rmtemp(clearfile);
1401 } else {
1402 if ((outputfile = savetemp(workfile, name)) == NULL) {
1403 errorLvl = UNKNOWN_FILE_ERROR;
1404 user_error();
1405 }
1406 if (!quietmode) {
1407 if (encrypt_flag)
1408 fprintf(pgpout,
1409 LANG("\nCiphertext file: %s\n"), outputfile);
1410 else if (sign_flag)
1411 fprintf(pgpout,
1412 LANG("\nSignature file: %s\n"), outputfile);
1413 }
1414 }
1415 #ifdef MACTC5
1416 AddOutputFiles(name);
1417 if (addresfork) {
1418 if(!AddResourceFork(name)) {
1419 short frefnum,len,i;
1420 char *p,*q;
1421 Handle h;
1422 c2pstr(name);
1423 q=file_tail(argv[2]);
1424 len=strlen(q);
1425 frefnum=OpenResFile((uchar *)name);
1426 h=NewHandle(len+1);
1427 HLock(h);
1428 p=*h;
1429 *p++=len;
1430 for (i=0; i<len; i++) *p++=*q++;
1431 AddResource(h,'STR ',500,(uchar *)"");
1432 ChangedResource(h);
1433 WriteResource(h);
1434 UpdateResFile(frefnum);
1435 CloseResFile(frefnum);
1436 p2cstr((uchar *)name);
1437 } else {
1438 BailoutAlert("AddResFork failed!");
1439 exitPGP(-1);
1440 }
1441 }
1442 if (binhex_flag) {
1443 if (binhex(name)) {
1444 BailoutAlert("BinHex failed!");
1445 exitPGP(-1);
1446 }
1447 remove(name);
1448 }
1449 if (use_clipboard) File2Scrap(name);
1450 #endif /* MACTC5 */
1451 }
1452
1453 if (wipeflag) {
1454 /* destroy every trace of plaintext */
1455 if (wipefile(inputfile) == 0) {
1456 remove(inputfile);
1457 fprintf(pgpout, LANG("\nFile %s wiped and deleted. "), inputfile);
1458 fprintf(pgpout, "\n");
1459 }
1460 }
1461
1462 #ifdef MACTC5
1463 if(!addresfork && !use_clipboard)
1464 if (!emit_radix_64) PGPSetFinfo(outputfile,'Cryp','MPGP');
1465 #endif
1466
1467 exitPGP(EXIT_OK);
1468 return 0; /* to shut up lint and some compilers */
1469 #ifdef MACTC5
1470 } /* pgp_dispatch */
1471 #else
1472 } /* main */
1473 #endif
1474
1475 #ifdef MSDOS
1476 #include <dos.h>
1477 static char *dos_errlst[] =
1478 {
1479 "Write protect error", /* LANG ("Write protect error") */
1480 "Unknown unit",
1481 "Drive not ready", /* LANG ("Drive not ready") */
1482 "3", "4", "5", "6", "7", "8", "9",
1483 "Write error", /* LANG ("Write error") */
1484 "Read error", /* LANG ("Read error") */
1485 "General failure",
1486 };
1487
1488 /* handler for msdos 'harderrors' */
1489 #ifndef OS2
1490 #ifdef __TURBOC__ /* Turbo C 2.0 */
dostrap(int errval)1491 static int dostrap(int errval)
1492 #else
1493 static void dostrap(unsigned deverr, unsigned errval)
1494 #endif
1495 {
1496 char errbuf[64];
1497 int i;
1498 sprintf(errbuf, "\r\nDOS error: %s\r\n", dos_errlst[errval]);
1499 i = 0;
1500 do
1501 bdos(2, (unsigned int) errbuf[i], 0);
1502 while (errbuf[++i]);
1503 #ifdef __TURBOC__
1504 return 0; /* ignore (fopen will return NULL) */
1505 #else
1506 return;
1507 #endif
1508 }
1509 #endif /* MSDOS */
1510 #endif
1511
initsigs()1512 static void initsigs()
1513 {
1514 #ifdef MSDOS
1515 #ifndef OS2
1516 #ifdef __TURBOC__
1517 harderr(dostrap);
1518 #else /* MSC */
1519 #ifndef __GNUC__ /* DJGPP's not MSC */
1520 _harderr(dostrap);
1521 #endif
1522 #endif
1523 #endif
1524 #endif /* MSDOS */
1525 #ifdef SIGINT
1526 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1527 signal(SIGINT, breakHandler);
1528 #if defined(UNIX) || defined(VMS) || defined(ATARI)
1529 #ifndef __PUREC__ /* PureC doesn't recognise all signals */
1530 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1531 signal(SIGHUP, breakHandler);
1532 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1533 signal(SIGQUIT, breakHandler);
1534 #endif
1535 #ifdef UNIX
1536 signal(SIGPIPE, breakHandler);
1537 #endif
1538 signal(SIGTERM, breakHandler);
1539 #ifdef MACTC5
1540 signal(SIGABRT,breakHandler);
1541 signal(SIGTERM,breakHandler);
1542 #ifndef DEBUG
1543 signal(SIGTRAP, breakHandler);
1544 signal(SIGSEGV, breakHandler);
1545 signal(SIGILL, breakHandler);
1546 #ifdef SIGBUS
1547 signal(SIGBUS, breakHandler);
1548 #endif
1549 #endif /* DEBUG */
1550 #endif /* MACTC5 */
1551 #endif /* UNIX */
1552 #endif /* SIGINT */
1553 } /* initsigs */
1554
1555
do_armorfile(char * armorfile)1556 static void do_armorfile(char *armorfile)
1557 {
1558 char *tempf;
1559 char cipherfile[MAX_PATH];
1560 long lastpos, linepos = 0;
1561 int status;
1562 int success = 0;
1563
1564 for (;;) {
1565 /* Handle transport armor stripping */
1566 tempf = tempfile(0);
1567 strip_spaces = FALSE; /* de_armor_file() sets
1568 this for clear signature files */
1569 use_charset_header = TRUE;
1570 lastpos = linepos;
1571 status = de_armor_file(armorfile, tempf, &linepos);
1572 if (status) {
1573 fprintf(pgpout,
1574 LANG("\n\007Error: Transport armor stripping failed for file %s\n"),
1575 armorfile);
1576 errorLvl = INVALID_FILE_ERROR;
1577 user_error(); /* Bad file */
1578 }
1579 if (keepctx || de_armor_only) {
1580 if (outputfile && de_armor_only) {
1581 if (strcmp(outputfile, "-") == 0) {
1582 writePhantomOutput(tempf);
1583 rmtemp(tempf);
1584 return;
1585 }
1586 strcpy(cipherfile, outputfile);
1587 } else {
1588 strcpy(cipherfile, file_tail(armorfile));
1589 force_extension(cipherfile, PGP_EXTENSION);
1590 }
1591 if ((tempf = savetemp(tempf, cipherfile)) == NULL) {
1592 errorLvl = UNKNOWN_FILE_ERROR;
1593 user_error();
1594 }
1595 if (!quietmode)
1596 fprintf(pgpout,
1597 LANG("Stripped transport armor from '%s', producing '%s'.\n"),
1598 armorfile, tempf);
1599 /* -da flag: don't decrypt */
1600 if (de_armor_only || do_decrypt(tempf) >= 0)
1601 ++success;
1602 } else {
1603 if (charset_header[0]) /* Check signature with charset from Charset: header */
1604 checksig_pass = 1;
1605 if (do_decrypt(tempf) >= 0)
1606 ++success;
1607 rmtemp(tempf);
1608 if (charset_header[0]) {
1609 if (checksig_pass == 2) { /* Sigcheck failed: try again with local charset */
1610 tempf = tempfile(0);
1611 use_charset_header = FALSE;
1612 linepos = lastpos;
1613 de_armor_file(armorfile, tempf, &linepos);
1614 if (do_decrypt(tempf) >= 0)
1615 ++success;
1616 rmtemp(tempf);
1617 }
1618 checksig_pass = 0;
1619 }
1620 }
1621
1622 if (!is_armor_file(armorfile, linepos)) {
1623 if (!success) /* print error msg if we didn't
1624 decrypt anything */
1625 user_error();
1626 return;
1627 }
1628 fprintf(pgpout,
1629 LANG("\nLooking for next packet in '%s'...\n"), armorfile);
1630 }
1631 } /* do_armorfile */
1632
1633
do_decrypt(char * cipherfile)1634 static int do_decrypt(char *cipherfile)
1635 {
1636 char *outfile = NULL;
1637 int status, i;
1638 boolean nested_info = FALSE;
1639 char ringfile[MAX_PATH];
1640 byte ctb;
1641 byte header[8]; /* used to classify file type at the end. */
1642 char preserved_name[MAX_PATH];
1643 char *newname;
1644
1645 /* will be set to the original file name after processing a
1646 literal packet */
1647 preserved_name[0] = '\0';
1648
1649 do { /* while nested parsable info present */
1650 if (nested_info) {
1651 rmtemp(cipherfile); /* never executed on first pass */
1652 cipherfile = outfile;
1653 }
1654 if (get_header_info_from_file(cipherfile, &ctb, 1) < 0) {
1655 fprintf(pgpout,
1656 LANG("\n\007Can't open ciphertext file '%s'\n"), cipherfile);
1657 errorLvl = FILE_NOT_FOUND_ERROR;
1658 return -1;
1659 }
1660 if (!is_ctb(ctb)) /* not a real CTB -- complain */
1661 break;
1662
1663 if (moreflag)
1664 outfile = tempfile(TMP_WIPE | TMP_TMPDIR);
1665 else
1666 outfile = tempfile(TMP_WIPE);
1667
1668 /* PKE is Public Key Encryption */
1669 if (is_ctb_type(ctb, CTB_PKE_TYPE)) {
1670
1671 if (!quietmode)
1672 fprintf(pgpout,
1673 LANG("\nFile is encrypted. Secret key is required to read it. "));
1674
1675 /* Decrypt to scratch file since we may have a LITERAL2 */
1676 status = decryptfile(cipherfile, outfile);
1677
1678 if (status < 0) { /* error return */
1679 errorLvl = RSA_DECR_ERROR;
1680 return -1;
1681 }
1682 nested_info = (status > 0);
1683
1684 } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
1685
1686 if (decrypt_only_flag) {
1687 /* swap file names instead of just copying the file */
1688 rmtemp(outfile);
1689 outfile = cipherfile;
1690 cipherfile = NULL;
1691 if (!quietmode)
1692 fprintf(pgpout,
1693 LANG("\nThis file has a signature, which will be left in place.\n"));
1694 nested_info = FALSE;
1695 break; /* Do no more */
1696 }
1697 if (!quietmode && checksig_pass<=1)
1698 fprintf(pgpout,
1699 LANG("\nFile has signature. Public key is required to check signature.\n"));
1700
1701 status = check_signaturefile(cipherfile, outfile,
1702 strip_sig_flag, preserved_name);
1703
1704 if (status < 0) { /* error return */
1705 errorLvl = SIGNATURE_CHECK_ERROR;
1706 return -1;
1707 }
1708 nested_info = (status > 0);
1709
1710 if (strcmp(preserved_name, "/dev/null") == 0) {
1711 rmtemp(outfile);
1712 fprintf(pgpout, "\n");
1713 return 0;
1714 }
1715 } else if (is_ctb_type(ctb, CTB_CKE_TYPE)) {
1716
1717 /* Conventional Key Encrypted ciphertext. */
1718 /* Tell user it's encrypted here, and prompt for
1719 password in subroutine. */
1720 if (!quietmode)
1721 fprintf(pgpout, LANG("\nFile is conventionally encrypted. "));
1722 /* Decrypt to scratch file since it may be a LITERAL2 */
1723 status = idea_decryptfile(cipherfile, outfile);
1724 if (status < 0) { /* error return */
1725 errorLvl = DECR_ERROR;
1726 return -1; /* error exit status */
1727 }
1728 nested_info = (status > 0);
1729
1730 } else if (is_ctb_type(ctb, CTB_COMPRESSED_TYPE)) {
1731
1732 /* Compressed text. */
1733 status = decompress_file(cipherfile, outfile);
1734 if (status < 0) { /* error return */
1735 errorLvl = DECOMPRESS_ERROR;
1736 return -1;
1737 }
1738 /* Always assume nested information... */
1739 nested_info = TRUE;
1740
1741 } else if (is_ctb_type(ctb, CTB_LITERAL_TYPE) ||
1742 is_ctb_type(ctb, CTB_LITERAL2_TYPE)) { /* Raw plaintext.
1743 Just copy it.
1744 No more nesting.
1745 */
1746
1747 /* Strip off CTB_LITERAL prefix byte from file: */
1748 /* strip_literal may alter plainfile; will set mode */
1749 status = strip_literal(cipherfile, outfile,
1750 preserved_name, &literal_mode);
1751 if (status < 0) { /* error return */
1752 errorLvl = UNKNOWN_FILE_ERROR;
1753 return -1;
1754 }
1755 nested_info = FALSE;
1756 } else if (ctb == CTB_CERT_SECKEY || ctb == CTB_CERT_PUBKEY) {
1757
1758 rmtemp(outfile);
1759 if (decrypt_only_flag) {
1760 /* swap file names instead of just copying the file */
1761 outfile = cipherfile;
1762 cipherfile = NULL;
1763 nested_info = FALSE; /* No error */
1764 break; /* no further processing */
1765 }
1766 /* Key ring. View it. */
1767 fprintf(pgpout,
1768 LANG("\nFile contains key(s). Contents follow..."));
1769 if (view_keyring(NULL, cipherfile, TRUE, FALSE) < 0) {
1770 errorLvl = KEYRING_VIEW_ERROR;
1771 return -1;
1772 }
1773 /* filter mode explicit requested with -f */
1774 if (filter_mode && !preserve_filename)
1775 return 0; /* No output file */
1776 if (batchmode)
1777 return 0;
1778 if (ctb == CTB_CERT_SECKEY)
1779 strcpy(ringfile, globalSecringName);
1780 else
1781 strcpy(ringfile, globalPubringName);
1782 /* Ask if it should be put on key ring */
1783 fprintf(pgpout,
1784 LANG("\nDo you want to add this keyfile to keyring '%s' (y/N)? "), ringfile);
1785 if (!getyesno('n'))
1786 return 0;
1787 status = addto_keyring(cipherfile, ringfile);
1788 if (status < 0) {
1789 fprintf(pgpout, LANG("\007Keyring add error. "));
1790 errorLvl = KEYRING_ADD_ERROR;
1791 return -1;
1792 }
1793 return 0; /* No output file */
1794
1795 } else { /* Unrecognized CTB */
1796 break;
1797 }
1798
1799 } while (nested_info);
1800 /* No more nested parsable information */
1801
1802 /* Stopped early due to error */
1803 if (nested_info) {
1804 fprintf(pgpout,
1805 "\7\nERROR: Nested data has unexpected format. CTB=0x%02X\n", ctb);
1806 if (outfile)
1807 rmtemp(outfile);
1808 if (cipherfile)
1809 rmtemp(cipherfile);
1810 errorLvl = UNKNOWN_FILE_ERROR;
1811 return -1;
1812 }
1813 if (outfile == NULL) { /* file was not encrypted */
1814 if (!filter_mode && !moreflag) {
1815 fprintf(pgpout,
1816 LANG("\007\nError: '%s' is not a ciphertext, signature, or key file.\n"),
1817 cipherfile);
1818 errorLvl = UNKNOWN_FILE_ERROR;
1819 return -1;
1820 }
1821 outfile = cipherfile;
1822 } else {
1823 if (cipherfile)
1824 rmtemp(cipherfile);
1825 }
1826
1827 if (moreflag || (strcmp(preserved_name, CONSOLE_FILENAME) == 0)) {
1828 /* blort to screen */
1829 if (strcmp(preserved_name, CONSOLE_FILENAME) == 0) {
1830 fprintf(pgpout,
1831 LANG("\n\nThis message is marked \"For your eyes only\". Display now \
1832 (Y/n)? "));
1833 if (batchmode
1834 #ifdef UNIX
1835 || !isatty(fileno(stdout)) /* stdout is redirected! */
1836 #endif
1837 || filter_mode || !getyesno('y')) {
1838 /* no -- abort display, and clean up */
1839 fprintf(pgpout, "\n");
1840 rmtemp(outfile);
1841 return 0;
1842 }
1843 }
1844 if (!quietmode)
1845 fprintf(pgpout, LANG("\n\nPlaintext message follows...\n"));
1846 else
1847 putc('\n', pgpout);
1848 fprintf(pgpout, "------------------------------\n");
1849 more_file(outfile, strcmp(preserved_name, CONSOLE_FILENAME) == 0);
1850 /* Disallow saving to disk if outfile is console-only: */
1851 if (strcmp(preserved_name, CONSOLE_FILENAME) == 0) {
1852 clearscreen(); /* remove all evidence */
1853 } else if (!quietmode && !batchmode) {
1854 fprintf(pgpout, LANG("Save this file permanently (y/N)? "));
1855 if (getyesno('n')) {
1856 char moreFilename[256];
1857 fprintf(pgpout, LANG("Enter filename to save file as: "));
1858 #ifdef AMIGA
1859 requesterdesc=LANG("Enter filename to save file as: ");
1860 #endif
1861 if (preserved_name[0]) {
1862 fprintf(pgpout, "[%s]: ", file_tail(preserved_name));
1863 #ifdef AMIGA
1864 strcat(requesterdesc, "[");
1865 strcat(requesterdesc, file_tail(preserved_name));
1866 strcat(requesterdesc, "]:");
1867 #endif
1868 }
1869 #ifdef MACTC5
1870 if(!GetFilePath(LANG("Enter filename to save file as:"),moreFilename,PUTFILE))
1871 strcpy(moreFilename,"");
1872 else
1873 fprintf(pgpout, "%s\n",moreFilename);
1874 #else
1875 getstring(moreFilename, 255, TRUE);
1876 #endif
1877 if (*moreFilename == '\0') {
1878 if (*preserved_name != '\0')
1879 savetemp(outfile, file_tail(preserved_name));
1880 else
1881 rmtemp(outfile);
1882 } else
1883 savetemp(outfile, moreFilename);
1884 return 0;
1885 }
1886 }
1887 rmtemp(outfile);
1888 return 0;
1889 } /* blort to screen */
1890 if (outputfile) {
1891 if (!strcmp(outputfile, "/dev/null")) {
1892 rmtemp(outfile);
1893 return 0;
1894 }
1895 filter_mode = (strcmp(outputfile, "-") == 0);
1896 strcpy(plainfile, outputfile);
1897 } else {
1898 #ifdef VMS
1899 /* VMS null extension has to be ".", not "" */
1900 force_extension(plainfile, ".");
1901 #else /* not VMS */
1902 drop_extension(plainfile);
1903 #endif /* not VMS */
1904 }
1905
1906 if (!preserve_filename && filter_mode) {
1907 if (writePhantomOutput(outfile) < 0) {
1908 errorLvl = UNKNOWN_FILE_ERROR;
1909 return -1;
1910 }
1911 rmtemp(outfile);
1912 return 0;
1913 }
1914 if (preserve_filename && preserved_name[0] != '\0')
1915 strcpy(plainfile, file_tail(preserved_name));
1916
1917 if (quietmode) {
1918 if (savetemp(outfile, plainfile) == NULL) {
1919 errorLvl = UNKNOWN_FILE_ERROR;
1920 return -1;
1921 }
1922 return 0;
1923 }
1924 if (!verbose) /* if other filename messages were suppressed */
1925 fprintf(pgpout, LANG("\nPlaintext filename: %s"), plainfile);
1926
1927
1928 /*---------------------------------------------------------*/
1929
1930 /* One last thing-- let's attempt to classify some of the more
1931 frequently occurring cases of plaintext output files, as an
1932 aid to the user.
1933
1934 For example, if output file is a public key, it should have
1935 the right extension on the filename.
1936
1937 Also, it will likely be common to encrypt files created by
1938 various archivers, so they should be renamed with the archiver
1939 extension.
1940 */
1941 get_header_info_from_file(outfile, header, 8);
1942
1943 newname = NULL;
1944 #ifdef MACTC5
1945 if (header[0] == CTB_CERT_SECKEY)
1946 PGPSetFinfo(plainfile,'SKey','MPGP');
1947 #endif
1948 if (header[0] == CTB_CERT_PUBKEY) {
1949 /* Special case--may be public key, worth renaming */
1950 #ifdef MACTC5
1951 PGPSetFinfo(plainfile,'PKey','MPGP');
1952 #endif
1953 fprintf(pgpout,
1954 LANG("\nPlaintext file '%s' looks like it contains a public key."),
1955 plainfile);
1956 newname = maybe_force_extension(plainfile, PGP_EXTENSION);
1957 }
1958 /* Possible public key output file */
1959 else if ((i = compressSignature(header)) >= 0) {
1960 /* Special case--may be an archived/compressed file,
1961 worth renaming
1962 */
1963 fprintf(pgpout, LANG("\nPlaintext file '%s' looks like a %s file."),
1964 plainfile, compressName[i]);
1965 newname = maybe_force_extension(plainfile, compressExt[i]);
1966 } else if (is_ctb(header[0]) &&
1967 (is_ctb_type(header[0], CTB_PKE_TYPE)
1968 || is_ctb_type(header[0], CTB_SKE_TYPE)
1969 || is_ctb_type(header[0], CTB_CKE_TYPE))) {
1970 /* Special case--may be another ciphertext file, worth renaming */
1971 fprintf(pgpout,
1972 LANG("\n\007Output file '%s' may contain more ciphertext or signature."),
1973 plainfile);
1974 newname = maybe_force_extension(plainfile, PGP_EXTENSION);
1975 } /* Possible ciphertext output file */
1976 #ifdef MACTC5
1977 if( (newname = savetemp(outfile, (newname ? newname : plainfile))) == NULL) {
1978 #else
1979 if (savetemp(outfile, (newname ? newname : plainfile)) == NULL) {
1980 #endif
1981 errorLvl = UNKNOWN_FILE_ERROR;
1982 return -1;
1983 }
1984 #ifdef MACTC5
1985 else if( strcmp(newname, plainfile) != 0 ) /* 203a */
1986 strcpy(plainfile, newname);
1987 #endif
1988 fprintf(pgpout, "\n");
1989 return 0;
1990 } /* do_decrypt */
1991
1992 static int do_keyopt(char keychar)
1993 {
1994 char keyfile[MAX_PATH];
1995 char ringfile[MAX_PATH];
1996 char *workfile;
1997 int status;
1998
1999 if ((filter_mode || batchmode) && (keychar == 'g' || keychar == 'e')) {
2000 errorLvl = NO_BATCH;
2001 arg_error(); /* interactive process, no go in batch mode */
2002 }
2003 /*
2004 * If we're not doing anything that uses stdout, produce output there,
2005 * in case user wants to redirect it.
2006 */
2007 if (!filter_mode)
2008 pgpout = stdout;
2009
2010 switch (keychar) {
2011
2012 /*-------------------------------------------------------*/
2013 case 'g':
2014 { /* Key generation
2015 Arguments: bitcount, bitcount, factor1, factor2, mask1, mask2
2016 */
2017 char keybits[6], ebits[6], *username = NULL;
2018 word32 factor1, factor2, mask1, mask2;
2019
2020 /*
2021 * Why all this code?
2022 *
2023 * Some people may object to PGP insisting on finding the
2024 * manual somewhere in the neighborhood to generate a key.
2025 * They bristle against this seemingly authoritarian
2026 * attitude. Some people have even modified PGP to defeat
2027 * this feature, and redistributed their hotwired version to
2028 * others. That creates problems for me (PRZ).
2029 *
2030 * Here is the problem. Before I added this feature, there
2031 * were maimed versions of the PGP distribution package
2032 * floating around that lacked the manual. One of them was
2033 * uploaded to Compuserve, and was distributed to countless
2034 * users who called me on the phone to ask me why such a
2035 * complicated program had no manual. It spread out to BBS
2036 * systems around the country. And a freeware distributor got
2037 * hold of the package from Compuserve and enshrined it on
2038 * CD-ROM, distributing thousands of copies without the
2039 * manual. What a mess.
2040 *
2041 * Please don't make my life harder by modifying PGP to
2042 * disable this feature so that others may redistribute PGP
2043 * without the manual. If you run PGP on a palmtop with no
2044 * memory for the manual, is it too much to ask that you type
2045 * one little extra word on the command line to do a key
2046 * generation, a command that is seldom used by people who
2047 * already know how to use PGP? If you can't stand even this
2048 * trivial inconvenience, can you suggest a better method of
2049 * reducing PGP's distribution without the manual?
2050 *
2051 * PLEASE DO NOT DISABLE THIS CHECK IN THE SOURCE CODE
2052 * WITHOUT AT LEAST CALLING PHILIP ZIMMERMANN
2053 * (+1 303 541-0140, or prz@acm.org) TO DISCUSS IT.
2054 */
2055 if (!nomanual && manuals_missing()) {
2056 char const *const *dir;
2057 fputs(LANG("\a\nError: PGP User's Guide not found.\n\
2058 PGP looked for it in the following directories:\n"), pgpout);
2059 #ifdef MACTC5
2060 fprintf(pgpout, "\t\"%s\"\n", appPathName);
2061 #else
2062 for (dir = manual_dirs; *dir; dir++)
2063 fprintf(pgpout, "\t\"%s\"\n", *dir);
2064 #endif /* MACTC5 */
2065 fputs(
2066 LANG("and the doc subdirectory of each of the above. Please put a copy of\n\
2067 both volumes of the User's Guide in one of these directories.\n\
2068 \n\
2069 Under NO CIRCUMSTANCES should PGP ever be distributed without the PGP\n\
2070 User's Guide, which is included in the standard distribution package.\n\
2071 If you got a copy of PGP without the manual, please inform whomever you\n\
2072 got it from that this is an incomplete package that should not be\n\
2073 distributed further.\n\
2074 \n\
2075 PGP will not generate a key without finding the User's Guide.\n\
2076 There is a simple way to override this restriction. See the\n\
2077 PGP User's Guide for details on how to do it.\n\
2078 \n"), pgpout);
2079 return KEYGEN_ERROR;
2080 }
2081 if (myArgc > 2)
2082 strncpy(keybits, myArgv[2], sizeof(keybits) - 1);
2083 else
2084 keybits[0] = '\0';
2085
2086 if (myArgc > 3)
2087 strncpy(ebits, myArgv[3], sizeof(ebits) - 1);
2088 else
2089 ebits[0] = '\0';
2090
2091 if (myArgc > 4) {
2092 sscanf(myArgv[4], "%li", &factor1);
2093 factor2 = 1;
2094 mask1 = mask2 = 0xffffffffl;
2095 } else {
2096 factor1 = factor2 = mask1 = mask2 = 1;
2097 }
2098 if (myArgc > 5) sscanf(myArgv[5], "%li", &factor2);
2099 if (myArgc > 6) sscanf(myArgv[6], "%li", &mask1);
2100 if (myArgc > 7) sscanf(myArgv[7], "%li", &mask2);
2101
2102 /* If the -u option is given, use that username */
2103 if (u_flag && my_name != NULL && *my_name != '\0')
2104 username = my_name;
2105
2106 /* dokeygen writes the keys out to the key rings... */
2107 status = dokeygen(keybits, ebits, factor1, factor2, mask1, mask2, username);
2108
2109 if (status < 0) {
2110 fprintf(pgpout, LANG("\007Keygen error. "));
2111 errorLvl = KEYGEN_ERROR;
2112 }
2113 #ifdef MACTC5
2114 else {
2115 strcpy(ringfile, globalPubringName );
2116 PGPSetFinfo(ringfile,'PKey','MPGP');
2117 strcpy(ringfile, globalSecringName );
2118 PGPSetFinfo(ringfile,'SKey','MPGP');
2119 }
2120 #endif
2121 return status;
2122 } /* Key generation */
2123
2124 /*-------------------------------------------------------*/
2125 case 'c':
2126 { /* Key checking
2127 Arguments: userid, ringfile
2128 */
2129
2130 if (myArgc < 3) { /* Default to all user ID's */
2131 mcguffin[0] = '\0';
2132 } else {
2133 strcpy(mcguffin, myArgv[2]);
2134 if (strcmp(mcguffin, "*") == 0)
2135 mcguffin[0] = '\0';
2136 }
2137 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2138
2139 if (myArgc < 4) /* default key ring filename */
2140 strcpy(ringfile, globalPubringName);
2141 else
2142 strncpy(ringfile, myArgv[3], sizeof(ringfile) - 1);
2143
2144 if ((myArgc < 4 && myArgc > 2) /* Allow just key file as arg */
2145 &&has_extension(myArgv[2], PGP_EXTENSION)) {
2146 strcpy(ringfile, myArgv[2]);
2147 mcguffin[0] = '\0';
2148 }
2149 status = dokeycheck(mcguffin, ringfile, CHECK_ALL);
2150
2151 if (status < 0) {
2152 fprintf(pgpout, LANG("\007Keyring check error.\n"));
2153 errorLvl = KEYRING_CHECK_ERROR;
2154 }
2155 if (status >= 0 && mcguffin[0] != '\0')
2156 return status; /* just checking a single user,
2157 dont do maintenance */
2158
2159 if ((status = maint_check(ringfile, 0)) < 0 && status != -7) {
2160 fprintf(pgpout, LANG("\007Maintenance pass error. "));
2161 errorLvl = KEYRING_CHECK_ERROR;
2162 }
2163 #ifdef MACTC5
2164 {
2165 byte ctb;
2166 get_header_info_from_file(ringfile, &ctb, 1);
2167 if (ctb == CTB_CERT_SECKEY)
2168 PGPSetFinfo(ringfile,'SKey','MPGP');
2169 else if (ctb == CTB_CERT_PUBKEY)
2170 PGPSetFinfo(ringfile,'PKey','MPGP');
2171 }
2172 #endif
2173 return status == -7 ? 0 : status;
2174 } /* Key check */
2175
2176 /*-------------------------------------------------------*/
2177 case 'm':
2178 { /* Maintenance pass
2179 Arguments: ringfile
2180 */
2181
2182 if (myArgc < 3) /* default key ring filename */
2183 strcpy(ringfile, globalPubringName);
2184 else
2185 strcpy(ringfile, myArgv[2]);
2186
2187 #ifdef MSDOS
2188 strlwr(ringfile);
2189 #endif
2190 if (!file_exists(ringfile))
2191 default_extension(ringfile, PGP_EXTENSION);
2192
2193 if ((status = maint_check(ringfile,
2194 MAINT_VERBOSE | (c_flag ? MAINT_CHECK : 0))) < 0) {
2195 if (status == -7)
2196 fprintf(pgpout,
2197 LANG("File '%s' is not a public keyring\n"),
2198 ringfile);
2199 fprintf(pgpout, LANG("\007Maintenance pass error. "));
2200 errorLvl = KEYRING_CHECK_ERROR;
2201 }
2202 #ifdef MACTC5
2203 PGPSetFinfo(ringfile,'PKey','MPGP');
2204 #endif
2205 return status;
2206 } /* Maintenance pass */
2207
2208 /*-------------------------------------------------------*/
2209 case 's':
2210 { /* Key signing
2211 Arguments: her_id, keyfile
2212 */
2213
2214 if (myArgc >= 4)
2215 strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
2216 else
2217 strcpy(keyfile, globalPubringName);
2218
2219 if (myArgc >= 3) {
2220 strcpy(mcguffin, myArgv[2]); /* Userid to sign */
2221 } else {
2222 fprintf(pgpout,
2223 LANG("\nA user ID is required to select the public key you want to sign. "));
2224 if (batchmode) /* not interactive, userid
2225 must be on command line */
2226 return -1;
2227 fprintf(pgpout, LANG("\nEnter the public key's user ID: "));
2228 #ifdef AMIGA
2229 requesterdesc=LANG("\nEnter the public key's user ID: ");
2230 #endif
2231 getstring(mcguffin, 255, TRUE); /* echo keyboard */
2232 }
2233 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2234
2235 if (my_name[0] == '\0') {
2236 fprintf(pgpout,
2237 LANG("\nA secret key is required to make a signature. "));
2238 fprintf(pgpout,
2239 LANG("\nYou specified no user ID to select your secret key,\n\
2240 so the default user ID and key will be the most recently\n\
2241 added key on your secret keyring.\n"));
2242 }
2243 status = signkey(mcguffin, my_name, keyfile);
2244
2245 if (status >= 0) {
2246 status = maint_update(keyfile, 0);
2247 if (status == -7) { /* ringfile is a keyfile or
2248 secret keyring */
2249 fprintf(pgpout,
2250 "Warning: '%s' is not a public keyring\n",
2251 keyfile);
2252 return 0;
2253 }
2254 if (status < 0)
2255 fprintf(pgpout, LANG("\007Maintenance pass error. "));
2256 }
2257 if (status < 0) {
2258 fprintf(pgpout, LANG("\007Key signature error. "));
2259 errorLvl = KEY_SIGNATURE_ERROR;
2260 }
2261 #ifdef MACTC5
2262 PGPSetFinfo(keyfile,'PKey','MPGP');
2263 #endif
2264 return status;
2265 } /* Key signing */
2266
2267
2268 /*-------------------------------------------------------*/
2269 case 'd':
2270 { /* disable/revoke key/cert
2271 Arguments: userid, keyfile
2272 */
2273
2274 if (myArgc >= 4)
2275 strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
2276 else
2277 strcpy(keyfile, globalPubringName);
2278
2279 if (myArgc >= 3) {
2280 strcpy(mcguffin, myArgv[2]); /* Userid to revoke */
2281 } else {
2282 fprintf(pgpout,
2283 LANG("\nA user ID is required to select the key you want to revoke or \
2284 disable. "));
2285 fprintf(pgpout, LANG("\nEnter user ID: "));
2286 #ifdef AMIGA
2287 requesterdesc=LANG("\nEnter user ID: ");
2288 #endif
2289 getstring(mcguffin, 255, TRUE); /* echo keyboard */
2290 }
2291 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2292
2293 status = sign_flag
2294 ? revoke_cert(mcguffin, my_name, keyfile)
2295 : disable_key(mcguffin, keyfile);
2296
2297 if (status >= 0) {
2298 status = maint_update(keyfile, 0);
2299 if (status == -7) { /* ringfile is a keyfile or
2300 secret keyring */
2301 fprintf(pgpout, "Warning: '%s' is not a public keyring\n",
2302 keyfile);
2303 return 0;
2304 }
2305 if (status < 0)
2306 fprintf(pgpout, LANG("\007Maintenance pass error. "));
2307 }
2308 if (status < 0)
2309 errorLvl = KEY_SIGNATURE_ERROR;
2310 #ifdef MACTC5
2311 PGPSetFinfo(keyfile,'PKey','MPGP');
2312 #endif
2313 return status;
2314 } /* Key compromise / ID/Cert revocation */
2315
2316 /*-------------------------------------------------------*/
2317 case 'e':
2318 { /* Key editing
2319 Arguments: userid, ringfile
2320 */
2321
2322 if (myArgc >= 4)
2323 strncpy(ringfile, myArgv[3], sizeof(ringfile) - 1);
2324 else /* default key ring filename */
2325 strcpy(ringfile, globalPubringName);
2326
2327 if (myArgc >= 3) {
2328 strcpy(mcguffin, myArgv[2]); /* Userid to edit */
2329 } else {
2330 fprintf(pgpout,
2331 LANG("\nA user ID is required to select the key you want to edit. "));
2332 fprintf(pgpout, LANG("\nEnter the key's user ID: "));
2333 #ifdef AMIGA
2334 requesterdesc=LANG("\nEnter the key's user ID: ");
2335 #endif
2336 getstring(mcguffin, 255, TRUE); /* echo keyboard */
2337 }
2338 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2339
2340 status = dokeyedit(mcguffin, ringfile);
2341
2342 if (status >= 0) {
2343 status = maint_update(ringfile, 0);
2344 if (status == -7)
2345 status = 0; /* ignore "not a public keyring" error */
2346 if (status < 0)
2347 fprintf(pgpout, LANG("\007Maintenance pass error. "));
2348 }
2349 if (status < 0) {
2350 fprintf(pgpout, LANG("\007Keyring edit error. "));
2351 errorLvl = KEYRING_EDIT_ERROR;
2352 }
2353 #ifdef MACTC5
2354 {
2355 byte ctb;
2356 get_header_info_from_file(ringfile, &ctb, 1);
2357 if (ctb == CTB_CERT_SECKEY)
2358 PGPSetFinfo(ringfile,'SKey','MPGP');
2359 else if (ctb == CTB_CERT_PUBKEY)
2360 PGPSetFinfo(ringfile,'PKey','MPGP');
2361 }
2362 #endif
2363 return status;
2364 } /* Key edit */
2365
2366 /*-------------------------------------------------------*/
2367 case 'a':
2368 { /* Add key to key ring
2369 Arguments: keyfile, ringfile
2370 */
2371
2372 if (myArgc < 3 && !filter_mode)
2373 arg_error();
2374
2375 if (!filter_mode) { /* Get the keyfile from args */
2376 strncpy(keyfile, myArgv[2], sizeof(keyfile) - 1);
2377
2378 #ifdef MSDOS
2379 strlwr(keyfile);
2380 #endif
2381 if (!file_exists(keyfile))
2382 default_extension(keyfile, PGP_EXTENSION);
2383
2384 if (!file_exists(keyfile)) {
2385 fprintf(pgpout,
2386 LANG("\n\007Key file '%s' does not exist.\n"),
2387 keyfile);
2388 errorLvl = NONEXIST_KEY_ERROR;
2389 return -1;
2390 }
2391 workfile = keyfile;
2392
2393 } else {
2394 workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
2395 readPhantomInput(workfile);
2396 }
2397
2398 if (myArgc < (filter_mode ? 3 : 4)) { /* default key ring
2399 filename */
2400 byte ctb;
2401 get_header_info_from_file(workfile, &ctb, 1);
2402 if (ctb == CTB_CERT_SECKEY)
2403 strcpy(ringfile, globalSecringName);
2404 else
2405 strcpy(ringfile, globalPubringName);
2406 } else {
2407 strncpy(ringfile, myArgv[(filter_mode ? 2 : 3)],
2408 sizeof(ringfile) - 1);
2409 default_extension(ringfile, PGP_EXTENSION);
2410 }
2411 #ifdef MSDOS
2412 strlwr(ringfile);
2413 #endif
2414
2415 status = addto_keyring(workfile, ringfile);
2416
2417 if (filter_mode)
2418 rmtemp(workfile);
2419
2420 if (status < 0) {
2421 fprintf(pgpout, LANG("\007Keyring add error. "));
2422 errorLvl = KEYRING_ADD_ERROR;
2423 }
2424 #ifdef MACTC5
2425 {
2426 byte ctb;
2427 get_header_info_from_file(ringfile, &ctb, 1);
2428 if (ctb == CTB_CERT_SECKEY)
2429 PGPSetFinfo(ringfile,'SKey','MPGP');
2430 else if (ctb == CTB_CERT_PUBKEY)
2431 PGPSetFinfo(ringfile,'PKey','MPGP');
2432 }
2433 #endif
2434 return status;
2435 } /* Add key to key ring */
2436
2437 /*-------------------------------------------------------*/
2438 case 'x':
2439 { /* Extract key from key ring
2440 Arguments: mcguffin, keyfile, ringfile
2441 */
2442
2443 if (myArgc >= (filter_mode ? 4 : 5)) /* default key ring
2444 filename */
2445 strncpy(ringfile, myArgv[(filter_mode ? 3 : 4)],
2446 sizeof(ringfile) - 1);
2447 else
2448 strcpy(ringfile, globalPubringName);
2449
2450 if (myArgc >= (filter_mode ? 2 : 3)) {
2451 if (myArgv[2])
2452 /* Userid to extract */
2453 strcpy(mcguffin, myArgv[2]);
2454 else
2455 strcpy(mcguffin, "");
2456 } else {
2457 fprintf(pgpout,
2458 LANG("\nA user ID is required to select the key you want to extract. "));
2459 if (batchmode) /* not interactive, userid
2460 must be on command line */
2461 return -1;
2462 fprintf(pgpout, LANG("\nEnter the key's user ID: "));
2463 #ifdef AMIGA
2464 requesterdesc=LANG("\nEnter the key's user ID: ");
2465 #endif
2466 getstring(mcguffin, 255, TRUE); /* echo keyboard */
2467 }
2468 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2469
2470 if (!filter_mode) {
2471 if (myArgc >= 4)
2472 strncpy(keyfile, myArgv[3], sizeof(keyfile) - 1);
2473 else
2474 keyfile[0] = '\0';
2475
2476 workfile = keyfile;
2477 } else {
2478 workfile = tempfile(TMP_WIPE | TMP_TMPDIR);
2479 }
2480
2481 #ifdef MSDOS
2482 strlwr(workfile);
2483 strlwr(ringfile);
2484 #endif
2485
2486 default_extension(ringfile, PGP_EXTENSION);
2487
2488 status = extract_from_keyring(mcguffin, workfile,
2489 ringfile, (filter_mode ? FALSE :
2490 emit_radix_64));
2491
2492 if (status < 0) {
2493 fprintf(pgpout, LANG("\007Keyring extract error. "));
2494 errorLvl = KEYRING_EXTRACT_ERROR;
2495 if (filter_mode)
2496 rmtemp(workfile);
2497 return status;
2498 }
2499 if (filter_mode && !status) {
2500 if (emit_radix_64) {
2501 /* NULL for outputfile means write to stdout */
2502 if (armor_file(workfile, NULL, NULL, NULL, FALSE) != 0) {
2503 errorLvl = UNKNOWN_FILE_ERROR;
2504 return -1;
2505 }
2506 } else {
2507 if (writePhantomOutput(workfile) < 0) {
2508 errorLvl = UNKNOWN_FILE_ERROR;
2509 return -1;
2510 }
2511 }
2512 rmtemp(workfile);
2513 }
2514 #ifdef MACTC5
2515 if (status)
2516 return KEYRING_EXTRACT_ERROR;
2517 if ((!emit_radix_64)&&(strlen(keyfile)>0)) {
2518 byte ctb;
2519 get_header_info_from_file(keyfile, &ctb, 1);
2520 if (ctb == CTB_CERT_SECKEY)
2521 PGPSetFinfo(ringfile,'SKey','MPGP');
2522 else if (ctb == CTB_CERT_PUBKEY)
2523 PGPSetFinfo(ringfile,'PKey','MPGP');
2524 }
2525 #endif
2526 return 0;
2527 } /* Extract key from key ring */
2528
2529 /*-------------------------------------------------------*/
2530 case 'r':
2531 { /* Remove keys or selected key signatures from userid keys
2532 Arguments: userid, ringfile
2533 */
2534
2535 if (myArgc >= 4)
2536 strcpy(ringfile, myArgv[3]);
2537 else /* default key ring filename */
2538 strcpy(ringfile, globalPubringName);
2539
2540 if (myArgc >= 3) {
2541 strcpy(mcguffin, myArgv[2]); /* Userid to work on */
2542 } else {
2543 if (sign_flag) {
2544 fprintf(pgpout,
2545 LANG("\nA user ID is required to select the public key you want to\n\
2546 remove certifying signatures from. "));
2547 } else {
2548 fprintf(pgpout,
2549 LANG("\nA user ID is required to select the key you want to remove. "));
2550 }
2551 if (batchmode) /* not interactive, userid must be on
2552 command line */
2553 return -1;
2554 fprintf(pgpout, LANG("\nEnter the key's user ID: "));
2555 #ifdef AMIGA
2556 requesterdesc=LANG("\nEnter the key's user ID: ");
2557 #endif
2558 getstring(mcguffin, 255, TRUE); /* echo keyboard */
2559 }
2560 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2561
2562 #ifdef MSDOS
2563 strlwr(ringfile);
2564 #endif
2565 if (!file_exists(ringfile))
2566 default_extension(ringfile, PGP_EXTENSION);
2567
2568 if (sign_flag) { /* Remove signatures */
2569 if (remove_sigs(mcguffin, ringfile) < 0) {
2570 fprintf(pgpout, LANG("\007Key signature remove error. "));
2571 errorLvl = KEYSIG_REMOVE_ERROR;
2572 return -1;
2573 }
2574 } else { /* Remove keyring */
2575 #ifdef MACTC5
2576 if (remove_from_keyring( NULL, mcguffin, ringfile,
2577 (boolean)!strcmp(ringfile, globalPubringName))) {
2578 #else
2579 if (remove_from_keyring(NULL, mcguffin, ringfile,
2580 (boolean) (myArgc < 4)) < 0) {
2581 #endif
2582 fprintf(pgpout, LANG("\007Keyring remove error. "));
2583 errorLvl = KEYRING_REMOVE_ERROR;
2584 return -1;
2585 }
2586 }
2587 #ifdef MACTC5
2588 {
2589 byte ctb;
2590 get_header_info_from_file(ringfile, &ctb, 1);
2591 if (ctb == CTB_CERT_SECKEY)
2592 PGPSetFinfo(ringfile,'SKey','MPGP');
2593 else if (ctb == CTB_CERT_PUBKEY)
2594 PGPSetFinfo(ringfile,'PKey','MPGP');
2595 PGPSetFinfo(globalPubringName,'PKey','MPGP');
2596 }
2597 #endif
2598 return 0;
2599 } /* remove key signatures from userid */
2600
2601 /*-------------------------------------------------------*/
2602 case 'v':
2603 case 'V': /* -kvv */
2604 { /* View or remove key ring entries,
2605 with userid match
2606 Arguments: userid, ringfile
2607 */
2608
2609 if (myArgc < 4) /* default key ring filename */
2610 strcpy(ringfile, globalPubringName);
2611 else
2612 strcpy(ringfile, myArgv[3]);
2613
2614 if (myArgc > 2) {
2615 strcpy(mcguffin, myArgv[2]);
2616 if (strcmp(mcguffin, "*") == 0)
2617 mcguffin[0] = '\0';
2618 } else {
2619 *mcguffin = '\0';
2620 }
2621
2622 if ((myArgc == 3) && has_extension(myArgv[2], PGP_EXTENSION)) {
2623 strcpy(ringfile, myArgv[2]);
2624 mcguffin[0] = '\0';
2625 }
2626 CONVERT_TO_CANONICAL_CHARSET(mcguffin);
2627
2628 #ifdef MSDOS
2629 strlwr(ringfile);
2630 #endif
2631 if (!file_exists(ringfile))
2632 default_extension(ringfile, PGP_EXTENSION);
2633
2634 /* If a second 'v' (keychar = V), show signatures too */
2635 status = view_keyring(mcguffin, ringfile,
2636 (boolean) (keychar == 'V'), c_flag);
2637 if (status < 0) {
2638 fprintf(pgpout, LANG("\007Keyring view error. "));
2639 errorLvl = KEYRING_VIEW_ERROR;
2640 }
2641 #ifdef MACTC5
2642 {
2643 byte ctb;
2644 get_header_info_from_file(ringfile, &ctb, 1);
2645 if (ctb == CTB_CERT_SECKEY)
2646 PGPSetFinfo(ringfile,'SKey','MPGP');
2647 else if (ctb == CTB_CERT_PUBKEY)
2648 PGPSetFinfo(ringfile,'PKey','MPGP');
2649 }
2650 #endif
2651 return status;
2652 } /* view key ring entries, with userid match */
2653
2654 default:
2655 arg_error();
2656 }
2657 return 0;
2658 } /* do_keyopt */
2659
2660 /* comes here if user made a boo-boo. */
2661 void user_error()
2662 {
2663 fprintf(pgpout, LANG("\nFor a usage summary, type: pgp -h\n"));
2664 fprintf(pgpout,
2665 LANG("For more detailed help, consult the PGP User's Guide.\n"));
2666 exitPGP(errorLvl ? errorLvl : 127); /* error exit */
2667 }
2668
2669 #if defined(DEBUG) && defined(linux)
2670 #include <malloc.h>
2671 #endif
2672
2673 /*
2674 * exitPGP: wipes and removes temporary files, also tries to wipe
2675 * the stack.
2676 */
2677 void exitPGP(int returnval)
2678 {
2679 char buf[STACK_WIPE];
2680 struct hashedpw *hpw;
2681
2682 if (verbose)
2683 fprintf(pgpout, "exitPGP: exitcode = %d\n", returnval);
2684 for (hpw = passwds; hpw; hpw = hpw->next)
2685 memset(hpw->hash, 0, sizeof(hpw->hash));
2686 for (hpw = keypasswds; hpw; hpw = hpw->next)
2687 memset(hpw->hash, 0, sizeof(hpw->hash));
2688 #ifdef MACTC5
2689 mac_cleanup_tmpf();
2690 #else
2691 cleanup_tmpf();
2692 #endif
2693 /* Merge any entropy we collected into the randseed.bin file */
2694 if (cryptRandOpen((struct IdeaCfbContext *)0) >= 0)
2695 cryptRandSave((struct IdeaCfbContext *)0);
2696 #if defined(DEBUG) && defined(linux)
2697 if (verbose) {
2698 struct mstats mstat;
2699 mstat = mstats();
2700 printf("%d chunks used (%d bytes) %d bytes total\n",
2701 mstat.chunks_used, mstat.bytes_used, mstat.bytes_total);
2702 }
2703 #endif
2704 memset(buf, 0, sizeof(buf)); /* wipe stack */
2705 #ifdef VMS
2706 /*
2707 * Fake VMS style error returns with severity in bottom 3 bits
2708 */
2709 if (returnval)
2710 returnval = (returnval << 3) | 0x10000002;
2711 else
2712 returnval = 0x10000001;
2713 #endif /* VMS */
2714 exit(returnval);
2715 }
2716
2717 static void arg_error()
2718 {
2719 signon_msg();
2720 fprintf(pgpout, LANG("\nInvalid arguments.\n"));
2721 errorLvl = BAD_ARG_ERROR;
2722 user_error();
2723 }
2724
2725 /*
2726 * Check for language specific help files in PGPPATH, then the system
2727 * directory. If that fails, check for the default pgp.hlp, again
2728 * first a private copy, then the system-wide one.
2729 *
2730 * System-wide copies currently only exist on Unix.
2731 */
2732 static void build_helpfile(char *helpfile, char const *extra)
2733 {
2734 if (strcmp(language, "en")) {
2735 buildfilename(helpfile, language);
2736 strcat(helpfile, extra);
2737 force_extension(helpfile, HLP_EXTENSION);
2738 if (file_exists(helpfile))
2739 return;
2740 #ifdef PGP_SYSTEM_DIR
2741 strcpy(helpfile, PGP_SYSTEM_DIR);
2742 strcat(helpfile, language);
2743 strcat(helpfile, extra);
2744 force_extension(helpfile, HLP_EXTENSION);
2745 if (file_exists(helpfile))
2746 return;
2747 #endif
2748 }
2749 buildfilename(helpfile, "pgp");
2750 strcat(helpfile, extra);
2751 force_extension(helpfile, HLP_EXTENSION);
2752 #ifdef PGP_SYSTEM_DIR
2753 if (file_exists(helpfile))
2754 return;
2755 strcpy(helpfile, PGP_SYSTEM_DIR);
2756 strcat(helpfile, "pgp");
2757 strcat(helpfile, extra);
2758 force_extension(helpfile, HLP_EXTENSION);
2759 #endif
2760 }
2761
2762 static void usage()
2763 {
2764 char helpfile[MAX_PATH];
2765 char *tmphelp = helpfile;
2766 extern unsigned char *ext_c_ptr;
2767
2768 signon_msg();
2769 build_helpfile(helpfile, "");
2770
2771 if (ext_c_ptr) {
2772 /* conversion to external format necessary */
2773 tmphelp = tempfile(TMP_TMPDIR);
2774 CONVERSION = EXT_CONV;
2775 if (copyfiles_by_name(helpfile, tmphelp) < 0) {
2776 rmtemp(tmphelp);
2777 tmphelp = helpfile;
2778 }
2779 CONVERSION = NO_CONV;
2780 }
2781 /* built-in help if pgp.hlp is not available */
2782 if (more_file(tmphelp, FALSE) < 0)
2783 fprintf(pgpout, LANG("\nUsage summary:\
2784 \nTo encrypt a plaintext file with recipent's public key, type:\
2785 \n pgp -e textfile her_userid [other userids] (produces textfile.pgp)\
2786 \nTo sign a plaintext file with your secret key:\
2787 \n pgp -s textfile [-u your_userid] (produces textfile.pgp)\
2788 \nTo sign a plaintext file with your secret key, and then encrypt it\
2789 \n with recipent's public key, producing a .pgp file:\
2790 \n pgp -es textfile her_userid [other userids] [-u your_userid]\
2791 \nTo encrypt with conventional encryption only:\
2792 \n pgp -c textfile\
2793 \nTo decrypt or check a signature for a ciphertext (.pgp) file:\
2794 \n pgp ciphertextfile [-o plaintextfile]\
2795 \nTo produce output in ASCII for email, add the -a option to other options.\
2796 \nTo generate your own unique public/secret key pair: pgp -kg\
2797 \nFor help on other key management functions, type: pgp -k\n"));
2798 if (ext_c_ptr)
2799 rmtemp(tmphelp);
2800 exit(BAD_ARG_ERROR); /* error exit */
2801 }
2802
2803 static void key_usage()
2804 {
2805 char helpfile[MAX_PATH];
2806 char *tmphelp = helpfile;
2807 extern unsigned char *ext_c_ptr;
2808
2809 signon_msg();
2810 build_helpfile(helpfile, "key");
2811
2812 if (ext_c_ptr) {
2813 /* conversion to external format necessary */
2814 tmphelp = tempfile(TMP_TMPDIR);
2815 CONVERSION = EXT_CONV;
2816 if (copyfiles_by_name(helpfile, tmphelp) < 0) {
2817 rmtemp(tmphelp);
2818 tmphelp = helpfile;
2819 }
2820 CONVERSION = NO_CONV;
2821 }
2822 /* built-in help if key.hlp is not available */
2823 if (more_file(tmphelp, FALSE) < 0)
2824 /* only use built-in help if there is no helpfile */
2825 fprintf(pgpout, LANG("\nKey management functions:\
2826 \nTo generate your own unique public/secret key pair:\
2827 \n pgp -kg\
2828 \nTo add a key file's contents to your public or secret key ring:\
2829 \n pgp -ka keyfile [keyring]\
2830 \nTo remove a key or a user ID from your public or secret key ring:\
2831 \n pgp -kr userid [keyring]\
2832 \nTo edit your user ID or pass phrase:\
2833 \n pgp -ke your_userid [keyring]\
2834 \nTo extract (copy) a key from your public or secret key ring:\
2835 \n pgp -kx userid keyfile [keyring]\
2836 \nTo view the contents of your public key ring:\
2837 \n pgp -kv[v] [userid] [keyring]\
2838 \nTo check signatures on your public key ring:\
2839 \n pgp -kc [userid] [keyring]\
2840 \nTo sign someone else's public key on your public key ring:\
2841 \n pgp -ks her_userid [-u your_userid] [keyring]\
2842 \nTo remove selected signatures from a userid on a keyring:\
2843 \n pgp -krs userid [keyring]\
2844 \n"));
2845 if (ext_c_ptr)
2846 rmtemp(tmphelp);
2847 exit(BAD_ARG_ERROR); /* error exit */
2848 }
2849
2850 char **ParseRecipients(char **recipients)
2851 {
2852 /*
2853 * ParseRecipients() expects an array of pointers to
2854 * characters, usually the array returned by the C startup
2855 * code. Then it will look for entries beginning with the
2856 * string "-@" followed by a filename, which may be appended
2857 * directly or seperated by a blank.
2858 *
2859 * If the file exists and is readable, the routine will load
2860 * the contents and insert it into the command line as if the
2861 * names had been specified there.
2862 *
2863 * Each entry in the file consists of one line. The file line
2864 * will be treated as one argument, no matter whether it
2865 * contains spaces or not. Lines beginning with "#" will be
2866 * ignored and treated as comments. Empty lines will be ignored
2867 * also. Trailing white spaces will be removed.
2868 *
2869 * Currently, ParseRecipients() uses one fixed buffer, meaning,
2870 * that one single line must not be longer than 255 characters.
2871 * The number of included lines is unlimited.
2872 *
2873 * When any kind of problem occurs, PGP will terminate and do
2874 * nothing. No need to test for an error, the result is always
2875 * correct.
2876 *
2877 * 21-Sep-95, Peter Simons <simons@peti.rhein.de>
2878 */
2879
2880 char **backup = recipients, **new;
2881 int entrynum;
2882 int MAX_RECIPIENTS = 128; /* The name is somewhat wrong. of
2883 * course the memory handling is
2884 * dynamic.
2885 */
2886
2887 /* Check whether we need to do something or not. */
2888 while(*recipients) {
2889 if (!strncmp(*recipients, INCLUDE_MARK, INCLUDE_MARK_LEN))
2890 break;
2891 recipients++;
2892 }
2893 if (!*recipients)
2894 return backup; /* nothin' happened */
2895
2896 recipients=backup;
2897 if (!(new = malloc(MAX_RECIPIENTS * sizeof(char *))))
2898 exitPGP(OUT_OF_MEM);
2899 entrynum = 0;
2900
2901 while(*recipients) {
2902 if (strncmp(*recipients, INCLUDE_MARK, INCLUDE_MARK_LEN))
2903 {
2904 new[entrynum++] = *recipients++;
2905 if (entrynum == MAX_RECIPIENTS) {
2906 /* Current buffer is too small.
2907 * Use realloc() to largen itt.
2908 */
2909 MAX_RECIPIENTS += 128;
2910 if (!(new = realloc(new,
2911 MAX_RECIPIENTS * sizeof(char *))))
2912 exitPGP(OUT_OF_MEM);
2913 }
2914 }
2915 else {
2916 /* We got a hit! Load the file and parse it. */
2917 FILE *fh;
2918 char *filename, tempbuf[256];
2919
2920 if (strlen(*recipients) == INCLUDE_MARK_LEN)
2921 filename = *++recipients;
2922 else
2923 filename = *recipients+INCLUDE_MARK_LEN;
2924 fprintf(pgpout, LANG("\nIncluding \"%s\"...\n"), filename);
2925 if (!(fh = fopen(filename, "r"))) {
2926 perror("PGP");
2927 exitPGP(UNKNOWN_FILE_ERROR);
2928 }
2929 while(fgets(tempbuf, sizeof(tempbuf)-1, fh)) {
2930 int i = strlen(tempbuf);
2931
2932 /* Test for comments or empty lines. */
2933 if (!i || *tempbuf == '#')
2934 continue;
2935
2936 /* Remove trailing blanks. */
2937 while (isspace(tempbuf[i-1]))
2938 i--;
2939 tempbuf[i] = '\0';
2940
2941 /* Copy new entry to new */
2942 if (!(new[entrynum++] = store_str(tempbuf)))
2943 exitPGP(OUT_OF_MEM);
2944 if (entrynum == MAX_RECIPIENTS) {
2945 /* Current buffer is too small.
2946 * Use realloc() to largen itt.
2947 */
2948 MAX_RECIPIENTS += 128;
2949 if (!(new = realloc(new,
2950 MAX_RECIPIENTS * sizeof(char *))))
2951 exitPGP(OUT_OF_MEM);
2952 }
2953 }
2954 if (ferror(fh)) {
2955 perror("PGP");
2956 exitPGP(UNKNOWN_FILE_ERROR);
2957 }
2958 fclose(fh);
2959 recipients++;
2960 }
2961 }
2962
2963 /*
2964 * We have to write one trailing NULL pointer.
2965 * Check array size first.
2966 */
2967 if (entrynum == MAX_RECIPIENTS) {
2968 if (!(new = realloc(new, (MAX_RECIPIENTS+1) * sizeof(char *))))
2969 exitPGP(OUT_OF_MEM);
2970 }
2971 new[entrynum] = NULL;
2972 return new;
2973 }
2974