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