|
|
1.1.1.3 ! root 1: #undef 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: Note that while many PGP source modules bear the copyright notice of ! 34: Philip Zimmermann, some of them may have been revised or in some ! 35: cases entirely written by other members of the PGP development team, ! 36: who often failed to put their names in their code. ! 37: ! 38: Revisions: ! 39: Version 1.0 - 5 Jun 91 ! 40: Version 1.4 - 19 Jan 92 ! 41: Version 1.5 - 12 Feb 92 ! 42: Version 1.6 - 24 Feb 92 ! 43: Version 1.7 - 29 Mar 92 ! 44: Version 1.8 - 23 May 92 ! 45: Version 2.0 - 2 Sep 92 ! 46: Version 2.1 - 6 Dec 92 ! 47: ! 48: (c) Copyright 1990-1992 by Philip Zimmermann. All rights reserved. ! 49: The author assumes no liability for damages resulting from the use ! 50: of this software, even if the damage results from defects in this ! 51: software. No warranty is expressed or implied. ! 52: ! 53: All the source code Philip Zimmermann wrote for PGP is available for ! 54: free under the "Copyleft" General Public License from the Free ! 55: Software Foundation. A copy of that license agreement is included in ! 56: the source release package of PGP. Code developed by others for PGP ! 57: is also freely available. Other code that has been incorporated into ! 58: PGP from other sources was either originally published in the public ! 59: domain or was used with permission from the various authors. See the ! 60: PGP User's Guide for more complete information about licensing, ! 61: patent restrictions on certain algorithms, trademarks, copyrights, ! 62: and export controls. ! 63: ! 64: Philip Zimmermann may be reached at: ! 65: Boulder Software Engineering ! 66: 3021 Eleventh Street ! 67: Boulder, Colorado 80304 USA ! 68: (303) 541-0140 (voice or FAX) ! 69: email: [email protected] ! 70: ! 71: ! 72: PGP will run on MSDOS, Sun Unix, VAX/VMS, Ultrix, Atari ST, ! 73: Commodore Amiga, and OS/2. Note: Don't try to do anything with ! 74: this source code without looking at the PGP User's Guide. ! 75: ! 76: PGP combines the convenience of the Rivest-Shamir-Adleman (RSA) ! 77: public key cryptosystem with the speed of fast conventional ! 78: cryptographic algorithms, fast message digest algorithms, data ! 79: compression, and sophisticated key management. And PGP performs ! 80: the RSA functions faster than most other software implementations. ! 81: PGP is RSA public key cryptography for the masses. ! 82: ! 83: Uses RSA Data Security, Inc. MD5 Message Digest Algorithm ! 84: as a hash for signatures. Uses the ZIP algorithm for compression. ! 85: Uses the ETH IPES/IDEA algorithm for conventional encryption. ! 86: ! 87: PGP generally zeroes its used stack and memory areas before exiting. ! 88: This avoids leaving sensitive information in RAM where other users ! 89: could find it later. The RSA library and keygen routines also ! 90: sanitize their own stack areas. This stack sanitizing has not been ! 91: checked out under all the error exit conditions, when routines exit ! 92: abnormally. Also, we must find a way to clear the C I/O library ! 93: file buffers, the disk buffers, and and cache buffers. ! 94: ! 95: If you modify this code, PLEASE preserve the style of indentation ! 96: used for {begin...end} blocks. It drives me bats to have to deal ! 97: with more than one style in the same program. ! 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 "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: int maintenance(char *ringfile, int options); /* from keymaint.c */ ! 119: int processConfigLine( char *option ); /* From config.c */ ! 120: #ifdef M_XENIX ! 121: char *strstr(); ! 122: long time(); ! 123: #endif ! 124: ! 125: #ifdef MSDOS ! 126: #ifdef __ZTC__ /* Extend stack for Zortech C */ ! 127: unsigned _stack_ = 12*1024; ! 128: #endif ! 129: #ifdef __TURBOC__ ! 130: unsigned _stklen = 12*1024; ! 131: #endif ! 132: #endif ! 133: #define STACK_WIPE 4096 ! 134: ! 135: /* Global filenames and system-wide file extensions... */ ! 136: char rel_version[] = "2.1"; /* release version */ ! 137: char rel_date[] = "6 Dec 92"; /* release date */ ! 138: char CTX_EXTENSION[] = ".pgp"; ! 139: char PGP_EXTENSION[] = ".pgp"; ! 140: char ASC_EXTENSION[] = ".asc"; ! 141: char SIG_EXTENSION[] = ".sig"; ! 142: char BAK_EXTENSION[] = ".bak"; ! 143: char HLP_EXTENSION[] = ".hlp"; ! 144: char CONSOLE_FILENAME[] = "_CONSOLE"; ! 145: char HELP_FILENAME[] = "pgp.hlp"; ! 146: ! 147: /* These files use the environmental variable PGPPATH as a default path: */ ! 148: char CONFIG_FILENAME[] = "config.txt"; ! 149: char PUBLIC_KEYRING_FILENAME[32] = "pubring.pgp"; ! 150: char SECRET_KEYRING_FILENAME[32] = "secring.pgp"; ! 151: char RANDSEED_FILENAME[32] = "randseed.bin"; ! 152: ! 153: /* Flags which are global across the driver code files */ ! 154: boolean verbose = FALSE; /* -l option: display maximum information */ ! 155: FILE *pgpout; /* Place for routine messages */ ! 156: ! 157: /* Prototype for function in config.c */ ! 158: ! 159: int processConfigFile( char *configFileName ); ! 160: ! 161: static void usage(); ! 162: static void key_usage(); ! 163: static void arg_error(); ! 164: static void initsigs(); ! 165: static void do_keyopt(char); ! 166: static void do_decrypt(char *); ! 167: static void do_armorfile(char *); ! 168: void user_error(); ! 169: void exitPGP(int); ! 170: ! 171: ! 172: #if 0 /* unused */ ! 173: boolean strcontains( char *s1, char *s2 ) ! 174: { /* ! 175: ** Searches s1 for s2, without case sensitivity. ! 176: ** Return TRUE if found. ! 177: ** ! 178: ** If s2 is an empty string then return TRUE. This is because, ! 179: ** at least in the world of mathematics, the empty set is contained ! 180: ** in all other sets. The Microsoft C version 6.0 strstr function ! 181: ** behaves this way but version 5.1 does not, so we need to ! 182: ** explicitly test for the situation. -- ALH 91/2/17 ! 183: */ ! 184: ! 185: if (s2 != NULL && s2[0] != '\0') ! 186: { ! 187: char buf1[256], buf2[256]; /* scratch buffers */ ! 188: ! 189: if (s1 != NULL) ! 190: { ! 191: strncpy( buf1, s1, 256 ); ! 192: strlwr( buf1 ); /* converts to lower case */ ! 193: } ! 194: else ! 195: buf1[0] = '\0'; ! 196: strncpy( buf2, s2, 256 ); strlwr( buf2 ); /* converts to lower case */ ! 197: ! 198: if (strstr( buf1, buf2 ) == NULL) ! 199: return( FALSE ); /* string not found */ ! 200: } ! 201: return(TRUE); ! 202: } /* strcontains */ ! 203: #endif ! 204: ! 205: ! 206: /* Various compression signatures: PKZIP, Zoo, GIF, Arj, and HPACK. ! 207: Lha(rc) is handled specially in the code; it is missing from the ! 208: compressSig structure intentionally. If more formats are added, ! 209: put them before lharc to keep the code consistent. ! 210: */ ! 211: char *compressSig[] = { "PK\03\04", "ZOO ", "GIF8", "\352\140", "HPAK" }; ! 212: char *compressName[] = { "PKZIP", "Zoo", "GIF", "Arj", "Hpack", "LHarc" }; ! 213: char *compressExt[] = { ".zip", ".zoo", ".gif", ".arj", ".hpk", ".lzh" }; ! 214: ! 215: int compressSignature(byte *header) ! 216: /* Returns file signature type from a number of popular compression formats ! 217: or -1 if no match */ ! 218: { int i; ! 219: ! 220: for (i=0; i<sizeof(compressSig)/sizeof(*compressSig); i++) ! 221: if (!strncmp((char *)header, compressSig[i], strlen(compressSig[i]))) ! 222: return(i); ! 223: /* Special check for lharc files */ ! 224: if (header[2]=='-' && header[3]=='l' && (header[4]=='z'||header[4]=='h') && ! 225: header[6]=='-') ! 226: return(i); ! 227: return(-1); ! 228: } /* compressSignature */ ! 229: ! 230: ! 231: boolean file_compressible(char *filename) ! 232: { /* returns TRUE iff file is likely to be compressible */ ! 233: byte header[8]; ! 234: get_header_info_from_file( filename, header, 8 ); ! 235: if (compressSignature( header ) >= 0) ! 236: return (FALSE); /* probably not compressible */ ! 237: return (TRUE); /* possibly compressible */ ! 238: } /* compressible */ ! 239: ! 240: ! 241: /* Possible error exit codes - not all of these are used. Note that we ! 242: don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE. To make things ! 243: easier for compilers which don't support enum we use #defines */ ! 244: ! 245: #define EXIT_OK 0 ! 246: #define INVALID_FILE_ERROR 1 ! 247: #define FILE_NOT_FOUND_ERROR 2 ! 248: #define UNKNOWN_FILE_ERROR 3 ! 249: #define NO_BATCH 4 ! 250: #define BAD_ARG_ERROR 5 ! 251: #define INTERRUPT 6 ! 252: #define OUT_OF_MEM 7 ! 253: ! 254: /* Keyring errors: Base value = 10 */ ! 255: #define KEYGEN_ERROR 10 ! 256: #define NONEXIST_KEY_ERROR 11 ! 257: #define KEYRING_ADD_ERROR 12 ! 258: #define KEYRING_EXTRACT_ERROR 13 ! 259: #define KEYRING_EDIT_ERROR 14 ! 260: #define KEYRING_VIEW_ERROR 15 ! 261: #define KEYRING_REMOVE_ERROR 16 ! 262: #define KEYRING_CHECK_ERROR 17 ! 263: #define KEY_SIGNATURE_ERROR 18 ! 264: #define KEYSIG_REMOVE_ERROR 19 ! 265: ! 266: /* Encode errors: Base value = 20 */ ! 267: #define SIGNATURE_ERROR 20 ! 268: #define RSA_ENCR_ERROR 21 ! 269: #define ENCR_ERROR 22 ! 270: #define COMPRESS_ERROR 23 ! 271: ! 272: /* Decode errors: Base value = 30 */ ! 273: #define SIGNATURE_CHECK_ERROR 30 ! 274: #define RSA_DECR_ERROR 31 ! 275: #define DECR_ERROR 32 ! 276: #define DECOMPRESS_ERROR 33 ! 277: ! 278: ! 279: #ifdef SIGINT ! 280: void breakHandler(int sig) ! 281: /* This function is called if a BREAK signal is sent to the program. In this ! 282: case we zap the temporary files. ! 283: */ ! 284: { ! 285: #ifdef UNIX ! 286: if (sig == SIGPIPE) ! 287: { signal(SIGPIPE, SIG_IGN); ! 288: exitPGP(INTERRUPT); ! 289: } ! 290: if (sig != SIGINT) ! 291: fprintf(stderr, "\nreceived signal %d\n", sig); ! 292: else ! 293: #endif ! 294: fprintf(pgpout,PSTR("\nStopped at user request\n")); ! 295: exitPGP(INTERRUPT); ! 296: } ! 297: #endif ! 298: ! 299: ! 300: void clearscreen(void) ! 301: { /* Clears screen and homes the cursor. */ ! 302: fprintf(pgpout,"\n\033[0;0H\033[J\r \r"); /* ANSI sequence. */ ! 303: fflush(pgpout); ! 304: } ! 305: ! 306: void signon_msg() ! 307: { /* We had to process the config file first to possibly select the ! 308: foreign language to translate the sign-on line that follows... */ ! 309: word32 tstamp; ! 310: /* display message only once to allow calling multiple times */ ! 311: static boolean printed = FALSE; ! 312: ! 313: if (filter_mode || printed) ! 314: return; ! 315: printed = TRUE; ! 316: fprintf(stderr,PSTR("Pretty Good Privacy %s - Public-key encryption for the masses.\n"), ! 317: rel_version); ! 318: #ifdef TEMP_VERSION ! 319: fprintf(stderr, "Internal development version only - not for general release.\n"); ! 320: #endif ! 321: fprintf(stderr, PSTR("(c) 1990-1992 Philip Zimmermann, Phil's Pretty Good Software. %s\n"), ! 322: rel_date); ! 323: ! 324: get_timestamp((byte *)&tstamp); /* timestamp points to tstamp */ ! 325: fprintf(pgpout,"Date: %s\n",ctdate(&tstamp)); ! 326: } ! 327: ! 328: ! 329: #ifdef TEMP_VERSION /* temporary experimental version of PGP */ ! 330: #include <time.h> ! 331: #define CREATION_DATE ((unsigned long) 0x2a6f17dcL) ! 332: /* CREATION_DATE is Thu Jul 23 14:34:36 1992 */ ! 333: #define LIFESPAN ((unsigned long) 30L * (unsigned long) 86400L) ! 334: /* LIFESPAN is 30 days */ ! 335: void check_expiration_date(void) ! 336: { /* If this is an experimental version of PGP, cut its life short */ ! 337: word32 t; ! 338: t = time(NULL); ! 339: if (t > (CREATION_DATE + LIFESPAN)) ! 340: { fprintf(stderr,"\n\007This experimental version of PGP has expired.\n"); ! 341: exit(-1); /* error exit */ ! 342: } ! 343: } /* check_expiration_date */ ! 344: #else /* no expiration date */ ! 345: #define check_expiration_date() /* null statement */ ! 346: #endif /* TEMP_VERSION */ ! 347: ! 348: ! 349: ! 350: /* -f means act as a unix-style filter */ ! 351: /* -i means internalize extended file attribute information, only supported ! 352: * between like (or very compatible) operating systems. ! 353: /* -l means show longer more descriptive diagnostic messages */ ! 354: /* -m means display plaintext output on screen, like unix "more" */ ! 355: /* -d means decrypt only, leaving inner signature wrapping intact */ ! 356: /* -t means treat as pure text and convert to canonical text format */ ! 357: ! 358: /* Used by getopt function... */ ! 359: #define OPTIONS "abcdefghiklmo:prstu:vwxz:ABCDEFGHIKLMO:PRSTU:VWX?" ! 360: extern int optind; ! 361: extern char *optarg; ! 362: ! 363: boolean emit_radix_64 = FALSE; /* set by config file */ ! 364: boolean sign_flag = FALSE; ! 365: boolean moreflag = FALSE; ! 366: boolean filter_mode = FALSE; ! 367: boolean preserve_filename = FALSE; ! 368: boolean decrypt_only_flag = FALSE; ! 369: boolean de_armor_only = FALSE; ! 370: boolean strip_sig_flag = FALSE; ! 371: boolean clear_signatures = FALSE; ! 372: boolean c_flag = FALSE; ! 373: #ifdef VMS /* kludge for those stupid VMS variable-length text records */ ! 374: char lit_mode = MODE_TEXT; /* MODE_TEXT or MODE_BINARY for literal packet */ ! 375: #else /* not VMS */ ! 376: char lit_mode = MODE_BINARY; /* MODE_TEXT or MODE_BINARY for literal packet */ ! 377: #endif /* not VMS */ ! 378: /* my_name is substring of default userid for secret key to make signatures */ ! 379: char my_name[256] = "\0"; /* null my_name means take first userid in ring */ ! 380: boolean keepctx = FALSE; /* TRUE means keep .ctx file on decrypt */ ! 381: boolean compress_enabled = TRUE; /* attempt compression before encryption */ ! 382: long timeshift = 0L; /* seconds from GMT timezone */ ! 383: boolean attempt_compression; /* attempt compression before encryption */ ! 384: char *outputfile = NULL; ! 385: int errorLvl = EXIT_OK; ! 386: char mcguffin[256]; /* userid search tag */ ! 387: char plainfile[MAX_PATH]; ! 388: #define MAXARGC 8 ! 389: int myArgc = 2; ! 390: char *myArgv[MAXARGC] = { NULL, }; ! 391: char password[256] = ""; ! 392: ! 393: ! 394: int main(int argc, char *argv[]) ! 395: { ! 396: int status, opt; ! 397: char *inputfile = NULL; ! 398: char *recipient = NULL; ! 399: char *workfile, *tempf; ! 400: boolean nestflag = FALSE; ! 401: boolean decrypt_mode = FALSE; ! 402: boolean wipeflag = FALSE; ! 403: boolean armor_flag = FALSE; /* -a option */ ! 404: boolean separate_signature = FALSE; ! 405: boolean keyflag = FALSE; ! 406: boolean encrypt_flag = FALSE; ! 407: boolean conventional_flag = FALSE; ! 408: char *clearfile = NULL; ! 409: char *literal_file = NULL; ! 410: char literal_file_name[MAX_PATH]; ! 411: char cipherfile[MAX_PATH]; ! 412: char keychar = '\0'; ! 413: char *p; ! 414: byte ctb; ! 415: ! 416: /* Initial messages to stderr */ ! 417: pgpout = stderr; ! 418: ! 419: #ifdef DEBUG1 ! 420: verbose = TRUE; ! 421: #endif ! 422: ! 423: #ifndef UNIX ! 424: if ((p = getenv("PGPPASS")) != NULL) ! 425: strcpy(password, p); ! 426: #else ! 427: for (opt = 1; opt < argc; ++opt) ! 428: { if (strcmp(argv[opt], "-z") == 0 && ++opt < argc) ! 429: { strcpy(password, argv[opt]); ! 430: for (p = argv[opt]; *p; ++p) ! 431: *p = ' '; ! 432: } ! 433: } ! 434: #endif ! 435: ! 436: /* Process the config file first. Any command-line arguments will ! 437: override the config file settings */ ! 438: buildfilename( mcguffin, CONFIG_FILENAME ); ! 439: if ( processConfigFile( mcguffin ) < 0 ) ! 440: exit(BAD_ARG_ERROR); ! 441: init_charset(); ! 442: ! 443: #ifdef MSDOS /* only on MSDOS systems */ ! 444: if ((p = getenv("TZ")) == NULL || *p == '\0') ! 445: { fprintf(pgpout,PSTR("\007WARNING: Environmental variable TZ is not defined, so GMT timestamps\n\ ! 446: may be wrong. See the PGP User's Guide to properly define TZ\n\ ! 447: in AUTOEXEC.BAT file.\n")); ! 448: } ! 449: #endif /* MSDOS */ ! 450: ! 451: #ifdef XVMS /* When we can trust FILEIO.C, change this to VMS, HAJK */ ! 452: #define TEMP "SYS$SCRATCH" ! 453: #else ! 454: #define TEMP "TMP" ! 455: #endif /* VMS */ ! 456: if ((p = getenv(TEMP)) != NULL && *p != '\0') ! 457: settmpdir(p); ! 458: ! 459: /* Process all the command-line option switches: */ ! 460: while (optind < argc) ! 461: { /* ! 462: * Allow random order of options and arguments (like GNU getopt) ! 463: * NOTE: this does not work with GNU getopt, use getopt.c from ! 464: * the PGP distribution. ! 465: */ ! 466: if ((opt = getopt(argc, argv, OPTIONS)) == EOF) ! 467: { if (optind == argc) /* -- at end */ ! 468: break; ! 469: if (myArgc == MAXARGC) ! 470: { signon_msg(); ! 471: fprintf(pgpout, PSTR("\007Too many arguments.\n")); ! 472: errorLvl = BAD_ARG_ERROR; ! 473: user_error(); ! 474: } ! 475: myArgv[myArgc++] = argv[optind++]; ! 476: continue; ! 477: } ! 478: opt = to_lower(opt); ! 479: if (keyflag && (keychar == '\0' || (keychar == 'v' && opt == 'v'))) ! 480: { ! 481: if (keychar == 'v') ! 482: keychar = 'V'; ! 483: else ! 484: keychar = opt; ! 485: continue; ! 486: } ! 487: switch (opt) ! 488: { ! 489: case 'a': armor_flag = TRUE; emit_radix_64 = 1; break; ! 490: case 'b': separate_signature = strip_sig_flag = TRUE; break; ! 491: case 'c': encrypt_flag = conventional_flag = TRUE; ! 492: c_flag = TRUE; break; ! 493: case 'd': decrypt_only_flag = TRUE; break; ! 494: case 'e': encrypt_flag = TRUE; break; ! 495: case 'f': filter_mode = TRUE; break; ! 496: case '?': ! 497: case 'h': usage(); break; ! 498: #ifdef VMS ! 499: case 'i': lit_mode = MODE_LOCAL; break; ! 500: #endif /* VMS */ ! 501: case 'k': keyflag = TRUE; break; ! 502: case 'l': verbose = TRUE; break; ! 503: case 'm': moreflag = TRUE; break; ! 504: case 'p': preserve_filename = TRUE; break; ! 505: case 'o': outputfile = optarg; break; ! 506: case 's': sign_flag = TRUE; break; ! 507: case 't': lit_mode = MODE_TEXT; break; ! 508: case 'u': strncpy(my_name, optarg, sizeof(my_name)-1); ! 509: CONVERT_TO_CANONICAL_CHARSET(my_name); ! 510: break; ! 511: case 'w': wipeflag = TRUE; break; ! 512: case 'z': break; ! 513: /* '+' special option: does not require - */ ! 514: case '+': ! 515: if (processConfigLine(optarg) == 0) ! 516: break; ! 517: fprintf(stderr, "\n"); ! 518: /* fallthrough */ ! 519: default: ! 520: arg_error(); ! 521: } ! 522: } ! 523: if (keyflag && keychar == '\0') ! 524: key_usage(); ! 525: ! 526: signon_msg(); ! 527: check_expiration_date(); /* hobble any experimental version */ ! 528: ! 529: #ifndef UNIX ! 530: if (!filter_mode) ! 531: pgpout = stdout; ! 532: #endif ! 533: ! 534: #if defined(UNIX) || defined(VMS) ! 535: umask(077); /* Make files default to private */ ! 536: #endif ! 537: ! 538: initsigs(); ! 539: ! 540: if (keyflag) ! 541: { do_keyopt(keychar); ! 542: exitPGP(EXIT_OK); ! 543: } ! 544: ! 545: /* -db means break off signature certificate into separate file */ ! 546: if (decrypt_only_flag && strip_sig_flag) ! 547: decrypt_only_flag = FALSE; ! 548: ! 549: if (decrypt_only_flag && armor_flag) ! 550: decrypt_mode = de_armor_only = TRUE; ! 551: ! 552: if (outputfile != NULL) ! 553: preserve_filename = FALSE; ! 554: ! 555: if (!sign_flag && !encrypt_flag && !conventional_flag && !armor_flag) ! 556: { if (wipeflag) /* wipe only */ ! 557: { if (myArgc != 3) ! 558: arg_error(); /* need one argument */ ! 559: if (wipefile(myArgv[2]) == 0 && remove(myArgv[2]) == 0) ! 560: { fprintf(pgpout,PSTR("\nFile %s wiped and deleted. "),myArgv[2]); ! 561: fprintf(pgpout, "\n"); ! 562: exitPGP(EXIT_OK); ! 563: } ! 564: exitPGP(UNKNOWN_FILE_ERROR); ! 565: } ! 566: /* decrypt if none of the -s -e -c -a -w options are specified */ ! 567: decrypt_mode = TRUE; ! 568: } ! 569: ! 570: if (myArgc == 2) /* no arguments */ ! 571: { ! 572: #ifdef UNIX ! 573: if (!filter_mode && !isatty(fileno(stdin))) ! 574: { /* piping to pgp without arguments and no -f: ! 575: * switch to filter mode but don't write output to stdout ! 576: * if it's a tty, use the preserved filename */ ! 577: filter_mode = TRUE; ! 578: if (isatty(fileno(stdout)) && !moreflag) ! 579: preserve_filename = TRUE; ! 580: } ! 581: #endif ! 582: if (!filter_mode) ! 583: { fprintf(pgpout,PSTR("\nFor details on licensing and distribution, see the PGP User's Guide.\ ! 584: \nFor other cryptography products and custom development services, contact:\ ! 585: \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA, phone (303)541-0140\n")); ! 586: if (strcmp((p = PSTR("@translator@")), "@translator@")) ! 587: fprintf(pgpout, p); ! 588: fprintf(pgpout,PSTR("\nFor a usage summary, type: pgp -h\n")); ! 589: exit(BAD_ARG_ERROR); /* error exit */ ! 590: } ! 591: } ! 592: else ! 593: { if (filter_mode) ! 594: recipient = myArgv[2]; ! 595: else ! 596: { inputfile = myArgv[2]; ! 597: recipient = myArgv[3]; ! 598: } ! 599: } ! 600: ! 601: ! 602: if (filter_mode) ! 603: { inputfile = "stdin"; ! 604: filter_mode = TRUE; ! 605: } ! 606: else ! 607: { if (decrypt_mode && no_extension(inputfile)) ! 608: { strcpy(cipherfile, inputfile); ! 609: force_extension( cipherfile, ASC_EXTENSION ); ! 610: if (file_exists (cipherfile)) ! 611: inputfile = cipherfile; ! 612: else ! 613: { force_extension( cipherfile, CTX_EXTENSION ); ! 614: if (file_exists (cipherfile)) ! 615: inputfile = cipherfile; ! 616: else ! 617: { force_extension( cipherfile, SIG_EXTENSION ); ! 618: if (file_exists (cipherfile)) ! 619: inputfile = cipherfile; ! 620: } ! 621: } ! 622: } ! 623: if (! file_exists( inputfile )) ! 624: { fprintf(pgpout, PSTR("\007File [%s] does not exist.\n"), inputfile); ! 625: errorLvl = FILE_NOT_FOUND_ERROR; ! 626: user_error(); ! 627: } ! 628: workfile = inputfile; ! 629: } ! 630: ! 631: if (strlen(inputfile) >= (unsigned) MAX_PATH-4) ! 632: { fprintf(pgpout, PSTR("\007Invalid filename: [%s] too long\n"), inputfile ); ! 633: errorLvl = INVALID_FILE_ERROR; ! 634: user_error(); ! 635: } ! 636: strcpy(plainfile, inputfile); ! 637: ! 638: if (filter_mode) ! 639: setoutdir(NULL); /* NULL means use tmpdir */ ! 640: else ! 641: { if (outputfile) ! 642: setoutdir(outputfile); ! 643: else ! 644: setoutdir(inputfile); ! 645: } ! 646: ! 647: if (filter_mode) ! 648: { workfile = tempfile(TMP_WIPE|TMP_TMPDIR); ! 649: readPhantomInput(workfile); ! 650: } ! 651: ! 652: get_header_info_from_file( workfile, &ctb, 1 ); ! 653: if (decrypt_mode) ! 654: { if (!outputfile) ! 655: outputfile = myArgv[3]; ! 656: if (!is_ctb(ctb) && is_armor_file(workfile, 0L)) ! 657: do_armorfile(workfile); ! 658: else ! 659: do_decrypt(workfile); ! 660: exitPGP(EXIT_OK); ! 661: } ! 662: ! 663: ! 664: /* See if plaintext input file was actually created by PGP earlier-- ! 665: If it was, maybe we should NOT encapsulate it in a literal packet. ! 666: Otherwise, always encapsulate it. ! 667: */ ! 668: nestflag = FALSE; /* First assume we will encapsulate it. */ ! 669: if (!filter_mode && legal_ctb(ctb)) ! 670: { /* Special case--may be a PGP-created packet, so ! 671: do we inhibit encapsulation in literal packet? */ ! 672: fprintf(pgpout, PSTR("\n\007Input file '%s' looks like it may have been created by PGP. "), ! 673: inputfile ); ! 674: fprintf(pgpout, PSTR("\nIs it safe to assume that it was created by PGP (y/N)? ")); ! 675: if (getyesno('n')) ! 676: nestflag = TRUE; /* don't re-encapsulate PGP packet */ ! 677: } /* Possible ciphertext input file */ ! 678: ! 679: if (moreflag) /* special name to cause printout on decrypt */ ! 680: { strcpy (literal_file_name, CONSOLE_FILENAME); ! 681: lit_mode = MODE_TEXT; /* will check for text file later */ ! 682: } ! 683: else ! 684: { strcpy (literal_file_name, inputfile); ! 685: #ifdef MSDOS ! 686: strlwr (literal_file_name); ! 687: #endif ! 688: } ! 689: literal_file = literal_file_name; ! 690: ! 691: /* Make sure non-text files are not accidentally converted ! 692: to canonical text. This precaution should only be followed ! 693: for US ASCII text files, since European text files may have ! 694: 8-bit character codes and still be legitimate text files ! 695: suitable for conversion to canonical (CR/LF-terminated) ! 696: text format. */ ! 697: if (lit_mode==MODE_TEXT && !is_text_file(workfile)) ! 698: { fprintf(pgpout, ! 699: PSTR("\n\007Warning: '%s' is not a pure text file.\nFile will be treated as binary data.\n"), ! 700: workfile); ! 701: lit_mode = MODE_BINARY; /* now expect straight binary */ ! 702: } ! 703: ! 704: if (moreflag && lit_mode==MODE_BINARY) /* For eyes only? Can't display binary file. */ ! 705: { fprintf(pgpout, ! 706: PSTR("\n\007Error: Only text files may be sent as display-only.\n")); ! 707: errorLvl = INVALID_FILE_ERROR; ! 708: user_error(); ! 709: } ! 710: ! 711: ! 712: /* See if plainfile looks like it might be incompressible, ! 713: by examining its contents for compression headers for ! 714: commonly-used compressed file formats like PKZIP, etc. ! 715: Remember this information for later, when we are deciding ! 716: whether to attempt compression before encryption. ! 717: */ ! 718: attempt_compression = compress_enabled && file_compressible(plainfile); ! 719: ! 720: ! 721: if (sign_flag) ! 722: { ! 723: if (!filter_mode) ! 724: fprintf(pgpout, PSTR("\nA secret key is required to make a signature. ")); ! 725: if (my_name[0] == '\0') ! 726: { ! 727: fprintf(pgpout, PSTR("\nYou specified no user ID to select your secret key,\n\ ! 728: so the default user ID and key will be the most recently\n\ ! 729: added key on your secret keyring.\n")); ! 730: } ! 731: ! 732: if (lit_mode==MODE_TEXT) ! 733: { /* Text mode requires becoming canonical */ ! 734: tempf = tempfile(TMP_WIPE|TMP_TMPDIR); ! 735: make_canonical( workfile, tempf ); ! 736: /* +clear means output file with signature in the clear, ! 737: only in combination with -t and -a, not with -e or -b */ ! 738: if (!encrypt_flag && !separate_signature && ! 739: emit_radix_64 && clear_signatures) { ! 740: clearfile = workfile; ! 741: } else { ! 742: rmtemp(workfile); ! 743: } ! 744: workfile = tempf; ! 745: } ! 746: if ((emit_radix_64 || encrypt_flag) && !separate_signature) ! 747: tempf = tempfile(TMP_WIPE|TMP_TMPDIR); ! 748: else ! 749: tempf = tempfile(TMP_WIPE); ! 750: /* for clear signatures we create a separate signature */ ! 751: status = signfile(nestflag, separate_signature || (clearfile != NULL), ! 752: my_name, workfile, tempf, lit_mode, literal_file ); ! 753: rmtemp(workfile); ! 754: workfile = tempf; ! 755: ! 756: if (status < 0) /* signfile failed */ ! 757: { fprintf(pgpout, PSTR("\007Signature error\n") ); ! 758: errorLvl = SIGNATURE_ERROR; ! 759: user_error(); ! 760: } ! 761: ! 762: /* If we just sign it without encryption, and we want radix-64 ! 763: output, we may as well compress it before converting to ! 764: radix-64 format. */ ! 765: if (attempt_compression && emit_radix_64 && !encrypt_flag && ! 766: !clearfile) ! 767: { tempf = tempfile(TMP_WIPE|TMP_TMPDIR); ! 768: squish_file(workfile, tempf); ! 769: rmtemp(workfile); ! 770: workfile = tempf; ! 771: } ! 772: ! 773: } /* sign file */ ! 774: else if (!nestflag) ! 775: { /* Prepend CTB_LITERAL byte to plaintext file. ! 776: --sure wish this pass could be optimized away. */ ! 777: tempf = tempfile(TMP_WIPE); ! 778: status = make_literal( workfile, tempf, lit_mode, literal_file ); ! 779: rmtemp(workfile); ! 780: workfile = tempf; ! 781: } ! 782: ! 783: if (encrypt_flag) ! 784: { ! 785: if (!conventional_flag) ! 786: { ! 787: if (!filter_mode) ! 788: fprintf(pgpout, PSTR("\n\nRecipient's public key will be used to encrypt. ")); ! 789: if (recipient == NULL) ! 790: { /* no recipient specified on command line */ ! 791: fprintf(pgpout, PSTR("\nA user ID is required to select the recipient's public key. ")); ! 792: fprintf(pgpout, PSTR("\nEnter the recipient's user ID: ")); ! 793: getstring( mcguffin, 255, TRUE ); /* echo keyboard */ ! 794: } ! 795: else ! 796: { /* recipient specified on command line */ ! 797: strcpy( mcguffin, recipient ); /* Userid of recipient */ ! 798: } ! 799: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 800: } ! 801: ! 802: tempf = tempfile(TMP_WIPE); ! 803: if (conventional_flag) ! 804: status = idea_encryptfile( workfile, tempf, attempt_compression); ! 805: else ! 806: status = encryptfile( mcguffin, workfile, tempf, attempt_compression); ! 807: ! 808: rmtemp(workfile); ! 809: workfile = tempf; ! 810: ! 811: if (status < 0) ! 812: { fprintf(pgpout, PSTR("\007Encryption error\n") ); ! 813: errorLvl = (conventional_flag ? ENCR_ERROR : RSA_ENCR_ERROR); ! 814: user_error(); ! 815: } ! 816: } /* encrypt file */ ! 817: ! 818: if (outputfile) /* explicit output file overrides filter mode */ ! 819: filter_mode = (strcmp(outputfile, "-") == 0); ! 820: ! 821: if (filter_mode) ! 822: { if (emit_radix_64) ! 823: { /* NULL for outputfile means write to stdout */ ! 824: if (armor_file(workfile, NULL, inputfile, clearfile) != 0) ! 825: { errorLvl = UNKNOWN_FILE_ERROR; ! 826: user_error(); ! 827: } ! 828: if (clearfile) ! 829: rmtemp(clearfile); ! 830: } ! 831: else ! 832: if (writePhantomOutput(workfile) < 0) ! 833: { errorLvl = UNKNOWN_FILE_ERROR; ! 834: user_error(); ! 835: } ! 836: rmtemp(workfile); ! 837: } ! 838: else ! 839: { char name[MAX_PATH]; ! 840: if (outputfile) ! 841: strcpy(name, outputfile); ! 842: else ! 843: { strcpy(name, inputfile); ! 844: drop_extension(name); ! 845: } ! 846: if (no_extension(name)) ! 847: { if (emit_radix_64) ! 848: force_extension(name, ASC_EXTENSION); ! 849: else if (sign_flag && separate_signature) ! 850: force_extension(name, SIG_EXTENSION); ! 851: else ! 852: force_extension(name, CTX_EXTENSION); ! 853: } ! 854: if (emit_radix_64) ! 855: { ! 856: if (armor_file(workfile, name, inputfile, clearfile) != 0) ! 857: { errorLvl = UNKNOWN_FILE_ERROR; ! 858: user_error(); ! 859: } ! 860: if (clearfile) ! 861: rmtemp(clearfile); ! 862: } ! 863: else ! 864: { if ((outputfile = savetemp(workfile, name)) == NULL) ! 865: { errorLvl = UNKNOWN_FILE_ERROR; ! 866: user_error(); ! 867: } ! 868: if (!verbose && encrypt_flag) ! 869: fprintf(pgpout, PSTR("\nCiphertext file: %s\n"), outputfile); ! 870: else if (!verbose && sign_flag) ! 871: fprintf(pgpout, PSTR("\nSignature file: %s\n"), outputfile); ! 872: } ! 873: } ! 874: ! 875: if (wipeflag) ! 876: { /* destroy every trace of plaintext */ ! 877: if (wipefile(inputfile) == 0) ! 878: { remove(inputfile); ! 879: fprintf(pgpout,PSTR("\nFile %s wiped and deleted. "),inputfile); ! 880: fprintf(pgpout, "\n"); ! 881: } ! 882: } ! 883: ! 884: exitPGP(EXIT_OK); ! 885: } /* main */ ! 886: ! 887: #ifdef MSDOS ! 888: #include <dos.h> ! 889: static char *dos_errlst[] = { ! 890: "Write protect error", /* PSTR ("Write protect error") */ ! 891: "Unknown unit", ! 892: "Drive not ready", /* PSTR ("Drive not ready") */ ! 893: "3", "4", "5", "6", "7", "8", "9", ! 894: "Write error", /* PSTR ("Write error") */ ! 895: "Read error", /* PSTR ("Read error") */ ! 896: "General failure", ! 897: }; ! 898: ! 899: /* handler for msdos 'harderrors' */ ! 900: #ifndef OS2 ! 901: #ifdef __TURBOC__ /* Turbo C 2.0 */ ! 902: static int dostrap(int errval) ! 903: #else ! 904: static void dostrap(unsigned deverr, unsigned errval) ! 905: #endif ! 906: { ! 907: char errbuf[64]; ! 908: int i; ! 909: sprintf(errbuf, "\r\nDOS error: %s\r\n", dos_errlst[errval]); ! 910: i = 0; ! 911: do ! 912: bdos(2,(unsigned int)errbuf[i],0); ! 913: while (errbuf[++i]); ! 914: #ifdef __TURBOC__ ! 915: return 0; /* ignore (fopen will return NULL) */ ! 916: #else ! 917: return; ! 918: #endif ! 919: } ! 920: #endif /* MSDOS */ ! 921: #endif ! 922: ! 923: static void initsigs() ! 924: { ! 925: #ifdef MSDOS ! 926: #ifndef OS2 ! 927: #ifdef __TURBOC__ ! 928: harderr(dostrap); ! 929: #else /* MSC */ ! 930: _harderr(dostrap); ! 931: #endif ! 932: #endif ! 933: #endif /* MSDOS */ ! 934: #ifdef SIGINT ! 935: #ifdef ATARI ! 936: signal(SIGINT,(sigfunc_t) breakHandler); ! 937: #else ! 938: signal(SIGINT,breakHandler); ! 939: #if defined(UNIX) || defined(VMS) ! 940: signal(SIGHUP,breakHandler); ! 941: signal(SIGQUIT,breakHandler); ! 942: #ifdef UNIX ! 943: signal(SIGPIPE,breakHandler); ! 944: #endif ! 945: signal(SIGTERM,breakHandler); ! 946: #ifndef DEBUG ! 947: signal(SIGSEGV,breakHandler); ! 948: signal(SIGILL,breakHandler); ! 949: #ifdef SIGBUS ! 950: signal(SIGBUS,breakHandler); ! 951: #endif ! 952: #endif /* DEBUG */ ! 953: #endif /* UNIX */ ! 954: #endif /* not Atari */ ! 955: #endif /* SIGINT */ ! 956: } /* initsigs */ ! 957: ! 958: ! 959: static void do_armorfile(char *armorfile) ! 960: { ! 961: char *tempf; ! 962: char cipherfile[MAX_PATH]; ! 963: long linepos = 0; ! 964: int status; ! 965: ! 966: while (TRUE) ! 967: { /* Handle transport armor stripping */ ! 968: tempf = tempfile(0); ! 969: status = de_armor_file(armorfile,tempf,&linepos); ! 970: if (status) ! 971: { fprintf(pgpout,PSTR("\n\007Error: Transport armor stripping failed for file %s\n"),armorfile); ! 972: errorLvl = INVALID_FILE_ERROR; ! 973: user_error(); /* Bad file */ ! 974: } ! 975: if (keepctx || de_armor_only) ! 976: { if (outputfile) ! 977: strcpy(cipherfile, outputfile); ! 978: else ! 979: { strcpy(cipherfile, file_tail(armorfile)); ! 980: force_extension(cipherfile, CTX_EXTENSION); ! 981: } ! 982: if ((tempf = savetemp(tempf, cipherfile)) == NULL) ! 983: { errorLvl = UNKNOWN_FILE_ERROR; ! 984: user_error(); ! 985: } ! 986: fprintf(pgpout,PSTR("Stripped transport armor from '%s', producing '%s'.\n"), ! 987: armorfile, tempf); ! 988: if (!de_armor_only) ! 989: do_decrypt(tempf); ! 990: } ! 991: else ! 992: { do_decrypt(tempf); ! 993: rmtemp(tempf); ! 994: } ! 995: ! 996: if (!is_armor_file(armorfile, linepos)) ! 997: break; ! 998: ! 999: fprintf (pgpout, PSTR("\nLooking for next packet in '%s'...\n"), armorfile); ! 1000: } ! 1001: } /* do_armorfile */ ! 1002: ! 1003: ! 1004: static void do_decrypt(char *cipherfile) ! 1005: { ! 1006: char *outfile = NULL; ! 1007: int status, i; ! 1008: boolean nested_info = FALSE; ! 1009: char ringfile[MAX_PATH]; ! 1010: byte ctb; ! 1011: byte header[8]; /* used to classify file type at the end. */ ! 1012: char preserved_name[MAX_PATH]; ! 1013: char *newname; ! 1014: ! 1015: /* will be set to the original file name after processing a literal packet */ ! 1016: preserved_name[0] = '\0'; ! 1017: ! 1018: do /* while nested parsable info present */ ! 1019: { ! 1020: if (nested_info) ! 1021: { rmtemp(cipherfile); /* never executed on first pass */ ! 1022: cipherfile = outfile; ! 1023: } ! 1024: if (get_header_info_from_file( cipherfile, &ctb, 1) < 0) ! 1025: { fprintf(pgpout,PSTR("\n\007Can't open ciphertext file '%s'\n"),cipherfile); ! 1026: errorLvl = FILE_NOT_FOUND_ERROR; ! 1027: user_error(); ! 1028: } ! 1029: ! 1030: if (!is_ctb(ctb)) /* not a real CTB -- complain */ ! 1031: break; ! 1032: ! 1033: outfile = tempfile(TMP_WIPE); ! 1034: ! 1035: /* PKE is Public Key Encryption */ ! 1036: if (is_ctb_type( ctb, CTB_PKE_TYPE )) ! 1037: { ! 1038: if (!filter_mode) ! 1039: fprintf(pgpout,PSTR("\nFile is encrypted. Secret key is required to read it. ")); ! 1040: ! 1041: /* Decrypt to scratch file since we may have a LITERAL2 */ ! 1042: status = decryptfile( cipherfile, outfile ); ! 1043: ! 1044: if (status < 0) /* error return */ ! 1045: { errorLvl = RSA_DECR_ERROR; ! 1046: user_error(); ! 1047: } ! 1048: nested_info = (status > 0); ! 1049: } /* outer CTB is PKE type */ ! 1050: ! 1051: if (is_ctb_type( ctb, CTB_SKE_TYPE )) ! 1052: { ! 1053: if (decrypt_only_flag) ! 1054: { /* swap file names instead of just copying the file */ ! 1055: rmtemp(outfile); ! 1056: outfile = cipherfile; ! 1057: cipherfile = NULL; ! 1058: fprintf(pgpout,PSTR("\nThis file has a signature, which will be left in place.\n")); ! 1059: break; /* Do no more */ ! 1060: } ! 1061: fprintf(pgpout,PSTR("\nFile has signature. Public key is required to check signature. ")); ! 1062: ! 1063: status = check_signaturefile( cipherfile, outfile, strip_sig_flag, preserved_name ); ! 1064: ! 1065: if (status < 0) /* error return */ ! 1066: { errorLvl = SIGNATURE_CHECK_ERROR; ! 1067: user_error(); ! 1068: } ! 1069: nested_info = (status > 0); ! 1070: ! 1071: if (strcmp(preserved_name, "/dev/null") == 0) ! 1072: { rmtemp(outfile); ! 1073: fprintf(pgpout, "\n"); ! 1074: return; ! 1075: } ! 1076: } /* outer CTB is SKE type */ ! 1077: ! 1078: ! 1079: if (is_ctb_type( ctb, CTB_CKE_TYPE )) ! 1080: { /* Conventional Key Encrypted ciphertext. */ ! 1081: /* Tell user it's encrypted here, and prompt for password in subroutine. */ ! 1082: if (!filter_mode) ! 1083: fprintf(pgpout,PSTR("\nFile is conventionally encrypted. ")); ! 1084: /* Decrypt to scratch file since it may be a LITERAL2 */ ! 1085: status = idea_decryptfile( cipherfile, outfile ); ! 1086: if (status < 0) /* error return */ ! 1087: { errorLvl = DECR_ERROR; ! 1088: user_error(); /* error exit status */ ! 1089: } ! 1090: nested_info = (status > 0); ! 1091: } /* CTB is CKE type */ ! 1092: ! 1093: ! 1094: if (is_ctb_type( ctb, CTB_COMPRESSED_TYPE )) ! 1095: { /* Compressed text. */ ! 1096: status = decompress_file( cipherfile, outfile ); ! 1097: if (status < 0) /* error return */ ! 1098: { errorLvl = DECOMPRESS_ERROR; ! 1099: user_error(); ! 1100: } ! 1101: /* Always assume nested information... */ ! 1102: nested_info = TRUE; ! 1103: } /* CTB is COMPRESSED type */ ! 1104: ! 1105: ! 1106: if (is_ctb_type( ctb, CTB_LITERAL_TYPE ) || is_ctb_type( ctb, CTB_LITERAL2_TYPE)) ! 1107: { /* Raw plaintext. Just copy it. No more nesting. */ ! 1108: /* Strip off CTB_LITERAL prefix byte from file: */ ! 1109: /* strip_literal may alter plainfile; will set mode */ ! 1110: status = strip_literal( cipherfile, outfile, ! 1111: preserved_name, &lit_mode); ! 1112: if (status < 0) /* error return */ ! 1113: { errorLvl = UNKNOWN_FILE_ERROR; ! 1114: user_error(); ! 1115: } ! 1116: nested_info = FALSE; ! 1117: } /* CTB is LITERAL type */ ! 1118: ! 1119: ! 1120: if ((ctb == CTB_CERT_SECKEY) || (ctb == CTB_CERT_PUBKEY)) ! 1121: { rmtemp(outfile); ! 1122: if (decrypt_only_flag) ! 1123: { /* swap file names instead of just copying the file */ ! 1124: outfile = cipherfile; ! 1125: cipherfile = NULL; ! 1126: break; /* no further processing */ ! 1127: } ! 1128: /* Key ring. View it. */ ! 1129: fprintf(pgpout, PSTR("\nFile contains key(s). Contents follow...") ); ! 1130: if (filter_mode && !preserve_filename) ! 1131: { /* filter mode explicit requested with -f */ ! 1132: if (view_keyring( NULL, cipherfile, TRUE, FALSE ) < 0) ! 1133: { errorLvl = KEYRING_VIEW_ERROR; ! 1134: user_error(); ! 1135: } ! 1136: return; /* No output file */ ! 1137: } ! 1138: if (ctb == CTB_CERT_SECKEY) ! 1139: buildfilename(ringfile,SECRET_KEYRING_FILENAME); ! 1140: else ! 1141: buildfilename(ringfile,PUBLIC_KEYRING_FILENAME); ! 1142: /* Ask if it should be put on key ring */ ! 1143: status = addto_keyring(cipherfile,ringfile,TRUE); ! 1144: if (status < 0) ! 1145: { fprintf(pgpout, PSTR("\007Keyring add error. ") ); ! 1146: errorLvl = KEYRING_ADD_ERROR; ! 1147: user_error(); ! 1148: } ! 1149: return; /* No output file */ ! 1150: } /* key ring. view it. */ ! 1151: ! 1152: } while (nested_info); ! 1153: /* No more nested parsable information */ ! 1154: ! 1155: if (outfile == NULL) /* file was not encrypted */ ! 1156: { if (!filter_mode && !moreflag) ! 1157: { fprintf(pgpout,PSTR("\007\nError: '%s' is not a ciphertext, signature, or key file.\n"), ! 1158: cipherfile); ! 1159: errorLvl = UNKNOWN_FILE_ERROR; ! 1160: user_error(); ! 1161: } ! 1162: outfile = cipherfile; ! 1163: } ! 1164: else ! 1165: if (cipherfile) ! 1166: rmtemp(cipherfile); ! 1167: ! 1168: if (moreflag || (strcmp(preserved_name,CONSOLE_FILENAME) == 0)) ! 1169: { /* blort to screen */ ! 1170: if (strcmp(preserved_name,CONSOLE_FILENAME) == 0) ! 1171: { fprintf(pgpout, ! 1172: PSTR("\n\nThis message is marked \"For your eyes only\". Display now (Y/n)? ")); ! 1173: if (!getyesno('y')) ! 1174: { /* no -- abort display, and clean up */ ! 1175: rmtemp(outfile); ! 1176: return; ! 1177: } ! 1178: } ! 1179: fprintf(pgpout, PSTR("\n\nPlaintext message follows...\n")); ! 1180: more_file(outfile); ! 1181: /* Disallow saving to disk if outfile is console-only: */ ! 1182: if (strcmp(preserved_name,CONSOLE_FILENAME) == 0) ! 1183: clearscreen(); /* remove all evidence */ ! 1184: else ! 1185: { fprintf(pgpout, PSTR("Save this file permanently (y/N)? ")); ! 1186: if (getyesno('n')) ! 1187: { char moreFilename[256]; ! 1188: fprintf(pgpout,PSTR("Enter filename to save file as: ")); ! 1189: if (preserved_name[0]) ! 1190: fprintf(pgpout, "[%s]: ", file_tail(preserved_name)); ! 1191: getstring( moreFilename, 255, TRUE ); ! 1192: if (*moreFilename == '\0') ! 1193: { if (*preserved_name != '\0') ! 1194: savetemp (outfile, file_tail(preserved_name)); ! 1195: else ! 1196: rmtemp(outfile); ! 1197: } ! 1198: else ! 1199: savetemp (outfile, moreFilename); ! 1200: return; ! 1201: } ! 1202: } ! 1203: rmtemp(outfile); ! 1204: return; ! 1205: } /* blort to screen */ ! 1206: ! 1207: if (outputfile) ! 1208: { if (!strcmp(outputfile, "/dev/null")) ! 1209: { rmtemp(outfile); ! 1210: return; ! 1211: } ! 1212: filter_mode = (strcmp(outputfile, "-") == 0); ! 1213: strcpy(plainfile, outputfile); ! 1214: } ! 1215: else ! 1216: #ifdef VMS ! 1217: /* VMS null extension has to be ".", not "" */ ! 1218: force_extension(plainfile, "."); ! 1219: #else /* not VMS */ ! 1220: drop_extension(plainfile); ! 1221: #endif /* not VMS */ ! 1222: ! 1223: if (!preserve_filename && filter_mode) ! 1224: { if (writePhantomOutput(outfile) < 0) ! 1225: { errorLvl = UNKNOWN_FILE_ERROR; ! 1226: user_error(); ! 1227: } ! 1228: rmtemp(outfile); ! 1229: return; ! 1230: } ! 1231: ! 1232: if (preserve_filename && preserved_name[0] != '\0') ! 1233: strcpy(plainfile, file_tail(preserved_name)); ! 1234: ! 1235: if (!verbose) /* if other filename messages were suppressed */ ! 1236: fprintf(pgpout,PSTR("\nPlaintext filename: %s"), plainfile); ! 1237: ! 1238: ! 1239: /*---------------------------------------------------------*/ ! 1240: ! 1241: /* One last thing-- let's attempt to classify some of the more ! 1242: frequently occurring cases of plaintext output files, as an ! 1243: aid to the user. ! 1244: ! 1245: For example, if output file is a public key, it should have ! 1246: the right extension on the filename. ! 1247: ! 1248: Also, it will likely be common to encrypt files created by ! 1249: various archivers, so they should be renamed with the archiver ! 1250: extension. ! 1251: */ ! 1252: get_header_info_from_file( outfile, header, 8 ); ! 1253: ! 1254: newname = NULL; ! 1255: if (header[0] == CTB_CERT_PUBKEY) ! 1256: { /* Special case--may be public key, worth renaming */ ! 1257: fprintf(pgpout, PSTR("\nPlaintext file '%s' looks like it contains a public key."), ! 1258: plainfile ); ! 1259: newname = maybe_force_extension( plainfile, PGP_EXTENSION ); ! 1260: } /* Possible public key output file */ ! 1261: ! 1262: else ! 1263: if ((i = compressSignature( header )) >= 0) ! 1264: { /* Special case--may be an archived/compressed file, worth renaming */ ! 1265: fprintf(pgpout, PSTR("\nPlaintext file '%s' looks like a %s file."), ! 1266: plainfile, compressName[i] ); ! 1267: newname = maybe_force_extension( plainfile, compressExt[i] ); ! 1268: } /* Possible archived/compressed output file */ ! 1269: ! 1270: else ! 1271: if (is_ctb(header[0]) && ! 1272: (is_ctb_type (header[0], CTB_PKE_TYPE) ! 1273: || is_ctb_type (header[0], CTB_SKE_TYPE) ! 1274: || is_ctb_type (header[0], CTB_CKE_TYPE))) ! 1275: { /* Special case--may be another ciphertext file, worth renaming */ ! 1276: fprintf(pgpout, PSTR("\n\007Output file '%s' may contain more ciphertext or signature."), ! 1277: plainfile ); ! 1278: newname = maybe_force_extension( plainfile, CTX_EXTENSION ); ! 1279: } /* Possible ciphertext output file */ ! 1280: ! 1281: if (savetemp(outfile, (newname ? newname : plainfile)) == NULL) ! 1282: { errorLvl = UNKNOWN_FILE_ERROR; ! 1283: user_error(); ! 1284: } ! 1285: ! 1286: fprintf (pgpout, "\n"); ! 1287: ! 1288: } /* do_decrypt */ ! 1289: ! 1290: ! 1291: static void do_keyopt(char keychar) ! 1292: { ! 1293: char keyfile[MAX_PATH]; ! 1294: char ringfile[MAX_PATH]; ! 1295: int status; ! 1296: ! 1297: if (filter_mode && keychar != 'r') ! 1298: { errorLvl = NO_BATCH; ! 1299: arg_error(); /* interactive process, no go in batch mode */ ! 1300: } ! 1301: ! 1302: switch (keychar) ! 1303: { ! 1304: ! 1305: /*-------------------------------------------------------*/ ! 1306: case 'g': ! 1307: { /* Key generation ! 1308: Arguments: bitcount, bitcount ! 1309: */ ! 1310: char keybits[6], ebits[6]; ! 1311: ! 1312: if (myArgc > 2) ! 1313: strncpy( keybits, myArgv[2], sizeof(keybits)-1 ); ! 1314: else ! 1315: keybits[0] = '\0'; ! 1316: ! 1317: if (myArgc > 3) ! 1318: strncpy( ebits, myArgv[3], sizeof(ebits)-1 ); ! 1319: else ! 1320: ebits[0] = '\0'; ! 1321: ! 1322: /* dokeygen writes the keys out to the key rings... */ ! 1323: status = dokeygen(keybits, ebits); ! 1324: ! 1325: if (status < 0) ! 1326: { fprintf(pgpout, PSTR("\007Keygen error. ") ); ! 1327: errorLvl = KEYGEN_ERROR; ! 1328: user_error(); ! 1329: } ! 1330: return; ! 1331: } /* Key generation */ ! 1332: ! 1333: /*-------------------------------------------------------*/ ! 1334: case 'c': ! 1335: { /* Key checking ! 1336: Arguments: userid, ringfile ! 1337: */ ! 1338: ! 1339: if (myArgc < 3) /* Default to all user ID's */ ! 1340: mcguffin[0] = '\0'; ! 1341: else ! 1342: { strcpy ( mcguffin, myArgv[2] ); ! 1343: if (strcmp( mcguffin, "*" ) == 0) ! 1344: mcguffin[0] = '\0'; ! 1345: } ! 1346: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1347: ! 1348: if (myArgc < 4) /* default key ring filename */ ! 1349: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); ! 1350: else ! 1351: strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 ); ! 1352: ! 1353: if ((myArgc < 4 && myArgc > 2) /* Allow just key file as arg */ ! 1354: && has_extension( myArgv[2], PGP_EXTENSION ) ) ! 1355: { strcpy( ringfile, myArgv[2] ); ! 1356: mcguffin[0] = '\0'; ! 1357: } ! 1358: ! 1359: status = dokeycheck( mcguffin, ringfile, NULL ); ! 1360: ! 1361: errorLvl = 0; ! 1362: if (status < 0) ! 1363: { fprintf(pgpout, PSTR("\007Keyring check error. ") ); ! 1364: errorLvl = KEYRING_CHECK_ERROR; ! 1365: } ! 1366: if (errorLvl == 0 && mcguffin[0] != '\0') ! 1367: return; /* just checking a single user, dont do maintenance */ ! 1368: ! 1369: if ((status = maintenance(ringfile, 0)) < 0 && status != -7) ! 1370: { fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); ! 1371: errorLvl = KEYRING_CHECK_ERROR; ! 1372: } ! 1373: if (errorLvl) ! 1374: user_error(); ! 1375: ! 1376: return; ! 1377: } /* Key check */ ! 1378: ! 1379: /*-------------------------------------------------------*/ ! 1380: case 'm': ! 1381: { /* Maintenance pass ! 1382: Arguments: ringfile ! 1383: */ ! 1384: ! 1385: if (myArgc < 3) /* default key ring filename */ ! 1386: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); ! 1387: else ! 1388: strcpy( ringfile, myArgv[2] ); ! 1389: ! 1390: #ifdef MSDOS ! 1391: strlwr( ringfile ); ! 1392: #endif ! 1393: if (! file_exists( ringfile )) ! 1394: default_extension( ringfile, PGP_EXTENSION ); ! 1395: ! 1396: if ((status = maintenance(ringfile, ! 1397: MAINT_VERBOSE|(c_flag ? MAINT_CHECK : 0))) < 0) ! 1398: { if (status == -7) ! 1399: fprintf(pgpout, PSTR("File '%s' is not a public keyring\n"), ringfile); ! 1400: fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); ! 1401: errorLvl = KEYRING_CHECK_ERROR; ! 1402: user_error(); ! 1403: } ! 1404: return; ! 1405: } /* Maintenance pass */ ! 1406: ! 1407: /*-------------------------------------------------------*/ ! 1408: case 's': ! 1409: { /* Key signing ! 1410: Arguments: her_id, keyfile ! 1411: */ ! 1412: ! 1413: if (myArgc >= 4) ! 1414: strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 ); ! 1415: else ! 1416: buildfilename( keyfile, PUBLIC_KEYRING_FILENAME ); ! 1417: ! 1418: if (myArgc >= 3) ! 1419: strcpy( mcguffin, myArgv[2] ); /* Userid to sign */ ! 1420: else ! 1421: { ! 1422: fprintf(pgpout, PSTR("\nA user ID is required to select the public key you want to sign. ")); ! 1423: fprintf(pgpout, PSTR("\nEnter the public key's user ID: ")); ! 1424: getstring( mcguffin, 255, TRUE ); /* echo keyboard */ ! 1425: } ! 1426: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1427: ! 1428: if (my_name[0] == '\0') ! 1429: { ! 1430: fprintf(pgpout, PSTR("\nA secret key is required to make a signature. ")); ! 1431: fprintf(pgpout, PSTR("\nYou specified no user ID to select your secret key,\n\ ! 1432: so the default user ID and key will be the most recently\n\ ! 1433: added key on your secret keyring.\n")); ! 1434: } ! 1435: ! 1436: status = signkey ( mcguffin, my_name, keyfile ); ! 1437: ! 1438: if (status >= 0) { ! 1439: status = maintenance(keyfile, MAINT_SILENT); ! 1440: if (status == -7) /* ringfile is a keyfile or secret keyring */ ! 1441: { fprintf(pgpout, "Warning: '%s' is not a public keyring\n", keyfile); ! 1442: return; ! 1443: } ! 1444: if (status < 0) ! 1445: fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); ! 1446: } ! 1447: ! 1448: if (status < 0) ! 1449: { fprintf(pgpout, PSTR("\007Key signature error. ") ); ! 1450: errorLvl = KEY_SIGNATURE_ERROR; ! 1451: user_error(); ! 1452: } ! 1453: return; ! 1454: } /* Key signing */ ! 1455: ! 1456: ! 1457: /*-------------------------------------------------------*/ ! 1458: case 'd': ! 1459: { /* Key compromise ! 1460: Arguments: userid, keyfile ! 1461: */ ! 1462: ! 1463: if (myArgc >= 4) ! 1464: strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 ); ! 1465: else ! 1466: buildfilename( keyfile, PUBLIC_KEYRING_FILENAME ); ! 1467: ! 1468: if (myArgc >= 3) ! 1469: strcpy( mcguffin, myArgv[2] ); /* Userid to sign */ ! 1470: else ! 1471: { ! 1472: fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to revoke. ")); ! 1473: fprintf(pgpout, PSTR("\nEnter user ID: ")); ! 1474: getstring( mcguffin, 255, TRUE ); /* echo keyboard */ ! 1475: } ! 1476: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1477: ! 1478: status = compromise ( mcguffin, keyfile ); ! 1479: ! 1480: if (status >= 0) { ! 1481: status = maintenance(keyfile, MAINT_SILENT); ! 1482: if (status == -7) /* ringfile is a keyfile or secret keyring */ ! 1483: { fprintf(pgpout, "Warning: '%s' is not a public keyring\n", keyfile); ! 1484: return; ! 1485: } ! 1486: if (status < 0) ! 1487: fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); ! 1488: } ! 1489: ! 1490: if (status < 0) ! 1491: { ! 1492: errorLvl = KEY_SIGNATURE_ERROR; ! 1493: user_error(); ! 1494: } ! 1495: return; ! 1496: } /* Key compromise */ ! 1497: ! 1498: /*-------------------------------------------------------*/ ! 1499: case 'e': ! 1500: { /* Key editing ! 1501: Arguments: userid, ringfile ! 1502: */ ! 1503: ! 1504: if (myArgc >= 4) ! 1505: strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 ); ! 1506: else /* default key ring filename */ ! 1507: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); ! 1508: ! 1509: if (myArgc >= 3) ! 1510: strcpy( mcguffin, myArgv[2] ); /* Userid to edit */ ! 1511: else ! 1512: { ! 1513: fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to edit. ")); ! 1514: fprintf(pgpout, PSTR("\nEnter the key's user ID: ")); ! 1515: getstring( mcguffin, 255, TRUE ); /* echo keyboard */ ! 1516: } ! 1517: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1518: ! 1519: status = dokeyedit( mcguffin, ringfile ); ! 1520: ! 1521: if (status >= 0) { ! 1522: status = maintenance(ringfile, MAINT_SILENT); ! 1523: if (status < 0 && status != -7) ! 1524: fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); ! 1525: } ! 1526: ! 1527: if (status < 0 && status != -7) ! 1528: { fprintf(pgpout, PSTR("\007Keyring edit error. ") ); ! 1529: errorLvl = KEYRING_EDIT_ERROR; ! 1530: user_error(); ! 1531: } ! 1532: return; ! 1533: } /* Key edit */ ! 1534: ! 1535: /*-------------------------------------------------------*/ ! 1536: case 'a': ! 1537: { /* Add key to key ring ! 1538: Arguments: keyfile, ringfile ! 1539: */ ! 1540: ! 1541: if (myArgc < 3) ! 1542: arg_error(); ! 1543: ! 1544: strncpy( keyfile, myArgv[2], sizeof(keyfile)-1 ); ! 1545: ! 1546: #ifdef MSDOS ! 1547: strlwr( keyfile ); ! 1548: #endif ! 1549: if (! file_exists( keyfile )) ! 1550: default_extension( keyfile, PGP_EXTENSION ); ! 1551: ! 1552: if (! file_exists( keyfile )) ! 1553: { fprintf(pgpout, PSTR("\n\007Key file '%s' does not exist.\n"), keyfile ); ! 1554: errorLvl = NONEXIST_KEY_ERROR; ! 1555: user_error(); ! 1556: } ! 1557: ! 1558: if (myArgc < 4) /* default key ring filename */ ! 1559: { byte ctb; ! 1560: get_header_info_from_file(keyfile, &ctb, 1); ! 1561: if (ctb == CTB_CERT_SECKEY) ! 1562: buildfilename(ringfile,SECRET_KEYRING_FILENAME); ! 1563: else ! 1564: buildfilename(ringfile,PUBLIC_KEYRING_FILENAME); ! 1565: } ! 1566: else ! 1567: { strncpy( ringfile, myArgv[3], sizeof(ringfile)-1 ); ! 1568: default_extension( ringfile, PGP_EXTENSION ); ! 1569: } ! 1570: #ifdef MSDOS ! 1571: strlwr( ringfile ); ! 1572: #endif ! 1573: ! 1574: status = addto_keyring( keyfile, ringfile, FALSE ); ! 1575: ! 1576: if (status < 0) ! 1577: { fprintf(pgpout, PSTR("\007Keyring add error. ") ); ! 1578: errorLvl = KEYRING_ADD_ERROR; ! 1579: user_error(); ! 1580: } ! 1581: return; ! 1582: } /* Add key to key ring */ ! 1583: ! 1584: /*-------------------------------------------------------*/ ! 1585: case 'x': ! 1586: { /* Extract key from key ring ! 1587: Arguments: mcguffin, keyfile, ringfile ! 1588: */ ! 1589: ! 1590: if (myArgc >= 5) /* default key ring filename */ ! 1591: strncpy( ringfile, myArgv[4], sizeof(ringfile)-1 ); ! 1592: else ! 1593: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); ! 1594: ! 1595: if (myArgc >= 3) ! 1596: strcpy( mcguffin, myArgv[2] ); /* Userid to extract */ ! 1597: else ! 1598: { ! 1599: fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to extract. ")); ! 1600: fprintf(pgpout, PSTR("\nEnter the key's user ID: ")); ! 1601: getstring( mcguffin, 255, TRUE ); /* echo keyboard */ ! 1602: } ! 1603: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1604: ! 1605: if (myArgc >= 4) ! 1606: { strncpy( keyfile, myArgv[3], sizeof(keyfile)-1 ); ! 1607: } ! 1608: else ! 1609: keyfile[0] = '\0'; ! 1610: ! 1611: #ifdef MSDOS ! 1612: strlwr( keyfile ); ! 1613: strlwr( ringfile ); ! 1614: #endif ! 1615: ! 1616: default_extension( ringfile, PGP_EXTENSION ); ! 1617: ! 1618: status = extract_from_keyring( mcguffin, keyfile, ! 1619: ringfile, emit_radix_64 ); ! 1620: ! 1621: if (status < 0) ! 1622: { fprintf(pgpout, PSTR("\007Keyring extract error. ") ); ! 1623: errorLvl = KEYRING_EXTRACT_ERROR; ! 1624: user_error(); ! 1625: } ! 1626: return; ! 1627: } /* Extract key from key ring */ ! 1628: ! 1629: /*-------------------------------------------------------*/ ! 1630: case 'r': ! 1631: { /* Remove keys or selected key signatures from userid keys ! 1632: Arguments: userid, ringfile ! 1633: */ ! 1634: ! 1635: if (myArgc >= 4) ! 1636: strcpy( ringfile, myArgv[3] ); ! 1637: else /* default key ring filename */ ! 1638: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); ! 1639: ! 1640: if (myArgc >= 3) ! 1641: strcpy( mcguffin, myArgv[2] ); /* Userid to work on */ ! 1642: else ! 1643: { if (sign_flag) ! 1644: { ! 1645: fprintf(pgpout, PSTR("\nA user ID is required to select the public key you want to\n\ ! 1646: remove certifying signatures from. ")); ! 1647: } ! 1648: else ! 1649: { ! 1650: fprintf(pgpout, PSTR("\nA user ID is required to select the key you want to remove. ")); ! 1651: } ! 1652: fprintf(pgpout, PSTR("\nEnter the key's user ID: ")); ! 1653: getstring( mcguffin, 255, TRUE ); /* echo keyboard */ ! 1654: } ! 1655: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1656: ! 1657: #ifdef MSDOS ! 1658: strlwr( ringfile ); ! 1659: #endif ! 1660: if (! file_exists( ringfile )) ! 1661: default_extension( ringfile, PGP_EXTENSION ); ! 1662: ! 1663: if (sign_flag) /* Remove signatures */ ! 1664: { if (remove_sigs( mcguffin, ringfile ) < 0) ! 1665: { fprintf(pgpout, PSTR("\007Key signature remove error. ") ); ! 1666: errorLvl = KEYSIG_REMOVE_ERROR; ! 1667: user_error(); ! 1668: } ! 1669: } ! 1670: else /* Remove keyring */ ! 1671: { if (remove_from_keyring( NULL, mcguffin, ringfile, (boolean) (myArgc < 4) ) < 0) ! 1672: { fprintf(pgpout, PSTR("\007Keyring remove error. ") ); ! 1673: errorLvl = KEYRING_REMOVE_ERROR; ! 1674: user_error(); ! 1675: } ! 1676: } ! 1677: if ((status = maintenance(ringfile, MAINT_SILENT)) < 0 && status != -7) ! 1678: { fprintf(pgpout, PSTR("\007Maintenance pass error. ") ); ! 1679: errorLvl = KEYRING_CHECK_ERROR; ! 1680: user_error(); ! 1681: } ! 1682: return; ! 1683: } /* remove key signatures from userid */ ! 1684: ! 1685: /*-------------------------------------------------------*/ ! 1686: case 'v': ! 1687: case 'V': /* -kvv */ ! 1688: { /* View or remove key ring entries, with userid match ! 1689: Arguments: userid, ringfile ! 1690: */ ! 1691: ! 1692: if (myArgc < 4) /* default key ring filename */ ! 1693: buildfilename( ringfile, PUBLIC_KEYRING_FILENAME ); ! 1694: else ! 1695: strcpy( ringfile, myArgv[3] ); ! 1696: ! 1697: if (myArgc > 2) ! 1698: { strcpy( mcguffin, myArgv[2] ); ! 1699: if (strcmp( mcguffin, "*" ) == 0) ! 1700: mcguffin[0] = '\0'; ! 1701: } ! 1702: else ! 1703: *mcguffin = '\0'; ! 1704: ! 1705: if ((myArgc == 3) && has_extension( myArgv[2], PGP_EXTENSION )) ! 1706: { strcpy( ringfile, myArgv[2] ); ! 1707: mcguffin[0] = '\0'; ! 1708: } ! 1709: CONVERT_TO_CANONICAL_CHARSET(mcguffin); ! 1710: ! 1711: #ifdef MSDOS ! 1712: strlwr( ringfile ); ! 1713: #endif ! 1714: if (! file_exists( ringfile )) ! 1715: default_extension( ringfile, PGP_EXTENSION ); ! 1716: ! 1717: /* If a second 'v' (keychar = V), show signatures too */ ! 1718: if (view_keyring(mcguffin, ringfile, (boolean) (keychar == 'V'), c_flag) < 0) ! 1719: { fprintf(pgpout, PSTR("\007Keyring view error. ") ); ! 1720: errorLvl = KEYRING_VIEW_ERROR; ! 1721: user_error(); ! 1722: } ! 1723: return; ! 1724: } /* view key ring entries, with userid match */ ! 1725: ! 1726: ! 1727: default: ! 1728: arg_error(); ! 1729: } ! 1730: ! 1731: } /* do_keyopt */ ! 1732: ! 1733: ! 1734: ! 1735: void user_error() /* comes here if user made a boo-boo. */ ! 1736: { ! 1737: fprintf(pgpout,PSTR("\nFor a usage summary, type: pgp -h\n")); ! 1738: fprintf(pgpout,PSTR("For more detailed help, consult the PGP User's Guide.\n")); ! 1739: exitPGP(errorLvl); /* error exit */ ! 1740: } ! 1741: ! 1742: /* ! 1743: * exitPGP: wipes and removes temporary files, also tries to wipe ! 1744: * the stack. ! 1745: */ ! 1746: void exitPGP(int returnval) ! 1747: { ! 1748: char buf[STACK_WIPE]; ! 1749: ! 1750: if (verbose) ! 1751: fprintf(pgpout, "exitPGP: exitcode = %d\n", returnval); ! 1752: memset(password, 0, sizeof(password)); ! 1753: cleanup_tmpf(); ! 1754: memset(buf, 0, sizeof(buf)); /* wipe stack */ ! 1755: #ifdef VMS ! 1756: /* ! 1757: * Fake VMS style error returns with severity in bottom 3 bits ! 1758: */ ! 1759: if (returnval) ! 1760: returnval = (returnval << 3) | 0x10000002; ! 1761: else ! 1762: returnval = 0x10000001; ! 1763: #endif /* VMS */ ! 1764: exit(returnval); ! 1765: } ! 1766: ! 1767: ! 1768: static void arg_error() ! 1769: { ! 1770: signon_msg(); ! 1771: fprintf(pgpout,PSTR("\nInvalid arguments.\n")); ! 1772: errorLvl = BAD_ARG_ERROR; ! 1773: user_error(); ! 1774: } ! 1775: ! 1776: static void build_helpfile(char *helpfile) ! 1777: { ! 1778: if (strcmp(language, "en")) ! 1779: { buildfilename(helpfile, language); ! 1780: force_extension(helpfile, HLP_EXTENSION); ! 1781: if (!file_exists(helpfile)) ! 1782: buildfilename(helpfile, HELP_FILENAME); ! 1783: } ! 1784: else ! 1785: buildfilename(helpfile, HELP_FILENAME); ! 1786: } ! 1787: ! 1788: static void usage() ! 1789: { ! 1790: char helpfile[MAX_PATH]; ! 1791: char *tmphelp = helpfile; ! 1792: extern unsigned char *ext_c_ptr; ! 1793: ! 1794: signon_msg(); ! 1795: build_helpfile(helpfile); ! 1796: ! 1797: if (ext_c_ptr) ! 1798: { /* conversion to external format necessary */ ! 1799: tmphelp = tempfile(TMP_TMPDIR); ! 1800: CONVERSION = EXT_CONV; ! 1801: if (copyfiles_by_name(helpfile, tmphelp) < 0) ! 1802: tmphelp = helpfile; ! 1803: CONVERSION = NO_CONV; ! 1804: } ! 1805: ! 1806: /* built-in help if pgp.hlp is not available */ ! 1807: if (more_file(tmphelp) < 0) ! 1808: fprintf(pgpout,PSTR("\nUsage summary:\ ! 1809: \nTo encrypt a plaintext file with recipent's public key, type:\ ! 1810: \n pgp -e textfile her_userid (produces textfile.pgp)\ ! 1811: \nTo sign a plaintext file with your secret key:\ ! 1812: \n pgp -s textfile [-u your_userid] (produces textfile.pgp)\ ! 1813: \nTo sign a plaintext file with your secret key, and then encrypt it\ ! 1814: \n with recipent's public key, producing a .pgp file:\ ! 1815: \n pgp -es textfile her_userid [-u your_userid]\ ! 1816: \nTo encrypt with conventional encryption only:\ ! 1817: \n pgp -c textfile\ ! 1818: \nTo decrypt or check a signature for a ciphertext (.pgp) file:\ ! 1819: \n pgp ciphertextfile [plaintextfile]\ ! 1820: \nTo produce output in ASCII for email, add the -a option to other options.\ ! 1821: \nTo generate your own unique public/secret key pair: pgp -kg\ ! 1822: \nFor help on other key management functions, type: pgp -k\n")); ! 1823: if (ext_c_ptr) ! 1824: rmtemp(tmphelp); ! 1825: exit(BAD_ARG_ERROR); /* error exit */ ! 1826: } ! 1827: ! 1828: ! 1829: static void key_usage() ! 1830: { ! 1831: char helpfile[MAX_PATH]; ! 1832: ! 1833: signon_msg(); ! 1834: build_helpfile(helpfile); ! 1835: if (file_exists(helpfile)) ! 1836: { fprintf(pgpout,PSTR("\nFor a usage summary, type: pgp -h\n")); ! 1837: fprintf(pgpout,PSTR("For more detailed help, consult the PGP User's Guide.\n")); ! 1838: } ! 1839: else ! 1840: fprintf(pgpout,PSTR("\nKey management functions:\ ! 1841: \nTo generate your own unique public/secret key pair:\ ! 1842: \n pgp -kg\ ! 1843: \nTo add a key file's contents to your public or secret key ring:\ ! 1844: \n pgp -ka keyfile [keyring]\ ! 1845: \nTo remove a key or a user ID from your public or secret key ring:\ ! 1846: \n pgp -kr userid [keyring]\ ! 1847: \nTo edit your user ID or pass phrase:\ ! 1848: \n pgp -ke your_userid [keyring]\ ! 1849: \nTo extract (copy) a key from your public or secret key ring:\ ! 1850: \n pgp -kx userid keyfile [keyring]\ ! 1851: \nTo view the contents of your public key ring:\ ! 1852: \n pgp -kv[v] [userid] [keyring]\ ! 1853: \nTo check signatures on your public key ring:\ ! 1854: \n pgp -kc [userid] [keyring]\ ! 1855: \nTo sign someone else's public key on your public key ring:\ ! 1856: \n pgp -ks her_userid [-u your_userid] [keyring]\ ! 1857: \nTo remove selected signatures from a userid on a keyring:\ ! 1858: \n pgp -krs userid [keyring]\ ! 1859: \n")); ! 1860: exit(BAD_ARG_ERROR); /* error exit */ ! 1861: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.