home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / varia / pgp / pgpamiga / source / pgp.c < prev    next >
C/C++ Source or Header  |  1993-12-23  |  88KB  |  2,106 lines

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