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