NeoMutt  2025-12-11-1059-g2f5469
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pgp.c
Go to the documentation of this file.
1
24
34
35#include "config.h"
36#include <stdbool.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/types.h>
41#include <unistd.h>
42#include "mutt/lib.h"
43#include "address/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "gui/lib.h"
48#include "mutt.h"
49#include "lib.h"
50#include "attach/lib.h"
51#include "editor/lib.h"
52#include "history/lib.h"
53#include "hooks/lib.h"
54#include "question/lib.h"
55#include "send/lib.h"
56#include "crypt.h"
57#include "cryptglue.h"
58#include "globals.h"
59#include "module_data.h"
60#include "pgpinvoke.h"
61#include "pgpkey.h"
62#include "pgpmicalg.h"
63#ifdef CRYPT_BACKEND_CLASSIC_PGP
64#include "pgp.h"
65#include "pgplib.h"
66#endif
67
72{
74 memset(mod_data->pgp_pass, 0, sizeof(mod_data->pgp_pass));
75 mod_data->pgp_exptime = 0;
76}
77
82{
85 {
86 *mod_data->pgp_pass = '\0';
87 return true; /* handled by gpg-agent */
88 }
89
90 if (mutt_date_now() < mod_data->pgp_exptime)
91 {
92 /* Use cached copy. */
93 return true;
94 }
95
97
98 struct Buffer *buf = buf_pool_get();
99 const int rc = mw_get_field(_("Enter PGP passphrase:"), buf,
101 mutt_str_copy(mod_data->pgp_pass, buf_string(buf), sizeof(mod_data->pgp_pass));
102 buf_pool_release(&buf);
103
104 if (rc == 0)
105 {
106 const long c_pgp_timeout = cs_subset_long(NeoMutt->sub, "pgp_timeout");
107 mod_data->pgp_exptime = mutt_date_add_timeout(mutt_date_now(), c_pgp_timeout);
108 return true;
109 }
110 else
111 {
112 mod_data->pgp_exptime = 0;
113 }
114
115 return false;
116}
117
125{
126 char *tty = NULL;
127
128 /* GnuPG 2.1 no longer exports GPG_AGENT_INFO */
129 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
130 if (!c_pgp_use_gpg_agent)
131 return false;
132
133 tty = ttyname(0);
134 if (tty)
135 {
136 setenv("GPG_TTY", tty, 0);
137 envlist_set(&NeoMutt->env, "GPG_TTY", tty, false);
138 }
139
140 return true;
141}
142
148static struct PgpKeyInfo *key_parent(struct PgpKeyInfo *k)
149{
150 const bool c_pgp_ignore_subkeys = cs_subset_bool(NeoMutt->sub, "pgp_ignore_subkeys");
151 if ((k->flags & KEYFLAG_SUBKEY) && k->parent && c_pgp_ignore_subkeys)
152 k = k->parent;
153
154 return k;
155}
156
163{
164 k = key_parent(k);
165
166 return k->keyid;
167}
168
175{
176 k = key_parent(k);
177
178 return k->keyid + 8;
179}
180
189{
190 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
191 if (c_pgp_long_ids)
192 return k->keyid;
193 return k->keyid + 8;
194}
195
201char *pgp_keyid(struct PgpKeyInfo *k)
202{
203 k = key_parent(k);
204
205 return pgp_this_keyid(k);
206}
207
213static char *pgp_fingerprint(struct PgpKeyInfo *k)
214{
215 k = key_parent(k);
216
217 return k->fingerprint;
218}
219
232{
233 char *fingerprint = pgp_fingerprint(k);
235}
236
237/* ----------------------------------------------------------------------------
238 * Routines for handing PGP input.
239 */
240
248static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
249{
250 if (!fp_in || !fp_out)
251 return -1;
252
253 int rc = -1;
254
255 const struct Regex *c_pgp_good_sign = cs_subset_regex(NeoMutt->sub, "pgp_good_sign");
256 if (c_pgp_good_sign && c_pgp_good_sign->regex)
257 {
258 char *line = NULL;
259 size_t linelen = 0;
260
261 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
262 {
263 if (mutt_regex_match(c_pgp_good_sign, line))
264 {
265 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
266 rc = 0;
267 }
268 else
269 {
270 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
271 }
272
273 if (mutt_strn_equal(line, "[GNUPG:] ", 9))
274 continue;
275 fputs(line, fp_out);
276 fputc('\n', fp_out);
277 }
278 FREE(&line);
279 }
280 else
281 {
282 mutt_debug(LL_DEBUG2, "No pattern\n");
283 mutt_file_copy_stream(fp_in, fp_out);
284 rc = 1;
285 }
286
287 return rc;
288}
289
301{
302 int rc = -1;
303
304 const struct Regex *c_pgp_decryption_okay = cs_subset_regex(NeoMutt->sub, "pgp_decryption_okay");
305 if (c_pgp_decryption_okay && c_pgp_decryption_okay->regex)
306 {
307 char *line = NULL;
308 size_t linelen = 0;
309
310 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
311 {
312 if (mutt_regex_match(c_pgp_decryption_okay, line))
313 {
314 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
315 rc = 0;
316 break;
317 }
318 else
319 {
320 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
321 }
322 }
323 FREE(&line);
324 }
325 else
326 {
327 mutt_debug(LL_DEBUG2, "No pattern\n");
328 rc = 1;
329 }
330
331 return rc;
332}
333
354static int pgp_check_decryption_okay(FILE *fp_in)
355{
356 int rc = -1;
357 char *line = NULL;
358 char *s = NULL;
359 size_t linelen = 0;
360 int inside_decrypt = 0;
361
362 const bool c_pgp_check_gpg_decrypt_status_fd = cs_subset_bool(NeoMutt->sub, "pgp_check_gpg_decrypt_status_fd");
363 if (!c_pgp_check_gpg_decrypt_status_fd)
365
366 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NONE)))
367 {
368 size_t plen = mutt_str_startswith(line, "[GNUPG:] ");
369 if (plen == 0)
370 continue;
371 s = line + plen;
372 mutt_debug(LL_DEBUG2, "checking \"%s\"\n", line);
373 if (mutt_str_startswith(s, "BEGIN_DECRYPTION"))
374 {
375 inside_decrypt = 1;
376 }
377 else if (mutt_str_startswith(s, "END_DECRYPTION"))
378 {
379 inside_decrypt = 0;
380 }
381 else if (mutt_str_startswith(s, "PLAINTEXT"))
382 {
383 if (!inside_decrypt)
384 {
385 mutt_debug(LL_DEBUG2, " PLAINTEXT encountered outside of DECRYPTION\n");
386 rc = -2;
387 break;
388 }
389 }
390 else if (mutt_str_startswith(s, "DECRYPTION_FAILED"))
391 {
392 mutt_debug(LL_DEBUG2, " DECRYPTION_FAILED encountered. Failure\n");
393 rc = -3;
394 break;
395 }
396 else if (mutt_str_startswith(s, "DECRYPTION_OKAY"))
397 {
398 /* Don't break out because we still have to check for
399 * PLAINTEXT outside of the decryption boundaries. */
400 mutt_debug(LL_DEBUG2, " DECRYPTION_OKAY encountered\n");
401 rc = 0;
402 }
403 }
404 FREE(&line);
405
406 return rc;
407}
408
422static void pgp_copy_clearsigned(FILE *fp_in, struct State *state, char *charset)
423{
424 char buf[8192] = { 0 };
425 bool complete, armor_header;
426
427 fseek(fp_in, 0, SEEK_SET);
428 clearerr(fp_in);
429
430 /* fromcode comes from the MIME Content-Type charset label. It might
431 * be a wrong label, so we want the ability to do corrections via
432 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
433 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_in, charset, cc_charset(), MUTT_ICONV_HOOK_FROM);
434
435 for (complete = true, armor_header = true;
436 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
437 {
438 if (!complete)
439 {
440 if (!armor_header)
441 state_puts(state, buf);
442 continue;
443 }
444
445 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
446 break;
447
448 if (armor_header)
449 {
450 char *p = mutt_str_skip_whitespace(buf);
451 if (*p == '\0')
452 armor_header = false;
453 continue;
454 }
455
456 if (state->prefix)
457 state_puts(state, state->prefix);
458
459 if ((buf[0] == '-') && (buf[1] == ' '))
460 state_puts(state, buf + 2);
461 else
462 state_puts(state, buf);
463 }
464
466}
467
471int pgp_class_application_handler(struct Body *b, struct State *state)
472{
474 bool could_not_decrypt = false;
475 int decrypt_okay_rc = 0;
476 int needpass = -1;
477 bool pgp_keyblock = false;
478 bool clearsign = false;
479 int rc = -1;
480 int c = 1;
481 long bytes;
482 LOFF_T last_pos;
483 LOFF_T offset;
484 char buf[8192] = { 0 };
485 FILE *fp_pgp_out = NULL;
486 FILE *fp_pgp_in = NULL;
487 FILE *fp_pgp_err = NULL;
488 FILE *fp_tmp = NULL;
489 pid_t pid;
490 struct Buffer *tempfile = buf_pool_get();
491
492 bool maybe_goodsig = true;
493 bool have_any_sigs = false;
494
495 char *gpgcharset = NULL;
496 char body_charset[256] = { 0 };
497 mutt_body_get_charset(b, body_charset, sizeof(body_charset));
498
499 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
500 {
501 return -1;
502 }
503 last_pos = b->offset;
504
505 for (bytes = b->length; bytes > 0;)
506 {
507 if (!fgets(buf, sizeof(buf), state->fp_in))
508 break;
509
510 offset = ftello(state->fp_in);
511 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
512 last_pos = offset;
513
514 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
515 if (plen != 0)
516 {
517 needpass = false;
518 clearsign = false;
519 could_not_decrypt = false;
520 decrypt_okay_rc = 0;
521
522 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
523 {
524 needpass = 1;
525 }
526 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
527 {
528 clearsign = true;
529 }
530 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
531 {
532 pgp_keyblock = true;
533 }
534 else
535 {
536 /* XXX we may wish to recode here */
537 if (state->prefix)
538 state_puts(state, state->prefix);
539 state_puts(state, buf);
540 continue;
541 }
542
543 have_any_sigs = have_any_sigs || (clearsign && (state->flags & STATE_VERIFY));
544
545 /* Copy PGP material to temporary file */
546 buf_mktemp(tempfile);
547 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
548 if (!fp_tmp)
549 {
550 mutt_perror("%s", buf_string(tempfile));
551 FREE(&gpgcharset);
552 goto out;
553 }
554
555 fputs(buf, fp_tmp);
556 while ((bytes > 0) && fgets(buf, sizeof(buf) - 1, state->fp_in))
557 {
558 offset = ftello(state->fp_in);
559 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
560 last_pos = offset;
561
562 fputs(buf, fp_tmp);
563
564 if ((needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf)) ||
565 (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
566 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf))))
567 {
568 break;
569 }
570 /* remember optional Charset: armor header as defined by RFC4880 */
571 if (mutt_str_startswith(buf, "Charset: "))
572 {
573 size_t l = 0;
574 FREE(&gpgcharset);
575 gpgcharset = mutt_str_dup(buf + 9);
576 l = mutt_str_len(gpgcharset);
577 if ((l > 0) && (gpgcharset[l - 1] == '\n'))
578 gpgcharset[l - 1] = 0;
579 if (!mutt_ch_check_charset(gpgcharset, false))
580 mutt_str_replace(&gpgcharset, "UTF-8");
581 }
582 }
583
584 /* leave fp_tmp open in case we still need it - but flush it! */
585 fflush(fp_tmp);
586
587 /* Invoke PGP if needed */
588 if (!clearsign || (state->flags & STATE_VERIFY))
589 {
590 fp_pgp_out = mutt_file_mkstemp();
591 if (!fp_pgp_out)
592 {
593 mutt_perror(_("Can't create temporary file"));
594 goto out;
595 }
596
597 fp_pgp_err = mutt_file_mkstemp();
598 if (!fp_pgp_err)
599 {
600 mutt_perror(_("Can't create temporary file"));
601 goto out;
602 }
603
604 pid = pgp_invoke_decode(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
605 fileno(fp_pgp_err), buf_string(tempfile),
606 (needpass != 0));
607 if (pid == -1)
608 {
609 mutt_file_fclose(&fp_pgp_out);
610 maybe_goodsig = false;
611 fp_pgp_in = NULL;
612 state_attach_puts(state, _("[-- Error: unable to create PGP subprocess --]\n"));
613 }
614 else /* PGP started successfully */
615 {
616 if (needpass)
617 {
620 if (pgp_use_gpg_agent())
621 *mod_data->pgp_pass = '\0';
622 fprintf(fp_pgp_in, "%s\n", mod_data->pgp_pass);
623 }
624
625 mutt_file_fclose(&fp_pgp_in);
626
627 int wait_filter_rc = filter_wait(pid);
628
629 fflush(fp_pgp_err);
630 /* If we are expecting an encrypted message, verify status fd output.
631 * Note that BEGIN PGP MESSAGE does not guarantee the content is encrypted,
632 * so we need to be more selective about the value of decrypt_okay_rc.
633 *
634 * -3 indicates we actively found a DECRYPTION_FAILED.
635 * -2 and -1 indicate part or all of the content was plaintext. */
636 if (needpass)
637 {
638 fseek(fp_pgp_err, 0, SEEK_SET);
639 clearerr(fp_pgp_err);
640 decrypt_okay_rc = pgp_check_decryption_okay(fp_pgp_err);
641 if (decrypt_okay_rc <= -3)
642 mutt_file_fclose(&fp_pgp_out);
643 }
644
645 if (state->flags & STATE_DISPLAY)
646 {
647 fseek(fp_pgp_err, 0, SEEK_SET);
648 clearerr(fp_pgp_err);
649 crypt_current_time(state, "PGP");
650 int checksig_rc = pgp_copy_checksig(fp_pgp_err, state->fp_out);
651
652 if (checksig_rc == 0)
653 have_any_sigs = true;
654 /* Sig is bad if
655 * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
656 * Sig _is_ correct if
657 * gpg_good_sign="" && pgp_decode_command returned 0 */
658 if (checksig_rc == -1 || (wait_filter_rc != 0))
659 maybe_goodsig = false;
660
661 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
662 }
663 if (pgp_use_gpg_agent())
664 {
666 }
667 }
668
669 /* treat empty result as sign of failure */
670 /* TODO: maybe on failure neomutt should include the original undecoded text. */
671 if (fp_pgp_out)
672 {
673 fseek(fp_pgp_out, 0, SEEK_SET);
674 clearerr(fp_pgp_out);
675 c = fgetc(fp_pgp_out);
676 ungetc(c, fp_pgp_out);
677 }
678 if (!clearsign && (!fp_pgp_out || (c == EOF)))
679 {
680 could_not_decrypt = true;
682 }
683
684 if ((could_not_decrypt || (decrypt_okay_rc <= -3)) && !(state->flags & STATE_DISPLAY))
685 {
686 mutt_error(_("Could not decrypt PGP message"));
687 goto out;
688 }
689 }
690
691 /* Now, copy cleartext to the screen. */
692 if (state->flags & STATE_DISPLAY)
693 {
694 if (needpass)
695 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
696 else if (pgp_keyblock)
697 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
698 else
699 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
700 }
701
702 if (clearsign)
703 {
704 fseek(fp_tmp, 0, SEEK_SET);
705 clearerr(fp_tmp);
706 pgp_copy_clearsigned(fp_tmp, state, body_charset);
707 }
708 else if (fp_pgp_out)
709 {
710 struct FgetConv *fc = NULL;
711 int ch;
712 char *expected_charset = (gpgcharset && *gpgcharset) ? gpgcharset : "utf-8";
713
714 mutt_debug(LL_DEBUG3, "pgp: recoding inline from [%s] to [%s]\n",
715 expected_charset, cc_charset());
716
717 fseek(fp_pgp_out, 0, SEEK_SET);
718 clearerr(fp_pgp_out);
719 state_set_prefix(state);
720 fc = mutt_ch_fgetconv_open(fp_pgp_out, expected_charset, cc_charset(),
722 while ((ch = mutt_ch_fgetconv(fc)) != EOF)
723 state_prefix_putc(state, ch);
725 }
726
727 /* Multiple PGP blocks can exist, so these need to be closed and
728 * unlinked inside the loop. */
729 mutt_file_fclose(&fp_tmp);
730 mutt_file_unlink(buf_string(tempfile));
731 mutt_file_fclose(&fp_pgp_out);
732 mutt_file_fclose(&fp_pgp_err);
733
734 if (state->flags & STATE_DISPLAY)
735 {
736 state_putc(state, '\n');
737 if (needpass)
738 {
739 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
740 if (could_not_decrypt || (decrypt_okay_rc <= -3))
741 {
742 mutt_error(_("Could not decrypt PGP message"));
743 }
744 else if (decrypt_okay_rc < 0)
745 {
746 /* L10N: You will see this error message if (1) you are decrypting
747 (not encrypting) something and (2) it is a plaintext. So the
748 message does not mean "You failed to encrypt the message." */
749 mutt_error(_("PGP message is not encrypted"));
750 }
751 else
752 {
753 mutt_message(_("PGP message successfully decrypted"));
754 }
755 }
756 else if (pgp_keyblock)
757 {
758 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
759 }
760 else
761 {
762 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
763 }
764 }
765 }
766 else
767 {
768 /* A traditional PGP part may mix signed and unsigned content */
769 /* XXX we may wish to recode here */
770 if (state->prefix)
771 state_puts(state, state->prefix);
772 state_puts(state, buf);
773 }
774 }
775
776 rc = 0;
777
778out:
779 b->goodsig = (maybe_goodsig && have_any_sigs);
780
781 if (fp_tmp)
782 {
783 mutt_file_fclose(&fp_tmp);
784 mutt_file_unlink(buf_string(tempfile));
785 }
786 mutt_file_fclose(&fp_pgp_out);
787 mutt_file_fclose(&fp_pgp_err);
788
789 buf_pool_release(&tempfile);
790
791 FREE(&gpgcharset);
792
793 if (needpass == -1)
794 {
795 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
796 return -1;
797 }
798
799 return rc;
800}
801
809static bool pgp_check_traditional_one_body(FILE *fp, struct Body *b)
810{
811 struct Buffer *tempfile = NULL;
812 char buf[8192] = { 0 };
813 bool rc = false;
814
815 bool sgn = false;
816 bool enc = false;
817 bool key = false;
818
819 if (b->type != TYPE_TEXT)
820 goto cleanup;
821
822 tempfile = buf_pool_get();
823 buf_mktemp(tempfile);
825 {
826 unlink(buf_string(tempfile));
827 goto cleanup;
828 }
829
830 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
831 if (!fp_tmp)
832 {
833 unlink(buf_string(tempfile));
834 goto cleanup;
835 }
836
837 while (fgets(buf, sizeof(buf), fp_tmp))
838 {
839 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
840 if (plen != 0)
841 {
842 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
843 enc = true;
844 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
845 sgn = true;
846 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
847 key = true;
848 }
849 }
850 mutt_file_fclose(&fp_tmp);
851 unlink(buf_string(tempfile));
852
853 if (!enc && !sgn && !key)
854 goto cleanup;
855
856 /* fix the content type */
857
858 mutt_param_set(&b->parameter, "format", "fixed");
859 if (enc)
860 mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
861 else if (sgn)
862 mutt_param_set(&b->parameter, "x-action", "pgp-signed");
863 else if (key)
864 mutt_param_set(&b->parameter, "x-action", "pgp-keys");
865
866 rc = true;
867
868cleanup:
869 buf_pool_release(&tempfile);
870 return rc;
871}
872
876bool pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
877{
878 bool rc = false;
879 int r;
880 for (; b; b = b->next)
881 {
882 if (!just_one && is_multipart(b))
883 {
884 rc = pgp_class_check_traditional(fp, b->parts, false) || rc;
885 }
886 else if (b->type == TYPE_TEXT)
887 {
889 if (r)
890 rc = rc || r;
891 else
892 rc = pgp_check_traditional_one_body(fp, b) || rc;
893 }
894
895 if (just_one)
896 break;
897 }
898
899 return rc;
900}
901
905int pgp_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
906{
907 FILE *fp_pgp_out = NULL;
908 pid_t pid;
909 int badsig = -1;
910 struct Buffer *sigfile = buf_pool_get();
911
912 buf_printf(sigfile, "%s.asc", tempfile);
913
914 FILE *fp_sig = mutt_file_fopen(buf_string(sigfile), "w");
915 if (!fp_sig)
916 {
917 mutt_perror("%s", buf_string(sigfile));
918 goto cleanup;
919 }
920
921 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
922 {
923 mutt_file_fclose(&fp_sig);
924 goto cleanup;
925 }
926 mutt_file_copy_bytes(state->fp_in, fp_sig, b->length);
927 mutt_file_fclose(&fp_sig);
928
929 FILE *fp_pgp_err = mutt_file_mkstemp();
930 if (!fp_pgp_err)
931 {
932 mutt_perror(_("Can't create temporary file"));
933 unlink(buf_string(sigfile));
934 goto cleanup;
935 }
936
937 crypt_current_time(state, "PGP");
938
939 pid = pgp_invoke_verify(NULL, &fp_pgp_out, NULL, -1, -1, fileno(fp_pgp_err),
940 tempfile, buf_string(sigfile));
941 if (pid != -1)
942 {
943 if (pgp_copy_checksig(fp_pgp_out, state->fp_out) >= 0)
944 badsig = 0;
945
946 mutt_file_fclose(&fp_pgp_out);
947 fflush(fp_pgp_err);
948 fseek(fp_pgp_err, 0, SEEK_SET);
949 clearerr(fp_pgp_err);
950
951 if (pgp_copy_checksig(fp_pgp_err, state->fp_out) >= 0)
952 badsig = 0;
953
954 const int rv = filter_wait(pid);
955 if (rv)
956 badsig = -1;
957
958 mutt_debug(LL_DEBUG1, "filter_wait returned %d\n", rv);
959 }
960
961 mutt_file_fclose(&fp_pgp_err);
962
963 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
964
966
967cleanup:
968 buf_pool_release(&sigfile);
969
970 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
971 return badsig;
972}
973
979static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *b)
980{
981 struct State state = { 0 };
982 struct Buffer *tempfile = buf_pool_get();
983
984 buf_mktemp(tempfile);
985 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
986 if (!fp_tmp)
987 {
988 mutt_perror("%s", buf_string(tempfile));
989 goto cleanup;
990 }
991
992 state.fp_in = fp;
993 state.fp_out = fp_tmp;
994
995 mutt_body_handler(b, &state);
996
997 mutt_file_fclose(&fp_tmp);
998
1001
1002 mutt_file_unlink(buf_string(tempfile));
1003
1004cleanup:
1005 buf_pool_release(&tempfile);
1006}
1007
1012{
1013 if (!fp)
1014 {
1015 mutt_error(_("Internal error. Please submit a bug report."));
1016 return;
1017 }
1018
1019 mutt_endwin();
1020
1021 OptDontHandlePgpKeys = true;
1023 OptDontHandlePgpKeys = false;
1024}
1025
1034static struct Body *pgp_decrypt_part(struct Body *a, struct State *state,
1035 FILE *fp_out, struct Body *p)
1036{
1037 if (!a || !state || !fp_out || !p)
1038 return NULL;
1039
1041 char buf[1024] = { 0 };
1042 FILE *fp_pgp_in = NULL;
1043 FILE *fp_pgp_out = NULL;
1044 FILE *fp_pgp_tmp = NULL;
1045 struct Body *tattach = NULL;
1046 pid_t pid;
1047 int rv;
1048 struct Buffer *tempfile = buf_pool_get();
1049
1050 FILE *fp_pgp_err = mutt_file_mkstemp();
1051 if (!fp_pgp_err)
1052 {
1053 mutt_perror(_("Can't create temporary file"));
1054 goto cleanup;
1055 }
1056
1057 buf_mktemp(tempfile);
1058 fp_pgp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1059 if (!fp_pgp_tmp)
1060 {
1061 mutt_perror("%s", buf_string(tempfile));
1062 mutt_file_fclose(&fp_pgp_err);
1063 goto cleanup;
1064 }
1065
1066 /* Position the stream at the beginning of the body, and send the data to
1067 * the temporary file. */
1068
1069 if (!mutt_file_seek(state->fp_in, a->offset, SEEK_SET))
1070 {
1071 mutt_file_fclose(&fp_pgp_tmp);
1072 mutt_file_fclose(&fp_pgp_err);
1073 goto cleanup;
1074 }
1075 mutt_file_copy_bytes(state->fp_in, fp_pgp_tmp, a->length);
1076 mutt_file_fclose(&fp_pgp_tmp);
1077
1078 pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1079 fileno(fp_pgp_err), buf_string(tempfile));
1080 if (pid == -1)
1081 {
1082 mutt_file_fclose(&fp_pgp_err);
1083 unlink(buf_string(tempfile));
1084 if (state->flags & STATE_DISPLAY)
1085 {
1086 state_attach_puts(state, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1087 }
1088 goto cleanup;
1089 }
1090
1091 /* send the PGP passphrase to the subprocess. Never do this if the agent is
1092 * active, because this might lead to a passphrase send as the message. */
1093 if (!pgp_use_gpg_agent())
1094 fputs(mod_data->pgp_pass, fp_pgp_in);
1095 fputc('\n', fp_pgp_in);
1096 mutt_file_fclose(&fp_pgp_in);
1097
1098 /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1099 * read_mime_header has a hard time parsing the message. */
1100 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1101 {
1102 size_t len = mutt_str_len(buf);
1103 if ((len > 1) && (buf[len - 2] == '\r'))
1104 strcpy(buf + len - 2, "\n");
1105 fputs(buf, fp_out);
1106 }
1107
1108 mutt_file_fclose(&fp_pgp_out);
1109
1110 rv = filter_wait(pid);
1111 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
1112 if (c_pgp_use_gpg_agent)
1114
1115 mutt_file_unlink(buf_string(tempfile));
1116
1117 fflush(fp_pgp_err);
1118 fseek(fp_pgp_err, 0, SEEK_SET);
1119 clearerr(fp_pgp_err);
1120 if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1121 {
1122 mutt_error(_("Decryption failed"));
1124 mutt_file_fclose(&fp_pgp_err);
1125 goto cleanup;
1126 }
1127
1128 if (state->flags & STATE_DISPLAY)
1129 {
1130 fseek(fp_pgp_err, 0, SEEK_SET);
1131 clearerr(fp_pgp_err);
1132 if ((pgp_copy_checksig(fp_pgp_err, state->fp_out) == 0) && !rv)
1133 p->goodsig = true;
1134 else
1135 p->goodsig = false;
1136 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
1137 }
1138 mutt_file_fclose(&fp_pgp_err);
1139
1140 fflush(fp_out);
1141 fseek(fp_out, 0, SEEK_SET);
1142 clearerr(fp_out);
1143
1144 if (fgetc(fp_out) == EOF)
1145 {
1146 mutt_error(_("Decryption failed"));
1148 goto cleanup;
1149 }
1150
1151 fseek(fp_out, 0, SEEK_SET);
1152 clearerr(fp_out);
1153 const long size = mutt_file_get_size_fp(fp_out);
1154 if (size == 0)
1155 {
1156 goto cleanup;
1157 }
1158
1159 tattach = mutt_read_mime_header(fp_out, 0);
1160 if (tattach)
1161 {
1162 /* Need to set the length of this body part. */
1163 tattach->length = size - tattach->offset;
1164
1165 /* See if we need to recurse on this MIME part. */
1166 mutt_parse_part(fp_out, tattach);
1167 }
1168
1169cleanup:
1170 buf_pool_release(&tempfile);
1171 return tattach;
1172}
1173
1177int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1178{
1179 struct State state = { 0 };
1180 struct Body *p = b;
1181 bool need_decode = false;
1182 LOFF_T saved_offset = 0;
1183 size_t saved_length = 0;
1184 FILE *fp_decoded = NULL;
1185 int rc = 0;
1186
1188 {
1189 b = b->parts->next;
1190 /* Some clients improperly encode the octetstream part. */
1191 if (b->encoding != ENC_7BIT)
1192 need_decode = true;
1193 }
1195 {
1196 b = b->parts->next->next;
1197 need_decode = true;
1198 }
1199 else
1200 {
1201 return -1;
1202 }
1203
1204 state.fp_in = fp_in;
1205
1206 if (need_decode)
1207 {
1208 saved_offset = b->offset;
1209 saved_length = b->length;
1210
1211 fp_decoded = mutt_file_mkstemp();
1212 if (!fp_decoded)
1213 {
1214 mutt_perror(_("Can't create temporary file"));
1215 return -1;
1216 }
1217
1218 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1219 {
1220 rc = -1;
1221 goto bail;
1222 }
1223 state.fp_out = fp_decoded;
1224
1225 mutt_decode_attachment(b, &state);
1226
1227 fflush(fp_decoded);
1228 b->length = ftello(fp_decoded);
1229 b->offset = 0;
1230 fseek(fp_decoded, 0, SEEK_SET);
1231 clearerr(fp_decoded);
1232 state.fp_in = fp_decoded;
1233 state.fp_out = 0;
1234 }
1235
1236 *fp_out = mutt_file_mkstemp();
1237 if (!*fp_out)
1238 {
1239 mutt_perror(_("Can't create temporary file"));
1240 rc = -1;
1241 goto bail;
1242 }
1243
1244 *b_dec = pgp_decrypt_part(b, &state, *fp_out, p);
1245 if (!*b_dec)
1246 {
1247 rc = -1;
1248 mutt_file_fclose(fp_out);
1249 goto bail;
1250 }
1251 fseek(*fp_out, 0, SEEK_SET);
1252 clearerr(*fp_out);
1253
1254bail:
1255 if (need_decode)
1256 {
1257 b->length = saved_length;
1258 b->offset = saved_offset;
1259 mutt_file_fclose(&fp_decoded);
1260 }
1261
1262 return rc;
1263}
1264
1268int pgp_class_encrypted_handler(struct Body *b, struct State *state)
1269{
1270 FILE *fp_in = NULL;
1271 struct Body *tattach = NULL;
1272 int rc = 0;
1273
1274 FILE *fp_out = mutt_file_mkstemp();
1275 if (!fp_out)
1276 {
1277 mutt_perror(_("Can't create temporary file"));
1278 if (state->flags & STATE_DISPLAY)
1279 {
1280 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
1281 }
1282 return -1;
1283 }
1284
1285 if (state->flags & STATE_DISPLAY)
1286 crypt_current_time(state, "PGP");
1287
1288 tattach = pgp_decrypt_part(b, state, fp_out, b);
1289 if (tattach)
1290 {
1291 if (state->flags & STATE_DISPLAY)
1292 {
1293 state_attach_puts(state, _("[-- The following data is PGP/MIME encrypted --]\n"));
1294 mutt_protected_headers_handler(tattach, state);
1295 }
1296
1297 /* Store any protected headers in the parent so they can be
1298 * accessed for index updates after the handler recursion is done.
1299 * This is done before the handler to prevent a nested encrypted
1300 * handler from freeing the headers. */
1302 b->mime_headers = tattach->mime_headers;
1303 tattach->mime_headers = NULL;
1304
1305 fp_in = state->fp_in;
1306 state->fp_in = fp_out;
1307 rc = mutt_body_handler(tattach, state);
1308 state->fp_in = fp_in;
1309
1310 /* Embedded multipart signed protected headers override the
1311 * encrypted headers. We need to do this after the handler so
1312 * they can be printed in the pager. */
1313 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
1314 {
1316 b->mime_headers = tattach->parts->mime_headers;
1317 tattach->parts->mime_headers = NULL;
1318 }
1319
1320 /* if a multipart/signed is the _only_ sub-part of a
1321 * multipart/encrypted, cache signature verification
1322 * status. */
1323 if (mutt_is_multipart_signed(tattach) && !tattach->next)
1324 b->goodsig |= tattach->goodsig;
1325
1326 if (state->flags & STATE_DISPLAY)
1327 state_attach_puts(state, _("[-- End of PGP/MIME encrypted data --]\n"));
1328
1329 mutt_body_free(&tattach);
1330 /* clear 'Invoking...' message, since there's no error */
1331 mutt_message(_("PGP message successfully decrypted"));
1332 }
1333 else
1334 {
1335 mutt_error(_("Could not decrypt PGP message"));
1336 /* void the passphrase, even if it's not necessarily the problem */
1338 rc = -1;
1339 }
1340
1341 mutt_file_fclose(&fp_out);
1342
1343 return rc;
1344}
1345
1346/* ----------------------------------------------------------------------------
1347 * Routines for sending PGP/MIME messages.
1348 */
1349
1353struct Body *pgp_class_sign_message(struct Body *b, const struct AddressList *from)
1354{
1356 struct Body *b_enc = NULL;
1357 struct Body *rv = NULL;
1358 char buf[1024] = { 0 };
1359 FILE *fp_pgp_in = NULL;
1360 FILE *fp_pgp_out = NULL;
1361 FILE *fp_pgp_err = NULL;
1362 FILE *fp_signed = NULL;
1363 bool err = false;
1364 bool empty = true;
1365 pid_t pid;
1366 struct Buffer *sigfile = buf_pool_get();
1367 struct Buffer *signedfile = buf_pool_get();
1368
1369 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
1370
1371 buf_mktemp(sigfile);
1372 FILE *fp_sig = mutt_file_fopen(buf_string(sigfile), "w");
1373 if (!fp_sig)
1374 {
1375 goto cleanup;
1376 }
1377
1378 buf_mktemp(signedfile);
1379 fp_signed = mutt_file_fopen(buf_string(signedfile), "w");
1380 if (!fp_signed)
1381 {
1382 mutt_perror("%s", buf_string(signedfile));
1383 mutt_file_fclose(&fp_sig);
1384 unlink(buf_string(sigfile));
1385 goto cleanup;
1386 }
1387
1388 mutt_write_mime_header(b, fp_signed, NeoMutt->sub);
1389 fputc('\n', fp_signed);
1390 mutt_write_mime_body(b, fp_signed, NeoMutt->sub);
1391 mutt_file_fclose(&fp_signed);
1392
1393 pid = pgp_invoke_sign(&fp_pgp_in, &fp_pgp_out, &fp_pgp_err, -1, -1, -1,
1394 buf_string(signedfile));
1395 if (pid == -1)
1396 {
1397 mutt_perror(_("Can't open PGP subprocess"));
1398 mutt_file_fclose(&fp_sig);
1399 unlink(buf_string(sigfile));
1400 unlink(buf_string(signedfile));
1401 goto cleanup;
1402 }
1403
1404 if (!pgp_use_gpg_agent())
1405 fputs(mod_data->pgp_pass, fp_pgp_in);
1406 fputc('\n', fp_pgp_in);
1407 mutt_file_fclose(&fp_pgp_in);
1408
1409 /* Read back the PGP signature. Also, change MESSAGE=>SIGNATURE as
1410 * recommended for future releases of PGP. */
1411 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1412 {
1413 if (mutt_str_equal("-----BEGIN PGP MESSAGE-----\n", buf))
1414 fputs("-----BEGIN PGP SIGNATURE-----\n", fp_sig);
1415 else if (mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
1416 fputs("-----END PGP SIGNATURE-----\n", fp_sig);
1417 else
1418 fputs(buf, fp_sig);
1419 empty = false; /* got some output, so we're ok */
1420 }
1421
1422 /* check for errors from PGP */
1423 err = false;
1424 while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1425 {
1426 err = true;
1427 fputs(buf, stdout);
1428 }
1429
1430 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1431 if (filter_wait(pid) && c_pgp_check_exit)
1432 empty = true;
1433
1434 mutt_file_fclose(&fp_pgp_err);
1435 mutt_file_fclose(&fp_pgp_out);
1436 unlink(buf_string(signedfile));
1437
1438 if (mutt_file_fclose(&fp_sig) != 0)
1439 {
1440 mutt_perror("fclose");
1441 unlink(buf_string(sigfile));
1442 goto cleanup;
1443 }
1444
1445 if (err)
1447 if (empty)
1448 {
1449 unlink(buf_string(sigfile));
1450 /* most likely error is a bad passphrase, so automatically forget it */
1452 goto cleanup; /* fatal error while signing */
1453 }
1454
1455 b_enc = mutt_body_new();
1456 b_enc->type = TYPE_MULTIPART;
1457 b_enc->subtype = mutt_str_dup("signed");
1458 b_enc->encoding = ENC_7BIT;
1459 b_enc->use_disp = false;
1460 b_enc->disposition = DISP_INLINE;
1461 rv = b_enc;
1462
1464 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-signature");
1465 mutt_param_set(&b_enc->parameter, "micalg", pgp_micalg(buf_string(sigfile)));
1466
1467 b_enc->parts = b;
1468
1469 b_enc->parts->next = mutt_body_new();
1470 b_enc = b_enc->parts->next;
1471 b_enc->type = TYPE_APPLICATION;
1472 b_enc->subtype = mutt_str_dup("pgp-signature");
1473 b_enc->filename = buf_strdup(sigfile);
1474 b_enc->use_disp = false;
1475 b_enc->disposition = DISP_NONE;
1476 b_enc->encoding = ENC_7BIT;
1477 b_enc->unlink = true; /* ok to remove this file after sending. */
1478 mutt_param_set(&b_enc->parameter, "name", "signature.asc");
1479
1480cleanup:
1481 buf_pool_release(&sigfile);
1482 buf_pool_release(&signedfile);
1483 return rv;
1484}
1485
1489char *pgp_class_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
1490{
1491 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
1492 struct ListNode *crypt_hook = NULL;
1493 const char *keyid = NULL;
1494 char *keylist = NULL;
1495 size_t keylist_size = 0;
1496 size_t keylist_used = 0;
1497 struct Address *p = NULL;
1498 struct PgpKeyInfo *k_info = NULL;
1499 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
1500 char buf[1024] = { 0 };
1501 bool key_selected;
1502 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
1503
1504 struct Address *a = NULL;
1505 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
1506 /* Iterate through each recipient address to find an encryption key */
1507 TAILQ_FOREACH(a, addrlist, entries)
1508 {
1509 key_selected = false;
1510 /* Check for crypt-hook overrides for this recipient */
1511 mutt_crypt_hook(&crypt_hook_list, a);
1512 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
1513 do
1514 {
1515 p = a;
1516 k_info = NULL;
1517
1518 /* If a crypt-hook provides a key ID, confirm with the user unless
1519 * in opportunistic encryption mode */
1520 if (crypt_hook)
1521 {
1522 keyid = crypt_hook->data;
1523 enum QuadOption ans = MUTT_YES;
1524 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
1525 {
1526 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
1527 buf_string(p->mailbox));
1528 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
1529 }
1530 if (ans == MUTT_YES)
1531 {
1532 if (crypt_is_numerical_keyid(keyid))
1533 {
1534 if (mutt_strn_equal(keyid, "0x", 2))
1535 keyid += 2;
1536 goto bypass_selection; /* you don't see this. */
1537 }
1538
1539 /* check for e-mail address */
1540 mutt_addrlist_clear(&hookal);
1541 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
1542 {
1543 mutt_addrlist_qualify(&hookal, fqdn);
1544 p = TAILQ_FIRST(&hookal);
1545 }
1546 else if (!oppenc_mode)
1547 {
1549 }
1550 }
1551 else if (ans == MUTT_NO)
1552 {
1553 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
1554 {
1555 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1556 continue;
1557 }
1558 }
1559 else if (ans == MUTT_ABORT)
1560 {
1561 FREE(&keylist);
1562 mutt_addrlist_clear(&hookal);
1563 mutt_list_free(&crypt_hook_list);
1564 return NULL;
1565 }
1566 }
1567
1568 /* If no key found yet, try looking up by address in the keyring */
1569 if (!k_info)
1570 {
1572 k_info = pgp_getkeybyaddr(p, KEYFLAG_CANENCRYPT, PGP_PUBRING, oppenc_mode);
1573 }
1574
1575 /* Last resort: prompt the user to enter a key ID interactively */
1576 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
1577 {
1578 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
1580 }
1581
1582 if (!k_info)
1583 {
1584 FREE(&keylist);
1585 mutt_addrlist_clear(&hookal);
1586 mutt_list_free(&crypt_hook_list);
1587 return NULL;
1588 }
1589
1590 keyid = pgp_fpr_or_lkeyid(k_info);
1591
1592 bypass_selection:
1593 /* Append the selected key ID to the space-separated keylist string */
1594 keylist_size += mutt_str_len(keyid) + 4;
1595 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
1596 sprintf(keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", keyid);
1597 keylist_used = mutt_str_len(keylist);
1598
1599 key_selected = true;
1600
1601 pgp_key_free(&k_info);
1602 mutt_addrlist_clear(&hookal);
1603
1604 if (crypt_hook)
1605 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1606
1607 } while (crypt_hook);
1608
1609 mutt_list_free(&crypt_hook_list);
1610 }
1611 return keylist;
1612}
1613
1620struct Body *pgp_class_encrypt_message(struct Body *b, char *keylist, bool sign,
1621 const struct AddressList *from)
1622{
1624 char buf[1024] = { 0 };
1625 FILE *fp_pgp_in = NULL;
1626 FILE *fp_tmp = NULL;
1627 struct Body *b_enc = NULL;
1628 bool err = false;
1629 bool empty = false;
1630 pid_t pid;
1631 struct Buffer *tempfile = buf_pool_get();
1632 struct Buffer *pgpinfile = buf_pool_get();
1633
1634 buf_mktemp(tempfile);
1635 FILE *fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
1636 if (!fp_out)
1637 {
1638 mutt_perror("%s", buf_string(tempfile));
1639 goto cleanup;
1640 }
1641
1642 FILE *fp_pgp_err = mutt_file_mkstemp();
1643 if (!fp_pgp_err)
1644 {
1645 mutt_perror(_("Can't create temporary file"));
1646 unlink(buf_string(tempfile));
1647 mutt_file_fclose(&fp_out);
1648 goto cleanup;
1649 }
1650
1651 buf_mktemp(pgpinfile);
1652 fp_tmp = mutt_file_fopen(buf_string(pgpinfile), "w");
1653 if (!fp_tmp)
1654 {
1655 mutt_perror("%s", buf_string(pgpinfile));
1656 unlink(buf_string(tempfile));
1657 mutt_file_fclose(&fp_out);
1658 mutt_file_fclose(&fp_pgp_err);
1659 goto cleanup;
1660 }
1661
1662 if (sign)
1664
1665 mutt_write_mime_header(b, fp_tmp, NeoMutt->sub);
1666 fputc('\n', fp_tmp);
1667 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
1668 mutt_file_fclose(&fp_tmp);
1669
1670 pid = pgp_invoke_encrypt(&fp_pgp_in, NULL, NULL, -1, fileno(fp_out),
1671 fileno(fp_pgp_err), buf_string(pgpinfile), keylist, sign);
1672 if (pid == -1)
1673 {
1674 mutt_file_fclose(&fp_out);
1675 mutt_file_fclose(&fp_pgp_err);
1676 unlink(buf_string(pgpinfile));
1677 goto cleanup;
1678 }
1679
1680 if (sign)
1681 {
1682 if (!pgp_use_gpg_agent())
1683 fputs(mod_data->pgp_pass, fp_pgp_in);
1684 fputc('\n', fp_pgp_in);
1685 }
1686 mutt_file_fclose(&fp_pgp_in);
1687
1688 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1689 if (filter_wait(pid) && c_pgp_check_exit)
1690 empty = true;
1691
1692 unlink(buf_string(pgpinfile));
1693
1694 fflush(fp_out);
1695 fseek(fp_out, 0, SEEK_SET);
1696 clearerr(fp_out);
1697 if (!empty)
1698 empty = (fgetc(fp_out) == EOF);
1699 mutt_file_fclose(&fp_out);
1700
1701 fflush(fp_pgp_err);
1702 fseek(fp_pgp_err, 0, SEEK_SET);
1703 clearerr(fp_pgp_err);
1704 while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1705 {
1706 err = true;
1707 fputs(buf, stdout);
1708 }
1709 mutt_file_fclose(&fp_pgp_err);
1710
1711 /* pause if there is any error output from PGP */
1712 if (err)
1714
1715 if (empty)
1716 {
1717 /* fatal error while trying to encrypt message */
1718 if (sign)
1719 pgp_class_void_passphrase(); /* just in case */
1720 unlink(buf_string(tempfile));
1721 goto cleanup;
1722 }
1723
1724 b_enc = mutt_body_new();
1725 b_enc->type = TYPE_MULTIPART;
1726 b_enc->subtype = mutt_str_dup("encrypted");
1727 b_enc->encoding = ENC_7BIT;
1728 b_enc->use_disp = false;
1729 b_enc->disposition = DISP_INLINE;
1730
1732 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-encrypted");
1733
1734 b_enc->parts = mutt_body_new();
1735 b_enc->parts->type = TYPE_APPLICATION;
1736 b_enc->parts->subtype = mutt_str_dup("pgp-encrypted");
1737 b_enc->parts->encoding = ENC_7BIT;
1738
1739 b_enc->parts->next = mutt_body_new();
1740 b_enc->parts->next->type = TYPE_APPLICATION;
1741 b_enc->parts->next->subtype = mutt_str_dup("octet-stream");
1742 b_enc->parts->next->encoding = ENC_7BIT;
1743 b_enc->parts->next->filename = buf_strdup(tempfile);
1744 b_enc->parts->next->use_disp = true;
1745 b_enc->parts->next->disposition = DISP_ATTACH;
1746 b_enc->parts->next->unlink = true; /* delete after sending the message */
1747 b_enc->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime can save */
1748
1749cleanup:
1750 buf_pool_release(&tempfile);
1751 buf_pool_release(&pgpinfile);
1752 return b_enc;
1753}
1754
1758struct Body *pgp_class_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
1759{
1761 struct Body *b_enc = NULL;
1762 char body_charset[256] = { 0 };
1763 const char *from_charset = NULL;
1764 const char *send_charset = NULL;
1765 bool empty = false;
1766 bool err;
1767 char buf[256] = { 0 };
1768 pid_t pid;
1769 struct Buffer *pgpinfile = buf_pool_get();
1770 struct Buffer *pgpoutfile = buf_pool_get();
1771
1772 if (b->type != TYPE_TEXT)
1773 goto cleanup;
1774 if (!mutt_istr_equal(b->subtype, "plain"))
1775 goto cleanup;
1776
1777 FILE *fp_body = mutt_file_fopen(b->filename, "r");
1778 if (!fp_body)
1779 {
1780 mutt_perror("%s", b->filename);
1781 goto cleanup;
1782 }
1783
1784 buf_mktemp(pgpinfile);
1785 FILE *fp_pgp_in = mutt_file_fopen(buf_string(pgpinfile), "w");
1786 if (!fp_pgp_in)
1787 {
1788 mutt_perror("%s", buf_string(pgpinfile));
1789 mutt_file_fclose(&fp_body);
1790 goto cleanup;
1791 }
1792
1793 /* The following code is really correct: If noconv is set,
1794 * b's charset parameter contains the on-disk character set, and
1795 * we have to convert from that to utf-8. If noconv is not set,
1796 * we have to convert from $charset to utf-8. */
1797
1798 mutt_body_get_charset(b, body_charset, sizeof(body_charset));
1799 if (b->noconv)
1800 from_charset = body_charset;
1801 else
1802 from_charset = cc_charset();
1803
1804 if (mutt_ch_is_us_ascii(body_charset))
1805 {
1806 send_charset = "us-ascii";
1807 mutt_file_copy_stream(fp_body, fp_pgp_in);
1808 }
1809 else
1810 {
1811 int c;
1812 struct FgetConv *fc = NULL;
1813
1814 if (flags & SEC_ENCRYPT)
1815 send_charset = "us-ascii";
1816 else
1817 send_charset = "utf-8";
1818
1819 /* fromcode is assumed to be correct: we set flags to 0 */
1820 fc = mutt_ch_fgetconv_open(fp_body, from_charset, "utf-8", MUTT_ICONV_NONE);
1821 while ((c = mutt_ch_fgetconv(fc)) != EOF)
1822 fputc(c, fp_pgp_in);
1823
1825 }
1826 mutt_file_fclose(&fp_body);
1827 mutt_file_fclose(&fp_pgp_in);
1828
1829 buf_mktemp(pgpoutfile);
1830 FILE *fp_pgp_out = mutt_file_fopen(buf_string(pgpoutfile), "w+");
1831 FILE *fp_pgp_err = mutt_file_mkstemp();
1832 if (!fp_pgp_out || !fp_pgp_err)
1833 {
1834 mutt_perror("%s", fp_pgp_out ? "Can't create temporary file" : buf_string(pgpoutfile));
1835 unlink(buf_string(pgpinfile));
1836 if (fp_pgp_out)
1837 {
1838 mutt_file_fclose(&fp_pgp_out);
1839 unlink(buf_string(pgpoutfile));
1840 }
1841 mutt_file_fclose(&fp_pgp_err);
1842 goto cleanup;
1843 }
1844
1845 pid = pgp_invoke_traditional(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
1846 fileno(fp_pgp_err), buf_string(pgpinfile), keylist, flags);
1847 if (pid == -1)
1848 {
1849 mutt_perror(_("Can't invoke PGP"));
1850 mutt_file_fclose(&fp_pgp_out);
1851 mutt_file_fclose(&fp_pgp_err);
1852 mutt_file_unlink(buf_string(pgpinfile));
1853 unlink(buf_string(pgpoutfile));
1854 goto cleanup;
1855 }
1856
1857 if (pgp_use_gpg_agent())
1858 *mod_data->pgp_pass = '\0';
1859 if (flags & SEC_SIGN)
1860 fprintf(fp_pgp_in, "%s\n", mod_data->pgp_pass);
1861 mutt_file_fclose(&fp_pgp_in);
1862
1863 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1864 if (filter_wait(pid) && c_pgp_check_exit)
1865 empty = true;
1866
1867 mutt_file_unlink(buf_string(pgpinfile));
1868
1869 fflush(fp_pgp_out);
1870 fflush(fp_pgp_err);
1871
1872 fseek(fp_pgp_out, 0, SEEK_SET);
1873 clearerr(fp_pgp_out);
1874 fseek(fp_pgp_err, 0, SEEK_SET);
1875 clearerr(fp_pgp_err);
1876
1877 if (!empty)
1878 empty = (fgetc(fp_pgp_out) == EOF);
1879 mutt_file_fclose(&fp_pgp_out);
1880
1881 err = false;
1882
1883 while (fgets(buf, sizeof(buf), fp_pgp_err))
1884 {
1885 err = true;
1886 fputs(buf, stdout);
1887 }
1888
1889 mutt_file_fclose(&fp_pgp_err);
1890
1891 if (err)
1893
1894 if (empty)
1895 {
1896 if (flags & SEC_SIGN)
1897 pgp_class_void_passphrase(); /* just in case */
1898 unlink(buf_string(pgpoutfile));
1899 goto cleanup;
1900 }
1901
1902 b_enc = mutt_body_new();
1903
1904 b_enc->encoding = ENC_7BIT;
1905
1906 b_enc->type = TYPE_TEXT;
1907 b_enc->subtype = mutt_str_dup("plain");
1908
1909 mutt_param_set(&b_enc->parameter, "x-action",
1910 (flags & SEC_ENCRYPT) ? "pgp-encrypted" : "pgp-signed");
1911 mutt_param_set(&b_enc->parameter, "charset", send_charset);
1912
1913 b_enc->filename = buf_strdup(pgpoutfile);
1914
1915 b_enc->disposition = DISP_NONE;
1916 b_enc->unlink = true;
1917
1918 b_enc->noconv = true;
1919 b_enc->use_disp = false;
1920
1921 if (!(flags & SEC_ENCRYPT))
1922 b_enc->encoding = b->encoding;
1923
1924cleanup:
1925 buf_pool_release(&pgpinfile);
1926 buf_pool_release(&pgpoutfile);
1927 return b_enc;
1928}
1929
1934{
1935 struct PgpKeyInfo *p = NULL;
1936 const char *prompt = NULL;
1937 const char *letters = NULL;
1938 const char *choices = NULL;
1939 char promptbuf[1024] = { 0 };
1940 int choice;
1941
1942 if (!(WithCrypto & APPLICATION_PGP))
1943 return e->security;
1944
1945 /* If autoinline and no crypto options set, then set inline. */
1946 const bool c_pgp_auto_inline = cs_subset_bool(NeoMutt->sub, "pgp_auto_inline");
1947 if (c_pgp_auto_inline &&
1948 !((e->security & APPLICATION_PGP) && (e->security & (SEC_SIGN | SEC_ENCRYPT))))
1949 {
1950 e->security |= SEC_INLINE;
1951 }
1952
1954
1955 char *mime_inline = NULL;
1956 if (e->security & SEC_INLINE)
1957 {
1958 /* L10N: The next string MUST have the same highlighted letter
1959 One of them will appear in each of the three strings marked "(inline"), below. */
1960 mime_inline = _("PGP/M(i)ME");
1961 }
1962 else
1963 {
1964 /* L10N: The previous string MUST have the same highlighted letter
1965 One of them will appear in each of the three strings marked "(inline"), below. */
1966 mime_inline = _("(i)nline");
1967 }
1968 /* Opportunistic encrypt is controlling encryption. Allow to toggle
1969 * between inline and mime, but not turn encryption on or off.
1970 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
1971 * letter choices for those. */
1972 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
1973 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
1974 {
1975 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1976 {
1977 snprintf(promptbuf, sizeof(promptbuf),
1978 /* L10N: PGP options (inline) (opportunistic encryption is on) */
1979 _("PGP (s)ign, sign (a)s, %s format, (c)lear, or (o)ppenc mode off?"),
1980 mime_inline);
1981 prompt = promptbuf;
1982 /* L10N: PGP options (inline) (opportunistic encryption is on)
1983 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1984 letters = _("saico");
1985 choices = "SaiCo";
1986 }
1987 else
1988 {
1989 /* L10N: PGP options (opportunistic encryption is on) */
1990 prompt = _("PGP (s)ign, sign (a)s, (c)lear, or (o)ppenc mode off?");
1991 /* L10N: PGP options (opportunistic encryption is on) */
1992 letters = _("saco");
1993 choices = "SaCo";
1994 }
1995 }
1996 else if (c_crypt_opportunistic_encrypt)
1997 {
1998 /* Opportunistic encryption option is set, but is toggled off
1999 * for this message. */
2000 /* When the message is not selected for signing or encryption, the toggle
2001 * between PGP/MIME and Traditional doesn't make sense. */
2002 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2003 {
2004 snprintf(promptbuf, sizeof(promptbuf),
2005 /* L10N: PGP options (inline) (opportunistic encryption is off) */
2006 _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, (c)lear, or (o)ppenc mode?"),
2007 mime_inline);
2008 prompt = promptbuf;
2009 /* L10N: PGP options (inline) (opportunistic encryption is off)
2010 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
2011 letters = _("esabico");
2012 choices = "esabicO";
2013 }
2014 else
2015 {
2016 /* L10N: PGP options (opportunistic encryption is off) */
2017 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode?");
2018 /* L10N: PGP options (opportunistic encryption is off) */
2019 letters = _("esabco");
2020 choices = "esabcO";
2021 }
2022 }
2023 else
2024 {
2025 /* Opportunistic encryption is unset */
2026 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2027 {
2028 snprintf(promptbuf, sizeof(promptbuf),
2029 /* L10N: PGP options (inline) */
2030 _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, or (c)lear?"),
2031 mime_inline);
2032 prompt = promptbuf;
2033 /* L10N: PGP options (inline)
2034 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
2035 letters = _("esabic");
2036 choices = "esabic";
2037 }
2038 else
2039 {
2040 /* L10N: PGP options */
2041 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (c)lear?");
2042 /* L10N: PGP options */
2043 letters = _("esabc");
2044 choices = "esabc";
2045 }
2046 }
2047
2048 choice = mw_multi_choice(prompt, letters);
2049 if (choice > 0)
2050 {
2051 switch (choices[choice - 1])
2052 {
2053 case 'a': /* sign (a)s */
2054 OptPgpCheckTrust = false;
2055
2056 p = pgp_ask_for_key(_("Sign as: "), NULL, KEYFLAG_NONE, PGP_SECRING);
2057 if (p)
2058 {
2059 char input_signas[128] = { 0 };
2060 snprintf(input_signas, sizeof(input_signas), "0x%s", pgp_fpr_or_lkeyid(p));
2061 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
2062 pgp_key_free(&p);
2063
2064 e->security |= SEC_SIGN;
2065
2066 crypt_pgp_void_passphrase(); /* probably need a different passphrase */
2067 }
2068 break;
2069
2070 case 'b': /* (b)oth */
2071 e->security |= (SEC_ENCRYPT | SEC_SIGN);
2072 break;
2073
2074 case 'C':
2075 e->security &= ~SEC_SIGN;
2076 break;
2077
2078 case 'c': /* (c)lear */
2079 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2080 break;
2081
2082 case 'e': /* (e)ncrypt */
2083 e->security |= SEC_ENCRYPT;
2084 e->security &= ~SEC_SIGN;
2085 break;
2086
2087 case 'i': /* toggle (i)nline */
2088 e->security ^= SEC_INLINE;
2089 break;
2090
2091 case 'O': /* oppenc mode on */
2094 break;
2095
2096 case 'o': /* oppenc mode off */
2098 break;
2099
2100 case 'S': /* (s)ign in oppenc mode */
2101 e->security |= SEC_SIGN;
2102 break;
2103
2104 case 's': /* (s)ign */
2105 e->security &= ~SEC_ENCRYPT;
2106 e->security |= SEC_SIGN;
2107 break;
2108
2109 default:
2110 break;
2111 }
2112 }
2113
2114 return e->security;
2115}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:687
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1473
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:481
Email Address Handling.
GUI display the mailboxes in a side panel.
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:99
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
long cs_subset_long(const struct ConfigSubset *sub, const char *name)
Get a long config item by name.
Definition helpers.c:95
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Convenience wrapper for the core headers.
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1052
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1490
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:409
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:468
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:505
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition crypt.c:64
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:815
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:549
Signing/encryption multiplexor.
void crypt_pgp_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase().
Definition cryptglue.c:211
Wrapper around crypto functions.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:101
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
Edit a string.
@ MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition wdata.h:49
@ MUTT_COMP_PASS
Password mode (no echo).
Definition wdata.h:48
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition body.c:134
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1982
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1517
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
bool envlist_set(char ***envp, const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition envlist.c:88
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
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:192
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1433
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition globals.c:46
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition globals.c:55
Global variables.
int pgp_class_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition pgp.c:471
int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Decrypt an encrypted MIME part - Implements CryptModuleSpecs::decrypt_mime() -.
Definition pgp.c:1177
int pgp_class_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
Definition pgp.c:1268
char * pgp_class_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition pgp.c:1489
bool pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
Look for inline (non-MIME) PGP content - Implements CryptModuleSpecs::pgp_check_traditional() -.
Definition pgp.c:876
struct Body * pgp_class_encrypt_message(struct Body *b, char *keylist, bool sign, const struct AddressList *from)
PGP encrypt an email - Implements CryptModuleSpecs::pgp_encrypt_message() -.
Definition pgp.c:1620
void pgp_class_extract_key_from_attachment(FILE *fp, struct Body *b)
Extract PGP key from an attachment - Implements CryptModuleSpecs::pgp_extract_key_from_attachment() -...
Definition pgp.c:1011
void pgp_class_invoke_getkeys(struct Address *addr)
Run a command to download a PGP key - Implements CryptModuleSpecs::pgp_invoke_getkeys() -.
Definition pgpinvoke.c:315
void pgp_class_invoke_import(const char *fname)
Import a key from a message into the user's public key ring - Implements CryptModuleSpecs::pgp_invoke...
Definition pgpinvoke.c:287
struct Body * pgp_class_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
Create an inline PGP encrypted, signed email - Implements CryptModuleSpecs::pgp_traditional_encryptsi...
Definition pgp.c:1758
SecurityFlags pgp_class_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition pgp.c:1933
struct Body * pgp_class_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition pgp.c:1353
bool pgp_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition pgp.c:81
int pgp_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition pgp.c:905
void pgp_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition pgp.c:71
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1124
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
Convenience wrapper for the gui headers.
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1675
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1950
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition exec.c:319
Hook Commands.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:92
#define MUTT_MEM_REALLOC(pptr, n, T)
Definition memory.h:78
@ ENC_7BIT
7-bit text
Definition mime.h:49
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
@ DISP_ATTACH
Content is attached.
Definition mime.h:63
@ DISP_INLINE
Content is inline.
Definition mime.h:62
@ DISP_NONE
No preferred disposition.
Definition mime.h:65
#define is_multipart(body)
Check if a body part is multipart or a message container.
Definition mime.h:84
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition multipart.c:93
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition charset.c:882
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition charset.c:968
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition charset.c:921
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1030
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:950
#define MUTT_ICONV_NONE
No flags are set.
Definition charset.h:66
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
#define mutt_ch_is_us_ascii(str)
Definition charset.h:108
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:896
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture().
Definition regex.c:621
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
void state_prefix_putc(struct State *state, char c)
Write a prefixed character to the state.
Definition state.c:168
#define state_puts(STATE, STR)
Definition state.h:64
#define state_set_prefix(state)
Definition state.h:62
#define state_putc(STATE, STR)
Definition state.h:65
@ STATE_NONE
No flags are set.
Definition state.h:36
@ STATE_VERIFY
Perform signature verification.
Definition state.h:38
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:557
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination).
Definition string.c:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NONE
Overwrite existing file (the default).
Definition mutt_attach.h:59
API for encryption/signing of emails.
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_INLINE
Email has an inline signature.
Definition lib.h:99
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:112
@ KEYFLAG_NONE
No flags are set.
Definition lib.h:146
@ KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:148
@ KEYFLAG_SUBKEY
Key is a subkey.
Definition lib.h:154
#define WithCrypto
Definition lib.h:132
Ncrypt private Module data.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key's long id.
Definition pgp.c:162
char * pgp_this_keyid(struct PgpKeyInfo *k)
Get the ID of this key.
Definition pgp.c:188
static struct Body * pgp_decrypt_part(struct Body *a, struct State *state, FILE *fp_out, struct Body *p)
Decrypt part of a PGP message.
Definition pgp.c:1034
static char * pgp_fingerprint(struct PgpKeyInfo *k)
Get the key's fingerprint.
Definition pgp.c:213
static int pgp_check_pgp_decryption_okay_regex(FILE *fp_in)
Check PGP output to look for successful outcome.
Definition pgp.c:300
char * pgp_keyid(struct PgpKeyInfo *k)
Get the ID of the main (parent) key.
Definition pgp.c:201
char * pgp_fpr_or_lkeyid(struct PgpKeyInfo *k)
Get the fingerprint or long keyid.
Definition pgp.c:231
static struct PgpKeyInfo * key_parent(struct PgpKeyInfo *k)
Find a key's parent (if it's a subkey).
Definition pgp.c:148
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:248
char * pgp_short_keyid(struct PgpKeyInfo *k)
Get a key's short id.
Definition pgp.c:174
static void pgp_copy_clearsigned(FILE *fp_in, struct State *state, char *charset)
Copy a clearsigned message, stripping the signature.
Definition pgp.c:422
static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *b)
Extract pgp keys from messages/attachments.
Definition pgp.c:979
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition pgp.c:124
static int pgp_check_decryption_okay(FILE *fp_in)
Check GPG output for status codes.
Definition pgp.c:354
static bool pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check the body of an inline PGP message.
Definition pgp.c:809
PGP sign, encrypt, check routines.
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:229
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:132
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:264
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:204
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:157
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:181
Wrapper around calls to external PGP program.
struct PgpKeyInfo * pgp_ask_for_key(char *tag, const char *whatfor, KeyFlags abilities, enum PgpRing keyring)
Ask the user for a PGP key.
Definition pgpkey.c:202
struct PgpKeyInfo * pgp_getkeybyaddr(struct Address *a, KeyFlags abilities, enum PgpRing keyring, bool oppenc_mode)
Find a PGP key by address.
Definition pgpkey.c:382
struct PgpKeyInfo * pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
Find a PGP key by string.
Definition pgpkey.c:523
PGP key management routines.
@ PGP_SECRING
Secret keys.
Definition pgpkey.h:41
@ PGP_PUBRING
Public keys.
Definition pgpkey.h:40
void pgp_key_free(struct PgpKeyInfo **kpp)
Free a PGP key info.
Definition pgplib.c:204
Misc PGP helper routines.
const char * pgp_micalg(const char *fname)
Find the hash algorithm of a file.
Definition pgpmicalg.c:229
Identify the hash algorithm from a PGP signature.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G).
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition question.c:357
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define STAILQ_FIRST(head)
Definition queue.h:388
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:304
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:763
Convenience wrapper for the send headers.
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:718
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
The body of an email.
Definition body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool noconv
Don't do character set conversion.
Definition body.h:46
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
bool use_disp
Content-Disposition uses filename= ?
Definition body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition body.h:42
struct Body * next
next attachment in the list
Definition body.h:72
char * subtype
content-type subtype
Definition body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
bool goodsig
Good cryptographic signature.
Definition body.h:45
unsigned int type
content-type primary type, ContentType
Definition body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:37
The envelope/body of an email.
Definition email.h:39
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
Cursor for converting a file's encoding.
Definition charset.h:45
FILE * fp
File to read from.
Definition charset.h:46
char * p
Current position in output buffer.
Definition charset.h:50
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Ncrypt private Module data.
Definition module_data.h:39
char pgp_pass[1024]
Cached PGP Passphrase.
Definition module_data.h:51
time_t pgp_exptime
Unix time when pgp_pass expires.
Definition module_data.h:52
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Information about a PGP key.
Definition pgplib.h:49
char * keyid
Key ID.
Definition pgplib.h:50
KeyFlags flags
Key flags.
Definition pgplib.h:53
char * fingerprint
Key fingerprint.
Definition pgplib.h:51
struct PgpKeyInfo * parent
Parent key.
Definition pgplib.h:58
Cached regular expression.
Definition regex3.h:85
regex_t * regex
compiled expression
Definition regex3.h:87
Keep track when processing files.
Definition state.h:54
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition subset.c:392
#define buf_mktemp(buf)
Definition tmp.h:33
#define mutt_file_mkstemp()
Definition tmp.h:36