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