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