/
pgp.c1
3005 lines (2759 loc) · 84.6 KB
/
pgp.c1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* #define TEMP_VERSION /* if defined, temporary experimental
version of PGP */
/* pgp.c -- main module for PGP.
PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
Synopsis: PGP uses public-key encryption to protect E-mail.
Communicate securely with people you've never met, with no secure
channels needed for prior exchange of keys. PGP is well featured and
fast, with sophisticated key management, digital signatures, data
compression, and good ergonomic design.
The original PGP version 1.0 was written by Philip Zimmermann, of
Phil's Pretty Good(tm) Software. Many parts of later versions of
PGP were developed by an international collaborative effort,
involving a number of contributors, including major efforts by:
Branko Lankester <branko@hacktic.nl>
Hal Finney <74076.1041@compuserve.com>
Peter Gutmann <pgut1@cs.aukuni.ac.nz>
Other contributors who ported or translated or otherwise helped include:
Jean-loup Gailly in France
Hugh Kennedy in Germany
Lutz Frank in Germany
Cor Bosman in The Netherlands
Felipe Rodriquez Svensson in The Netherlands
Armando Ramos in Spain
Miguel Angel Gallardo Ortiz in Spain
Harry Bush and Maris Gabalins in Latvia
Zygimantas Cepaitis in Lithuania
Alexander Smishlajev
Peter Suchkow and Andrew Chernov in Russia
David Vincenzetti in Italy
...and others.
(c) Copyright 1990-1996 by Philip Zimmermann. All rights reserved.
The author assumes no liability for damages resulting from the use
of this software, even if the damage results from defects in this
software. No warranty is expressed or implied.
Note that while most PGP source modules bear Philip Zimmermann's
copyright notice, many of them have been revised or entirely written
by contributors who frequently failed to put their names in their
code. Code that has been incorporated into PGP from other authors
was either originally published in the public domain or is used with
permission from the various authors.
PGP is available for free to the public under certain restrictions.
See the PGP User's Guide (included in the release package) for
important information about licensing, patent restrictions on
certain algorithms, trademarks, copyrights, and export controls.
Philip Zimmermann may be reached at:
Boulder Software Engineering
3021 Eleventh Street
Boulder, Colorado 80304 USA
(303) 541-0140 (voice or FAX)
email: prz@acm.org
PGP will run on MSDOS, Sun Unix, VAX/VMS, Ultrix, Atari ST,
Commodore Amiga, and OS/2. Note: Don't try to do anything with
this source code without looking at the PGP User's Guide.
PGP combines the convenience of the Rivest-Shamir-Adleman (RSA)
public key cryptosystem with the speed of fast conventional
cryptographic algorithms, fast message digest algorithms, data
compression, and sophisticated key management. And PGP performs
the RSA functions faster than most other software implementations.
PGP is RSA public key cryptography for the masses.
Uses RSA Data Security, Inc. MD5 Message Digest Algorithm
as a hash for signatures. Uses the ZIP algorithm for compression.
Uses the ETH IPES/IDEA algorithm for conventional encryption.
PGP generally zeroes its used stack and memory areas before exiting.
This avoids leaving sensitive information in RAM where other users
could find it later. The RSA library and keygen routines also
sanitize their own stack areas. This stack sanitizing has not been
checked out under all the error exit conditions, when routines exit
abnormally. Also, we must find a way to clear the C I/O library
file buffers, the disk buffers, and cache buffers.
Revisions:
Version 1.0 - 5 Jun 91
Version 1.4 - 19 Jan 92
Version 1.5 - 12 Feb 92
Version 1.6 - 24 Feb 92
Version 1.7 - 29 Mar 92
Version 1.8 - 23 May 92
Version 2.0 - 2 Sep 92
Version 2.1 - 6 Dec 92
Version 2.2 - 6 Mar 93
Version 2.3 - 13 Jun 93
Version 2.3a- 1 Jul 93
Version 2.4 - 6 Nov 93
Version 2.5 - 5 May 94
Version 2.6 - 22 May 94
Version 2.6.1 - 29 Aug 94
Version 2.6.2 - 11 Oct 94
Version 2.6.2i - 7 May 95
Version 2.6.3(i) - 18 Jan 96
Version 2.6.3(i)a - 4 Mar 96
*/
#include <ctype.h>
#ifndef AMIGA
#include <signal.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "system.h"
#include "mpilib.h"
#include "random.h"
#include "crypto.h"
#include "fileio.h"
#include "keymgmt.h"
#include "language.h"
#include "pgp.h"
#include "exitpgp.h"
#include "charset.h"
#include "getopt.h"
#include "config.h"
#include "keymaint.h"
#include "keyadd.h"
#include "rsaglue.h"
#include "noise.h"
#ifdef MACTC5
#include "Macutil.h"
#include "Macutil2.h"
#include "Macutil3.h"
#include "Macutil4.h"
#include "Macbinary.h"
#include "Binhex.h"
#include "MacPGP.h"
#include "mystr.h"
void AddOutputFiles(char *filepath);
void ReInitKeyMaint(void);
extern char appPathName[];
void ReInitGlobals(void);
extern int level,method;
extern Boolean explicit_plainfile;
extern long infile_line;
extern int eofonce;
extern boolean savedwashed;
extern char *special;
char *Outputfile = NULL;
void check_expiration_date(void);
#define BEST -1
#define exit Exit
void Exit(int x);
#endif
#ifdef M_XENIX
char *strstr();
long time();
#endif
#ifdef MSDOS
#ifdef __ZTC__ /* Extend stack for Zortech C */
unsigned _stack_ = 24 * 1024;
#endif
#ifdef __TURBOC__
unsigned _stklen = 24 * 1024;
#endif
#endif
#define STACK_WIPE 4096
#ifdef AMIGA
#ifdef __SASC_60
/* Let the compiler allocate us an appropriate stack. */
extern long __stack = 32768L;
#endif
/* Add the appropriate AmigaOS version string, depending on the
* compiler flags.
*/
#ifdef USA
static const char __DOSVer[] = "$VER: PGP 2.6.3a (04.03.96)"
# ifdef _M68020
" Amiga 68020 version by Rob Knop <rknop@mop.caltech.edu>";
# else
" Amiga 68000 version by Rob Knop <rknop@mop.caltech.edu>";
# endif
#else
static const char __DOSVer[] = "$VER: PGP 2.6.3ia (04.03.96)"
# ifdef _M68020
" Amiga 68020 version by Peter Simons <simons@peti.rhein.de>";
# else
" Amiga 68000 version by Peter Simons <simons@peti.rhein.de>";
# endif
#endif /* USA */
#endif /* AMIGA */
/* Global filenames and system-wide file extensions... */
#ifdef USA
char rel_version[] = _LANG("2.6.3a"); /* release version */
#else
char rel_version[] = _LANG("2.6.3ia"); /* release version */
#endif
char rel_date[] = "1996-03-04"; /* release date */
char PGP_EXTENSION[] = ".pgp";
char ASC_EXTENSION[] = ".asc";
char SIG_EXTENSION[] = ".sig";
char BAK_EXTENSION[] = ".bak";
static char HLP_EXTENSION[] = ".hlp";
char CONSOLE_FILENAME[] = "_CONSOLE";
#ifdef MACTC5
char HELP_FILENAME[256] = "pgp.hlp";
#else
static char HELP_FILENAME[] = "pgp.hlp";
#endif
/* These files use the environmental variable PGPPATH as a default path: */
char globalPubringName[MAX_PATH];
char globalSecringName[MAX_PATH];
char globalRandseedName[MAX_PATH];
char globalCommentString[128];
/* Flags which are global across the driver code files */
boolean verbose = FALSE; /* -l option: display maximum information */
FILE *pgpout; /* Place for routine messages */
static void usage(void);
static void key_usage(void);
static void arg_error(void);
static void initsigs(void);
static int do_keyopt(char);
static int do_decrypt(char *);
static int do_decrypt1(char *);
static void do_armorfile(char *);
char ** ParseRecipients(char **);
void hashpass (char *keystring, int keylen, byte *hash);
/* Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK.
Lha(rc) is handled specially in the code; it is missing from the
compressSig structure intentionally. If more formats are added,
put them before lharc to keep the code consistent.
27-Jun-95 simons@peti.rhein.de (Peter Simons)
Added support for lh5 archive as generated by Lha. Unfortunately,
lh5 requires special treatment also. I inserted the check right
_before_ lharc, because lh5/lha is a special type of an lharc
archive.
*/
static char *compressSig[] =
{"PK\03\04", "ZOO ", "GIF8", "\352\140", "Rar!",
"HPAK", "\037\213", "\037\235", "\032\013", "\032HP%"
/* lharc is special, must be last */ };
static char *compressName[] =
{"PKZIP", "Zoo", "GIF", "Arj", "RAR",
"Hpack", "gzip", "compressed", "PAK", "Hyper",
"Lha", "Lharc"};
static char *compressExt[] =
{".zip", ".zoo", ".gif", ".arj", ".rar",
".hpk", ".gz", ".Z", ".pak", ".hyp",
".lha", ".lzh"};
/* "\032\0??", "ARC", ".arc" */
/* Returns file signature type from a number of popular compression formats
or -1 if no match */
int compressSignature(byte * header)
{
int i;
for (i = 0; i < sizeof(compressSig) / sizeof(*compressSig); i++)
if (!strncmp((char *) header, compressSig[i], strlen(compressSig[i])))
return i;
/* Special check for lha files */
if (!strncmp((char *)header+2, "-lh5-", 5))
return i;
/* Special check for lharc files */
if (header[2] == '-' && header[3] == 'l' &&
(header[4] == 'z' || header[4] == 'h') &&
header[6] == '-')
return i+1;
return -1;
} /* compressSignature */
/* returns TRUE if file is likely to be compressible */
static boolean file_compressible(char *filename)
{
byte header[8];
get_header_info_from_file(filename, header, 8);
if (compressSignature(header) >= 0)
return FALSE; /* probably not compressible */
return TRUE; /* possibly compressible */
} /* compressible */
/* Possible error exit codes - not all of these are used. Note that we
don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE. To make things
easier for compilers which don't support enum we use #defines */
#define EXIT_OK 0
#define INVALID_FILE_ERROR 1
#define FILE_NOT_FOUND_ERROR 2
#define UNKNOWN_FILE_ERROR 3
#define NO_BATCH 4
#define BAD_ARG_ERROR 5
#define INTERRUPT 6
#define OUT_OF_MEM 7
/* Keyring errors: Base value = 10 */
#define KEYGEN_ERROR 10
#define NONEXIST_KEY_ERROR 11
#define KEYRING_ADD_ERROR 12
#define KEYRING_EXTRACT_ERROR 13
#define KEYRING_EDIT_ERROR 14
#define KEYRING_VIEW_ERROR 15
#define KEYRING_REMOVE_ERROR 16
#define KEYRING_CHECK_ERROR 17
#define KEY_SIGNATURE_ERROR 18
#define KEYSIG_REMOVE_ERROR 19
/* Encode errors: Base value = 20 */
#define SIGNATURE_ERROR 20
#define RSA_ENCR_ERROR 21
#define ENCR_ERROR 22
#define COMPRESS_ERROR 23
/* Decode errors: Base value = 30 */
#define SIGNATURE_CHECK_ERROR 30
#define RSA_DECR_ERROR 31
#define DECR_ERROR 32
#define DECOMPRESS_ERROR 33
#ifdef SIGINT
/* This function is called if a BREAK signal is sent to the program. In this
case we zap the temporary files.
*/
void breakHandler(int sig)
{
#ifdef UNIX
if (sig == SIGPIPE) {
signal(SIGPIPE, SIG_IGN);
exitPGP(INTERRUPT);
}
if (sig != SIGINT)
fprintf(stderr, "\nreceived signal %d\n", sig);
else
#endif
fprintf(pgpout, LANG("\nStopped at user request\n"));
exitPGP(INTERRUPT);
}
#endif
/* Clears screen and homes the cursor. */
static void clearscreen(void)
{
fprintf(pgpout, "\n\033[0;0H\033[J\r \r"); /* ANSI sequence. */
fflush(pgpout);
}
/* We had to process the config file first to possibly select the
foreign language to translate the sign-on line that follows... */
static void signon_msg(void)
{
word32 tstamp;
/* display message only once to allow calling multiple times */
static boolean printed = FALSE;
if (quietmode || printed)
return;
printed = TRUE;
fprintf(stderr,
LANG("Pretty Good Privacy(tm) %s - Public-key encryption for the masses.\n"),
rel_version);
#ifdef TEMP_VERSION
fputs(
"Internal development version only - not for general release.\n", stderr);
#endif
fputs(LANG("(c) 1990-96 Philip Zimmermann, Phil's Pretty Good Software."),
stderr);
fprintf(stderr, " %s\n",LANG(rel_date));
#ifdef USA
fputs(LANG(signon_legalese), stderr);
#endif
fputs(
#ifdef USA
LANG("Export of this software may be restricted by the U.S. government.\n"),
#else
LANG("International version - not for use in the USA. Does not use RSAREF.\n"),
#endif
stderr);
get_timestamp((byte *) & tstamp); /* timestamp points to tstamp */
fprintf(pgpout, LANG("Current time: %s\n"), ctdate(&tstamp));
}
#ifdef TEMP_VERSION /* temporary experimental version of PGP */
#include <time.h>
#define CREATION_DATE 0x30FE3640ul
/* CREATION_DATE is
Thu Jan 18, 1996 1200 hours UTC */
#define LIFESPAN ((unsigned long) 60L * (unsigned long) 86400L)
/* LIFESPAN is 60 days */
/* If this is an experimental version of PGP, cut its life short */
void check_expiration_date(void)
{
if (get_timestamp(NULL) > (CREATION_DATE + LIFESPAN)) {
fprintf(stderr,
"\n\007This experimental version of PGP has expired.\n");
exit(-1); /* error exit */
}
} /* check_expiration_date */
#else /* no expiration date */
#define check_expiration_date() /* null statement */
#endif /* TEMP_VERSION */
/* -f means act as a unix-style filter */
/* -i means internalize extended file attribute information, only supported
* between like (or very compatible) operating systems. */
/* -l means show longer more descriptive diagnostic messages */
/* -m means display plaintext output on screen, like unix "more" */
/* -d means decrypt only, leaving inner signature wrapping intact */
/* -t means treat as pure text and convert to canonical text format */
/* Used by getopt function... */
#define OPTIONS "abcdefghiklmo:prstu:vwxz:ABCDEFGHIKLMO:PRSTU:VWX?"
extern int optind;
extern char *optarg;
#define INCLUDE_MARK "-@"
#define INCLUDE_MARK_LEN sizeof(INCLUDE_MARK)-1 /* skip the \0 */
boolean emit_radix_64 = FALSE; /* set by config file */
static boolean sign_flag = FALSE;
boolean moreflag = FALSE;
boolean filter_mode = FALSE;
static boolean preserve_filename = FALSE;
static boolean decrypt_only_flag = FALSE;
static boolean de_armor_only = FALSE;
static boolean strip_sig_flag = FALSE;
boolean clear_signatures = TRUE;
boolean strip_spaces;
static boolean c_flag = FALSE;
static boolean u_flag = FALSE; /* Did I get my_name from -u? */
boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? */
boolean sign_new_userids = TRUE;
boolean batchmode = FALSE; /* if TRUE: don't ask questions */
boolean quietmode = FALSE;
boolean force_flag = TRUE; /* overwrite existing file without asking */
#ifdef VMS /* kludge for those stupid VMS variable-length
text records */
char literal_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal
packet */
#else /* not VMS */
char literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal
packet */
#endif /* not VMS */
/* my_name is substring of default userid for secret key to make signatures */
char my_name[256] = "\0"; /* null my_name means take first userid
in ring */
boolean keepctx = FALSE; /* TRUE means keep .ctx file on decrypt */
/* Ask for each key separately if it should be added to the keyring */
boolean interactive_add = FALSE;
boolean compress_enabled = TRUE; /* attempt compression before encryption */
long timeshift = 0L; /* seconds from GMT timezone */
int version_byte = VERSION_BYTE_NEW;
boolean nomanual = 0;
/* If non-zero, initialize file to this many random bytes */
int makerandom = 0;
static char *outputfile = NULL;
#ifndef MACTC5
static int errorLvl = EXIT_OK;
#else
int errorLvl = EXIT_OK;
#endif
static char mcguffin[256]; /* userid search tag */
boolean signature_checked = FALSE;
int checksig_pass = 0;
boolean use_charset_header;
char charset_header[16] = "";
char plainfile[MAX_PATH];
int myArgc = 2;
char **myArgv;
struct hashedpw *passwds = 0, *keypasswds = 0;
static struct hashedpw **passwdstail = &passwds;
#ifdef MACTC5
extern unsigned long PGPStart, WNECalls;
void ReInitGlobals()
{
int i;
char scratch[64];
WNECalls = 0;
if (verbose)
PGPStart = TickCount();
else
PGPStart = 0;
Abort = FALSE;
BreakCntl = 0;
pgpout = stderr;
optind = 1;
errorLvl = EXIT_OK;
myArgc = 2;
myArgv = nil;
emit_radix_64 = FALSE; /* set by config file */
sign_flag = FALSE;
moreflag = FALSE;
filter_mode = FALSE;
preserve_filename = FALSE;
decrypt_only_flag = FALSE;
de_armor_only = FALSE;
strip_sig_flag = FALSE;
u_flag = FALSE;
c_flag = FALSE;
signature_checked = FALSE;
literal_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal packet */
errorLvl = EXIT_OK;
outputfile = Outputfile;
method = BEST; /* one of BEST, DEFLATE (only), or STORE (only) */
level = 9; /* 0=fastest compression, 9=best compression */
special = NULL; /* List of special suffixes */
infile_line = 0;
eofonce = 0;
savedwashed = FALSE;
ReInitKeyMaint();
settmpdir(nil);
setoutdir(nil);
makerandom = 0;
if (xcli_opt[0]) {
if (argv[argc] == nil)
argv[argc] = malloc((size_t) 80);
if (argv[argc] == nil) {
BailoutAlert(LANG("Out of memory"));
ExitToShell();
}
strcpy(argv[argc], xcli_opt);
argc++;
fprintf(pgpout, " %s\n", xcli_opt);
}
for (i = 0; i <= 63; i++)
scratch[i] = to_upper(xcli_opt[i]);
if (strcmp(xcli_opt, "+NOMANUAL=ON")==0) nomanual = true;
else nomanual = false;
}
int init_pgp()
{
int err=0;
pgpout=stderr;
/* Process the config file first. Any command-line arguments will
override the config file settings */
buildfilename( mcguffin, "config.txt");
if ( processConfigFile( mcguffin ) < 0 )
err=BAD_ARG_ERROR;
init_charset();
signon_msg();
g_armor_flag=emit_radix_64;
g_text_mode=(literal_mode == MODE_TEXT);
g_clear_signatures=clear_signatures;
PGPSetFinfo(globalRandseedName,'RSed','MPGP');
set_precision(MAX_UNIT_PRECISION);
return err;
}
void Exit(int x) {
errorLvl = x;
if (myArgv)
free(myArgv);
if (mcguffins)
free(mcguffins);
mac_cleanup_tmpf();
longjmp(jmp_env,5);
}
int pgp_dispatch(int argc, char *argv[])
{
int status, opt;
char *inputfile = NULL;
char **recipient = NULL;
/* char **mcguffins; zigf made global so we can free */
boolean macbin_flag = FALSE;
#else
int main(int argc, char *argv[])
{
FILE* fgg=NULL;
long fgg1, fgg2;
int status, opt;
char *inputfile = NULL;
char **recipient = NULL;
char **mcguffins;
#endif /* MACTC5 */
char *workfile, *tempf;
boolean nestflag = FALSE;
boolean decrypt_mode = FALSE;
boolean wipeflag = FALSE;
boolean armor_flag = FALSE; /* -a option */
boolean separate_signature = FALSE;
boolean keyflag = FALSE;
boolean encrypt_flag = FALSE;
boolean conventional_flag = FALSE;
boolean attempt_compression; /* attempt compression before encryption */
boolean output_stdout; /* Output goes to stdout */
char *clearfile = NULL;
char *literal_file = NULL;
char literal_file_name[MAX_PATH];
char cipherfile[MAX_PATH];
char keychar = '\0';
char *p;
byte ctb;
struct hashedpw *hpw;
/* Initial messages to stderr */
pgpout = stderr;
#ifdef MACTC5
ReInitGlobals();
#endif
#ifdef DEBUG1
verbose = TRUE;
#endif
/* The various places one can get passwords from.
* We accumulate them all into two lists. One is
* to try on keys only, and is stored in no particular
* order, while the other is of unknown purpose so
* far (they may be used for conventional encryption
* or decryption as well), and are kept in a specific
* order. If any password in the general list is found
* to decode a key, it is moved to the key list.
* The general list is not grown after initialization,
* so the tail pointer is not used after this.
*/
#ifndef MACTC5
if ((p = getenv("PGPPASS")) != NULL) {
hpw = xmalloc(sizeof(struct hashedpw));
hashpass(p, strlen(p), hpw->hash);
/* Add to linked list of key passwords */
hpw->next = keypasswds;
keypasswds = hpw;
}
/* The -z "password" option should be used instead of PGPPASS if
* the environment can be displayed with the ps command (eg. BSD).
* If the system does not allow overwriting of the command line
* argument list but if it has a "hidden" environment, PGPPASS
* should be used.
*/
for (opt = 1; opt < argc; ++opt) {
p = argv[opt];
if (p[0] != '-' || p[1] != 'z')
continue;
/* Accept either "-zpassword" or "-z password" */
p += 2;
if (!*p)
p = argv[++opt];
/* p now points to password */
if (!p)
break; /* End of arg list - ignore */
hpw = xmalloc(sizeof(struct hashedpw));
hashpass(p, strlen(p), hpw->hash);
/* Wipe password */
while (*p)
*p++ = ' ';
/* Add to tail of linked list of passwords */
hpw->next = 0;
*passwdstail = hpw;
passwdstail = &hpw->next;
}
/*
* If PGPPASSFD is set in the environment try to read the password
* from this file descriptor. If you set PGPPASSFD to 0 pgp will
* use the first line read from stdin as password.
*/
if ((p = getenv("PGPPASSFD")) != NULL) {
int passfd;
if (*p && (passfd = atoi(p)) >= 0) {
char pwbuf[256];
p = pwbuf;
while (read(passfd, p, 1) == 1 && *p != '\n')
++p;
hpw = xmalloc(sizeof(struct hashedpw));
hashpass(pwbuf, p - pwbuf, hpw->hash);
memset(pwbuf, 0, p - pwbuf);
/* Add to tail of linked list of passwords */
hpw->next = 0;
*passwdstail = hpw;
passwdstail = &hpw->next;
}
}
/* Process the config file. The following override each other:
- Hard-coded defaults
- The system config file
- Hard-coded defaults for security-critical things
- The user's config file
- Environment variables
- Command-line options.
*/
opt = 0; /* Number of config files read */
#ifdef PGP_SYSTEM_DIR
#ifdef UNIX
buildsysfilename(mcguffin, ".pgprc");
if (access(mcguffin, 0) != 0)
#endif
buildsysfilename(mcguffin, "config.txt");
if (access(mcguffin, 0) == 0) {
opt++;
/*
* Note: errors here are NOT fatal, so that people
* can use PGP with a corrputed system file.
*/
processConfigFile(mcguffin);
}
#endif
/*
* These must be personal; the system config file may not
* influence them.
*/
buildfilename(globalPubringName, "pubring.pgp");
buildfilename(globalSecringName, "secring.pgp");
buildfilename(globalRandseedName, "randseed.bin");
my_name[0] = '\0';
/* Process the config file first. Any command-line arguments will
override the config file settings */
#if defined(UNIX) || defined(MSDOS) || defined(OS2) || defined (WIN32)
/* Try "pgp.ini" on MS-DOS or ".pgprc" on Unix */
#ifdef UNIX
buildfilename(mcguffin, ".pgprc");
#else
buildfilename(mcguffin, "pgp.ini");
#endif
if (access(mcguffin, 0) != 0)
buildfilename(mcguffin, "config.txt");
#else
buildfilename(mcguffin, "config.txt");
#endif
if (access(mcguffin, 0) == 0) {
opt++;
if (processConfigFile(mcguffin) < 0)
exit(BAD_ARG_ERROR);
}
if (!opt)
fprintf(pgpout, LANG("\007No configuration file found.\n"));
init_charset();
#endif /* MACTC5 */
#ifdef MSDOS /* only on MSDOS systems */
if ((p = getenv("TZ")) == NULL || *p == '\0') {
fprintf(pgpout,LANG("\007WARNING: Environmental variable TZ is not \
defined, so GMT timestamps\n\
may be wrong. See the PGP User's Guide to properly define TZ\n\
in AUTOEXEC.BAT file.\n"));
}
#endif /* MSDOS */
#ifdef VMS
#define TEMP "SYS$SCRATCH"
#else
#define TEMP "TMP"
#endif /* VMS */
if ((p = getenv(TEMP)) != NULL && *p != '\0')
settmpdir(p);
if ((myArgv = (char **) malloc((argc + 2) * sizeof(char **))) == NULL) {
fprintf(stderr, LANG("\n\007Out of memory.\n"));
exitPGP(7);
}
myArgv[0] = NULL;
myArgv[1] = NULL;
/* Process all the command-line option switches: */
while (optind < argc) {
/*
* Allow random order of options and arguments (like GNU getopt)
* NOTE: this does not work with GNU getopt, use getopt.c from
* the PGP distribution.
*/
if ((!strncmp(argv[optind], INCLUDE_MARK, INCLUDE_MARK_LEN)) ||
((opt = pgp_getopt(argc, argv, OPTIONS)) == EOF)) {
if (optind == argc) /* -- at end */
break;
myArgv[myArgc++] = argv[optind++];
continue;
}
opt = to_lower(opt);
if (keyflag && (keychar == '\0' || (keychar == 'v' && opt == 'v'))) {
if (keychar == 'v')
keychar = 'V';
else
keychar = opt;
continue;
}
switch (opt) {
case 'a':
armor_flag = TRUE;
emit_radix_64 = 1;
break;
case 'b':
separate_signature = strip_sig_flag = TRUE;
break;
case 'c':
encrypt_flag = conventional_flag = TRUE;
c_flag = TRUE;
break;
case 'd':
decrypt_only_flag = TRUE;
break;
case 'e':
encrypt_flag = TRUE;
break;
#ifdef MACTC5
case 'f':
if (macbin_flag == FALSE) filter_mode = TRUE;
break;
#else
case 'f':
filter_mode = TRUE;
break;
#endif
case '?':
case 'h':
usage();
break;
#ifdef VMS
case 'i':
literal_mode = MODE_LOCAL;
break;
#else
#ifdef MACTC5
case 'i':
macbin_flag = TRUE;
moreflag = FALSE;
literal_mode = MODE_BINARY;
filter_mode = FALSE;
break;
#endif /* MACTC5 */
#endif /* VMS */
case 'k':
keyflag = TRUE;
break;
case 'l':
verbose = TRUE;
break;
#ifdef MACTC5
case 'm':
if( macbin_flag == FALSE )
moreflag = TRUE;
break;
#else
case 'm':
moreflag = TRUE;
break;
#endif
case 'p':
preserve_filename = TRUE;
break;
case 'o':
outputfile = optarg;
break;
case 's':
sign_flag = TRUE;
break;
#ifdef MACTC5
case 't':
if( macbin_flag == FALSE )
literal_mode = MODE_TEXT;
break;
#else
case 't':
literal_mode = MODE_TEXT;
break;
#endif
case 'u':
strncpy(my_name, optarg, sizeof(my_name) - 1);
CONVERT_TO_CANONICAL_CHARSET(my_name);
u_flag = TRUE;
break;
case 'w':
wipeflag = TRUE;
break;
case 'z':
break;
/* '+' special option: does not require - */
case '+':
if (processConfigLine(optarg) == 0) {
if (!strncmp(optarg,"CH",2)) /* CHARSET */
init_charset();
break;
}
fprintf(stderr, "\n");
/* fallthrough */
default:
arg_error();
}
}
myArgv[myArgc] = NULL; /* Just to make it NULL terminated */
if (keyflag && keychar == '\0')
key_usage();
signon_msg();
check_expiration_date(); /* hobble any experimental version */
/*
* Write to stdout if explicitly asked to, or in filter mode and
* no explicit file name was given.
*/
output_stdout = outputfile ? strcmp(outputfile, "-") == 0 : filter_mode;
#if 1
/* At request of Peter Simons, use stderr always. Sounds reasonable. */
/* JIS: Put this code back in... removing it broke too many things */
if (!output_stdout)
pgpout = stdout;
#endif
#if defined(UNIX) || defined(VMS)
umask(077); /* Make files default to private */
#endif
initsigs(); /* Catch signals */
noise(); /* Start random number generation */
if (keyflag) {
status = do_keyopt(keychar);
if (status < 0)
user_error();
exitPGP(status);
}
/* -db means break off signature certificate into separate file */
if (decrypt_only_flag && strip_sig_flag)
decrypt_only_flag = FALSE;
if (decrypt_only_flag && armor_flag)
decrypt_mode = de_armor_only = TRUE;
if (outputfile != NULL)
preserve_filename = FALSE;
if (!sign_flag && !encrypt_flag && !conventional_flag && !armor_flag) {
if (wipeflag) { /* wipe only */
if (myArgc != 3)
arg_error(); /* need one argument */
if (wipefile(myArgv[2]) == 0 && remove(myArgv[2]) == 0) {
fprintf(pgpout,
LANG("\nFile %s wiped and deleted. "), myArgv[2]);
fprintf(pgpout, "\n");
exitPGP(EXIT_OK);
} else if (file_exists(myArgv[2]))
fprintf(pgpout,
LANG("\n\007Error: Can't wipe out file '%s' - read only, maybe?\n"),
myArgv[2]);
else {
fprintf(pgpout,
LANG("\n\007File '%s' does not exist.\n"), myArgv[2]);
}
exitPGP(UNKNOWN_FILE_ERROR);
}
/* decrypt if none of the -s -e -c -a -w options are specified */
decrypt_mode = TRUE;
}
if (myArgc == 2) { /* no arguments */
#ifdef UNIX
if (!filter_mode && !isatty(fileno(stdin))) {
/* piping to pgp without arguments and no -f:
* switch to filter mode but don't write output to stdout
* if it's a tty, use the preserved filename */
if (!moreflag)
pgpout = stderr;
filter_mode = TRUE;
if (isatty(fileno(stdout)) && !moreflag)
preserve_filename = TRUE;
}
#endif
if (!filter_mode) {
if (quietmode) {
quietmode = FALSE;
signon_msg();
}
fprintf(pgpout,