Use bette error msg too
[apps/madmutt.git] / lib-crypt / pgp.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
4  * Copyright (C) 1998,1999 Thomas Roessler <roessler@does-not-exist.org>
5  * Copyright (C) 2004 g10 Code GmbH
6  *
7  * This file is part of mutt-ng, see http://www.muttng.org/.
8  * It's licensed under the GNU General Public License,
9  * please see the file GPL in the top level source directory.
10  */
11
12 /*
13  * This file contains all of the PGP routines necessary to sign, encrypt,
14  * verify and decrypt PGP messages in either the new PGP/MIME format, or
15  * in the older Application/Pgp format.  It also contains some code to
16  * cache the user's passphrase for repeat use when decrypting or signing
17  * a message.
18  */
19
20 #include <lib-lib/lib-lib.h>
21
22 #ifdef HAVE_SYS_RESOURCE_H
23 # include <sys/resource.h>
24 #endif
25
26 #include <lib-mime/mime.h>
27 #include <lib-sys/unix.h>
28
29 #include <lib-ui/curses.h>
30 #include <lib-ui/enter.h>
31 #include <lib-ui/menu.h>
32 #include <lib-mx/mx.h>
33
34 #include "handler.h"
35 #include "pgp.h"
36 #include "copy.h"
37 #include "attach.h"
38
39 #include "crypt.h"
40
41
42 char PgpPass[LONG_STRING];
43 time_t PgpExptime = 0;          /* when does the cached passphrase expire? */
44
45 void pgp_void_passphrase (void)
46 {
47   p_clear(PgpPass, countof(PgpPass));
48   PgpExptime = 0;
49 }
50
51 int pgp_valid_passphrase (void)
52 {
53   time_t now = time (NULL);
54
55   if (pgp_use_gpg_agent ()) {
56     *PgpPass = 0;
57     return 1;                   /* handled by gpg-agent */
58   }
59
60   if (now < PgpExptime)
61     /* Use cached copy.  */
62     return 1;
63
64   pgp_void_passphrase ();
65
66   if (mutt_get_field_unbuffered (_("Enter PGP passphrase:"), PgpPass,
67                                  sizeof (PgpPass), M_PASS) == 0) {
68     PgpExptime = time (NULL) + PgpTimeout;
69     return (1);
70   }
71   else
72     PgpExptime = 0;
73
74   return 0;
75 }
76
77 void pgp_forget_passphrase (void)
78 {
79   pgp_void_passphrase ();
80   mutt_message _("PGP passphrase forgotten.");
81 }
82
83 int pgp_use_gpg_agent (void) {
84   char *tty;
85
86   if (!option (OPTUSEGPGAGENT) || !getenv ("GPG_AGENT_INFO"))
87     return 0;
88
89   if ((tty = ttyname(0)))
90     setenv ("GPG_TTY", tty, 0);
91
92   return 1;
93 }
94
95 char *pgp_keyid (pgp_key_t k)
96 {
97   if ((k->flags & KEYFLAG_SUBKEY) && k->parent && option (OPTPGPIGNORESUB))
98     k = k->parent;
99
100   return _pgp_keyid (k);
101 }
102
103 char *_pgp_keyid (pgp_key_t k)
104 {
105   if (option (OPTPGPLONGIDS))
106     return k->keyid;
107   else
108     return (k->keyid + 8);
109 }
110
111 /* ----------------------------------------------------------------------------
112  * Routines for handing PGP input.
113  */
114
115
116
117 /* Copy PGP output messages and look for signs of a good signature */
118
119 static int pgp_copy_checksig (FILE * fpin, FILE * fpout)
120 {
121   int rv = -1;
122
123   if (PgpGoodSign.pattern) {
124     char *line = NULL;
125     int lineno = 0;
126     ssize_t linelen;
127
128     while ((line = mutt_read_line (line, &linelen, fpin, &lineno)) != NULL) {
129       if (regexec (PgpGoodSign.rx, line, 0, NULL, 0) == 0) {
130         rv = 0;
131       }
132
133       if (strncmp (line, "[GNUPG:] ", 9) == 0)
134         continue;
135       fputs (line, fpout);
136       fputc ('\n', fpout);
137     }
138     p_delete(&line);
139   }
140   else {
141     mutt_copy_stream (fpin, fpout);
142     rv = 1;
143   }
144
145   return rv;
146 }
147
148 /* 
149  * Copy a clearsigned message, and strip the signature and PGP's
150  * dash-escaping.
151  * 
152  * XXX - charset handling: We assume that it is safe to do
153  * character set decoding first, dash decoding second here, while
154  * we do it the other way around in the main handler.
155  * 
156  * (Note that we aren't worse than Outlook &c in this, and also
157  * note that we can successfully handle anything produced by any
158  * existing versions of mutt.) 
159  */
160
161 static void pgp_copy_clearsigned (FILE * fpin, STATE * s, char *charset)
162 {
163   char buf[HUGE_STRING];
164   short complete, armor_header;
165
166   fgetconv_t *fc;
167
168   rewind (fpin);
169
170   fc = fgetconv_open (fpin, charset, Charset, M_ICONV_HOOK_FROM);
171
172   for (complete = 1, armor_header = 1;
173        fgetconvs (buf, sizeof (buf), fc) != NULL;
174        complete = strchr (buf, '\n') != NULL) {
175     if (!complete) {
176       if (!armor_header)
177         state_puts (buf, s);
178       continue;
179     }
180
181     if (m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n") == 0)
182       break;
183
184     if (armor_header) {
185       char *p = vskipspaces(buf);
186
187       if (*p == '\0')
188         armor_header = 0;
189       continue;
190     }
191
192     if (s->prefix)
193       state_puts (s->prefix, s);
194
195     if (buf[0] == '-' && buf[1] == ' ')
196       state_puts (buf + 2, s);
197     else
198       state_puts (buf, s);
199   }
200
201   fgetconv_close (&fc);
202 }
203
204
205 /* Support for the Application/PGP Content Type. */
206
207 int pgp_application_pgp_handler (BODY * m, STATE * s)
208 {
209   int could_not_decrypt = 0;
210   int needpass = -1, pgp_keyblock = 0;
211   int c = 1;
212   int clearsign = 0, rv, rc;
213   long start_pos = 0;
214   long bytes;
215   off_t last_pos, offset;
216   char buf[HUGE_STRING];
217   char outfile[_POSIX_PATH_MAX];
218   char tmpfname[_POSIX_PATH_MAX];
219   FILE *pgpout = NULL, *pgpin = NULL, *pgperr = NULL;
220   FILE *tmpfp = NULL;
221   pid_t thepid;
222
223   short maybe_goodsig = 1;
224   short have_any_sigs = 0;
225
226   char body_charset[STRING];
227
228   mutt_get_body_charset (body_charset, sizeof (body_charset), m);
229
230   rc = 0;                       /* silence false compiler warning if (s->flags & M_DISPLAY) */
231
232   fseeko (s->fpin, m->offset, 0);
233   last_pos = m->offset;
234
235   for (bytes = m->length; bytes > 0;) {
236     if (fgets (buf, sizeof (buf), s->fpin) == NULL)
237       break;
238
239     offset = ftello (s->fpin);
240     bytes -= (offset - last_pos);       /* don't rely on m_strlen(buf) */
241     last_pos = offset;
242
243     if (m_strncmp("-----BEGIN PGP ", buf, 15) == 0) {
244       clearsign = 0;
245       start_pos = last_pos;
246
247       if (m_strcmp("MESSAGE-----\n", buf + 15) == 0)
248         needpass = 1;
249       else if (m_strcmp("SIGNED MESSAGE-----\n", buf + 15) == 0) {
250         clearsign = 1;
251         needpass = 0;
252       }
253       else if (!option (OPTDONTHANDLEPGPKEYS) &&
254                m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15) == 0) {
255         needpass = 0;
256         pgp_keyblock = 1;
257       }
258       else {
259         /* XXX - we may wish to recode here */
260         if (s->prefix)
261           state_puts (s->prefix, s);
262         state_puts (buf, s);
263         continue;
264       }
265
266       have_any_sigs = have_any_sigs || (clearsign && (s->flags & M_VERIFY));
267
268       /* Copy PGP material to temporary file */
269       tmpfp = m_tempfile(tmpfname, sizeof(tmpfname), NONULL(Tempdir), NULL);
270       if (tmpfp == NULL) {
271         mutt_perror (tmpfname);
272         return (-1);
273       }
274
275       fputs (buf, tmpfp);
276       while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
277         offset = ftello (s->fpin);
278         bytes -= (offset - last_pos);   /* don't rely on m_strlen(buf) */
279         last_pos = offset;
280
281         fputs (buf, tmpfp);
282
283         if ((needpass
284              && m_strcmp("-----END PGP MESSAGE-----\n", buf) == 0)
285             || (!needpass
286                 && (m_strcmp("-----END PGP SIGNATURE-----\n", buf) == 0
287                     || m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
288                                     buf) == 0)))
289           break;
290       }
291
292       /* leave tmpfp open in case we still need it - but flush it! */
293       fflush (tmpfp);
294
295
296       /* Invoke PGP if needed */
297       if (!clearsign || (s->flags & M_VERIFY)) {
298         pgpout = m_tempfile(outfile, sizeof(outfile), NONULL(Tempdir), NULL);
299         if (pgpout == NULL) {
300           mutt_perror (outfile);
301           return (-1);
302         }
303
304         if ((thepid = pgp_invoke_decode (&pgpin, NULL, &pgperr, -1,
305                                          fileno (pgpout), -1, tmpfname,
306                                          needpass)) == -1) {
307           m_fclose(&pgpout);
308           maybe_goodsig = 0;
309           pgpin = NULL;
310           pgperr = NULL;
311           state_attach_puts (_
312                              ("[-- Error: unable to create PGP subprocess! --]\n"),
313                              s);
314         }
315         else {                  /* PGP started successfully */
316
317           if (needpass) {
318             if (!pgp_valid_passphrase ())
319               pgp_void_passphrase ();
320             if (pgp_use_gpg_agent ())
321               *PgpPass = 0;
322             fprintf (pgpin, "%s\n", PgpPass);
323           }
324
325           m_fclose(&pgpin);
326
327           if (s->flags & M_DISPLAY) {
328             crypt_current_time (s, "PGP");
329             rc = pgp_copy_checksig (pgperr, s->fpout);
330           }
331
332           m_fclose(&pgperr);
333           rv = mutt_wait_filter (thepid);
334
335           if (s->flags & M_DISPLAY) {
336             if (rc == 0)
337               have_any_sigs = 1;
338
339             /*
340              * Sig is bad if
341              * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
342              * Sig _is_ correct if
343              * gpg_good_sign="" && pgp_decode_command returned 0
344              */
345             if (rc == -1 || rv)
346               maybe_goodsig = 0;
347
348             state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
349           }
350         }
351
352         /* treat empty result as sign of failure */
353         /* TODO: maybe on failure mutt should include the original undecoded text. */
354         if (pgpout) {
355           rewind (pgpout);
356           c = fgetc (pgpout);
357           ungetc (c, pgpout);
358         }
359         if (!clearsign && (!pgpout || c == EOF)) {
360           could_not_decrypt = 1;
361           pgp_void_passphrase ();
362         }
363
364         if (could_not_decrypt && !(s->flags & M_DISPLAY)) {
365           mutt_error _("Could not decrypt PGP message");
366           mutt_sleep (1);
367           rc = -1;
368           goto out;
369         }
370       }
371
372       /*
373        * Now, copy cleartext to the screen.  NOTE - we expect that PGP
374        * outputs utf-8 cleartext.  This may not always be true, but it 
375        * seems to be a reasonable guess.
376        */
377
378       if (s->flags & M_DISPLAY) {
379         if (needpass)
380           state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
381         else if (pgp_keyblock)
382           state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
383         else
384           state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
385       }
386
387       if (clearsign) {
388         rewind (tmpfp);
389         if (tmpfp)
390           pgp_copy_clearsigned (tmpfp, s, body_charset);
391       }
392       else if (pgpout) {
393         fgetconv_t *fc;
394
395         rewind (pgpout);
396         state_set_prefix (s);
397         fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
398         while ((c = fgetconv (fc)) != EOF)
399           state_prefix_putc (c, s);
400         fgetconv_close (&fc);
401       }
402
403       if (s->flags & M_DISPLAY) {
404         state_putc ('\n', s);
405         if (needpass) {
406           state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
407           if (could_not_decrypt)
408             mutt_error _("Could not decrypt PGP message.");
409           else
410             mutt_message _("PGP message successfully decrypted.");
411         }
412         else if (pgp_keyblock)
413           state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
414         else
415           state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
416       }
417
418     }
419     else {
420       /* XXX - we may wish to recode here */
421       if (s->prefix)
422         state_puts (s->prefix, s);
423       state_puts (buf, s);
424     }
425   }
426
427   rc = 0;
428
429 out:
430   m->goodsig = (maybe_goodsig && have_any_sigs);
431
432   if (tmpfp) {
433     m_fclose(&tmpfp);
434     mutt_unlink (tmpfname);
435   }
436   if (pgpout) {
437     m_fclose(&pgpout);
438     mutt_unlink (outfile);
439   }
440
441   if (needpass == -1) {
442     state_attach_puts (_
443                        ("[-- Error: could not find beginning of PGP message! --]\n\n"),
444                        s);
445     return (-1);
446   }
447
448   return (rc);
449 }
450
451 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
452                                            int tagged_only)
453 {
454   char tempfile[_POSIX_PATH_MAX];
455   char buf[HUGE_STRING];
456   FILE *tfp;
457
458   short sgn = 0;
459   short enc = 0;
460   short key = 0;
461
462   if (b->type != TYPETEXT)
463     return 0;
464
465   if (tagged_only && !b->tagged)
466     return 0;
467
468   mutt_mktemp (tempfile);
469   if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
470     unlink (tempfile);
471     return 0;
472   }
473
474   if ((tfp = fopen (tempfile, "r")) == NULL) {
475     unlink (tempfile);
476     return 0;
477   }
478
479   while (fgets (buf, sizeof (buf), tfp)) {
480     if (m_strncmp("-----BEGIN PGP ", buf, 15) == 0) {
481       if (m_strcmp("MESSAGE-----\n", buf + 15) == 0)
482         enc = 1;
483       else if (m_strcmp("SIGNED MESSAGE-----\n", buf + 15) == 0)
484         sgn = 1;
485       else if (m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15) == 0)
486         key = 1;
487     }
488   }
489   m_fclose(&tfp);
490   unlink (tempfile);
491
492   if (!enc && !sgn && !key)
493     return 0;
494
495   /* fix the content type */
496
497   parameter_setval(&b->parameter, "format", "fixed");
498   if (enc)
499     parameter_setval(&b->parameter, "x-action", "pgp-encrypted");
500   else if (sgn)
501     parameter_setval(&b->parameter, "x-action", "pgp-signed");
502   else if (key)
503     parameter_setval(&b->parameter, "x-action", "pgp-keys");
504
505   return 1;
506 }
507
508 int pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
509 {
510   int rv = 0;
511   int r;
512
513   for (; b; b = b->next) {
514     if (is_multipart (b))
515       rv = pgp_check_traditional (fp, b->parts, tagged_only) || rv;
516     else if (b->type == TYPETEXT) {
517       if ((r = mutt_is_application_pgp (b)))
518         rv = rv || r;
519       else
520         rv = pgp_check_traditional_one_body (fp, b, tagged_only) || rv;
521     }
522   }
523
524   return rv;
525 }
526
527
528
529
530
531 int pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
532 {
533   char sigfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
534   FILE *fp, *pgpout, *pgperr;
535   pid_t thepid;
536   int badsig = -1;
537   int rv;
538
539   snprintf (sigfile, sizeof (sigfile), "%s.asc", tempfile);
540
541   if (!(fp = safe_fopen (sigfile, "w"))) {
542     mutt_perror (sigfile);
543     return -1;
544   }
545
546   fseeko (s->fpin, sigbdy->offset, 0);
547   mutt_copy_bytes (s->fpin, fp, sigbdy->length);
548   m_fclose(&fp);
549
550   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
551   if (pgperr == NULL) {
552     mutt_perror (pgperrfile);
553     unlink (sigfile);
554     return -1;
555   }
556
557   crypt_current_time (s, "PGP");
558
559   if ((thepid = pgp_invoke_verify (NULL, &pgpout, NULL,
560                                    -1, -1, fileno (pgperr),
561                                    tempfile, sigfile)) != -1) {
562     if (pgp_copy_checksig (pgpout, s->fpout) >= 0)
563       badsig = 0;
564
565
566     m_fclose(&pgpout);
567     fflush (pgperr);
568     rewind (pgperr);
569
570     if (pgp_copy_checksig (pgperr, s->fpout) >= 0)
571       badsig = 0;
572
573     if ((rv = mutt_wait_filter (thepid)))
574       badsig = -1;
575   }
576
577   m_fclose(&pgperr);
578
579   state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
580
581   mutt_unlink (sigfile);
582   mutt_unlink (pgperrfile);
583
584   return badsig;
585 }
586
587
588 /* Extract pgp public keys from messages or attachments */
589
590 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
591 {
592   STATE s;
593   FILE *tempfp;
594   char tempfname[_POSIX_PATH_MAX];
595
596   tempfp = m_tempfile(tempfname, sizeof(tempfname), NONULL(Tempdir), NULL);
597   if (tempfp == NULL) {
598     mutt_perror (_("Can't create temporary file"));
599     return;
600   }
601
602   p_clear(&s, 1);
603
604   s.fpin = fp;
605   s.fpout = tempfp;
606
607   mutt_body_handler (top, &s);
608
609   m_fclose(&tempfp);
610
611   pgp_invoke_import (tempfname);
612   mutt_any_key_to_continue (NULL);
613
614   mutt_unlink (tempfname);
615 }
616
617 void pgp_extract_keys_from_attachment_list (FILE * fp, int tag, BODY * top)
618 {
619   if (!fp) {
620     mutt_error _("Internal error. Inform <roessler@does-not-exist.org>.");
621
622     return;
623   }
624
625   mutt_endwin (NULL);
626   set_option (OPTDONTHANDLEPGPKEYS);
627
628   for (; top; top = top->next) {
629     if (!tag || top->tagged)
630       pgp_extract_keys_from_attachment (fp, top);
631
632     if (!tag)
633       break;
634   }
635
636   unset_option (OPTDONTHANDLEPGPKEYS);
637 }
638
639 BODY *pgp_decrypt_part (BODY * a, STATE * s, FILE * fpout, BODY * p)
640 {
641   char buf[LONG_STRING];
642   FILE *pgpin, *pgpout, *pgperr, *pgptmp;
643   struct stat info;
644   BODY *tattach;
645   int len;
646   char pgperrfile[_POSIX_PATH_MAX];
647   char pgptmpfile[_POSIX_PATH_MAX];
648   pid_t thepid;
649   int rv;
650
651   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
652   if (!pgperr) {
653     mutt_perror (pgperrfile);
654     return NULL;
655   }
656   unlink (pgperrfile);
657
658   pgptmp = m_tempfile(pgptmpfile, sizeof(pgptmpfile), NONULL(Tempdir), NULL);
659   if (!pgptmp) {
660     mutt_perror (pgptmpfile);
661     m_fclose(&pgperr);
662     return NULL;
663   }
664
665   /* Position the stream at the beginning of the body, and send the data to
666    * the temporary file.
667    */
668
669   fseeko (s->fpin, a->offset, 0);
670   mutt_copy_bytes (s->fpin, pgptmp, a->length);
671   m_fclose(&pgptmp);
672
673   if ((thepid = pgp_invoke_decrypt (&pgpin, &pgpout, NULL, -1, -1,
674                                     fileno (pgperr), pgptmpfile)) == -1) {
675     m_fclose(&pgperr);
676     unlink (pgptmpfile);
677     if (s->flags & M_DISPLAY)
678       state_attach_puts (_
679                          ("[-- Error: could not create a PGP subprocess! --]\n\n"),
680                          s);
681     return (NULL);
682   }
683
684   /* send the PGP passphrase to the subprocess.  Never do this if the
685      agent is active, because this might lead to a passphrase send as
686      the message. */
687   if (!pgp_use_gpg_agent ())
688     fputs (PgpPass, pgpin);
689   fputc ('\n', pgpin);
690   m_fclose(&pgpin);
691
692   /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
693    * read_mime_header has a hard time parsing the message.
694    */
695   while (fgets (buf, sizeof (buf) - 1, pgpout) != NULL) {
696     len = m_strlen(buf);
697     if (len > 1 && buf[len - 2] == '\r')
698       strcpy (buf + len - 2, "\n");     /* __STRCPY_CHECKED__ */
699     fputs (buf, fpout);
700   }
701
702   m_fclose(&pgpout);
703   rv = mutt_wait_filter (thepid);
704   mutt_unlink (pgptmpfile);
705
706   if (s->flags & M_DISPLAY) {
707     fflush (pgperr);
708     rewind (pgperr);
709     if (pgp_copy_checksig (pgperr, s->fpout) == 0 && !rv && p)
710       p->goodsig = 1;
711     else
712       p->goodsig = 0;
713     state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
714   }
715   m_fclose(&pgperr);
716
717   fflush (fpout);
718   rewind (fpout);
719
720   if (fgetc (fpout) == EOF) {
721     mutt_error (_("Decryption failed."));
722     pgp_void_passphrase ();
723     return NULL;
724   }
725
726   rewind (fpout);
727
728   if ((tattach = mutt_read_mime_header (fpout, 0)) != NULL) {
729     /*
730      * Need to set the length of this body part.
731      */
732     fstat (fileno (fpout), &info);
733     tattach->length = info.st_size - tattach->offset;
734
735     /* See if we need to recurse on this MIME part.  */
736
737     mutt_parse_part (fpout, tattach);
738   }
739
740   return (tattach);
741 }
742
743 int pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
744 {
745   char tempfile[_POSIX_PATH_MAX];
746   STATE s;
747   BODY *p = b;
748
749   if (!mutt_is_multipart_encrypted (b))
750     return -1;
751
752   if (!b->parts || !b->parts->next)
753     return -1;
754
755   b = b->parts->next;
756
757   p_clear(&s, 1);
758   s.fpin = fpin;
759   *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
760   if (*fpout == NULL) {
761     mutt_perror (_("Can't create temporary file"));
762     return (-1);
763   }
764   unlink (tempfile);
765
766   *cur = pgp_decrypt_part (b, &s, *fpout, p);
767
768   rewind (*fpout);
769
770   if (!*cur)
771     return -1;
772
773   return (0);
774 }
775
776 int pgp_encrypted_handler (BODY * a, STATE * s)
777 {
778   char tempfile[_POSIX_PATH_MAX];
779   FILE *fpout, *fpin;
780   BODY *tattach;
781   BODY *p = a;
782   int rc = 0;
783
784   a = a->parts;
785   if (!a || a->type != TYPEAPPLICATION || !a->subtype ||
786       ascii_strcasecmp ("pgp-encrypted", a->subtype) != 0 ||
787       !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype ||
788       ascii_strcasecmp ("octet-stream", a->next->subtype) != 0) {
789     if (s->flags & M_DISPLAY)
790       state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
791                          s);
792     return (-1);
793   }
794
795   /*
796    * Move forward to the application/pgp-encrypted body.
797    */
798   a = a->next;
799
800   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
801   if (fpout == NULL) {
802     if (s->flags & M_DISPLAY)
803       state_attach_puts (_
804                          ("[-- Error: could not create temporary file! --]\n"),
805                          s);
806     return (-1);
807   }
808
809   if (s->flags & M_DISPLAY)
810     crypt_current_time (s, "PGP");
811
812   if ((tattach = pgp_decrypt_part (a, s, fpout, p)) != NULL) {
813     if (s->flags & M_DISPLAY)
814       state_attach_puts (_
815                          ("[-- The following data is PGP/MIME encrypted --]\n\n"),
816                          s);
817
818     fpin = s->fpin;
819     s->fpin = fpout;
820     rc = mutt_body_handler (tattach, s);
821     s->fpin = fpin;
822
823     /* 
824      * if a multipart/signed is the _only_ sub-part of a
825      * multipart/encrypted, cache signature verification
826      * status.
827      *
828      */
829
830     if (mutt_is_multipart_signed (tattach) && !tattach->next)
831       p->goodsig |= tattach->goodsig;
832
833     if (s->flags & M_DISPLAY) {
834       state_puts ("\n", s);
835       state_attach_puts (_("[-- End of PGP/MIME encrypted data --]\n"), s);
836     }
837
838     body_list_wipe(&tattach);
839     /* clear 'Invoking...' message, since there's no error */
840     mutt_message _("PGP message successfully decrypted.");
841   } else {
842     mutt_error _("Could not decrypt PGP message");
843     pgp_void_passphrase ();
844     rc = -1;
845   }
846
847   m_fclose(&fpout);
848   mutt_unlink (tempfile);
849
850   return (rc);
851 }
852
853 /* ----------------------------------------------------------------------------
854  * Routines for sending PGP/MIME messages.
855  */
856
857
858 BODY *pgp_sign_message (BODY * a)
859 {
860   BODY *t;
861   char buffer[LONG_STRING];
862   char sigfile[_POSIX_PATH_MAX], signedfile[_POSIX_PATH_MAX];
863   FILE *pgpin, *pgpout, *pgperr, *fp, *sfp;
864   int err = 0;
865   int empty = 1;
866   pid_t thepid;
867
868   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
869
870   fp = m_tempfile(sigfile, sizeof(sigfile), NONULL(Tempdir), NULL);
871   if (fp == NULL) {
872     return (NULL);
873   }
874
875   sfp = m_tempfile(signedfile, sizeof(signedfile), NONULL(Tempdir), NULL);
876   if (sfp == NULL) {
877     mutt_perror (signedfile);
878     m_fclose(&fp);
879     unlink (sigfile);
880     return NULL;
881   }
882
883   mutt_write_mime_header (a, sfp);
884   fputc ('\n', sfp);
885   mutt_write_mime_body (a, sfp);
886   m_fclose(&sfp);
887
888   if ((thepid = pgp_invoke_sign (&pgpin, &pgpout, &pgperr,
889                                  -1, -1, -1, signedfile)) == -1) {
890     mutt_perror (_("Can't open PGP subprocess!"));
891
892     m_fclose(&fp);
893     unlink (sigfile);
894     unlink (signedfile);
895     return NULL;
896   }
897
898   if (!pgp_use_gpg_agent ())
899     fputs (PgpPass, pgpin);
900   fputc ('\n', pgpin);
901   m_fclose(&pgpin);
902
903   /*
904    * Read back the PGP signature.  Also, change MESSAGE=>SIGNATURE as
905    * recommended for future releases of PGP.
906    */
907   while (fgets (buffer, sizeof (buffer) - 1, pgpout) != NULL) {
908     if (m_strcmp("-----BEGIN PGP MESSAGE-----\n", buffer) == 0)
909       fputs ("-----BEGIN PGP SIGNATURE-----\n", fp);
910     else if (m_strcmp("-----END PGP MESSAGE-----\n", buffer) == 0)
911       fputs ("-----END PGP SIGNATURE-----\n", fp);
912     else
913       fputs (buffer, fp);
914     empty = 0;                  /* got some output, so we're ok */
915   }
916
917   /* check for errors from PGP */
918   err = 0;
919   while (fgets (buffer, sizeof (buffer) - 1, pgperr) != NULL) {
920     err = 1;
921     fputs (buffer, stdout);
922   }
923
924   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
925     empty = 1;
926
927   m_fclose(&pgperr);
928   m_fclose(&pgpout);
929   unlink (signedfile);
930
931   if (m_fclose(&fp) != 0) {
932     mutt_perror ("fclose");
933     unlink (sigfile);
934     return (NULL);
935   }
936
937   if (err) {
938     pgp_void_passphrase ();
939     mutt_any_key_to_continue (NULL);
940   }
941
942   if (empty) {
943     unlink (sigfile);
944     return (NULL);              /* fatal error while signing */
945   }
946
947   t = body_new();
948   t->type = TYPEMULTIPART;
949   t->subtype = m_strdup("signed");
950   t->encoding = ENC7BIT;
951   t->use_disp = 0;
952   t->disposition = DISPINLINE;
953
954   parameter_set_boundary(&t->parameter);
955   parameter_setval(&t->parameter, "protocol", "application/pgp-signature");
956   parameter_setval(&t->parameter, "micalg", pgp_micalg (sigfile));
957
958   t->parts = a;
959   a = t;
960
961   t->parts->next = body_new();
962   t = t->parts->next;
963   t->type = TYPEAPPLICATION;
964   t->subtype = m_strdup("pgp-signature");
965   t->filename = m_strdup(sigfile);
966   t->use_disp = 0;
967   t->disposition = DISPINLINE;
968   t->encoding = ENC7BIT;
969   t->unlink = 1;                /* ok to remove this file after sending. */
970
971   return (a);
972 }
973
974 static short is_numerical_keyid (const char *s)
975 {
976   /* or should we require the "0x"? */
977   if (strncmp (s, "0x", 2) == 0)
978     s += 2;
979   if (m_strlen(s) % 8)
980     return 0;
981   while (*s)
982     if (strchr ("0123456789ABCDEFabcdef", *s++) == NULL)
983       return 0;
984
985   return 1;
986 }
987
988 /* This routine attempts to find the keyids of the recipients of a message.
989  * It returns NULL if any of the keys can not be found.
990  */
991 char *pgp_findKeys (address_t * to, address_t * cc, address_t * bcc)
992 {
993   char *keylist = NULL, *t;
994   const char *keyID;
995   size_t keylist_size = 0;
996   size_t keylist_used = 0;
997   address_t *tmp = NULL, *addr = NULL;
998   address_t **last = &tmp;
999   address_t *p, *q;
1000   int i;
1001   pgp_key_t k_info = NULL, key = NULL;
1002
1003   const char *fqdn = mutt_fqdn (1);
1004
1005   for (i = 0; i < 3; i++) {
1006     switch (i) {
1007     case 0:
1008       p = to;
1009       break;
1010     case 1:
1011       p = cc;
1012       break;
1013     case 2:
1014       p = bcc;
1015       break;
1016     default:
1017       abort ();
1018     }
1019
1020     *last = address_list_dup (p);
1021     while (*last)
1022       last = &((*last)->next);
1023   }
1024
1025   if (fqdn)
1026     rfc822_qualify (tmp, fqdn);
1027
1028   address_list_uniq(tmp);
1029
1030   for (p = tmp; p; p = p->next) {
1031     char buf[LONG_STRING];
1032
1033     q = p;
1034     k_info = NULL;
1035
1036     if ((keyID = mutt_crypt_hook (p)) != NULL) {
1037       int r;
1038
1039       snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID,
1040                 p->mailbox);
1041       if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
1042         if (is_numerical_keyid (keyID)) {
1043           if (strncmp (keyID, "0x", 2) == 0)
1044             keyID += 2;
1045           goto bypass_selection;        /* you don't see this. */
1046         }
1047
1048         /* check for e-mail address */
1049         if ((t = strchr (keyID, '@')) &&
1050             (addr = rfc822_parse_adrlist (NULL, keyID))) {
1051           if (fqdn)
1052             rfc822_qualify (addr, fqdn);
1053           q = addr;
1054         }
1055         else
1056           k_info = pgp_getkeybystr (keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
1057       }
1058       else if (r == -1) {
1059         p_delete(&keylist);
1060         address_list_wipe(&tmp);
1061         address_list_wipe(&addr);
1062         return NULL;
1063       }
1064     }
1065
1066     if (k_info == NULL)
1067       pgp_invoke_getkeys (q);
1068
1069     if (k_info == NULL
1070         && (k_info =
1071             pgp_getkeybyaddr (q, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1072       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
1073
1074       if ((key = pgp_ask_for_key (buf, q->mailbox,
1075                                   KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1076         p_delete(&keylist);
1077         address_list_wipe(&tmp);
1078         address_list_wipe(&addr);
1079         return NULL;
1080       }
1081     }
1082     else
1083       key = k_info;
1084
1085     keyID = pgp_keyid (key);
1086
1087   bypass_selection:
1088     keylist_size += m_strlen(keyID) + 4;
1089     p_realloc(&keylist, keylist_size);
1090     sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", /* __SPRINTF_CHECKED__ */
1091              keyID);
1092     keylist_used = m_strlen(keylist);
1093
1094     pgp_free_key (&key);
1095     address_list_wipe(&addr);
1096
1097   }
1098   address_list_wipe(&tmp);
1099   return (keylist);
1100 }
1101
1102 /* Warning: "a" is no longer freed in this routine, you need
1103  * to free it later.  This is necessary for $fcc_attach. */
1104
1105 BODY *pgp_encrypt_message (BODY * a, char *keylist, int sign)
1106 {
1107   char buf[LONG_STRING];
1108   char tempfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
1109   char pgpinfile[_POSIX_PATH_MAX];
1110   FILE *pgpin, *pgperr, *fpout, *fptmp;
1111   BODY *t;
1112   int err = 0;
1113   int empty = 0;
1114   pid_t thepid;
1115
1116   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1117   if (fpout == NULL) {
1118     mutt_perror (_("Can't create temporary file"));
1119     return (NULL);
1120   }
1121
1122   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
1123   if (pgperr == NULL) {
1124     mutt_perror (pgperrfile);
1125     m_fclose(&fpout);
1126     unlink (tempfile);
1127     return NULL;
1128   }
1129   unlink (pgperrfile);
1130
1131   fptmp = m_tempfile(pgpinfile, sizeof(pgpinfile), NONULL(Tempdir), NULL);
1132   if (fptmp == NULL) {
1133     mutt_perror (pgpinfile);
1134     m_fclose(&fpout);
1135     unlink (tempfile);
1136     m_fclose(&pgperr);
1137     unlink (pgperrfile);
1138     return NULL;
1139   }
1140
1141   if (sign)
1142     convert_to_7bit (a);
1143
1144   mutt_write_mime_header (a, fptmp);
1145   fputc ('\n', fptmp);
1146   mutt_write_mime_body (a, fptmp);
1147   m_fclose(&fptmp);
1148
1149   if ((thepid = pgp_invoke_encrypt (&pgpin, NULL, NULL, -1,
1150                                     fileno (fpout), fileno (pgperr),
1151                                     pgpinfile, keylist, sign)) == -1) {
1152     m_fclose(&pgperr);
1153     unlink (pgpinfile);
1154     return (NULL);
1155   }
1156
1157   if (sign) {
1158     if (!pgp_use_gpg_agent ())
1159       fputs (PgpPass, pgpin);
1160     fputc ('\n', pgpin);
1161   }
1162   m_fclose(&pgpin);
1163
1164   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1165     empty = 1;
1166
1167   unlink (pgpinfile);
1168
1169   fflush (fpout);
1170   rewind (fpout);
1171   if (!empty)
1172     empty = (fgetc (fpout) == EOF);
1173   m_fclose(&fpout);
1174
1175   fflush (pgperr);
1176   rewind (pgperr);
1177   while (fgets (buf, sizeof (buf) - 1, pgperr) != NULL) {
1178     err = 1;
1179     fputs (buf, stdout);
1180   }
1181   m_fclose(&pgperr);
1182
1183   /* pause if there is any error output from PGP */
1184   if (err)
1185     mutt_any_key_to_continue (NULL);
1186
1187   if (empty) {
1188     /* fatal error while trying to encrypt message */
1189     if (sign)
1190       pgp_void_passphrase (); /* just in case */
1191     unlink (tempfile);
1192     return (NULL);
1193   }
1194
1195   t = body_new();
1196   t->type = TYPEMULTIPART;
1197   t->subtype = m_strdup("encrypted");
1198   t->encoding = ENC7BIT;
1199   t->use_disp = 0;
1200   t->disposition = DISPINLINE;
1201
1202   parameter_set_boundary(&t->parameter);
1203   parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
1204
1205   t->parts = body_new();
1206   t->parts->type = TYPEAPPLICATION;
1207   t->parts->subtype = m_strdup("pgp-encrypted");
1208   t->parts->encoding = ENC7BIT;
1209
1210   t->parts->next = body_new();
1211   t->parts->next->type = TYPEAPPLICATION;
1212   t->parts->next->subtype = m_strdup("octet-stream");
1213   t->parts->next->encoding = ENC7BIT;
1214   t->parts->next->filename = m_strdup(tempfile);
1215   t->parts->next->use_disp = 1;
1216   t->parts->next->disposition = DISPINLINE;
1217   t->parts->next->unlink = 1;   /* delete after sending the message */
1218   t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime can save */
1219
1220   return (t);
1221 }
1222
1223 BODY *pgp_traditional_encryptsign (BODY * a, int flags, char *keylist)
1224 {
1225   BODY *b;
1226
1227   char pgpoutfile[_POSIX_PATH_MAX];
1228   char pgperrfile[_POSIX_PATH_MAX];
1229   char pgpinfile[_POSIX_PATH_MAX];
1230
1231   char body_charset[STRING];
1232   char *from_charset;
1233   const char *send_charset;
1234
1235   FILE *pgpout = NULL, *pgperr = NULL, *pgpin = NULL;
1236   FILE *fp;
1237
1238   int empty = 0;
1239   int err;
1240
1241   char buff[STRING];
1242
1243   pid_t thepid;
1244
1245   if (a->type != TYPETEXT)
1246     return NULL;
1247   if (ascii_strcasecmp (a->subtype, "plain"))
1248     return NULL;
1249
1250   if ((fp = fopen (a->filename, "r")) == NULL) {
1251     mutt_perror (a->filename);
1252     return NULL;
1253   }
1254
1255   pgpin = m_tempfile(pgpinfile, sizeof(pgpinfile), NONULL(Tempdir), NULL);
1256   if (pgpin == NULL) {
1257     mutt_perror (pgpinfile);
1258     m_fclose(&fp);
1259     return NULL;
1260   }
1261
1262   /* The following code is really correct:  If noconv is set,
1263    * a's charset parameter contains the on-disk character set, and
1264    * we have to convert from that to utf-8.  If noconv is not set,
1265    * we have to convert from $charset to utf-8.
1266    */
1267
1268   mutt_get_body_charset (body_charset, sizeof (body_charset), a);
1269   if (a->noconv)
1270     from_charset = body_charset;
1271   else
1272     from_charset = Charset;
1273
1274   if (!charset_is_us_ascii (body_charset)) {
1275     int c;
1276     fgetconv_t *fc;
1277
1278     if (flags & ENCRYPT)
1279       send_charset = "us-ascii";
1280     else
1281       send_charset = "utf-8";
1282
1283     fc = fgetconv_open (fp, from_charset, "utf-8", M_ICONV_HOOK_FROM);
1284     while ((c = fgetconv (fc)) != EOF)
1285       fputc (c, pgpin);
1286
1287     fgetconv_close (&fc);
1288   }
1289   else {
1290     send_charset = "us-ascii";
1291     mutt_copy_stream (fp, pgpin);
1292   }
1293   m_fclose(&fp);
1294   m_fclose(&pgpin);
1295
1296   pgpout = m_tempfile(pgpoutfile, sizeof(pgpoutfile), NONULL(Tempdir), NULL);
1297   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
1298   if (pgpout == NULL || pgperr == NULL) {
1299     mutt_perror (pgpout ? pgperrfile : pgpoutfile);
1300     m_fclose(&pgpin);
1301     unlink (pgpinfile);
1302     m_fclose(&pgpout);
1303     unlink (pgpoutfile);
1304     m_fclose(&pgperr);
1305     unlink(pgperrfile);
1306     return NULL;
1307   }
1308
1309   unlink (pgperrfile);
1310
1311   if ((thepid = pgp_invoke_traditional (&pgpin, NULL, NULL,
1312                                         -1, fileno (pgpout), fileno (pgperr),
1313                                         pgpinfile, keylist, flags)) == -1) {
1314     mutt_perror (_("Can't invoke PGP"));
1315
1316     m_fclose(&pgpout);
1317     m_fclose(&pgperr);
1318     mutt_unlink (pgpinfile);
1319     unlink (pgpoutfile);
1320     return NULL;
1321   }
1322
1323   if (pgp_use_gpg_agent ())
1324     *PgpPass = 0;
1325   if (flags & SIGN)
1326     fprintf (pgpin, "%s\n", PgpPass);
1327   m_fclose(&pgpin);
1328
1329   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1330     empty = 1;
1331
1332   mutt_unlink (pgpinfile);
1333
1334   fflush (pgpout);
1335   fflush (pgperr);
1336
1337   rewind (pgpout);
1338   rewind (pgperr);
1339
1340   if (!empty)
1341     empty = (fgetc (pgpout) == EOF);
1342   m_fclose(&pgpout);
1343
1344   err = 0;
1345
1346   while (fgets (buff, sizeof (buff), pgperr)) {
1347     err = 1;
1348     fputs (buff, stdout);
1349   }
1350
1351   m_fclose(&pgperr);
1352
1353   if (err)
1354     mutt_any_key_to_continue (NULL);
1355
1356   if (empty) {
1357     if (flags & SIGN)
1358       pgp_void_passphrase (); /* just in case */
1359     unlink (pgpoutfile);
1360     return NULL;
1361   }
1362
1363   b = body_new();
1364
1365   b->encoding = ENC7BIT;
1366
1367   b->type = TYPETEXT;
1368   b->subtype = m_strdup("plain");
1369
1370   parameter_setval(&b->parameter, "x-action",
1371                    flags & ENCRYPT ? "pgp-encrypted" : "pgp-signed");
1372   parameter_setval(&b->parameter, "charset", send_charset);
1373
1374   b->filename = m_strdup(pgpoutfile);
1375
1376   b->disposition = DISPINLINE;
1377   b->unlink = 1;
1378
1379   b->noconv = 1;
1380   b->use_disp = 0;
1381
1382   if (!(flags & ENCRYPT))
1383     b->encoding = a->encoding;
1384
1385   return b;
1386 }
1387
1388 int pgp_send_menu (HEADER * msg, int *redraw)
1389 {
1390   pgp_key_t p;
1391   char input_signas[SHORT_STRING];
1392
1393   char prompt[LONG_STRING];
1394
1395   /* If autoinline and no crypto options set, then set inline. */
1396   if (option (OPTPGPAUTOINLINE) && !((msg->security & APPLICATION_PGP)
1397                                      && (msg->security & (SIGN | ENCRYPT))))
1398     msg->security |= INLINE;
1399
1400   snprintf (prompt, sizeof (prompt),
1401             _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s, or (c)lear? "),
1402             (msg->security & INLINE) ? _("PGP/M(i)ME") : _("(i)nline"));
1403
1404   switch (mutt_multi_choice (prompt, _("esabifc"))) {
1405   case 1:                      /* (e)ncrypt */
1406     msg->security |= ENCRYPT;
1407     msg->security &= ~SIGN;
1408     break;
1409
1410   case 2:                      /* (s)ign */
1411     msg->security |= SIGN;
1412     msg->security &= ~ENCRYPT;
1413     break;
1414
1415   case 3:                      /* sign (a)s */
1416     unset_option (OPTPGPCHECKTRUST);
1417
1418     if ((p =
1419          pgp_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
1420                           PGP_PUBRING))) {
1421       snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
1422       m_strreplace(&PgpSignAs, input_signas);
1423       pgp_free_key (&p);
1424
1425       msg->security |= SIGN;
1426
1427       crypt_pgp_void_passphrase ();     /* probably need a different passphrase */
1428     }
1429 #if 0
1430     else {
1431       msg->security &= ~SIGN;
1432     }
1433 #endif
1434
1435     *redraw = REDRAW_FULL;
1436     break;
1437
1438   case 4:                      /* (b)oth */
1439     msg->security |= (ENCRYPT | SIGN);
1440     break;
1441
1442   case 5:                      /* (i)nline */
1443     if ((msg->security & (ENCRYPT | SIGN)))
1444       msg->security ^= INLINE;
1445     else
1446       msg->security &= ~INLINE;
1447     break;
1448
1449   case 6:                      /* (f)orget it */
1450   case 7:                      /* (c)lear     */
1451     msg->security = 0;
1452     break;
1453   }
1454
1455   if (msg->security) {
1456     if (!(msg->security & (ENCRYPT | SIGN)))
1457       msg->security = 0;
1458     else
1459       msg->security |= APPLICATION_PGP;
1460   }
1461
1462   return (msg->security);
1463 }