NeoMutt  2020-06-26-89-g172cd3
Teaching an old dog new tricks
DOXYGEN
pgp.c
Go to the documentation of this file.
1 
35 #include "config.h"
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/stat.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include "private.h"
44 #include "mutt/lib.h"
45 #include "address/lib.h"
46 #include "config/lib.h"
47 #include "email/lib.h"
48 #include "core/lib.h"
49 #include "gui/lib.h"
50 #include "mutt.h"
51 #include "lib.h"
52 #include "crypt.h"
53 #include "cryptglue.h"
54 #include "handler.h"
55 #include "hook.h"
56 #include "mutt_attach.h"
57 #include "muttlib.h"
58 #include "options.h"
59 #include "pgpinvoke.h"
60 #include "pgpkey.h"
61 #include "pgpmicalg.h"
62 #include "state.h"
63 #include "send/lib.h"
64 #ifdef CRYPT_BACKEND_CLASSIC_PGP
65 #include "pgp.h"
66 #include "pgplib.h"
67 #endif
68 
69 char PgpPass[1024];
70 time_t PgpExptime = 0; /* when does the cached passphrase expire? */
71 
76 {
77  memset(PgpPass, 0, sizeof(PgpPass));
78  PgpExptime = 0;
79 }
80 
85 {
86  if (pgp_use_gpg_agent())
87  {
88  *PgpPass = '\0';
89  return true; /* handled by gpg-agent */
90  }
91 
93  {
94  /* Use cached copy. */
95  return true;
96  }
97 
99 
100  if (mutt_get_password(_("Enter PGP passphrase:"), PgpPass, sizeof(PgpPass)) == 0)
101  {
103  return true;
104  }
105  else
106  PgpExptime = 0;
107 
108  return false;
109 }
110 
118 {
119  char *tty = NULL;
120 
121  /* GnuPG 2.1 no longer exports GPG_AGENT_INFO */
122  if (!C_PgpUseGpgAgent)
123  return false;
124 
125  tty = ttyname(0);
126  if (tty)
127  {
128  setenv("GPG_TTY", tty, 0);
129  mutt_envlist_set("GPG_TTY", tty, false);
130  }
131 
132  return true;
133 }
134 
140 static struct PgpKeyInfo *key_parent(struct PgpKeyInfo *k)
141 {
142  if ((k->flags & KEYFLAG_SUBKEY) && k->parent && C_PgpIgnoreSubkeys)
143  k = k->parent;
144 
145  return k;
146 }
147 
153 char *pgp_long_keyid(struct PgpKeyInfo *k)
154 {
155  k = key_parent(k);
156 
157  return k->keyid;
158 }
159 
165 char *pgp_short_keyid(struct PgpKeyInfo *k)
166 {
167  k = key_parent(k);
168 
169  return k->keyid + 8;
170 }
171 
179 char *pgp_this_keyid(struct PgpKeyInfo *k)
180 {
181  if (C_PgpLongIds)
182  return k->keyid;
183  return k->keyid + 8;
184 }
185 
191 char *pgp_keyid(struct PgpKeyInfo *k)
192 {
193  k = key_parent(k);
194 
195  return pgp_this_keyid(k);
196 }
197 
203 static char *pgp_fingerprint(struct PgpKeyInfo *k)
204 {
205  k = key_parent(k);
206 
207  return k->fingerprint;
208 }
209 
222 {
223  char *fingerprint = pgp_fingerprint(k);
224  return fingerprint ? fingerprint : pgp_long_keyid(k);
225 }
226 
227 /* ----------------------------------------------------------------------------
228  * Routines for handing PGP input.
229  */
230 
238 static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
239 {
240  if (!fp_in || !fp_out)
241  return -1;
242 
243  int rc = -1;
244 
246  {
247  char *line = NULL;
248  size_t linelen;
249 
250  while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, 0)))
251  {
252  if (mutt_regex_match(C_PgpGoodSign, line))
253  {
254  mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
255  rc = 0;
256  }
257  else
258  mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
259 
260  if (mutt_strn_equal(line, "[GNUPG:] ", 9))
261  continue;
262  fputs(line, fp_out);
263  fputc('\n', fp_out);
264  }
265  FREE(&line);
266  }
267  else
268  {
269  mutt_debug(LL_DEBUG2, "No pattern\n");
270  mutt_file_copy_stream(fp_in, fp_out);
271  rc = 1;
272  }
273 
274  return rc;
275 }
276 
287 static int pgp_check_pgp_decryption_okay_regex(FILE *fp_in)
288 {
289  int rc = -1;
290 
292  {
293  char *line = NULL;
294  size_t linelen;
295 
296  while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, 0)))
297  {
299  {
300  mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
301  rc = 0;
302  break;
303  }
304  else
305  mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
306  }
307  FREE(&line);
308  }
309  else
310  {
311  mutt_debug(LL_DEBUG2, "No pattern\n");
312  rc = 1;
313  }
314 
315  return rc;
316 }
317 
338 static int pgp_check_decryption_okay(FILE *fp_in)
339 {
340  int rc = -1;
341  char *line = NULL, *s = NULL;
342  size_t linelen;
343  int inside_decrypt = 0;
344 
347 
348  while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, 0)))
349  {
350  size_t plen = mutt_str_startswith(line, "[GNUPG:] ");
351  if (plen == 0)
352  continue;
353  s = line + plen;
354  mutt_debug(LL_DEBUG2, "checking \"%s\"\n", line);
355  if (mutt_str_startswith(s, "BEGIN_DECRYPTION"))
356  inside_decrypt = 1;
357  else if (mutt_str_startswith(s, "END_DECRYPTION"))
358  inside_decrypt = 0;
359  else if (mutt_str_startswith(s, "PLAINTEXT"))
360  {
361  if (!inside_decrypt)
362  {
364  "\tPLAINTEXT encountered outside of DECRYPTION\n");
365  rc = -2;
366  break;
367  }
368  }
369  else if (mutt_str_startswith(s, "DECRYPTION_FAILED"))
370  {
371  mutt_debug(LL_DEBUG2, "\tDECRYPTION_FAILED encountered. Failure\n");
372  rc = -3;
373  break;
374  }
375  else if (mutt_str_startswith(s, "DECRYPTION_OKAY"))
376  {
377  /* Don't break out because we still have to check for
378  * PLAINTEXT outside of the decryption boundaries. */
379  mutt_debug(LL_DEBUG2, "\tDECRYPTION_OKAY encountered\n");
380  rc = 0;
381  }
382  }
383  FREE(&line);
384 
385  return rc;
386 }
387 
401 static void pgp_copy_clearsigned(FILE *fp_in, struct State *s, char *charset)
402 {
403  char buf[8192];
404  bool complete, armor_header;
405 
406  rewind(fp_in);
407 
408  /* fromcode comes from the MIME Content-Type charset label. It might
409  * be a wrong label, so we want the ability to do corrections via
410  * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
411  struct FgetConv *fc =
413 
414  for (complete = true, armor_header = true;
415  mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
416  {
417  if (!complete)
418  {
419  if (!armor_header)
420  state_puts(s, buf);
421  continue;
422  }
423 
424  if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
425  break;
426 
427  if (armor_header)
428  {
429  char *p = mutt_str_skip_whitespace(buf);
430  if (*p == '\0')
431  armor_header = false;
432  continue;
433  }
434 
435  if (s->prefix)
436  state_puts(s, s->prefix);
437 
438  if ((buf[0] == '-') && (buf[1] == ' '))
439  state_puts(s, buf + 2);
440  else
441  state_puts(s, buf);
442  }
443 
445 }
446 
450 int pgp_class_application_handler(struct Body *m, struct State *s)
451 {
452  bool could_not_decrypt = false;
453  int decrypt_okay_rc = 0;
454  int needpass = -1;
455  bool pgp_keyblock = false;
456  bool clearsign = false;
457  int rc = -1;
458  int c = 1;
459  long bytes;
460  LOFF_T last_pos, offset;
461  char buf[8192];
462  FILE *fp_pgp_out = NULL, *fp_pgp_in = NULL, *fp_pgp_err = NULL;
463  FILE *fp_tmp = NULL;
464  pid_t pid;
465  struct Buffer *tmpfname = mutt_buffer_pool_get();
466 
467  bool maybe_goodsig = true;
468  bool have_any_sigs = false;
469 
470  char *gpgcharset = NULL;
471  char body_charset[256];
472  mutt_body_get_charset(m, body_charset, sizeof(body_charset));
473 
474  fseeko(s->fp_in, m->offset, SEEK_SET);
475  last_pos = m->offset;
476 
477  for (bytes = m->length; bytes > 0;)
478  {
479  if (!fgets(buf, sizeof(buf), s->fp_in))
480  break;
481 
482  offset = ftello(s->fp_in);
483  bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
484  last_pos = offset;
485 
486  size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
487  if (plen != 0)
488  {
489  clearsign = false;
490  could_not_decrypt = false;
491  decrypt_okay_rc = 0;
492 
493  if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
494  needpass = 1;
495  else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
496  {
497  clearsign = true;
498  needpass = 0;
499  }
500  else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
501  {
502  needpass = 0;
503  pgp_keyblock = true;
504  }
505  else
506  {
507  /* XXX we may wish to recode here */
508  if (s->prefix)
509  state_puts(s, s->prefix);
510  state_puts(s, buf);
511  continue;
512  }
513 
514  have_any_sigs = have_any_sigs || (clearsign && (s->flags & MUTT_VERIFY));
515 
516  /* Copy PGP material to temporary file */
517  mutt_buffer_mktemp(tmpfname);
518  fp_tmp = mutt_file_fopen(mutt_b2s(tmpfname), "w+");
519  if (!fp_tmp)
520  {
521  mutt_perror(mutt_b2s(tmpfname));
522  FREE(&gpgcharset);
523  goto out;
524  }
525 
526  fputs(buf, fp_tmp);
527  while ((bytes > 0) && fgets(buf, sizeof(buf) - 1, s->fp_in))
528  {
529  offset = ftello(s->fp_in);
530  bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
531  last_pos = offset;
532 
533  fputs(buf, fp_tmp);
534 
535  if ((needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf)) ||
536  (!needpass &&
537  (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
538  mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf))))
539  {
540  break;
541  }
542  /* remember optional Charset: armor header as defined by RFC4880 */
543  if (mutt_str_startswith(buf, "Charset: "))
544  {
545  size_t l = 0;
546  FREE(&gpgcharset);
547  gpgcharset = mutt_str_dup(buf + 9);
548  l = mutt_str_len(gpgcharset);
549  if ((l > 0) && (gpgcharset[l - 1] == '\n'))
550  gpgcharset[l - 1] = 0;
551  if (!mutt_ch_check_charset(gpgcharset, false))
552  mutt_str_replace(&gpgcharset, "UTF-8");
553  }
554  }
555 
556  /* leave fp_tmp open in case we still need it - but flush it! */
557  fflush(fp_tmp);
558 
559  /* Invoke PGP if needed */
560  if (!clearsign || (s->flags & MUTT_VERIFY))
561  {
562  fp_pgp_out = mutt_file_mkstemp();
563  if (!fp_pgp_out)
564  {
565  mutt_perror(_("Can't create temporary file"));
566  goto out;
567  }
568 
569  fp_pgp_err = mutt_file_mkstemp();
570  if (!fp_pgp_err)
571  {
572  mutt_perror(_("Can't create temporary file"));
573  goto out;
574  }
575 
576  pid = pgp_invoke_decode(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
577  fileno(fp_pgp_err), mutt_b2s(tmpfname), (needpass != 0));
578  if (pid == -1)
579  {
580  mutt_file_fclose(&fp_pgp_out);
581  maybe_goodsig = false;
582  fp_pgp_in = NULL;
584  s, _("[-- Error: unable to create PGP subprocess --]\n"));
585  }
586  else /* PGP started successfully */
587  {
588  if (needpass)
589  {
592  if (pgp_use_gpg_agent())
593  *PgpPass = '\0';
594  fprintf(fp_pgp_in, "%s\n", PgpPass);
595  }
596 
597  mutt_file_fclose(&fp_pgp_in);
598 
599  int wait_filter_rc = filter_wait(pid);
600 
601  fflush(fp_pgp_err);
602  /* If we are expecting an encrypted message, verify status fd output.
603  * Note that BEGIN PGP MESSAGE does not guarantee the content is encrypted,
604  * so we need to be more selective about the value of decrypt_okay_rc.
605  *
606  * -3 indicates we actively found a DECRYPTION_FAILED.
607  * -2 and -1 indicate part or all of the content was plaintext. */
608  if (needpass)
609  {
610  rewind(fp_pgp_err);
611  decrypt_okay_rc = pgp_check_decryption_okay(fp_pgp_err);
612  if (decrypt_okay_rc <= -3)
613  mutt_file_fclose(&fp_pgp_out);
614  }
615 
616  if (s->flags & MUTT_DISPLAY)
617  {
618  rewind(fp_pgp_err);
619  crypt_current_time(s, "PGP");
620  int checksig_rc = pgp_copy_checksig(fp_pgp_err, s->fp_out);
621 
622  if (checksig_rc == 0)
623  have_any_sigs = true;
624  /* Sig is bad if
625  * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
626  * Sig _is_ correct if
627  * gpg_good_sign="" && pgp_decode_command returned 0 */
628  if (checksig_rc == -1 || (wait_filter_rc != 0))
629  maybe_goodsig = false;
630 
631  state_attach_puts(s, _("[-- End of PGP output --]\n\n"));
632  }
633  if (pgp_use_gpg_agent())
635  }
636 
637  /* treat empty result as sign of failure */
638  /* TODO: maybe on failure neomutt should include the original undecoded text. */
639  if (fp_pgp_out)
640  {
641  rewind(fp_pgp_out);
642  c = fgetc(fp_pgp_out);
643  ungetc(c, fp_pgp_out);
644  }
645  if (!clearsign && (!fp_pgp_out || (c == EOF)))
646  {
647  could_not_decrypt = true;
649  }
650 
651  if ((could_not_decrypt || (decrypt_okay_rc <= -3)) && !(s->flags & MUTT_DISPLAY))
652  {
653  mutt_error(_("Could not decrypt PGP message"));
654  goto out;
655  }
656  }
657 
658  /* Now, copy cleartext to the screen. */
659  if (s->flags & MUTT_DISPLAY)
660  {
661  if (needpass)
662  state_attach_puts(s, _("[-- BEGIN PGP MESSAGE --]\n\n"));
663  else if (pgp_keyblock)
664  state_attach_puts(s, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
665  else
666  state_attach_puts(s, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
667  }
668 
669  if (clearsign)
670  {
671  rewind(fp_tmp);
672  pgp_copy_clearsigned(fp_tmp, s, body_charset);
673  }
674  else if (fp_pgp_out)
675  {
676  struct FgetConv *fc = NULL;
677  int ch;
678  char *expected_charset = (gpgcharset && *gpgcharset) ? gpgcharset : "utf-8";
679 
680  mutt_debug(LL_DEBUG3, "pgp: recoding inline from [%s] to [%s]\n",
681  expected_charset, C_Charset);
682 
683  rewind(fp_pgp_out);
684  state_set_prefix(s);
685  fc = mutt_ch_fgetconv_open(fp_pgp_out, expected_charset, C_Charset, MUTT_ICONV_HOOK_FROM);
686  while ((ch = mutt_ch_fgetconv(fc)) != EOF)
687  state_prefix_putc(s, ch);
689  }
690 
691  /* Multiple PGP blocks can exist, so these need to be closed and
692  * unlinked inside the loop. */
693  mutt_file_fclose(&fp_tmp);
694  mutt_file_unlink(mutt_b2s(tmpfname));
695  mutt_file_fclose(&fp_pgp_out);
696  mutt_file_fclose(&fp_pgp_err);
697 
698  if (s->flags & MUTT_DISPLAY)
699  {
700  state_putc(s, '\n');
701  if (needpass)
702  {
703  state_attach_puts(s, _("[-- END PGP MESSAGE --]\n"));
704  if (could_not_decrypt || (decrypt_okay_rc <= -3))
705  mutt_error(_("Could not decrypt PGP message"));
706  else if (decrypt_okay_rc < 0)
707  {
708  /* L10N: You will see this error message if (1) you are decrypting
709  (not encrypting) something and (2) it is a plaintext. So the
710  message does not mean "You failed to encrypt the message." */
711  mutt_error(_("PGP message is not encrypted"));
712  }
713  else
714  mutt_message(_("PGP message successfully decrypted"));
715  }
716  else if (pgp_keyblock)
717  state_attach_puts(s, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
718  else
719  state_attach_puts(s, _("[-- END PGP SIGNED MESSAGE --]\n"));
720  }
721  }
722  else
723  {
724  /* A traditional PGP part may mix signed and unsigned content */
725  /* XXX we may wish to recode here */
726  if (s->prefix)
727  state_puts(s, s->prefix);
728  state_puts(s, buf);
729  }
730  }
731 
732  rc = 0;
733 
734 out:
735  m->goodsig = (maybe_goodsig && have_any_sigs);
736 
737  if (fp_tmp)
738  {
739  mutt_file_fclose(&fp_tmp);
740  mutt_file_unlink(mutt_b2s(tmpfname));
741  }
742  mutt_file_fclose(&fp_pgp_out);
743  mutt_file_fclose(&fp_pgp_err);
744 
745  mutt_buffer_pool_release(&tmpfname);
746 
747  FREE(&gpgcharset);
748 
749  if (needpass == -1)
750  {
752  s, _("[-- Error: could not find beginning of PGP message --]\n\n"));
753  return -1;
754  }
755 
756  return rc;
757 }
758 
766 static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
767 {
768  struct Buffer *tempfile = NULL;
769  char buf[8192];
770  int rc = 0;
771 
772  bool sgn = false;
773  bool enc = false;
774  bool key = false;
775 
776  if (b->type != TYPE_TEXT)
777  goto cleanup;
778 
779  tempfile = mutt_buffer_pool_get();
780  mutt_buffer_mktemp(tempfile);
781  if (mutt_decode_save_attachment(fp, b, mutt_b2s(tempfile), 0, MUTT_SAVE_NO_FLAGS) != 0)
782  {
783  unlink(mutt_b2s(tempfile));
784  goto cleanup;
785  }
786 
787  FILE *fp_tmp = fopen(mutt_b2s(tempfile), "r");
788  if (!fp_tmp)
789  {
790  unlink(mutt_b2s(tempfile));
791  goto cleanup;
792  }
793 
794  while (fgets(buf, sizeof(buf), fp_tmp))
795  {
796  size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
797  if (plen != 0)
798  {
799  if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
800  enc = true;
801  else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
802  sgn = true;
803  else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
804  key = true;
805  }
806  }
807  mutt_file_fclose(&fp_tmp);
808  unlink(mutt_b2s(tempfile));
809 
810  if (!enc && !sgn && !key)
811  goto cleanup;
812 
813  /* fix the content type */
814 
815  mutt_param_set(&b->parameter, "format", "fixed");
816  if (enc)
817  mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
818  else if (sgn)
819  mutt_param_set(&b->parameter, "x-action", "pgp-signed");
820  else if (key)
821  mutt_param_set(&b->parameter, "x-action", "pgp-keys");
822 
823  rc = 1;
824 
825 cleanup:
826  mutt_buffer_pool_release(&tempfile);
827  return rc;
828 }
829 
833 int pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
834 {
835  int rc = 0;
836  int r;
837  for (; b; b = b->next)
838  {
839  if (!just_one && is_multipart(b))
840  rc = pgp_class_check_traditional(fp, b->parts, false) || rc;
841  else if (b->type == TYPE_TEXT)
842  {
844  if (r)
845  rc = rc || r;
846  else
847  rc = pgp_check_traditional_one_body(fp, b) || rc;
848  }
849 
850  if (just_one)
851  break;
852  }
853 
854  return rc;
855 }
856 
860 int pgp_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
861 {
862  FILE *fp_pgp_out = NULL;
863  pid_t pid;
864  int badsig = -1;
865  struct Buffer *sigfile = mutt_buffer_pool_get();
866 
867  mutt_buffer_printf(sigfile, "%s.asc", tempfile);
868 
869  FILE *fp_sig = mutt_file_fopen(mutt_b2s(sigfile), "w");
870  if (!fp_sig)
871  {
872  mutt_perror(mutt_b2s(sigfile));
873  goto cleanup;
874  }
875 
876  fseeko(s->fp_in, sigbdy->offset, SEEK_SET);
877  mutt_file_copy_bytes(s->fp_in, fp_sig, sigbdy->length);
878  mutt_file_fclose(&fp_sig);
879 
880  FILE *fp_pgp_err = mutt_file_mkstemp();
881  if (!fp_pgp_err)
882  {
883  mutt_perror(_("Can't create temporary file"));
884  unlink(mutt_b2s(sigfile));
885  goto cleanup;
886  }
887 
888  crypt_current_time(s, "PGP");
889 
890  pid = pgp_invoke_verify(NULL, &fp_pgp_out, NULL, -1, -1, fileno(fp_pgp_err),
891  tempfile, mutt_b2s(sigfile));
892  if (pid != -1)
893  {
894  if (pgp_copy_checksig(fp_pgp_out, s->fp_out) >= 0)
895  badsig = 0;
896 
897  mutt_file_fclose(&fp_pgp_out);
898  fflush(fp_pgp_err);
899  rewind(fp_pgp_err);
900 
901  if (pgp_copy_checksig(fp_pgp_err, s->fp_out) >= 0)
902  badsig = 0;
903 
904  const int rv = filter_wait(pid);
905  if (rv)
906  badsig = -1;
907 
908  mutt_debug(LL_DEBUG1, "filter_wait returned %d\n", rv);
909  }
910 
911  mutt_file_fclose(&fp_pgp_err);
912 
913  state_attach_puts(s, _("[-- End of PGP output --]\n\n"));
914 
915  mutt_file_unlink(mutt_b2s(sigfile));
916 
917 cleanup:
918  mutt_buffer_pool_release(&sigfile);
919 
920  mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
921  return badsig;
922 }
923 
929 static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *top)
930 {
931  struct State s = { 0 };
932  struct Buffer *tempfname = mutt_buffer_pool_get();
933 
934  mutt_buffer_mktemp(tempfname);
935  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tempfname), "w");
936  if (!fp_tmp)
937  {
938  mutt_perror(mutt_b2s(tempfname));
939  goto cleanup;
940  }
941 
942  s.fp_in = fp;
943  s.fp_out = fp_tmp;
944 
945  mutt_body_handler(top, &s);
946 
947  mutt_file_fclose(&fp_tmp);
948 
949  pgp_class_invoke_import(mutt_b2s(tempfname));
951 
952  mutt_file_unlink(mutt_b2s(tempfname));
953 
954 cleanup:
955  mutt_buffer_pool_release(&tempfname);
956 }
957 
961 void pgp_class_extract_key_from_attachment(FILE *fp, struct Body *top)
962 {
963  if (!fp)
964  {
965  mutt_error(_("Internal error. Please submit a bug report."));
966  return;
967  }
968 
969  mutt_endwin();
970 
971  OptDontHandlePgpKeys = true;
973  OptDontHandlePgpKeys = false;
974 }
975 
984 static struct Body *pgp_decrypt_part(struct Body *a, struct State *s,
985  FILE *fp_out, struct Body *p)
986 {
987  if (!a || !s || !fp_out || !p)
988  return NULL;
989 
990  char buf[1024];
991  FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_tmp = NULL;
992  struct stat info;
993  struct Body *tattach = NULL;
994  pid_t pid;
995  int rv;
996  struct Buffer *pgptmpfile = mutt_buffer_pool_get();
997 
998  FILE *fp_pgp_err = mutt_file_mkstemp();
999  if (!fp_pgp_err)
1000  {
1001  mutt_perror(_("Can't create temporary file"));
1002  goto cleanup;
1003  }
1004 
1005  mutt_buffer_mktemp(pgptmpfile);
1006  fp_pgp_tmp = mutt_file_fopen(mutt_b2s(pgptmpfile), "w");
1007  if (!fp_pgp_tmp)
1008  {
1009  mutt_perror(mutt_b2s(pgptmpfile));
1010  mutt_file_fclose(&fp_pgp_err);
1011  goto cleanup;
1012  }
1013 
1014  /* Position the stream at the beginning of the body, and send the data to
1015  * the temporary file. */
1016 
1017  fseeko(s->fp_in, a->offset, SEEK_SET);
1018  mutt_file_copy_bytes(s->fp_in, fp_pgp_tmp, a->length);
1019  mutt_file_fclose(&fp_pgp_tmp);
1020 
1021  pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1022  fileno(fp_pgp_err), mutt_b2s(pgptmpfile));
1023  if (pid == -1)
1024  {
1025  mutt_file_fclose(&fp_pgp_err);
1026  unlink(mutt_b2s(pgptmpfile));
1027  if (s->flags & MUTT_DISPLAY)
1028  {
1030  s, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1031  }
1032  goto cleanup;
1033  }
1034 
1035  /* send the PGP passphrase to the subprocess. Never do this if the agent is
1036  * active, because this might lead to a passphrase send as the message. */
1037  if (!pgp_use_gpg_agent())
1038  fputs(PgpPass, fp_pgp_in);
1039  fputc('\n', fp_pgp_in);
1040  mutt_file_fclose(&fp_pgp_in);
1041 
1042  /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1043  * read_mime_header has a hard time parsing the message. */
1044  while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1045  {
1046  size_t len = mutt_str_len(buf);
1047  if ((len > 1) && (buf[len - 2] == '\r'))
1048  strcpy(buf + len - 2, "\n");
1049  fputs(buf, fp_out);
1050  }
1051 
1052  mutt_file_fclose(&fp_pgp_out);
1053  rv = filter_wait(pid);
1054  mutt_file_unlink(mutt_b2s(pgptmpfile));
1055 
1056  fflush(fp_pgp_err);
1057  rewind(fp_pgp_err);
1058  if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1059  {
1060  mutt_error(_("Decryption failed"));
1062  mutt_file_fclose(&fp_pgp_err);
1063  goto cleanup;
1064  }
1065 
1066  if (s->flags & MUTT_DISPLAY)
1067  {
1068  rewind(fp_pgp_err);
1069  if ((pgp_copy_checksig(fp_pgp_err, s->fp_out) == 0) && !rv)
1070  p->goodsig = true;
1071  else
1072  p->goodsig = false;
1073  state_attach_puts(s, _("[-- End of PGP output --]\n\n"));
1074  }
1075  mutt_file_fclose(&fp_pgp_err);
1076 
1077  fflush(fp_out);
1078  rewind(fp_out);
1079 
1080  if (pgp_use_gpg_agent())
1082 
1083  if (fgetc(fp_out) == EOF)
1084  {
1085  mutt_error(_("Decryption failed"));
1087  goto cleanup;
1088  }
1089 
1090  rewind(fp_out);
1091 
1092  tattach = mutt_read_mime_header(fp_out, 0);
1093  if (tattach)
1094  {
1095  /* Need to set the length of this body part. */
1096  fstat(fileno(fp_out), &info);
1097  tattach->length = info.st_size - tattach->offset;
1098 
1099  /* See if we need to recurse on this MIME part. */
1100  mutt_parse_part(fp_out, tattach);
1101  }
1102 
1103 cleanup:
1104  mutt_buffer_pool_release(&pgptmpfile);
1105  return tattach;
1106 }
1107 
1111 int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
1112 {
1113  struct State s = { 0 };
1114  struct Body *p = b;
1115  bool need_decode = false;
1116  int saved_type = 0;
1117  LOFF_T saved_offset = 0;
1118  size_t saved_length = 0;
1119  FILE *fp_decoded = NULL;
1120  int rc = 0;
1121 
1123  {
1124  b = b->parts->next;
1125  /* Some clients improperly encode the octetstream part. */
1126  if (b->encoding != ENC_7BIT)
1127  need_decode = true;
1128  }
1130  {
1131  b = b->parts->next->next;
1132  need_decode = true;
1133  }
1134  else
1135  return -1;
1136 
1137  s.fp_in = fp_in;
1138 
1139  if (need_decode)
1140  {
1141  saved_type = b->type;
1142  saved_offset = b->offset;
1143  saved_length = b->length;
1144 
1145  fp_decoded = mutt_file_mkstemp();
1146  if (!fp_decoded)
1147  {
1148  mutt_perror(_("Can't create temporary file"));
1149  return -1;
1150  }
1151 
1152  fseeko(s.fp_in, b->offset, SEEK_SET);
1153  s.fp_out = fp_decoded;
1154 
1155  mutt_decode_attachment(b, &s);
1156 
1157  fflush(fp_decoded);
1158  b->length = ftello(fp_decoded);
1159  b->offset = 0;
1160  rewind(fp_decoded);
1161  s.fp_in = fp_decoded;
1162  s.fp_out = 0;
1163  }
1164 
1165  *fp_out = mutt_file_mkstemp();
1166  if (!*fp_out)
1167  {
1168  mutt_perror(_("Can't create temporary file"));
1169  rc = -1;
1170  goto bail;
1171  }
1172 
1173  *cur = pgp_decrypt_part(b, &s, *fp_out, p);
1174  if (!*cur)
1175  rc = -1;
1176  rewind(*fp_out);
1177 
1178 bail:
1179  if (need_decode)
1180  {
1181  b->type = saved_type;
1182  b->length = saved_length;
1183  b->offset = saved_offset;
1184  mutt_file_fclose(&fp_decoded);
1185  }
1186 
1187  return rc;
1188 }
1189 
1193 int pgp_class_encrypted_handler(struct Body *a, struct State *s)
1194 {
1195  FILE *fp_in = NULL;
1196  struct Body *tattach = NULL;
1197  int rc = 0;
1198 
1199  FILE *fp_out = mutt_file_mkstemp();
1200  if (!fp_out)
1201  {
1202  mutt_perror(_("Can't create temporary file"));
1203  if (s->flags & MUTT_DISPLAY)
1204  {
1206  _("[-- Error: could not create temporary file --]\n"));
1207  }
1208  return -1;
1209  }
1210 
1211  if (s->flags & MUTT_DISPLAY)
1212  crypt_current_time(s, "PGP");
1213 
1214  tattach = pgp_decrypt_part(a, s, fp_out, a);
1215  if (tattach)
1216  {
1217  if (s->flags & MUTT_DISPLAY)
1218  {
1220  s, _("[-- The following data is PGP/MIME encrypted --]\n\n"));
1221  mutt_protected_headers_handler(tattach, s);
1222  }
1223 
1224  /* Store any protected headers in the parent so they can be
1225  * accessed for index updates after the handler recursion is done.
1226  * This is done before the handler to prevent a nested encrypted
1227  * handler from freeing the headers. */
1229  a->mime_headers = tattach->mime_headers;
1230  tattach->mime_headers = NULL;
1231 
1232  fp_in = s->fp_in;
1233  s->fp_in = fp_out;
1234  rc = mutt_body_handler(tattach, s);
1235  s->fp_in = fp_in;
1236 
1237  /* Embedded multipart signed protected headers override the
1238  * encrypted headers. We need to do this after the handler so
1239  * they can be printed in the pager. */
1240  if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
1241  {
1243  a->mime_headers = tattach->parts->mime_headers;
1244  tattach->parts->mime_headers = NULL;
1245  }
1246 
1247  /* if a multipart/signed is the _only_ sub-part of a
1248  * multipart/encrypted, cache signature verification
1249  * status. */
1250  if (mutt_is_multipart_signed(tattach) && !tattach->next)
1251  a->goodsig |= tattach->goodsig;
1252 
1253  if (s->flags & MUTT_DISPLAY)
1254  {
1255  state_puts(s, "\n");
1256  state_attach_puts(s, _("[-- End of PGP/MIME encrypted data --]\n"));
1257  }
1258 
1259  mutt_body_free(&tattach);
1260  /* clear 'Invoking...' message, since there's no error */
1261  mutt_message(_("PGP message successfully decrypted"));
1262  }
1263  else
1264  {
1265  mutt_error(_("Could not decrypt PGP message"));
1266  /* void the passphrase, even if it's not necessarily the problem */
1268  rc = -1;
1269  }
1270 
1271  mutt_file_fclose(&fp_out);
1272 
1273  return rc;
1274 }
1275 
1276 /* ----------------------------------------------------------------------------
1277  * Routines for sending PGP/MIME messages.
1278  */
1279 
1283 struct Body *pgp_class_sign_message(struct Body *a, const struct AddressList *from)
1284 {
1285  struct Body *t = NULL, *rv = NULL;
1286  char buf[1024];
1287  FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_err = NULL, *fp_signed = NULL;
1288  bool err = false;
1289  bool empty = true;
1290  pid_t pid;
1291  struct Buffer *sigfile = mutt_buffer_pool_get();
1292  struct Buffer *signedfile = mutt_buffer_pool_get();
1293 
1294  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1295 
1296  mutt_buffer_mktemp(sigfile);
1297  FILE *fp_sig = mutt_file_fopen(mutt_b2s(sigfile), "w");
1298  if (!fp_sig)
1299  {
1300  goto cleanup;
1301  }
1302 
1303  mutt_buffer_mktemp(signedfile);
1304  fp_signed = mutt_file_fopen(mutt_b2s(signedfile), "w");
1305  if (!fp_signed)
1306  {
1307  mutt_perror(mutt_b2s(signedfile));
1308  mutt_file_fclose(&fp_sig);
1309  unlink(mutt_b2s(sigfile));
1310  goto cleanup;
1311  }
1312 
1313  mutt_write_mime_header(a, fp_signed, NeoMutt->sub);
1314  fputc('\n', fp_signed);
1315  mutt_write_mime_body(a, fp_signed, NeoMutt->sub);
1316  mutt_file_fclose(&fp_signed);
1317 
1318  pid = pgp_invoke_sign(&fp_pgp_in, &fp_pgp_out, &fp_pgp_err, -1, -1, -1,
1319  mutt_b2s(signedfile));
1320  if (pid == -1)
1321  {
1322  mutt_perror(_("Can't open PGP subprocess"));
1323  mutt_file_fclose(&fp_sig);
1324  unlink(mutt_b2s(sigfile));
1325  unlink(mutt_b2s(signedfile));
1326  goto cleanup;
1327  }
1328 
1329  if (!pgp_use_gpg_agent())
1330  fputs(PgpPass, fp_pgp_in);
1331  fputc('\n', fp_pgp_in);
1332  mutt_file_fclose(&fp_pgp_in);
1333 
1334  /* Read back the PGP signature. Also, change MESSAGE=>SIGNATURE as
1335  * recommended for future releases of PGP. */
1336  while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1337  {
1338  if (mutt_str_equal("-----BEGIN PGP MESSAGE-----\n", buf))
1339  fputs("-----BEGIN PGP SIGNATURE-----\n", fp_sig);
1340  else if (mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
1341  fputs("-----END PGP SIGNATURE-----\n", fp_sig);
1342  else
1343  fputs(buf, fp_sig);
1344  empty = false; /* got some output, so we're ok */
1345  }
1346 
1347  /* check for errors from PGP */
1348  err = false;
1349  while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1350  {
1351  err = true;
1352  fputs(buf, stdout);
1353  }
1354 
1355  if (filter_wait(pid) && C_PgpCheckExit)
1356  empty = true;
1357 
1358  mutt_file_fclose(&fp_pgp_err);
1359  mutt_file_fclose(&fp_pgp_out);
1360  unlink(mutt_b2s(signedfile));
1361 
1362  if (mutt_file_fclose(&fp_sig) != 0)
1363  {
1364  mutt_perror("fclose");
1365  unlink(mutt_b2s(sigfile));
1366  goto cleanup;
1367  }
1368 
1369  if (err)
1371  if (empty)
1372  {
1373  unlink(mutt_b2s(sigfile));
1374  /* most likely error is a bad passphrase, so automatically forget it */
1376  goto cleanup; /* fatal error while signing */
1377  }
1378 
1379  t = mutt_body_new();
1380  t->type = TYPE_MULTIPART;
1381  t->subtype = mutt_str_dup("signed");
1382  t->encoding = ENC_7BIT;
1383  t->use_disp = false;
1384  t->disposition = DISP_INLINE;
1385  rv = t;
1386 
1388  mutt_param_set(&t->parameter, "protocol", "application/pgp-signature");
1389  mutt_param_set(&t->parameter, "micalg", pgp_micalg(mutt_b2s(sigfile)));
1390 
1391  t->parts = a;
1392 
1393  t->parts->next = mutt_body_new();
1394  t = t->parts->next;
1395  t->type = TYPE_APPLICATION;
1396  t->subtype = mutt_str_dup("pgp-signature");
1397  t->filename = mutt_buffer_strdup(sigfile);
1398  t->use_disp = false;
1399  t->disposition = DISP_NONE;
1400  t->encoding = ENC_7BIT;
1401  t->unlink = true; /* ok to remove this file after sending. */
1402  mutt_param_set(&t->parameter, "name", "signature.asc");
1403 
1404 cleanup:
1405  mutt_buffer_pool_release(&sigfile);
1406  mutt_buffer_pool_release(&signedfile);
1407  return rv;
1408 }
1409 
1413 char *pgp_class_find_keys(struct AddressList *addrlist, bool oppenc_mode)
1414 {
1415  struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
1416  struct ListNode *crypt_hook = NULL;
1417  const char *keyid = NULL;
1418  char *keylist = NULL;
1419  size_t keylist_size = 0;
1420  size_t keylist_used = 0;
1421  struct Address *p = NULL;
1422  struct PgpKeyInfo *k_info = NULL;
1423  const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
1424  char buf[1024];
1425  bool key_selected;
1426  struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
1427 
1428  struct Address *a = NULL;
1429  TAILQ_FOREACH(a, addrlist, entries)
1430  {
1431  key_selected = false;
1432  mutt_crypt_hook(&crypt_hook_list, a);
1433  crypt_hook = STAILQ_FIRST(&crypt_hook_list);
1434  do
1435  {
1436  p = a;
1437  k_info = NULL;
1438 
1439  if (crypt_hook)
1440  {
1441  keyid = crypt_hook->data;
1442  enum QuadOption ans = MUTT_YES;
1443  if (!oppenc_mode && C_CryptConfirmhook)
1444  {
1445  snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
1446  ans = mutt_yesorno(buf, MUTT_YES);
1447  }
1448  if (ans == MUTT_YES)
1449  {
1450  if (crypt_is_numerical_keyid(keyid))
1451  {
1452  if (mutt_strn_equal(keyid, "0x", 2))
1453  keyid += 2;
1454  goto bypass_selection; /* you don't see this. */
1455  }
1456 
1457  /* check for e-mail address */
1458  mutt_addrlist_clear(&hookal);
1459  if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
1460  {
1461  mutt_addrlist_qualify(&hookal, fqdn);
1462  p = TAILQ_FIRST(&hookal);
1463  }
1464  else if (!oppenc_mode)
1465  {
1467  }
1468  }
1469  else if (ans == MUTT_NO)
1470  {
1471  if (key_selected || STAILQ_NEXT(crypt_hook, entries))
1472  {
1473  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1474  continue;
1475  }
1476  }
1477  else if (ans == MUTT_ABORT)
1478  {
1479  FREE(&keylist);
1480  mutt_addrlist_clear(&hookal);
1481  mutt_list_free(&crypt_hook_list);
1482  return NULL;
1483  }
1484  }
1485 
1486  if (!k_info)
1487  {
1489  k_info = pgp_getkeybyaddr(p, KEYFLAG_CANENCRYPT, PGP_PUBRING, oppenc_mode);
1490  }
1491 
1492  if (!k_info && !oppenc_mode)
1493  {
1494  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
1496  }
1497 
1498  if (!k_info)
1499  {
1500  FREE(&keylist);
1501  mutt_addrlist_clear(&hookal);
1502  mutt_list_free(&crypt_hook_list);
1503  return NULL;
1504  }
1505 
1506  keyid = pgp_fpr_or_lkeyid(k_info);
1507 
1508  bypass_selection:
1509  keylist_size += mutt_str_len(keyid) + 4;
1510  mutt_mem_realloc(&keylist, keylist_size);
1511  sprintf(keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", keyid);
1512  keylist_used = mutt_str_len(keylist);
1513 
1514  key_selected = true;
1515 
1516  pgp_key_free(&k_info);
1517  mutt_addrlist_clear(&hookal);
1518 
1519  if (crypt_hook)
1520  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1521 
1522  } while (crypt_hook);
1523 
1524  mutt_list_free(&crypt_hook_list);
1525  }
1526  return keylist;
1527 }
1528 
1535 struct Body *pgp_class_encrypt_message(struct Body *a, char *keylist, bool sign,
1536  const struct AddressList *from)
1537 {
1538  char buf[1024];
1539  FILE *fp_pgp_in = NULL, *fp_tmp = NULL;
1540  struct Body *t = NULL;
1541  int err = 0;
1542  bool empty = false;
1543  pid_t pid;
1544  struct Buffer *tempfile = mutt_buffer_pool_get();
1545  struct Buffer *pgpinfile = mutt_buffer_pool_get();
1546 
1547  mutt_buffer_mktemp(tempfile);
1548  FILE *fp_out = mutt_file_fopen(mutt_b2s(tempfile), "w+");
1549  if (!fp_out)
1550  {
1551  mutt_perror(mutt_b2s(tempfile));
1552  goto cleanup;
1553  }
1554 
1555  FILE *fp_pgp_err = mutt_file_mkstemp();
1556  if (!fp_pgp_err)
1557  {
1558  mutt_perror(_("Can't create temporary file"));
1559  unlink(mutt_b2s(tempfile));
1560  mutt_file_fclose(&fp_out);
1561  goto cleanup;
1562  }
1563 
1564  mutt_buffer_mktemp(pgpinfile);
1565  fp_tmp = mutt_file_fopen(mutt_b2s(pgpinfile), "w");
1566  if (!fp_tmp)
1567  {
1568  mutt_perror(mutt_b2s(pgpinfile));
1569  unlink(mutt_b2s(tempfile));
1570  mutt_file_fclose(&fp_out);
1571  mutt_file_fclose(&fp_pgp_err);
1572  goto cleanup;
1573  }
1574 
1575  if (sign)
1577 
1578  mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
1579  fputc('\n', fp_tmp);
1580  mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
1581  mutt_file_fclose(&fp_tmp);
1582 
1583  pid = pgp_invoke_encrypt(&fp_pgp_in, NULL, NULL, -1, fileno(fp_out),
1584  fileno(fp_pgp_err), mutt_b2s(pgpinfile), keylist, sign);
1585  if (pid == -1)
1586  {
1587  mutt_file_fclose(&fp_out);
1588  mutt_file_fclose(&fp_pgp_err);
1589  unlink(mutt_b2s(pgpinfile));
1590  goto cleanup;
1591  }
1592 
1593  if (sign)
1594  {
1595  if (!pgp_use_gpg_agent())
1596  fputs(PgpPass, fp_pgp_in);
1597  fputc('\n', fp_pgp_in);
1598  }
1599  mutt_file_fclose(&fp_pgp_in);
1600 
1601  if (filter_wait(pid) && C_PgpCheckExit)
1602  empty = true;
1603 
1604  unlink(mutt_b2s(pgpinfile));
1605 
1606  fflush(fp_out);
1607  rewind(fp_out);
1608  if (!empty)
1609  empty = (fgetc(fp_out) == EOF);
1610  mutt_file_fclose(&fp_out);
1611 
1612  fflush(fp_pgp_err);
1613  rewind(fp_pgp_err);
1614  while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1615  {
1616  err = 1;
1617  fputs(buf, stdout);
1618  }
1619  mutt_file_fclose(&fp_pgp_err);
1620 
1621  /* pause if there is any error output from PGP */
1622  if (err)
1624 
1625  if (empty)
1626  {
1627  /* fatal error while trying to encrypt message */
1628  if (sign)
1629  pgp_class_void_passphrase(); /* just in case */
1630  unlink(mutt_b2s(tempfile));
1631  goto cleanup;
1632  }
1633 
1634  t = mutt_body_new();
1635  t->type = TYPE_MULTIPART;
1636  t->subtype = mutt_str_dup("encrypted");
1637  t->encoding = ENC_7BIT;
1638  t->use_disp = false;
1639  t->disposition = DISP_INLINE;
1640 
1642  mutt_param_set(&t->parameter, "protocol", "application/pgp-encrypted");
1643 
1644  t->parts = mutt_body_new();
1645  t->parts->type = TYPE_APPLICATION;
1646  t->parts->subtype = mutt_str_dup("pgp-encrypted");
1647  t->parts->encoding = ENC_7BIT;
1648 
1649  t->parts->next = mutt_body_new();
1651  t->parts->next->subtype = mutt_str_dup("octet-stream");
1652  t->parts->next->encoding = ENC_7BIT;
1653  t->parts->next->filename = mutt_buffer_strdup(tempfile);
1654  t->parts->next->use_disp = true;
1656  t->parts->next->unlink = true; /* delete after sending the message */
1657  t->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime can save */
1658 
1659 cleanup:
1660  mutt_buffer_pool_release(&tempfile);
1661  mutt_buffer_pool_release(&pgpinfile);
1662  return t;
1663 }
1664 
1668 struct Body *pgp_class_traditional_encryptsign(struct Body *a, SecurityFlags flags, char *keylist)
1669 {
1670  struct Body *b = NULL;
1671  char body_charset[256];
1672  char *from_charset = NULL;
1673  const char *send_charset = NULL;
1674  bool empty = false;
1675  bool err;
1676  char buf[256];
1677  pid_t pid;
1678  struct Buffer *pgpinfile = mutt_buffer_pool_get();
1679  struct Buffer *pgpoutfile = mutt_buffer_pool_get();
1680 
1681  if (a->type != TYPE_TEXT)
1682  goto cleanup;
1683  if (!mutt_istr_equal(a->subtype, "plain"))
1684  goto cleanup;
1685 
1686  FILE *fp_body = fopen(a->filename, "r");
1687  if (!fp_body)
1688  {
1689  mutt_perror(a->filename);
1690  goto cleanup;
1691  }
1692 
1693  mutt_buffer_mktemp(pgpinfile);
1694  FILE *fp_pgp_in = mutt_file_fopen(mutt_b2s(pgpinfile), "w");
1695  if (!fp_pgp_in)
1696  {
1697  mutt_perror(mutt_b2s(pgpinfile));
1698  mutt_file_fclose(&fp_body);
1699  goto cleanup;
1700  }
1701 
1702  /* The following code is really correct: If noconv is set,
1703  * a's charset parameter contains the on-disk character set, and
1704  * we have to convert from that to utf-8. If noconv is not set,
1705  * we have to convert from $charset to utf-8. */
1706 
1707  mutt_body_get_charset(a, body_charset, sizeof(body_charset));
1708  if (a->noconv)
1709  from_charset = body_charset;
1710  else
1711  from_charset = C_Charset;
1712 
1713  if (!mutt_ch_is_us_ascii(body_charset))
1714  {
1715  int c;
1716  struct FgetConv *fc = NULL;
1717 
1718  if (flags & SEC_ENCRYPT)
1719  send_charset = "us-ascii";
1720  else
1721  send_charset = "utf-8";
1722 
1723  /* fromcode is assumed to be correct: we set flags to 0 */
1724  fc = mutt_ch_fgetconv_open(fp_body, from_charset, "utf-8", 0);
1725  while ((c = mutt_ch_fgetconv(fc)) != EOF)
1726  fputc(c, fp_pgp_in);
1727 
1729  }
1730  else
1731  {
1732  send_charset = "us-ascii";
1733  mutt_file_copy_stream(fp_body, fp_pgp_in);
1734  }
1735  mutt_file_fclose(&fp_body);
1736  mutt_file_fclose(&fp_pgp_in);
1737 
1738  mutt_buffer_mktemp(pgpoutfile);
1739  FILE *fp_pgp_out = mutt_file_fopen(mutt_b2s(pgpoutfile), "w+");
1740  FILE *fp_pgp_err = mutt_file_mkstemp();
1741  if (!fp_pgp_out || !fp_pgp_err)
1742  {
1743  mutt_perror(fp_pgp_out ? "Can't create temporary file" : mutt_b2s(pgpoutfile));
1744  unlink(mutt_b2s(pgpinfile));
1745  if (fp_pgp_out)
1746  {
1747  mutt_file_fclose(&fp_pgp_out);
1748  unlink(mutt_b2s(pgpoutfile));
1749  }
1750  mutt_file_fclose(&fp_pgp_err);
1751  goto cleanup;
1752  }
1753 
1754  pid = pgp_invoke_traditional(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
1755  fileno(fp_pgp_err), mutt_b2s(pgpinfile), keylist, flags);
1756  if (pid == -1)
1757  {
1758  mutt_perror(_("Can't invoke PGP"));
1759  mutt_file_fclose(&fp_pgp_out);
1760  mutt_file_fclose(&fp_pgp_err);
1761  mutt_file_unlink(mutt_b2s(pgpinfile));
1762  unlink(mutt_b2s(pgpoutfile));
1763  goto cleanup;
1764  }
1765 
1766  if (pgp_use_gpg_agent())
1767  *PgpPass = '\0';
1768  if (flags & SEC_SIGN)
1769  fprintf(fp_pgp_in, "%s\n", PgpPass);
1770  mutt_file_fclose(&fp_pgp_in);
1771 
1772  if (filter_wait(pid) && C_PgpCheckExit)
1773  empty = true;
1774 
1775  mutt_file_unlink(mutt_b2s(pgpinfile));
1776 
1777  fflush(fp_pgp_out);
1778  fflush(fp_pgp_err);
1779 
1780  rewind(fp_pgp_out);
1781  rewind(fp_pgp_err);
1782 
1783  if (!empty)
1784  empty = (fgetc(fp_pgp_out) == EOF);
1785  mutt_file_fclose(&fp_pgp_out);
1786 
1787  err = false;
1788 
1789  while (fgets(buf, sizeof(buf), fp_pgp_err))
1790  {
1791  err = true;
1792  fputs(buf, stdout);
1793  }
1794 
1795  mutt_file_fclose(&fp_pgp_err);
1796 
1797  if (err)
1799 
1800  if (empty)
1801  {
1802  if (flags & SEC_SIGN)
1803  pgp_class_void_passphrase(); /* just in case */
1804  unlink(mutt_b2s(pgpoutfile));
1805  goto cleanup;
1806  }
1807 
1808  b = mutt_body_new();
1809 
1810  b->encoding = ENC_7BIT;
1811 
1812  b->type = TYPE_TEXT;
1813  b->subtype = mutt_str_dup("plain");
1814 
1815  mutt_param_set(&b->parameter, "x-action",
1816  (flags & SEC_ENCRYPT) ? "pgp-encrypted" : "pgp-signed");
1817  mutt_param_set(&b->parameter, "charset", send_charset);
1818 
1819  b->filename = mutt_buffer_strdup(pgpoutfile);
1820 
1821  b->disposition = DISP_NONE;
1822  b->unlink = true;
1823 
1824  b->noconv = true;
1825  b->use_disp = false;
1826 
1827  if (!(flags & SEC_ENCRYPT))
1828  b->encoding = a->encoding;
1829 
1830 cleanup:
1831  mutt_buffer_pool_release(&pgpinfile);
1832  mutt_buffer_pool_release(&pgpoutfile);
1833  return b;
1834 }
1835 
1840 {
1841  struct PgpKeyInfo *p = NULL;
1842  const char *prompt = NULL;
1843  const char *letters = NULL;
1844  const char *choices = NULL;
1845  char promptbuf[1024];
1846  int choice;
1847 
1848  if (!(WithCrypto & APPLICATION_PGP))
1849  return e->security;
1850 
1851  /* If autoinline and no crypto options set, then set inline. */
1852  if (C_PgpAutoinline &&
1853  !((e->security & APPLICATION_PGP) && (e->security & (SEC_SIGN | SEC_ENCRYPT))))
1854  {
1855  e->security |= SEC_INLINE;
1856  }
1857 
1858  e->security |= APPLICATION_PGP;
1859 
1860  char *mime_inline = NULL;
1861  if (e->security & SEC_INLINE)
1862  {
1863  /* L10N: The next string MUST have the same highlighted letter
1864  One of them will appear in each of the three strings marked "(inline"), below. */
1865  mime_inline = _("PGP/M(i)ME");
1866  }
1867  else
1868  {
1869  /* L10N: The previous string MUST have the same highlighted letter
1870  One of them will appear in each of the three strings marked "(inline"), below. */
1871  mime_inline = _("(i)nline");
1872  }
1873  /* Opportunistic encrypt is controlling encryption. Allow to toggle
1874  * between inline and mime, but not turn encryption on or off.
1875  * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
1876  * letter choices for those. */
1878  {
1879  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1880  {
1881  snprintf(promptbuf, sizeof(promptbuf),
1882  /* L10N: PGP options (inline) (opportunistic encryption is on) */
1883  _("PGP (s)ign, sign (a)s, %s format, (c)lear, or (o)ppenc mode "
1884  "off?"),
1885  mime_inline);
1886  prompt = promptbuf;
1887  /* L10N: PGP options (inline) (opportunistic encryption is on)
1888  The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1889  letters = _("saico");
1890  choices = "SaiCo";
1891  }
1892  else
1893  {
1894  /* L10N: PGP options (opportunistic encryption is on) */
1895  prompt = _("PGP (s)ign, sign (a)s, (c)lear, or (o)ppenc mode off?");
1896  /* L10N: PGP options (opportunistic encryption is on) */
1897  letters = _("saco");
1898  choices = "SaCo";
1899  }
1900  }
1901  /* Opportunistic encryption option is set, but is toggled off
1902  * for this message. */
1903  else if (C_CryptOpportunisticEncrypt)
1904  {
1905  /* When the message is not selected for signing or encryption, the toggle
1906  * between PGP/MIME and Traditional doesn't make sense. */
1907  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1908  {
1909  snprintf(promptbuf, sizeof(promptbuf),
1910  /* L10N: PGP options (inline) (opportunistic encryption is off) */
1911  _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, "
1912  "(c)lear, or (o)ppenc mode?"),
1913  mime_inline);
1914  prompt = promptbuf;
1915  /* L10N: PGP options (inline) (opportunistic encryption is off)
1916  The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1917  letters = _("esabico");
1918  choices = "esabicO";
1919  }
1920  else
1921  {
1922  /* L10N: PGP options (opportunistic encryption is off) */
1923  prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (c)lear, or "
1924  "(o)ppenc mode?");
1925  /* L10N: PGP options (opportunistic encryption is off) */
1926  letters = _("esabco");
1927  choices = "esabcO";
1928  }
1929  }
1930  /* Opportunistic encryption is unset */
1931  else
1932  {
1933  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1934  {
1935  snprintf(promptbuf, sizeof(promptbuf),
1936  /* L10N: PGP options (inline) */
1937  _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, or "
1938  "(c)lear?"),
1939  mime_inline);
1940  prompt = promptbuf;
1941  /* L10N: PGP options (inline)
1942  The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1943  letters = _("esabic");
1944  choices = "esabic";
1945  }
1946  else
1947  {
1948  /* L10N: PGP options */
1949  prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (c)lear?");
1950  /* L10N: PGP options */
1951  letters = _("esabc");
1952  choices = "esabc";
1953  }
1954  }
1955 
1956  choice = mutt_multi_choice(prompt, letters);
1957  if (choice > 0)
1958  {
1959  switch (choices[choice - 1])
1960  {
1961  case 'a': /* sign (a)s */
1962  OptPgpCheckTrust = false;
1963 
1964  p = pgp_ask_for_key(_("Sign as: "), NULL, KEYFLAG_NO_FLAGS, PGP_SECRING);
1965  if (p)
1966  {
1967  char input_signas[128];
1968  snprintf(input_signas, sizeof(input_signas), "0x%s", pgp_fpr_or_lkeyid(p));
1969  mutt_str_replace(&C_PgpSignAs, input_signas);
1970  pgp_key_free(&p);
1971 
1972  e->security |= SEC_SIGN;
1973 
1974  crypt_pgp_void_passphrase(); /* probably need a different passphrase */
1975  }
1976  break;
1977 
1978  case 'b': /* (b)oth */
1979  e->security |= (SEC_ENCRYPT | SEC_SIGN);
1980  break;
1981 
1982  case 'C':
1983  e->security &= ~SEC_SIGN;
1984  break;
1985 
1986  case 'c': /* (c)lear */
1987  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
1988  break;
1989 
1990  case 'e': /* (e)ncrypt */
1991  e->security |= SEC_ENCRYPT;
1992  e->security &= ~SEC_SIGN;
1993  break;
1994 
1995  case 'i': /* toggle (i)nline */
1996  e->security ^= SEC_INLINE;
1997  break;
1998 
1999  case 'O': /* oppenc mode on */
2000  e->security |= SEC_OPPENCRYPT;
2002  break;
2003 
2004  case 'o': /* oppenc mode off */
2005  e->security &= ~SEC_OPPENCRYPT;
2006  break;
2007 
2008  case 'S': /* (s)ign in oppenc mode */
2009  e->security |= SEC_SIGN;
2010  break;
2011 
2012  case 's': /* (s)ign */
2013  e->security &= ~SEC_ENCRYPT;
2014  e->security |= SEC_SIGN;
2015  break;
2016  }
2017  }
2018 
2019  return e->security;
2020 }
int mutt_protected_headers_handler(struct Body *a, struct State *s)
Process a protected header - Implements handler_t.
Definition: crypt.c:1085
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:414
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1835
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:691
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
bool C_PgpUseGpgAgent
Config: Use a PGP agent for caching passwords.
Definition: config.c:75
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
Secret keys.
Definition: pgpkey.h:38
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
#define WithCrypto
Definition: lib.h:118
The envelope/body of an email.
Definition: email.h:37
#define state_puts(STATE, STR)
Definition: state.h:55
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:716
int pgp_class_send_menu(struct Email *e)
Implements CryptModuleSpecs::send_menu()
Definition: pgp.c:1839
#define mutt_perror(...)
Definition: logging.h:85
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
PGP key management routines.
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:908
Structs that make up an email.
#define is_multipart(body)
Definition: mime.h:77
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
Convenience wrapper for the send headers.
User aborted the question (with Ctrl-G)
Definition: quad.h:38
7-bit text
Definition: mime.h:49
#define mutt_message(...)
Definition: logging.h:83
#define mutt_get_password(msg, buf, buflen)
Definition: curs_lib.h:92
static int pgp_check_decryption_okay(FILE *fp_in)
Check GPG output for status codes.
Definition: pgp.c:338
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
Wrapper around crypto functions.
void crypt_pgp_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:187
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:799
No flags set.
Definition: mutt_attach.h:55
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
char * pgp_keyid(struct PgpKeyInfo *k)
Get the ID of the main (parent) key.
Definition: pgp.c:191
int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Implements CryptModuleSpecs::decrypt_mime()
Definition: pgp.c:1111
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1345
regex_t * regex
compiled expression
Definition: regex3.h:91
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
#define KEYFLAG_SUBKEY
Key is a subkey.
Definition: lib.h:136
String manipulation buffer.
Definition: buffer.h:33
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:469
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
char PgpPass[1024]
Definition: pgp.c:69
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
pid_t pgp_invoke_traditional(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *uids, SecurityFlags flags)
Use PGP to create in inline-signed message.
Definition: pgpinvoke.c:372
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition: charset.c:818
struct Body * next
next attachment in the list
Definition: body.h:53
An email address.
Definition: address.h:34
FILE * fp_out
File to write to.
Definition: state.h:47
char * mailbox
Mailbox and host address.
Definition: address.h:37
KeyFlags flags
Definition: pgplib.h:51
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:78
int pgp_class_encrypted_handler(struct Body *a, struct State *s)
Implements CryptModuleSpecs::encrypted_handler()
Definition: pgp.c:1193
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Wrapper around calls to external PGP program.
Shared constants/structs that are private to libconn.
static int pgp_check_pgp_decryption_okay_regex(FILE *fp_in)
Check PGP output to look for successful outcome.
Definition: pgp.c:287
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:130
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
Convenience wrapper for the config headers.
char * keyid
Definition: pgplib.h:48
Email Address Handling.
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:87
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Some miscellaneous functions.
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
Information about a PGP key.
Definition: pgplib.h:46
pid_t pgp_invoke_decrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to decrypt a file.
Definition: pgpinvoke.c:293
time_t mutt_date_add_timeout(time_t now, time_t timeout)
Safely add a timeout to a given time_t value.
Definition: date.c:623
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
Parse and execute user-defined hooks.
bool C_CryptOpportunisticEncrypt
Config: Enable encryption when the recipient&#39;s key is available.
Definition: config.c:41
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
char * pgp_short_keyid(struct PgpKeyInfo *k)
Get a key&#39;s short id.
Definition: pgp.c:165
void pgp_class_extract_key_from_attachment(FILE *fp, struct Body *top)
Implements CryptModuleSpecs::pgp_extract_key_from_attachment()
Definition: pgp.c:961
static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *top)
Extract pgp keys from messages/attachments.
Definition: pgp.c:929
void pgp_class_void_passphrase(void)
Implements CryptModuleSpecs::void_passphrase()
Definition: pgp.c:75
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
Convenience wrapper for the core headers.
char * C_PgpSignAs
Config: Use this alternative key for signing messages.
Definition: config.c:52
void crypt_current_time(struct State *s, const char *app_name)
Print the current time.
Definition: crypt.c:71
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:85
pid_t pgp_invoke_verify(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *sig_fname)
Use PGP to verify a message.
Definition: pgpinvoke.c:270
static char * pgp_fingerprint(struct PgpKeyInfo *k)
Get the key&#39;s fingerprint.
Definition: pgp.c:203
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:745
pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, bool need_passphrase)
Use PGP to decode a message.
Definition: pgpinvoke.c:246
Content is attached.
Definition: mime.h:63
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:755
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: body.c:131
WHERE bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition: options.h:36
void pgp_key_free(struct PgpKeyInfo **kpp)
Free a PGP key info.
Definition: pgplib.c:213
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:405
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
void pgp_class_invoke_import(const char *fname)
Implements CryptModuleSpecs::pgp_invoke_import()
Definition: pgpinvoke.c:392
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct PgpKeyInfo * pgp_getkeybyaddr(struct Address *a, KeyFlags abilities, enum PgpRing keyring, bool oppenc_mode)
Find a PGP key by address.
Definition: pgpkey.c:1028
char * subtype
content-type subtype
Definition: body.h:37
int pgp_class_application_handler(struct Body *m, struct State *s)
Implements CryptModuleSpecs::application_handler()
Definition: pgp.c:450
#define mutt_b2s(buf)
Definition: buffer.h:41
bool goodsig
Good cryptographic signature.
Definition: body.h:75
struct Body * pgp_class_sign_message(struct Body *a, const struct AddressList *from)
Implements CryptModuleSpecs::sign_message()
Definition: pgp.c:1283
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:930
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:550
static struct Body * pgp_decrypt_part(struct Body *a, struct State *s, FILE *fp_out, struct Body *p)
Decrypt part of a PGP message.
Definition: pgp.c:984
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
int pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
Implements CryptModuleSpecs::pgp_check_traditional()
Definition: pgp.c:833
Signing/encryption multiplexor.
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
FILE * fp
Definition: charset.h:43
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:569
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:128
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
static struct PgpKeyInfo * key_parent(struct PgpKeyInfo *k)
Find a key&#39;s parent (if it&#39;s a subkey)
Definition: pgp.c:140
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:961
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
Type: &#39;text/*&#39;.
Definition: mime.h:38
static void pgp_copy_clearsigned(FILE *fp_in, struct State *s, char *charset)
Copy a clearsigned message, stripping the signature.
Definition: pgp.c:401
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
Public keys.
Definition: pgpkey.h:37
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:117
#define mutt_file_mkstemp()
Definition: file.h:106
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:506
bool C_PgpLongIds
Config: Display long PGP key IDs to the user.
Definition: config.c:48
static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check the body of an inline PGP message.
Definition: pgp.c:766
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
WHERE bool OptPgpCheckTrust
(pseudo) used by pgp_select_key()
Definition: options.h:49
char * p
Definition: charset.h:47
Handling of email attachments.
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:241
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:88
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
PGP sign, encrypt, check routines.
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:598
char * pgp_fpr_or_lkeyid(struct PgpKeyInfo *k)
Get the fingerprint or long keyid.
Definition: pgp.c:221
#define SEC_SIGN
Email is signed.
Definition: lib.h:81
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:602
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:70
Keep track when processing files.
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:888
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1375
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1019
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
#define state_set_prefix(state)
Definition: state.h:53
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1179
char * data
String.
Definition: list.h:36
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:40
No preferred disposition.
Definition: mime.h:65
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
struct PgpKeyInfo * pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
Find a PGP key by string.
Definition: pgpkey.c:1162
bool C_PgpCheckExit
Config: Check the exit code of PGP subprocess.
Definition: config.c:70
#define mutt_error(...)
Definition: logging.h:84
void state_prefix_putc(struct State *s, char c)
Write a prefixed character to the state.
Definition: state.c:131
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
bool C_PgpAutoinline
Config: Use old-style inline PGP messages (not recommended)
Definition: config.c:50
pid_t pgp_invoke_encrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *uids, bool sign)
Use PGP to encrypt a file.
Definition: pgpinvoke.c:339
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:609
Misc PGP helper routines.
bool C_CryptConfirmhook
Config: Prompt the user to confirm keys before use.
Definition: config.c:40
long C_PgpTimeout
Config: Time in seconds to cache a passphrase.
Definition: config.c:74
#define FREE(x)
Definition: memory.h:40
pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to sign a file.
Definition: pgpinvoke.c:315
struct PgpKeyInfo * parent
Definition: pgplib.h:56
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file&#39;s charset into a string buffer.
Definition: charset.c:970
Keep track when processing files.
Definition: state.h:44
struct PgpKeyInfo * pgp_ask_for_key(char *tag, char *whatfor, KeyFlags abilities, enum PgpRing keyring)
Ask the user for a PGP key.
Definition: pgpkey.c:856
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
char * pgp_this_keyid(struct PgpKeyInfo *k)
Get the ID of this key.
Definition: pgp.c:179
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1585
const char * pgp_micalg(const char *fname)
Find the hash algorithm of a file.
Definition: pgpmicalg.c:229
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define state_putc(STATE, STR)
Definition: state.h:56
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Body * pgp_class_traditional_encryptsign(struct Body *a, SecurityFlags flags, char *keylist)
Implements CryptModuleSpecs::pgp_traditional_encryptsign()
Definition: pgp.c:1668
struct Regex * C_PgpGoodSign
Config: Text indicating a good signature.
Definition: config.c:73
int const char int line
Definition: acutest.h:617
bool C_PgpIgnoreSubkeys
Config: Only use the principal PGP key.
Definition: config.c:47
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, int flags)
Prepare a file for charset conversion.
Definition: charset.c:858
A List node for strings.
Definition: list.h:34
struct Regex * C_PgpDecryptionOkay
Config: Text indicating a successful decryption.
Definition: config.c:72
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
struct Body * pgp_class_encrypt_message(struct Body *a, char *keylist, bool sign, const struct AddressList *from)
Implements CryptModuleSpecs::pgp_encrypt_message()
Definition: pgp.c:1535
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
Decide how to display email content.
time_t PgpExptime
Definition: pgp.c:70
Content is inline.
Definition: mime.h:62
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:128
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
#define STAILQ_FIRST(head)
Definition: queue.h:347
char * fingerprint
Definition: pgplib.h:49
Cursor for converting a file&#39;s encoding.
Definition: charset.h:41
Type: &#39;application/*&#39;.
Definition: mime.h:33
Log at debug level 3.
Definition: logging.h:42
Identify the hash algorithm from a PGP signature.
bool C_PgpCheckGpgDecryptStatusFd
Config: File descriptor used for status info.
Definition: config.c:71
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1262
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
char * pgp_class_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Implements CryptModuleSpecs::find_keys()
Definition: pgp.c:1413
bool pgp_class_valid_passphrase(void)
Implements CryptModuleSpecs::valid_passphrase()
Definition: pgp.c:84
void pgp_class_invoke_getkeys(struct Address *addr)
Implements CryptModuleSpecs::pgp_invoke_getkeys()
Definition: pgpinvoke.c:416
static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
Copy PGP output and look for signs of a good signature.
Definition: pgp.c:238
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key&#39;s long id.
Definition: pgp.c:153
int pgp_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
Implements CryptModuleSpecs::verify_one()
Definition: pgp.c:860