297eb73764c12b24a4767ab32c2a12f9bdb6562c
[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 (m_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   int tempfd;
458
459   short sgn = 0;
460   short enc = 0;
461   short key = 0;
462
463   if (b->type != TYPETEXT)
464     return 0;
465
466   if (tagged_only && !b->tagged)
467     return 0;
468
469   tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
470   if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
471     unlink (tempfile);
472     return 0;
473   }
474
475   if (!(tfp = fopen(tempfile, "r"))) {
476     unlink(tempfile);
477     return 0;
478   }
479
480   while (fgets (buf, sizeof (buf), tfp)) {
481     if (m_strncmp("-----BEGIN PGP ", buf, 15) == 0) {
482       if (m_strcmp("MESSAGE-----\n", buf + 15) == 0)
483         enc = 1;
484       else if (m_strcmp("SIGNED MESSAGE-----\n", buf + 15) == 0)
485         sgn = 1;
486       else if (m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15) == 0)
487         key = 1;
488     }
489   }
490   m_fclose(&tfp);
491   unlink (tempfile);
492
493   if (!enc && !sgn && !key)
494     return 0;
495
496   /* fix the content type */
497
498   parameter_setval(&b->parameter, "format", "fixed");
499   if (enc)
500     parameter_setval(&b->parameter, "x-action", "pgp-encrypted");
501   else if (sgn)
502     parameter_setval(&b->parameter, "x-action", "pgp-signed");
503   else if (key)
504     parameter_setval(&b->parameter, "x-action", "pgp-keys");
505
506   return 1;
507 }
508
509 int pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
510 {
511   int rv = 0;
512   int r;
513
514   for (; b; b = b->next) {
515     if (is_multipart (b))
516       rv = pgp_check_traditional (fp, b->parts, tagged_only) || rv;
517     else if (b->type == TYPETEXT) {
518       if ((r = mutt_is_application_pgp (b)))
519         rv = rv || r;
520       else
521         rv = pgp_check_traditional_one_body (fp, b, tagged_only) || rv;
522     }
523   }
524
525   return rv;
526 }
527
528
529
530
531
532 int pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
533 {
534   char sigfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
535   FILE *fp, *pgpout, *pgperr;
536   pid_t thepid;
537   int badsig = -1;
538   int rv;
539
540   snprintf (sigfile, sizeof (sigfile), "%s.asc", tempfile);
541
542   if (!(fp = safe_fopen (sigfile, "w"))) {
543     mutt_perror (sigfile);
544     return -1;
545   }
546
547   fseeko (s->fpin, sigbdy->offset, 0);
548   mutt_copy_bytes (s->fpin, fp, sigbdy->length);
549   m_fclose(&fp);
550
551   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
552   if (pgperr == NULL) {
553     mutt_perror (pgperrfile);
554     unlink (sigfile);
555     return -1;
556   }
557
558   crypt_current_time (s, "PGP");
559
560   if ((thepid = pgp_invoke_verify (NULL, &pgpout, NULL,
561                                    -1, -1, fileno (pgperr),
562                                    tempfile, sigfile)) != -1) {
563     if (pgp_copy_checksig (pgpout, s->fpout) >= 0)
564       badsig = 0;
565
566
567     m_fclose(&pgpout);
568     fflush (pgperr);
569     rewind (pgperr);
570
571     if (pgp_copy_checksig (pgperr, s->fpout) >= 0)
572       badsig = 0;
573
574     if ((rv = mutt_wait_filter (thepid)))
575       badsig = -1;
576   }
577
578   m_fclose(&pgperr);
579
580   state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
581
582   mutt_unlink (sigfile);
583   mutt_unlink (pgperrfile);
584
585   return badsig;
586 }
587
588
589 /* Extract pgp public keys from messages or attachments */
590
591 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
592 {
593   STATE s;
594   FILE *tempfp;
595   char tempfname[_POSIX_PATH_MAX];
596
597   tempfp = m_tempfile(tempfname, sizeof(tempfname), NONULL(Tempdir), NULL);
598   if (tempfp == NULL) {
599     mutt_perror (_("Can't create temporary file"));
600     return;
601   }
602
603   p_clear(&s, 1);
604
605   s.fpin = fp;
606   s.fpout = tempfp;
607
608   mutt_body_handler (top, &s);
609
610   m_fclose(&tempfp);
611
612   pgp_invoke_import (tempfname);
613   mutt_any_key_to_continue (NULL);
614
615   mutt_unlink (tempfname);
616 }
617
618 void pgp_extract_keys_from_attachment_list (FILE * fp, int tag, BODY * top)
619 {
620   if (!fp) {
621     mutt_error _("Internal error. Inform <roessler@does-not-exist.org>.");
622
623     return;
624   }
625
626   mutt_endwin (NULL);
627   set_option (OPTDONTHANDLEPGPKEYS);
628
629   for (; top; top = top->next) {
630     if (!tag || top->tagged)
631       pgp_extract_keys_from_attachment (fp, top);
632
633     if (!tag)
634       break;
635   }
636
637   unset_option (OPTDONTHANDLEPGPKEYS);
638 }
639
640 BODY *pgp_decrypt_part (BODY * a, STATE * s, FILE * fpout, BODY * p)
641 {
642   char buf[LONG_STRING];
643   FILE *pgpin, *pgpout, *pgperr, *pgptmp;
644   struct stat info;
645   BODY *tattach;
646   int len;
647   char pgperrfile[_POSIX_PATH_MAX];
648   char pgptmpfile[_POSIX_PATH_MAX];
649   pid_t thepid;
650   int rv;
651
652   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
653   if (!pgperr) {
654     mutt_perror (pgperrfile);
655     return NULL;
656   }
657   unlink (pgperrfile);
658
659   pgptmp = m_tempfile(pgptmpfile, sizeof(pgptmpfile), NONULL(Tempdir), NULL);
660   if (!pgptmp) {
661     mutt_perror (pgptmpfile);
662     m_fclose(&pgperr);
663     return NULL;
664   }
665
666   /* Position the stream at the beginning of the body, and send the data to
667    * the temporary file.
668    */
669
670   fseeko (s->fpin, a->offset, 0);
671   mutt_copy_bytes (s->fpin, pgptmp, a->length);
672   m_fclose(&pgptmp);
673
674   if ((thepid = pgp_invoke_decrypt (&pgpin, &pgpout, NULL, -1, -1,
675                                     fileno (pgperr), pgptmpfile)) == -1) {
676     m_fclose(&pgperr);
677     unlink (pgptmpfile);
678     if (s->flags & M_DISPLAY)
679       state_attach_puts (_
680                          ("[-- Error: could not create a PGP subprocess! --]\n\n"),
681                          s);
682     return (NULL);
683   }
684
685   /* send the PGP passphrase to the subprocess.  Never do this if the
686      agent is active, because this might lead to a passphrase send as
687      the message. */
688   if (!pgp_use_gpg_agent ())
689     fputs (PgpPass, pgpin);
690   fputc ('\n', pgpin);
691   m_fclose(&pgpin);
692
693   /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
694    * read_mime_header has a hard time parsing the message.
695    */
696   while (fgets (buf, sizeof (buf) - 1, pgpout) != NULL) {
697     len = m_strlen(buf);
698     if (len > 1 && buf[len - 2] == '\r')
699       m_strcpy(buf + len - 2, len - 2,  "\n");
700     fputs (buf, fpout);
701   }
702
703   m_fclose(&pgpout);
704   rv = mutt_wait_filter (thepid);
705   mutt_unlink (pgptmpfile);
706
707   if (s->flags & M_DISPLAY) {
708     fflush (pgperr);
709     rewind (pgperr);
710     if (pgp_copy_checksig (pgperr, s->fpout) == 0 && !rv && p)
711       p->goodsig = 1;
712     else
713       p->goodsig = 0;
714     state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
715   }
716   m_fclose(&pgperr);
717
718   fflush (fpout);
719   rewind (fpout);
720
721   if (fgetc (fpout) == EOF) {
722     mutt_error (_("Decryption failed."));
723     pgp_void_passphrase ();
724     return NULL;
725   }
726
727   rewind (fpout);
728
729   if ((tattach = mutt_read_mime_header (fpout, 0)) != NULL) {
730     /*
731      * Need to set the length of this body part.
732      */
733     fstat (fileno (fpout), &info);
734     tattach->length = info.st_size - tattach->offset;
735
736     /* See if we need to recurse on this MIME part.  */
737
738     mutt_parse_part (fpout, tattach);
739   }
740
741   return (tattach);
742 }
743
744 int pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
745 {
746   char tempfile[_POSIX_PATH_MAX];
747   STATE s;
748   BODY *p = b;
749
750   if (!mutt_is_multipart_encrypted (b))
751     return -1;
752
753   if (!b->parts || !b->parts->next)
754     return -1;
755
756   b = b->parts->next;
757
758   p_clear(&s, 1);
759   s.fpin = fpin;
760   *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
761   if (*fpout == NULL) {
762     mutt_perror (_("Can't create temporary file"));
763     return (-1);
764   }
765   unlink (tempfile);
766
767   *cur = pgp_decrypt_part (b, &s, *fpout, p);
768
769   rewind (*fpout);
770
771   if (!*cur)
772     return -1;
773
774   return (0);
775 }
776
777 int pgp_encrypted_handler (BODY * a, STATE * s)
778 {
779   char tempfile[_POSIX_PATH_MAX];
780   FILE *fpout, *fpin;
781   BODY *tattach;
782   BODY *p = a;
783   int rc = 0;
784
785   a = a->parts;
786   if (!a || a->type != TYPEAPPLICATION || !a->subtype ||
787       ascii_strcasecmp ("pgp-encrypted", a->subtype) != 0 ||
788       !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype ||
789       ascii_strcasecmp ("octet-stream", a->next->subtype) != 0) {
790     if (s->flags & M_DISPLAY)
791       state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
792                          s);
793     return (-1);
794   }
795
796   /*
797    * Move forward to the application/pgp-encrypted body.
798    */
799   a = a->next;
800
801   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
802   if (fpout == NULL) {
803     if (s->flags & M_DISPLAY)
804       state_attach_puts (_
805                          ("[-- Error: could not create temporary file! --]\n"),
806                          s);
807     return (-1);
808   }
809
810   if (s->flags & M_DISPLAY)
811     crypt_current_time (s, "PGP");
812
813   if ((tattach = pgp_decrypt_part (a, s, fpout, p)) != NULL) {
814     if (s->flags & M_DISPLAY)
815       state_attach_puts (_
816                          ("[-- The following data is PGP/MIME encrypted --]\n\n"),
817                          s);
818
819     fpin = s->fpin;
820     s->fpin = fpout;
821     rc = mutt_body_handler (tattach, s);
822     s->fpin = fpin;
823
824     /* 
825      * if a multipart/signed is the _only_ sub-part of a
826      * multipart/encrypted, cache signature verification
827      * status.
828      *
829      */
830
831     if (mutt_is_multipart_signed (tattach) && !tattach->next)
832       p->goodsig |= tattach->goodsig;
833
834     if (s->flags & M_DISPLAY) {
835       state_puts ("\n", s);
836       state_attach_puts (_("[-- End of PGP/MIME encrypted data --]\n"), s);
837     }
838
839     body_list_wipe(&tattach);
840     /* clear 'Invoking...' message, since there's no error */
841     mutt_message _("PGP message successfully decrypted.");
842   } else {
843     mutt_error _("Could not decrypt PGP message");
844     pgp_void_passphrase ();
845     rc = -1;
846   }
847
848   m_fclose(&fpout);
849   mutt_unlink (tempfile);
850
851   return (rc);
852 }
853
854 /* ----------------------------------------------------------------------------
855  * Routines for sending PGP/MIME messages.
856  */
857
858
859 BODY *pgp_sign_message (BODY * a)
860 {
861   BODY *t;
862   char buffer[LONG_STRING];
863   char sigfile[_POSIX_PATH_MAX], signedfile[_POSIX_PATH_MAX];
864   FILE *pgpin, *pgpout, *pgperr, *fp, *sfp;
865   int err = 0;
866   int empty = 1;
867   pid_t thepid;
868
869   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
870
871   fp = m_tempfile(sigfile, sizeof(sigfile), NONULL(Tempdir), NULL);
872   if (fp == NULL) {
873     return (NULL);
874   }
875
876   sfp = m_tempfile(signedfile, sizeof(signedfile), NONULL(Tempdir), NULL);
877   if (sfp == NULL) {
878     mutt_perror (signedfile);
879     m_fclose(&fp);
880     unlink (sigfile);
881     return NULL;
882   }
883
884   mutt_write_mime_header (a, sfp);
885   fputc ('\n', sfp);
886   mutt_write_mime_body (a, sfp);
887   m_fclose(&sfp);
888
889   if ((thepid = pgp_invoke_sign (&pgpin, &pgpout, &pgperr,
890                                  -1, -1, -1, signedfile)) == -1) {
891     mutt_perror (_("Can't open PGP subprocess!"));
892
893     m_fclose(&fp);
894     unlink (sigfile);
895     unlink (signedfile);
896     return NULL;
897   }
898
899   if (!pgp_use_gpg_agent ())
900     fputs (PgpPass, pgpin);
901   fputc ('\n', pgpin);
902   m_fclose(&pgpin);
903
904   /*
905    * Read back the PGP signature.  Also, change MESSAGE=>SIGNATURE as
906    * recommended for future releases of PGP.
907    */
908   while (fgets (buffer, sizeof (buffer) - 1, pgpout) != NULL) {
909     if (m_strcmp("-----BEGIN PGP MESSAGE-----\n", buffer) == 0)
910       fputs ("-----BEGIN PGP SIGNATURE-----\n", fp);
911     else if (m_strcmp("-----END PGP MESSAGE-----\n", buffer) == 0)
912       fputs ("-----END PGP SIGNATURE-----\n", fp);
913     else
914       fputs (buffer, fp);
915     empty = 0;                  /* got some output, so we're ok */
916   }
917
918   /* check for errors from PGP */
919   err = 0;
920   while (fgets (buffer, sizeof (buffer) - 1, pgperr) != NULL) {
921     err = 1;
922     fputs (buffer, stdout);
923   }
924
925   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
926     empty = 1;
927
928   m_fclose(&pgperr);
929   m_fclose(&pgpout);
930   unlink (signedfile);
931
932   if (m_fclose(&fp) != 0) {
933     mutt_perror ("fclose");
934     unlink (sigfile);
935     return (NULL);
936   }
937
938   if (err) {
939     pgp_void_passphrase ();
940     mutt_any_key_to_continue (NULL);
941   }
942
943   if (empty) {
944     unlink (sigfile);
945     return (NULL);              /* fatal error while signing */
946   }
947
948   t = body_new();
949   t->type = TYPEMULTIPART;
950   t->subtype = m_strdup("signed");
951   t->encoding = ENC7BIT;
952   t->use_disp = 0;
953   t->disposition = DISPINLINE;
954
955   parameter_set_boundary(&t->parameter);
956   parameter_setval(&t->parameter, "protocol", "application/pgp-signature");
957   parameter_setval(&t->parameter, "micalg", pgp_micalg (sigfile));
958
959   t->parts = a;
960   a = t;
961
962   t->parts->next = body_new();
963   t = t->parts->next;
964   t->type = TYPEAPPLICATION;
965   t->subtype = m_strdup("pgp-signature");
966   t->filename = m_strdup(sigfile);
967   t->use_disp = 0;
968   t->disposition = DISPINLINE;
969   t->encoding = ENC7BIT;
970   t->unlink = 1;                /* ok to remove this file after sending. */
971
972   return (a);
973 }
974
975 static short is_numerical_keyid (const char *s)
976 {
977   /* or should we require the "0x"? */
978   if (m_strncmp (s, "0x", 2) == 0)
979     s += 2;
980   if (m_strlen(s) % 8)
981     return 0;
982   while (*s)
983     if (strchr ("0123456789ABCDEFabcdef", *s++) == NULL)
984       return 0;
985
986   return 1;
987 }
988
989 /* This routine attempts to find the keyids of the recipients of a message.
990  * It returns NULL if any of the keys can not be found.
991  */
992 char *pgp_findKeys (address_t * to, address_t * cc, address_t * bcc)
993 {
994   char *keylist = NULL, *t;
995   const char *keyID;
996   size_t keylist_size = 0;
997   size_t keylist_used = 0;
998   address_t *tmp = NULL, *addr = NULL;
999   address_t **last = &tmp;
1000   address_t *p, *q;
1001   int i;
1002   pgp_key_t k_info = NULL, key = NULL;
1003
1004   const char *fqdn = mutt_fqdn (1);
1005
1006   for (i = 0; i < 3; i++) {
1007     switch (i) {
1008     case 0:
1009       p = to;
1010       break;
1011     case 1:
1012       p = cc;
1013       break;
1014     case 2:
1015       p = bcc;
1016       break;
1017     default:
1018       abort ();
1019     }
1020
1021     *last = address_list_dup (p);
1022     while (*last)
1023       last = &((*last)->next);
1024   }
1025
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 (m_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           rfc822_qualify (addr, fqdn);
1052           q = addr;
1053         }
1054         else
1055           k_info = pgp_getkeybystr (keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
1056       }
1057       else if (r == -1) {
1058         p_delete(&keylist);
1059         address_list_wipe(&tmp);
1060         address_list_wipe(&addr);
1061         return NULL;
1062       }
1063     }
1064
1065     if (k_info == NULL)
1066       pgp_invoke_getkeys (q);
1067
1068     if (k_info == NULL
1069         && (k_info =
1070             pgp_getkeybyaddr (q, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1071       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
1072
1073       if ((key = pgp_ask_for_key (buf, q->mailbox,
1074                                   KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1075         p_delete(&keylist);
1076         address_list_wipe(&tmp);
1077         address_list_wipe(&addr);
1078         return NULL;
1079       }
1080     }
1081     else
1082       key = k_info;
1083
1084     keyID = pgp_keyid (key);
1085
1086   bypass_selection:
1087     keylist_size += m_strlen(keyID) + 4;
1088     p_realloc(&keylist, keylist_size);
1089     sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "",
1090              keyID);
1091     keylist_used = m_strlen(keylist);
1092
1093     pgp_free_key (&key);
1094     address_list_wipe(&addr);
1095
1096   }
1097   address_list_wipe(&tmp);
1098   return (keylist);
1099 }
1100
1101 /* Warning: "a" is no longer freed in this routine, you need
1102  * to free it later.  This is necessary for $fcc_attach. */
1103
1104 BODY *pgp_encrypt_message (BODY * a, char *keylist, int sign)
1105 {
1106   char buf[LONG_STRING];
1107   char tempfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
1108   char pgpinfile[_POSIX_PATH_MAX];
1109   FILE *pgpin, *pgperr, *fpout, *fptmp;
1110   BODY *t;
1111   int err = 0;
1112   int empty = 0;
1113   pid_t thepid;
1114
1115   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
1116   if (fpout == NULL) {
1117     mutt_perror (_("Can't create temporary file"));
1118     return (NULL);
1119   }
1120
1121   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
1122   if (pgperr == NULL) {
1123     mutt_perror (pgperrfile);
1124     m_fclose(&fpout);
1125     unlink (tempfile);
1126     return NULL;
1127   }
1128   unlink (pgperrfile);
1129
1130   fptmp = m_tempfile(pgpinfile, sizeof(pgpinfile), NONULL(Tempdir), NULL);
1131   if (fptmp == NULL) {
1132     mutt_perror (pgpinfile);
1133     m_fclose(&fpout);
1134     unlink (tempfile);
1135     m_fclose(&pgperr);
1136     unlink (pgperrfile);
1137     return NULL;
1138   }
1139
1140   if (sign)
1141     convert_to_7bit (a);
1142
1143   mutt_write_mime_header (a, fptmp);
1144   fputc ('\n', fptmp);
1145   mutt_write_mime_body (a, fptmp);
1146   m_fclose(&fptmp);
1147
1148   if ((thepid = pgp_invoke_encrypt (&pgpin, NULL, NULL, -1,
1149                                     fileno (fpout), fileno (pgperr),
1150                                     pgpinfile, keylist, sign)) == -1) {
1151     m_fclose(&pgperr);
1152     unlink (pgpinfile);
1153     return (NULL);
1154   }
1155
1156   if (sign) {
1157     if (!pgp_use_gpg_agent ())
1158       fputs (PgpPass, pgpin);
1159     fputc ('\n', pgpin);
1160   }
1161   m_fclose(&pgpin);
1162
1163   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1164     empty = 1;
1165
1166   unlink (pgpinfile);
1167
1168   fflush (fpout);
1169   rewind (fpout);
1170   if (!empty)
1171     empty = (fgetc (fpout) == EOF);
1172   m_fclose(&fpout);
1173
1174   fflush (pgperr);
1175   rewind (pgperr);
1176   while (fgets (buf, sizeof (buf) - 1, pgperr) != NULL) {
1177     err = 1;
1178     fputs (buf, stdout);
1179   }
1180   m_fclose(&pgperr);
1181
1182   /* pause if there is any error output from PGP */
1183   if (err)
1184     mutt_any_key_to_continue (NULL);
1185
1186   if (empty) {
1187     /* fatal error while trying to encrypt message */
1188     if (sign)
1189       pgp_void_passphrase (); /* just in case */
1190     unlink (tempfile);
1191     return (NULL);
1192   }
1193
1194   t = body_new();
1195   t->type = TYPEMULTIPART;
1196   t->subtype = m_strdup("encrypted");
1197   t->encoding = ENC7BIT;
1198   t->use_disp = 0;
1199   t->disposition = DISPINLINE;
1200
1201   parameter_set_boundary(&t->parameter);
1202   parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
1203
1204   t->parts = body_new();
1205   t->parts->type = TYPEAPPLICATION;
1206   t->parts->subtype = m_strdup("pgp-encrypted");
1207   t->parts->encoding = ENC7BIT;
1208
1209   t->parts->next = body_new();
1210   t->parts->next->type = TYPEAPPLICATION;
1211   t->parts->next->subtype = m_strdup("octet-stream");
1212   t->parts->next->encoding = ENC7BIT;
1213   t->parts->next->filename = m_strdup(tempfile);
1214   t->parts->next->use_disp = 1;
1215   t->parts->next->disposition = DISPINLINE;
1216   t->parts->next->unlink = 1;   /* delete after sending the message */
1217   t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime can save */
1218
1219   return (t);
1220 }
1221
1222 BODY *pgp_traditional_encryptsign (BODY * a, int flags, char *keylist)
1223 {
1224   BODY *b;
1225
1226   char pgpoutfile[_POSIX_PATH_MAX];
1227   char pgperrfile[_POSIX_PATH_MAX];
1228   char pgpinfile[_POSIX_PATH_MAX];
1229
1230   char body_charset[STRING];
1231   char *from_charset;
1232   const char *send_charset;
1233
1234   FILE *pgpout = NULL, *pgperr = NULL, *pgpin = NULL;
1235   FILE *fp;
1236
1237   int empty = 0;
1238   int err;
1239
1240   char buff[STRING];
1241
1242   pid_t thepid;
1243
1244   if (a->type != TYPETEXT)
1245     return NULL;
1246   if (ascii_strcasecmp (a->subtype, "plain"))
1247     return NULL;
1248
1249   if ((fp = fopen (a->filename, "r")) == NULL) {
1250     mutt_perror (a->filename);
1251     return NULL;
1252   }
1253
1254   pgpin = m_tempfile(pgpinfile, sizeof(pgpinfile), NONULL(Tempdir), NULL);
1255   if (pgpin == NULL) {
1256     mutt_perror (pgpinfile);
1257     m_fclose(&fp);
1258     return NULL;
1259   }
1260
1261   /* The following code is really correct:  If noconv is set,
1262    * a's charset parameter contains the on-disk character set, and
1263    * we have to convert from that to utf-8.  If noconv is not set,
1264    * we have to convert from $charset to utf-8.
1265    */
1266
1267   mutt_get_body_charset (body_charset, sizeof (body_charset), a);
1268   if (a->noconv)
1269     from_charset = body_charset;
1270   else
1271     from_charset = Charset;
1272
1273   if (!charset_is_us_ascii (body_charset)) {
1274     int c;
1275     fgetconv_t *fc;
1276
1277     if (flags & ENCRYPT)
1278       send_charset = "us-ascii";
1279     else
1280       send_charset = "utf-8";
1281
1282     fc = fgetconv_open (fp, from_charset, "utf-8", M_ICONV_HOOK_FROM);
1283     while ((c = fgetconv (fc)) != EOF)
1284       fputc (c, pgpin);
1285
1286     fgetconv_close (&fc);
1287   }
1288   else {
1289     send_charset = "us-ascii";
1290     mutt_copy_stream (fp, pgpin);
1291   }
1292   m_fclose(&fp);
1293   m_fclose(&pgpin);
1294
1295   pgpout = m_tempfile(pgpoutfile, sizeof(pgpoutfile), NONULL(Tempdir), NULL);
1296   pgperr = m_tempfile(pgperrfile, sizeof(pgperrfile), NONULL(Tempdir), NULL);
1297   if (pgpout == NULL || pgperr == NULL) {
1298     mutt_perror (pgpout ? pgperrfile : pgpoutfile);
1299     m_fclose(&pgpin);
1300     unlink (pgpinfile);
1301     m_fclose(&pgpout);
1302     unlink (pgpoutfile);
1303     m_fclose(&pgperr);
1304     unlink(pgperrfile);
1305     return NULL;
1306   }
1307
1308   unlink (pgperrfile);
1309
1310   if ((thepid = pgp_invoke_traditional (&pgpin, NULL, NULL,
1311                                         -1, fileno (pgpout), fileno (pgperr),
1312                                         pgpinfile, keylist, flags)) == -1) {
1313     mutt_perror (_("Can't invoke PGP"));
1314
1315     m_fclose(&pgpout);
1316     m_fclose(&pgperr);
1317     mutt_unlink (pgpinfile);
1318     unlink (pgpoutfile);
1319     return NULL;
1320   }
1321
1322   if (pgp_use_gpg_agent ())
1323     *PgpPass = 0;
1324   if (flags & SIGN)
1325     fprintf (pgpin, "%s\n", PgpPass);
1326   m_fclose(&pgpin);
1327
1328   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1329     empty = 1;
1330
1331   mutt_unlink (pgpinfile);
1332
1333   fflush (pgpout);
1334   fflush (pgperr);
1335
1336   rewind (pgpout);
1337   rewind (pgperr);
1338
1339   if (!empty)
1340     empty = (fgetc (pgpout) == EOF);
1341   m_fclose(&pgpout);
1342
1343   err = 0;
1344
1345   while (fgets (buff, sizeof (buff), pgperr)) {
1346     err = 1;
1347     fputs (buff, stdout);
1348   }
1349
1350   m_fclose(&pgperr);
1351
1352   if (err)
1353     mutt_any_key_to_continue (NULL);
1354
1355   if (empty) {
1356     if (flags & SIGN)
1357       pgp_void_passphrase (); /* just in case */
1358     unlink (pgpoutfile);
1359     return NULL;
1360   }
1361
1362   b = body_new();
1363
1364   b->encoding = ENC7BIT;
1365
1366   b->type = TYPETEXT;
1367   b->subtype = m_strdup("plain");
1368
1369   parameter_setval(&b->parameter, "x-action",
1370                    flags & ENCRYPT ? "pgp-encrypted" : "pgp-signed");
1371   parameter_setval(&b->parameter, "charset", send_charset);
1372
1373   b->filename = m_strdup(pgpoutfile);
1374
1375   b->disposition = DISPINLINE;
1376   b->unlink = 1;
1377
1378   b->noconv = 1;
1379   b->use_disp = 0;
1380
1381   if (!(flags & ENCRYPT))
1382     b->encoding = a->encoding;
1383
1384   return b;
1385 }
1386
1387 int pgp_send_menu (HEADER * msg, int *redraw)
1388 {
1389   pgp_key_t p;
1390   char input_signas[STRING];
1391
1392   char prompt[LONG_STRING];
1393
1394   /* If autoinline and no crypto options set, then set inline. */
1395   if (option (OPTPGPAUTOINLINE) && !((msg->security & APPLICATION_PGP)
1396                                      && (msg->security & (SIGN | ENCRYPT))))
1397     msg->security |= INLINE;
1398
1399   snprintf (prompt, sizeof (prompt),
1400             _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s, or (c)lear? "),
1401             (msg->security & INLINE) ? _("PGP/M(i)ME") : _("(i)nline"));
1402
1403   switch (mutt_multi_choice (prompt, _("esabifc"))) {
1404   case 1:                      /* (e)ncrypt */
1405     msg->security |= ENCRYPT;
1406     msg->security &= ~SIGN;
1407     break;
1408
1409   case 2:                      /* (s)ign */
1410     msg->security |= SIGN;
1411     msg->security &= ~ENCRYPT;
1412     break;
1413
1414   case 3:                      /* sign (a)s */
1415     unset_option (OPTPGPCHECKTRUST);
1416
1417     if ((p =
1418          pgp_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
1419                           PGP_PUBRING))) {
1420       snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
1421       m_strreplace(&PgpSignAs, input_signas);
1422       pgp_free_key (&p);
1423
1424       msg->security |= SIGN;
1425
1426       crypt_pgp_void_passphrase ();     /* probably need a different passphrase */
1427     }
1428
1429     *redraw = REDRAW_FULL;
1430     break;
1431
1432   case 4:                      /* (b)oth */
1433     msg->security |= (ENCRYPT | SIGN);
1434     break;
1435
1436   case 5:                      /* (i)nline */
1437     if ((msg->security & (ENCRYPT | SIGN)))
1438       msg->security ^= INLINE;
1439     else
1440       msg->security &= ~INLINE;
1441     break;
1442
1443   case 6:                      /* (f)orget it */
1444   case 7:                      /* (c)lear     */
1445     msg->security = 0;
1446     break;
1447   }
1448
1449   if (msg->security) {
1450     if (!(msg->security & (ENCRYPT | SIGN)))
1451       msg->security = 0;
1452     else
1453       msg->security |= APPLICATION_PGP;
1454   }
1455
1456   return (msg->security);
1457 }