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