NeoMutt  2024-02-01-25-ga71e95
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt_gpgme.c
Go to the documentation of this file.
1
35#include "config.h"
36#include <errno.h>
37#include <gpg-error.h>
38#include <gpgme.h>
39#include <langinfo.h>
40#include <locale.h>
41#include <stdbool.h>
42#include <stdio.h>
43#include <string.h>
44#include <time.h>
45#include <unistd.h>
46#include "private.h"
47#include "mutt/lib.h"
48#include "address/lib.h"
49#include "config/lib.h"
50#include "email/lib.h"
51#include "core/lib.h"
52#include "alias/lib.h"
53#include "gui/lib.h"
54#include "mutt.h"
55#include "crypt_gpgme.h"
56#include "lib.h"
57#include "attach/lib.h"
58#include "editor/lib.h"
59#include "history/lib.h"
60#include "question/lib.h"
61#include "send/lib.h"
62#include "crypt.h"
63#include "globals.h"
64#include "gpgme_functions.h"
65#include "handler.h"
66#include "hook.h"
67#include "mutt_logging.h"
68#ifdef USE_AUTOCRYPT
69#include "autocrypt/lib.h"
70#endif
71
72// clang-format off
73/* Values used for comparing addresses. */
74#define CRYPT_KV_VALID (1 << 0)
75#define CRYPT_KV_ADDR (1 << 1)
76#define CRYPT_KV_STRING (1 << 2)
77#define CRYPT_KV_STRONGID (1 << 3)
78#define CRYPT_KV_MATCH (CRYPT_KV_ADDR | CRYPT_KV_STRING)
79// clang-format on
80
85{
86 char *what;
87 char *dflt;
89};
90
92static struct CryptCache *IdDefaults = NULL;
94static gpgme_key_t SignatureKey = NULL;
96static char *CurrentSender = NULL;
97
98#define PKA_NOTATION_NAME "pka-address@gnupg.org"
99
100#define _LINE_COMPARE(_x, _y) line_compare(_x, sizeof(_x) - 1, _y)
101#define MESSAGE(_y) _LINE_COMPARE("MESSAGE-----", _y)
102#define SIGNED_MESSAGE(_y) _LINE_COMPARE("SIGNED MESSAGE-----", _y)
103#define PUBLIC_KEY_BLOCK(_y) _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
104#define BEGIN_PGP_SIGNATURE(_y) \
105 _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)
106
112static bool is_pka_notation(gpgme_sig_notation_t notation)
113{
114 return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
115}
116
121static void redraw_if_needed(gpgme_ctx_t ctx)
122{
123 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
124 if (!s /* flag not known */ || *s /* flag true */)
125 {
127 }
128}
129
138const char *crypt_keyid(struct CryptKeyInfo *k)
139{
140 const char *s = "????????";
141
142 if (k->kobj && k->kobj->subkeys)
143 {
144 s = k->kobj->subkeys->keyid;
145 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
146 if ((!c_pgp_long_ids) && (strlen(s) == 16))
147 {
148 /* Return only the short keyID. */
149 s += 8;
150 }
151 }
152
153 return s;
154}
155
163static const char *crypt_long_keyid(struct CryptKeyInfo *k)
164{
165 const char *s = "????????????????";
166
167 if (k->kobj && k->kobj->subkeys)
168 {
169 s = k->kobj->subkeys->keyid;
170 }
171
172 return s;
173}
174
180static const char *crypt_short_keyid(struct CryptKeyInfo *k)
181{
182 const char *s = "????????";
183
184 if (k->kobj && k->kobj->subkeys)
185 {
186 s = k->kobj->subkeys->keyid;
187 if (strlen(s) == 16)
188 s += 8;
189 }
190
191 return s;
192}
193
199static const char *crypt_fpr(struct CryptKeyInfo *k)
200{
201 const char *s = "";
202
203 if (k->kobj && k->kobj->subkeys)
204 s = k->kobj->subkeys->fpr;
205
206 return s;
207}
208
214const char *crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
215{
216 const char *s = "????????????????";
217
218 if (k->kobj && k->kobj->subkeys)
219 {
220 if (k->kobj->subkeys->fpr)
221 s = k->kobj->subkeys->fpr;
222 else
223 s = k->kobj->subkeys->keyid;
224 }
225
226 return s;
227}
228
235{
236 struct CryptKeyInfo *k = NULL;
237
238 k = mutt_mem_calloc(1, sizeof(*k));
239 k->kobj = key->kobj;
240 gpgme_key_ref(key->kobj);
241 k->idx = key->idx;
242 k->uid = key->uid;
243 k->flags = key->flags;
244 k->validity = key->validity;
245
246 return k;
247}
248
253static void crypt_key_free(struct CryptKeyInfo **keylist)
254{
255 if (!keylist)
256 return;
257
258 struct CryptKeyInfo *k = NULL;
259
260 while (*keylist)
261 {
262 k = *keylist;
263 *keylist = (*keylist)->next;
264
265 gpgme_key_unref(k->kobj);
266 FREE(&k);
267 }
268}
269
276{
277 if (!key)
278 return false;
279
280 bool is_strong = false;
281
282 if ((key->flags & KEYFLAG_ISX509))
283 return true;
284
285 switch (key->validity)
286 {
287 case GPGME_VALIDITY_MARGINAL:
288 case GPGME_VALIDITY_NEVER:
289 case GPGME_VALIDITY_UNDEFINED:
290 case GPGME_VALIDITY_UNKNOWN:
291 is_strong = false;
292 break;
293
294 case GPGME_VALIDITY_FULL:
295 case GPGME_VALIDITY_ULTIMATE:
296 is_strong = true;
297 break;
298 }
299
300 return is_strong;
301}
302
311{
312 if (!key)
313 return 0;
314
315 return !(key->flags & KEYFLAG_CANTUSE);
316}
317
328static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr,
329 struct CryptKeyInfo *key)
330{
331 int rc = 0;
332
333 if (crypt_id_is_valid(key))
334 rc |= CRYPT_KV_VALID;
335
336 if (crypt_id_is_strong(key))
337 rc |= CRYPT_KV_STRONGID;
338
339 if (addr && u_addr)
340 {
341 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
342 {
343 rc |= CRYPT_KV_ADDR;
344 }
345
346 if (addr->personal && u_addr->personal &&
347 buf_istr_equal(addr->personal, u_addr->personal))
348 {
349 rc |= CRYPT_KV_STRING;
350 }
351 }
352
353 return rc;
354}
355
361gpgme_ctx_t create_gpgme_context(bool for_smime)
362{
363 gpgme_ctx_t ctx = NULL;
364
365 gpgme_error_t err = gpgme_new(&ctx);
366
367#ifdef USE_AUTOCRYPT
368 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
369 if (!err && OptAutocryptGpgme)
370 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
371#endif
372
373 if (err != 0)
374 {
375 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
376 mutt_exit(1);
377 }
378
379 if (for_smime)
380 {
381 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
382 if (err != 0)
383 {
384 mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
385 mutt_exit(1);
386 }
387 }
388
389 return ctx;
390}
391
400static gpgme_data_t create_gpgme_data(void)
401{
402 gpgme_data_t data = NULL;
403
404 gpgme_error_t err = gpgme_data_new(&data);
405 if (err != 0)
406 {
407 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
408 mutt_exit(1);
409 }
410 return data;
411}
412
419static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
420{
421 int err = 0;
422 gpgme_data_t data = NULL;
423
424 struct Buffer *tempfile = buf_pool_get();
425 buf_mktemp(tempfile);
426 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
427 if (!fp_tmp)
428 {
429 mutt_perror("%s", buf_string(tempfile));
430 goto cleanup;
431 }
432
434 fputc('\n', fp_tmp);
435 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
436
437 if (convert)
438 {
439 int c, hadcr = 0;
440 unsigned char buf[1];
441
443 rewind(fp_tmp);
444 while ((c = fgetc(fp_tmp)) != EOF)
445 {
446 if (c == '\r')
447 {
448 hadcr = 1;
449 }
450 else
451 {
452 if ((c == '\n') && !hadcr)
453 {
454 buf[0] = '\r';
455 gpgme_data_write(data, buf, 1);
456 }
457
458 hadcr = 0;
459 }
460 /* FIXME: This is quite suboptimal */
461 buf[0] = c;
462 gpgme_data_write(data, buf, 1);
463 }
464 mutt_file_fclose(&fp_tmp);
465 gpgme_data_seek(data, 0, SEEK_SET);
466 }
467 else
468 {
469 mutt_file_fclose(&fp_tmp);
470 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
471 if (err != 0)
472 {
473 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
474 gpgme_data_release(data);
475 data = NULL;
476 /* fall through to unlink the tempfile */
477 }
478 }
479 unlink(buf_string(tempfile));
480
481cleanup:
482 buf_pool_release(&tempfile);
483 return data;
484}
485
493static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
494{
495 gpgme_data_t data = NULL;
496
497 int err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
498 if (err != 0)
499 {
500 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
501 return NULL;
502 }
503
504 return data;
505}
506
514static int data_object_to_stream(gpgme_data_t data, FILE *fp)
515{
516 char buf[4096] = { 0 };
517 ssize_t nread;
518
519 int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
520 if (err != 0)
521 {
522 mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
523 return -1;
524 }
525
526 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
527 {
528 /* fixme: we are not really converting CRLF to LF but just
529 * skipping CR. Doing it correctly needs a more complex logic */
530 for (char *p = buf; nread; p++, nread--)
531 {
532 if (*p != '\r')
533 putc(*p, fp);
534 }
535
536 if (ferror(fp))
537 {
538 mutt_perror(_("[tempfile]"));
539 return -1;
540 }
541 }
542 if (nread == -1)
543 {
544 mutt_error(_("error reading data object: %s"), strerror(errno));
545 return -1;
546 }
547 return 0;
548}
549
561static char *data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
562{
563 ssize_t nread = 0;
564 char *rv = NULL;
565 struct Buffer *tempf = buf_pool_get();
566
567 buf_mktemp(tempf);
568
569 FILE *fp = mutt_file_fopen(buf_string(tempf), "w+");
570 if (!fp)
571 {
572 mutt_perror(_("Can't create temporary file"));
573 goto cleanup;
574 }
575
576 int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
577 if (err == 0)
578 {
579 char buf[4096] = { 0 };
580
581 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
582 {
583 if (fwrite(buf, nread, 1, fp) != 1)
584 {
585 mutt_perror("%s", buf_string(tempf));
586 mutt_file_fclose(&fp);
587 unlink(buf_string(tempf));
588 goto cleanup;
589 }
590 }
591 }
592 if (fp_ret)
593 rewind(fp);
594 else
595 mutt_file_fclose(&fp);
596 if (nread == -1)
597 {
598 mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
599 unlink(buf_string(tempf));
600 mutt_file_fclose(&fp);
601 goto cleanup;
602 }
603 if (fp_ret)
604 *fp_ret = fp;
605 rv = buf_strdup(tempf);
606
607cleanup:
608 buf_pool_release(&tempf);
609 return rv;
610}
611
618static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
619{
620 unsigned int n = 0;
621
622 const char *s = keylist;
623 do
624 {
625 while (*s == ' ')
626 s++;
627 if (*s != '\0')
628 {
629 if (n == 0)
630 {
631 if (!use_smime)
632 buf_addstr(recpstring, "--\n");
633 }
634 else
635 {
636 buf_addch(recpstring, '\n');
637 }
638 n++;
639
640 while ((*s != '\0') && (*s != ' '))
641 buf_addch(recpstring, *s++);
642 }
643 } while (*s != '\0');
644}
645
654static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
655{
656 gpgme_error_t err;
657 gpgme_key_t key = NULL, key2 = NULL;
658 gpgme_ctx_t listctx = create_gpgme_context(for_smime);
659 err = gpgme_op_keylist_start(listctx, address, 1);
660 if (err == 0)
661 err = gpgme_op_keylist_next(listctx, &key);
662 if (err)
663 {
664 gpgme_release(listctx);
665 mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
666 return false;
667 }
668
669 char *fpr = "fpr1";
670 if (key->subkeys)
671 fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
672 while (gpgme_op_keylist_next(listctx, &key2) == 0)
673 {
674 char *fpr2 = "fpr2";
675 if (key2->subkeys)
676 fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
677 if (!mutt_str_equal(fpr, fpr2))
678 {
679 gpgme_key_unref(key);
680 gpgme_key_unref(key2);
681 gpgme_release(listctx);
682 mutt_error(_("ambiguous specification of secret key '%s'"), address);
683 return false;
684 }
685 else
686 {
687 gpgme_key_unref(key2);
688 }
689 }
690 gpgme_op_keylist_end(listctx);
691 gpgme_release(listctx);
692
693 gpgme_signers_clear(ctx);
694 err = gpgme_signers_add(ctx, key);
695 gpgme_key_unref(key);
696 if (err)
697 {
698 mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
699 return false;
700 }
701 return true;
702}
703
712static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
713{
714 const char *signid = NULL;
715
716 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
717 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
718 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
719 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
720 if (for_smime)
721 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
722#ifdef USE_AUTOCRYPT
723 else if (OptAutocryptGpgme)
724 signid = AutocryptSignAs;
725#endif
726 else
727 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
728
729 /* Try getting the signing key from config entries */
730 if (signid && set_signer_from_address(ctx, signid, for_smime))
731 {
732 return 0;
733 }
734
735 /* Try getting the signing key from the From line */
736 if (al)
737 {
738 struct Address *a;
739 TAILQ_FOREACH(a, al, entries)
740 {
741 if (a->mailbox && set_signer_from_address(ctx, buf_string(a->mailbox), for_smime))
742 {
743 return 0;
744 }
745 }
746 }
747
748 return (!signid && !al) ? 0 : -1;
749}
750
756static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
757{
758 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, CurrentSender, 0);
759 if (err)
760 {
761 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
762 }
763
764 return err;
765}
766
776static char *encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime,
777 bool combined_signed, const struct AddressList *from)
778{
779 gpgme_error_t err;
780 gpgme_ctx_t ctx = NULL;
781 gpgme_data_t ciphertext = NULL;
782 char *outfile = NULL;
783
784 struct Buffer *recpstring = buf_pool_get();
785 create_recipient_string(keylist, recpstring, use_smime);
786 if (buf_is_empty(recpstring))
787 {
788 buf_pool_release(&recpstring);
789 return NULL;
790 }
791
792 ctx = create_gpgme_context(use_smime);
793 if (!use_smime)
794 gpgme_set_armor(ctx, 1);
795
796 ciphertext = create_gpgme_data();
797
798 if (combined_signed)
799 {
800 if (set_signer(ctx, from, use_smime))
801 goto cleanup;
802
803 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
804 if (c_crypt_use_pka)
805 {
806 err = set_pka_sig_notation(ctx);
807 if (err != 0)
808 goto cleanup;
809 }
810
811 err = gpgme_op_encrypt_sign_ext(ctx, NULL, buf_string(recpstring),
812 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
813 }
814 else
815 {
816 err = gpgme_op_encrypt_ext(ctx, NULL, buf_string(recpstring),
817 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
818 }
819
820 redraw_if_needed(ctx);
821 if (err != 0)
822 {
823 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
824 goto cleanup;
825 }
826
827 outfile = data_object_to_tempfile(ciphertext, NULL);
828
829cleanup:
830 buf_pool_release(&recpstring);
831 gpgme_release(ctx);
832 gpgme_data_release(ciphertext);
833 return outfile;
834}
835
848static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
849{
850 gpgme_sign_result_t result = NULL;
851 const char *algorithm_name = NULL;
852
853 if (buflen < 5)
854 return -1;
855
856 *buf = '\0';
857 result = gpgme_op_sign_result(ctx);
858 if (result && result->signatures)
859 {
860 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
861 if (algorithm_name)
862 {
863 if (use_smime)
864 {
865 /* convert GPGME raw hash name to RFC2633 format */
866 snprintf(buf, buflen, "%s", algorithm_name);
867 mutt_str_lower(buf);
868 }
869 else
870 {
871 /* convert GPGME raw hash name to RFC3156 format */
872 snprintf(buf, buflen, "pgp-%s", algorithm_name);
873 mutt_str_lower(buf + 4);
874 }
875 }
876 }
877
878 return (buf[0] != '\0') ? 0 : -1;
879}
880
886static void print_time(time_t t, struct State *state)
887{
888 char p[256] = { 0 };
889 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
890 state_puts(state, p);
891}
892
901static struct Body *sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
902{
903 struct Body *b_sign = NULL;
904 char *sigfile = NULL;
905 int err = 0;
906 char buf[100] = { 0 };
907 gpgme_ctx_t ctx = NULL;
908 gpgme_data_t message = NULL, signature = NULL;
909 gpgme_sign_result_t sigres = NULL;
910
911 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
912
913 message = body_to_data_object(b, true);
914 if (!message)
915 return NULL;
916 signature = create_gpgme_data();
917
918 ctx = create_gpgme_context(use_smime);
919 if (!use_smime)
920 gpgme_set_armor(ctx, 1);
921
922 if (set_signer(ctx, from, use_smime))
923 {
924 gpgme_data_release(signature);
925 gpgme_data_release(message);
926 gpgme_release(ctx);
927 return NULL;
928 }
929
930 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
931 if (c_crypt_use_pka)
932 {
933 err = set_pka_sig_notation(ctx);
934 if (err != 0)
935 {
936 gpgme_data_release(signature);
937 gpgme_data_release(message);
938 gpgme_release(ctx);
939 return NULL;
940 }
941 }
942
943 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
944 redraw_if_needed(ctx);
945 gpgme_data_release(message);
946 if (err != 0)
947 {
948 gpgme_data_release(signature);
949 gpgme_release(ctx);
950 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
951 return NULL;
952 }
953 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
954 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
955 sigres = gpgme_op_sign_result(ctx);
956 if (!sigres->signatures)
957 {
958 gpgme_data_release(signature);
959 gpgme_release(ctx);
960 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
961 return NULL;
962 }
963
964 sigfile = data_object_to_tempfile(signature, NULL);
965 gpgme_data_release(signature);
966 if (!sigfile)
967 {
968 gpgme_release(ctx);
969 return NULL;
970 }
971
972 b_sign = mutt_body_new();
973 b_sign->type = TYPE_MULTIPART;
974 b_sign->subtype = mutt_str_dup("signed");
975 b_sign->encoding = ENC_7BIT;
976 b_sign->use_disp = false;
977 b_sign->disposition = DISP_INLINE;
978
980 mutt_param_set(&b_sign->parameter, "protocol",
981 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
982 /* Get the micalg from GPGME. Old gpgme versions don't support this
983 * for S/MIME so we assume sha-1 in this case. */
984 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
985 mutt_param_set(&b_sign->parameter, "micalg", buf);
986 else if (use_smime)
987 mutt_param_set(&b_sign->parameter, "micalg", "sha1");
988 gpgme_release(ctx);
989
990 b_sign->parts = b;
991 b = b_sign;
992
993 b_sign->parts->next = mutt_body_new();
994 b_sign = b_sign->parts->next;
995 b_sign->type = TYPE_APPLICATION;
996 if (use_smime)
997 {
998 b_sign->subtype = mutt_str_dup("pkcs7-signature");
999 mutt_param_set(&b_sign->parameter, "name", "smime.p7s");
1000 b_sign->encoding = ENC_BASE64;
1001 b_sign->use_disp = true;
1002 b_sign->disposition = DISP_ATTACH;
1003 b_sign->d_filename = mutt_str_dup("smime.p7s");
1004 }
1005 else
1006 {
1007 b_sign->subtype = mutt_str_dup("pgp-signature");
1008 mutt_param_set(&b_sign->parameter, "name", "signature.asc");
1009 b_sign->use_disp = false;
1010 b_sign->disposition = DISP_NONE;
1011 b_sign->encoding = ENC_7BIT;
1012 }
1013 b_sign->filename = sigfile;
1014 b_sign->unlink = true; /* ok to remove this file after sending. */
1015
1016 return b;
1017}
1018
1022struct Body *pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1023{
1024 return sign_message(b, from, false);
1025}
1026
1030struct Body *smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1031{
1032 return sign_message(b, from, true);
1033}
1034
1038struct Body *pgp_gpgme_encrypt_message(struct Body *b, char *keylist, bool sign,
1039 const struct AddressList *from)
1040{
1041 if (sign)
1043 gpgme_data_t plaintext = body_to_data_object(b, false);
1044 if (!plaintext)
1045 return NULL;
1046
1047 char *outfile = encrypt_gpgme_object(plaintext, keylist, false, sign, from);
1048 gpgme_data_release(plaintext);
1049 if (!outfile)
1050 return NULL;
1051
1052 struct Body *b_enc = mutt_body_new();
1053 b_enc->type = TYPE_MULTIPART;
1054 b_enc->subtype = mutt_str_dup("encrypted");
1055 b_enc->encoding = ENC_7BIT;
1056 b_enc->use_disp = false;
1057 b_enc->disposition = DISP_INLINE;
1058
1060 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-encrypted");
1061
1062 b_enc->parts = mutt_body_new();
1063 b_enc->parts->type = TYPE_APPLICATION;
1064 b_enc->parts->subtype = mutt_str_dup("pgp-encrypted");
1065 b_enc->parts->encoding = ENC_7BIT;
1066
1067 b_enc->parts->next = mutt_body_new();
1068 b_enc->parts->next->type = TYPE_APPLICATION;
1069 b_enc->parts->next->subtype = mutt_str_dup("octet-stream");
1070 b_enc->parts->next->encoding = ENC_7BIT;
1071 b_enc->parts->next->filename = outfile;
1072 b_enc->parts->next->use_disp = true;
1073 b_enc->parts->next->disposition = DISP_ATTACH;
1074 b_enc->parts->next->unlink = true; /* delete after sending the message */
1075 b_enc->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime
1076 can save */
1077
1078 return b_enc;
1079}
1080
1084struct Body *smime_gpgme_build_smime_entity(struct Body *b, char *keylist)
1085{
1086 /* OpenSSL converts line endings to crlf when encrypting. Some clients
1087 * depend on this for signed+encrypted messages: they do not convert line
1088 * endings between decrypting and checking the signature. */
1089 gpgme_data_t plaintext = body_to_data_object(b, true);
1090 if (!plaintext)
1091 return NULL;
1092
1093 char *outfile = encrypt_gpgme_object(plaintext, keylist, true, false, NULL);
1094 gpgme_data_release(plaintext);
1095 if (!outfile)
1096 return NULL;
1097
1098 struct Body *b_enc = mutt_body_new();
1099 b_enc->type = TYPE_APPLICATION;
1100 b_enc->subtype = mutt_str_dup("pkcs7-mime");
1101 mutt_param_set(&b_enc->parameter, "name", "smime.p7m");
1102 mutt_param_set(&b_enc->parameter, "smime-type", "enveloped-data");
1103 b_enc->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1104 b_enc->use_disp = true;
1105 b_enc->disposition = DISP_ATTACH;
1106 b_enc->d_filename = mutt_str_dup("smime.p7m");
1107 b_enc->filename = outfile;
1108 b_enc->unlink = true; /* delete after sending the message */
1109 b_enc->parts = 0;
1110 b_enc->next = 0;
1111
1112 return b_enc;
1113}
1114
1128static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key,
1129 int idx, struct State *state, gpgme_signature_t sig)
1130{
1131 if (!key)
1132 return 1;
1133
1134 bool severe = false;
1135
1136 if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1137 {
1138 state_puts(state, _("Warning: One of the keys has been revoked\n"));
1139 severe = true;
1140 }
1141
1142 if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1143 {
1144 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
1145 if (at)
1146 {
1147 state_puts(state, _("Warning: The key used to create the signature expired at: "));
1148 print_time(at, state);
1149 state_puts(state, "\n");
1150 }
1151 else
1152 {
1153 state_puts(state, _("Warning: At least one certification key has expired\n"));
1154 }
1155 }
1156
1157 if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1158 {
1159 gpgme_signature_t sig2 = NULL;
1160 unsigned int i;
1161
1162 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1163
1164 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1165 ; // do nothing
1166
1167 state_puts(state, _("Warning: The signature expired at: "));
1168 print_time(sig2 ? sig2->exp_timestamp : 0, state);
1169 state_puts(state, "\n");
1170 }
1171
1172 if ((sum & GPGME_SIGSUM_KEY_MISSING))
1173 {
1174 state_puts(state, _("Can't verify due to a missing key or certificate\n"));
1175 }
1176
1177 if ((sum & GPGME_SIGSUM_CRL_MISSING))
1178 {
1179 state_puts(state, _("The CRL is not available\n"));
1180 severe = true;
1181 }
1182
1183 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1184 {
1185 state_puts(state, _("Available CRL is too old\n"));
1186 severe = true;
1187 }
1188
1189 if ((sum & GPGME_SIGSUM_BAD_POLICY))
1190 state_puts(state, _("A policy requirement was not met\n"));
1191
1192 if ((sum & GPGME_SIGSUM_SYS_ERROR))
1193 {
1194 const char *t0 = NULL, *t1 = NULL;
1195 gpgme_verify_result_t result = NULL;
1196 gpgme_signature_t sig2 = NULL;
1197 unsigned int i;
1198
1199 state_puts(state, _("A system error occurred"));
1200
1201 /* Try to figure out some more detailed system error information. */
1202 result = gpgme_op_verify_result(ctx);
1203 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1204 ; // do nothing
1205
1206 if (sig2)
1207 {
1208 t0 = "";
1209 t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1210 }
1211
1212 if (t0 || t1)
1213 {
1214 state_puts(state, ": ");
1215 if (t0)
1216 state_puts(state, t0);
1217 if (t1 && !(t0 && (mutt_str_equal(t0, t1))))
1218 {
1219 if (t0)
1220 state_puts(state, ",");
1221 state_puts(state, t1);
1222 }
1223 }
1224 state_puts(state, "\n");
1225 }
1226
1227 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1228 if (c_crypt_use_pka)
1229 {
1230 if ((sig->pka_trust == 1) && sig->pka_address)
1231 {
1232 state_puts(state, _("WARNING: PKA entry does not match signer's address: "));
1233 state_puts(state, sig->pka_address);
1234 state_puts(state, "\n");
1235 }
1236 else if ((sig->pka_trust == 2) && sig->pka_address)
1237 {
1238 state_puts(state, _("PKA verified signer's address is: "));
1239 state_puts(state, sig->pka_address);
1240 state_puts(state, "\n");
1241 }
1242 }
1243
1244 return severe;
1245}
1246
1252static void show_fingerprint(gpgme_key_t key, struct State *state)
1253{
1254 if (!key)
1255 return;
1256
1257 const char *prefix = _("Fingerprint: ");
1258
1259 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1260 if (!s)
1261 return;
1262 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1263
1264 char *buf = mutt_mem_malloc(strlen(prefix) + strlen(s) * 4 + 2);
1265 strcpy(buf, prefix);
1266 char *p = buf + strlen(buf);
1267 if (is_pgp && (strlen(s) == 40))
1268 { /* PGP v4 style formatted. */
1269 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1270 {
1271 *p++ = s[0];
1272 *p++ = s[1];
1273 *p++ = s[2];
1274 *p++ = s[3];
1275 *p++ = ' ';
1276 if (i == 4)
1277 *p++ = ' ';
1278 }
1279 }
1280 else
1281 {
1282 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1283 {
1284 *p++ = s[0];
1285 *p++ = s[1];
1286 *p++ = is_pgp ? ' ' : ':';
1287 if (is_pgp && (i == 7))
1288 *p++ = ' ';
1289 }
1290 }
1291
1292 /* just in case print remaining odd digits */
1293 for (; *s; s++)
1294 *p++ = *s;
1295 *p++ = '\n';
1296 *p = '\0';
1297 state_puts(state, buf);
1298 FREE(&buf);
1299}
1300
1307static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
1308{
1309 gpgme_signature_t sig = NULL;
1310 const char *txt = NULL;
1311
1312 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1313 if (result)
1314 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1315 ; // do nothing
1316
1317 switch (sig ? sig->validity : 0)
1318 {
1319 case GPGME_VALIDITY_UNKNOWN:
1320 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1321 break;
1322 case GPGME_VALIDITY_UNDEFINED:
1323 break;
1324 case GPGME_VALIDITY_NEVER:
1325 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1326 break;
1327 case GPGME_VALIDITY_MARGINAL:
1328 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1329 break;
1330 case GPGME_VALIDITY_FULL:
1331 case GPGME_VALIDITY_ULTIMATE:
1332 txt = NULL;
1333 break;
1334 }
1335 if (txt)
1336 state_puts(state, txt);
1337}
1338
1346static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig,
1347 gpgme_key_t key, struct State *state)
1348{
1349 int msgwid;
1350
1351 state_puts(state, msg);
1352 state_puts(state, " ");
1353 /* key is NULL when not present in the user's keyring */
1354 if (key)
1355 {
1356 bool aka = false;
1357 for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1358 {
1359 if (uids->revoked)
1360 continue;
1361 if (aka)
1362 {
1363 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1364 if (msgwid < 0)
1365 msgwid = 0;
1366 for (int i = 0; i < msgwid; i++)
1367 state_puts(state, " ");
1368 state_puts(state, _("aka: "));
1369 }
1370 state_puts(state, uids->uid);
1371 state_puts(state, "\n");
1372
1373 aka = true;
1374 }
1375 }
1376 else
1377 {
1378 if (sig->fpr)
1379 {
1380 state_puts(state, _("KeyID "));
1381 state_puts(state, sig->fpr);
1382 }
1383 else
1384 {
1385 /* L10N: You will see this message in place of "KeyID "
1386 if the S/MIME key has no ID. This is quite an error. */
1387 state_puts(state, _("no signature fingerprint available"));
1388 }
1389 state_puts(state, "\n");
1390 }
1391
1392 /* timestamp is 0 when verification failed.
1393 * "Jan 1 1970" is not the created date. */
1394 if (sig->timestamp)
1395 {
1396 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1397 if (msgwid < 0)
1398 msgwid = 0;
1399 for (int i = 0; i < msgwid; i++)
1400 state_puts(state, " ");
1401 state_puts(state, _("created: "));
1402 print_time(sig->timestamp, state);
1403 state_puts(state, "\n");
1404 }
1405}
1406
1419static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
1420{
1421 const char *fpr = NULL;
1422 gpgme_key_t key = NULL;
1423 bool anybad = false, anywarn = false;
1424 gpgme_signature_t sig = NULL;
1425 gpgme_error_t err = GPG_ERR_NO_ERROR;
1426
1427 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1428 if (result)
1429 {
1430 /* FIXME: this code should use a static variable and remember
1431 * the current position in the list of signatures, IMHO.
1432 * -moritz. */
1433 int i;
1434 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1435 ; // do nothing
1436
1437 if (!sig)
1438 return -1; /* Signature not found. */
1439
1440 if (SignatureKey)
1441 {
1442 gpgme_key_unref(SignatureKey);
1443 SignatureKey = NULL;
1444 }
1445
1446 fpr = sig->fpr;
1447 const unsigned int sum = sig->summary;
1448
1449 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1450 anybad = true;
1451
1452 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1453 {
1454 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1455 if (err == 0)
1456 {
1457 if (!SignatureKey)
1458 SignatureKey = key;
1459 }
1460 else
1461 {
1462 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1463 error. Do it here to avoid a double free. */
1464 }
1465 }
1466 else
1467 {
1468 /* pubkey not present */
1469 }
1470
1471 if (!state || !state->fp_out || !(state->flags & STATE_DISPLAY))
1472 {
1473 ; /* No state information so no way to print anything. */
1474 }
1475 else if (err != 0)
1476 {
1477 char buf[1024] = { 0 };
1478 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1479 fpr, gpgme_strerror(err));
1480 state_puts(state, buf);
1481 anybad = true;
1482 }
1483 else if ((sum & GPGME_SIGSUM_GREEN))
1484 {
1485 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1486 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1487 anywarn = true;
1488 show_one_sig_validity(ctx, idx, state);
1489 }
1490 else if ((sum & GPGME_SIGSUM_RED))
1491 {
1492 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, state);
1493 show_sig_summary(sum, ctx, key, idx, state, sig);
1494 }
1495 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1496 { /* We can't decide (yellow) but this is a PGP key with a good
1497 signature, so we display what a PGP user expects: The name,
1498 fingerprint and the key validity (which is neither fully or
1499 ultimate). */
1500 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1501 show_one_sig_validity(ctx, idx, state);
1502 show_fingerprint(key, state);
1503 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1504 anywarn = true;
1505 }
1506 else /* can't decide (yellow) */
1507 {
1508 print_smime_keyinfo(_("Problem signature from:"), sig, key, state);
1509 /* 0 indicates no expiration */
1510 if (sig->exp_timestamp)
1511 {
1512 /* L10N: This is trying to match the width of the
1513 "Problem signature from:" translation just above. */
1514 state_puts(state, _(" expires: "));
1515 print_time(sig->exp_timestamp, state);
1516 state_puts(state, "\n");
1517 }
1518 show_sig_summary(sum, ctx, key, idx, state, sig);
1519 anywarn = true;
1520 }
1521
1522 if (key != SignatureKey)
1523 gpgme_key_unref(key);
1524 }
1525
1526 return anybad ? 1 : anywarn ? 2 : 0;
1527}
1528
1542static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
1543{
1544 int badsig = -1;
1545 int anywarn = 0;
1546 gpgme_ctx_t ctx = NULL;
1547 gpgme_data_t message = NULL;
1548
1549 gpgme_data_t signature = file_to_data_object(state->fp_in, b->offset, b->length);
1550 if (!signature)
1551 return -1;
1552
1553 /* We need to tell GPGME about the encoding because the backend can't
1554 * auto-detect plain base-64 encoding which is used by S/MIME. */
1555 if (is_smime)
1556 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1557
1558 int err = gpgme_data_new_from_file(&message, tempfile, 1);
1559 if (err != 0)
1560 {
1561 gpgme_data_release(signature);
1562 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1563 return -1;
1564 }
1565 ctx = create_gpgme_context(is_smime);
1566
1567 /* Note: We don't need a current time output because GPGME avoids
1568 * such an attack by separating the meta information from the data. */
1569 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1570
1571 err = gpgme_op_verify(ctx, signature, message, NULL);
1572 gpgme_data_release(message);
1573 gpgme_data_release(signature);
1574
1575 redraw_if_needed(ctx);
1576 if (err != 0)
1577 {
1578 char buf[200] = { 0 };
1579
1580 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1581 gpgme_strerror(err));
1582 state_puts(state, buf);
1583 }
1584 else
1585 { /* Verification succeeded, see what the result is. */
1586 gpgme_verify_result_t verify_result = NULL;
1587
1588 if (SignatureKey)
1589 {
1590 gpgme_key_unref(SignatureKey);
1591 SignatureKey = NULL;
1592 }
1593
1594 verify_result = gpgme_op_verify_result(ctx);
1595 if (verify_result && verify_result->signatures)
1596 {
1597 bool anybad = false;
1598 int res;
1599 for (int idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1600 {
1601 if (res == 1)
1602 anybad = true;
1603 else if (res == 2)
1604 anywarn = 2;
1605 }
1606 if (!anybad)
1607 badsig = 0;
1608 }
1609 }
1610
1611 if (badsig == 0)
1612 {
1613 gpgme_verify_result_t result = NULL;
1614 gpgme_sig_notation_t notation = NULL;
1615 gpgme_signature_t sig = NULL;
1616
1617 result = gpgme_op_verify_result(ctx);
1618 if (result)
1619 {
1620 for (sig = result->signatures; sig; sig = sig->next)
1621 {
1622 int non_pka_notations = 0;
1623 for (notation = sig->notations; notation; notation = notation->next)
1624 if (!is_pka_notation(notation))
1625 non_pka_notations++;
1626
1627 if (non_pka_notations)
1628 {
1629 char buf[128] = { 0 };
1630 snprintf(buf, sizeof(buf),
1631 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1632 state_puts(state, buf);
1633 for (notation = sig->notations; notation; notation = notation->next)
1634 {
1635 if (is_pka_notation(notation))
1636 continue;
1637
1638 if (notation->name)
1639 {
1640 state_puts(state, notation->name);
1641 state_puts(state, "=");
1642 }
1643 if (notation->value)
1644 {
1645 state_puts(state, notation->value);
1646 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1647 state_puts(state, "\n");
1648 }
1649 }
1650 state_puts(state, _("*** End Notation ***\n"));
1651 }
1652 }
1653 }
1654 }
1655
1656 gpgme_release(ctx);
1657
1658 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1659 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1660
1661 return badsig ? 1 : anywarn ? 2 : 0;
1662}
1663
1667int pgp_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1668{
1669 return verify_one(b, state, tempfile, false);
1670}
1671
1675int smime_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1676{
1677 return verify_one(b, state, tempfile, true);
1678}
1679
1693static struct Body *decrypt_part(struct Body *b, struct State *state,
1694 FILE *fp_out, bool is_smime, int *r_is_signed)
1695{
1696 if (!b || !state || !fp_out)
1697 return NULL;
1698
1699 struct Body *tattach = NULL;
1700 int err = 0;
1701 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1702 bool maybe_signed = false;
1703 bool anywarn = false;
1704 int sig_stat = 0;
1705
1706 if (r_is_signed)
1707 *r_is_signed = 0;
1708
1709 gpgme_ctx_t ctx = NULL;
1710restart:
1711 ctx = create_gpgme_context(is_smime);
1712
1713 if (b->length < 0)
1714 return NULL;
1715 /* Make a data object from the body, create context etc. */
1716 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1717 if (!ciphertext)
1718 goto cleanup;
1719 plaintext = create_gpgme_data();
1720
1721 /* Do the decryption or the verification in case of the S/MIME hack. */
1722 if ((!is_smime) || maybe_signed)
1723 {
1724 if (!is_smime)
1725 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1726 else if (maybe_signed)
1727 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1728
1729 if (err == GPG_ERR_NO_ERROR)
1730 {
1731 /* Check whether signatures have been verified. */
1732 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1733 if (verify_result->signatures)
1734 sig_stat = 1;
1735 }
1736 }
1737 else
1738 {
1739 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1740 }
1741 gpgme_data_release(ciphertext);
1742 ciphertext = NULL;
1743 if (err != 0)
1744 {
1745#ifdef USE_AUTOCRYPT
1746 /* Abort right away and silently.
1747 * Autocrypt will retry on the normal keyring. */
1749 goto cleanup;
1750#endif
1751 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1752 {
1753 /* Check whether this might be a signed message despite what the mime
1754 * header told us. Retry then. gpgsm returns the error information
1755 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1756 * algorithm, thus we test that it has not been set. */
1757 gpgme_decrypt_result_t result = NULL;
1758
1759 result = gpgme_op_decrypt_result(ctx);
1760 if (!result->unsupported_algorithm)
1761 {
1762 maybe_signed = true;
1763 gpgme_data_release(plaintext);
1764 plaintext = NULL;
1765 /* gpgsm ends the session after an error; restart it */
1766 gpgme_release(ctx);
1767 goto restart;
1768 }
1769 }
1770 redraw_if_needed(ctx);
1771 if ((state->flags & STATE_DISPLAY))
1772 {
1773 char buf[200] = { 0 };
1774
1775 snprintf(buf, sizeof(buf) - 1,
1776 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1777 state_attach_puts(state, buf);
1778 }
1779 goto cleanup;
1780 }
1781 redraw_if_needed(ctx);
1782
1783 /* Read the output from GPGME, and make sure to change CRLF to LF,
1784 * otherwise read_mime_header has a hard time parsing the message. */
1785 if (data_object_to_stream(plaintext, fp_out))
1786 {
1787 goto cleanup;
1788 }
1789 gpgme_data_release(plaintext);
1790 plaintext = NULL;
1791
1792 if (sig_stat)
1793 {
1794 int res, idx;
1795 int anybad = 0;
1796
1797 if (r_is_signed)
1798 *r_is_signed = -1; /* A signature exists. */
1799
1800 if ((state->flags & STATE_DISPLAY))
1801 {
1802 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1803 }
1804 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1805 {
1806 if (res == 1)
1807 anybad = 1;
1808 else if (res == 2)
1809 anywarn = true;
1810 }
1811 if (!anybad && idx && r_is_signed && *r_is_signed)
1812 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1813
1814 if ((state->flags & STATE_DISPLAY))
1815 {
1816 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1817 }
1818 }
1819 gpgme_release(ctx);
1820 ctx = NULL;
1821
1822 fflush(fp_out);
1823 rewind(fp_out);
1824 const long size = mutt_file_get_size_fp(fp_out);
1825 if (size == 0)
1826 {
1827 goto cleanup;
1828 }
1829 tattach = mutt_read_mime_header(fp_out, 0);
1830 if (tattach)
1831 {
1832 /* Need to set the length of this body part. */
1833 tattach->length = size - tattach->offset;
1834
1835 tattach->warnsig = anywarn;
1836
1837 /* See if we need to recurse on this MIME part. */
1838 mutt_parse_part(fp_out, tattach);
1839 }
1840
1841cleanup:
1842 gpgme_data_release(ciphertext);
1843 gpgme_data_release(plaintext);
1844 gpgme_release(ctx);
1845
1846 return tattach;
1847}
1848
1852int pgp_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1853{
1854 struct State state = { 0 };
1855 struct Body *first_part = b;
1856 int is_signed = 0;
1857 bool need_decode = false;
1858 LOFF_T saved_offset = 0;
1859 size_t saved_length = 0;
1860 FILE *fp_decoded = NULL;
1861 int rc = 0;
1862
1863 first_part->goodsig = false;
1864 first_part->warnsig = false;
1865
1867 {
1868 b = b->parts->next;
1869 /* Some clients improperly encode the octetstream part. */
1870 if (b->encoding != ENC_7BIT)
1871 need_decode = true;
1872 }
1874 {
1875 b = b->parts->next->next;
1876 need_decode = true;
1877 }
1878 else
1879 {
1880 return -1;
1881 }
1882
1883 state.fp_in = fp_in;
1884
1885 if (need_decode)
1886 {
1887 saved_offset = b->offset;
1888 saved_length = b->length;
1889
1890 fp_decoded = mutt_file_mkstemp();
1891 if (!fp_decoded)
1892 {
1893 mutt_perror(_("Can't create temporary file"));
1894 return -1;
1895 }
1896
1897 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1898 {
1899 rc = -1;
1900 goto bail;
1901 }
1902 state.fp_out = fp_decoded;
1903
1904 mutt_decode_attachment(b, &state);
1905
1906 fflush(fp_decoded);
1907 b->length = ftello(fp_decoded);
1908 b->offset = 0;
1909 rewind(fp_decoded);
1910 state.fp_in = fp_decoded;
1911 state.fp_out = 0;
1912 }
1913
1914 *fp_out = mutt_file_mkstemp();
1915 if (!*fp_out)
1916 {
1917 mutt_perror(_("Can't create temporary file"));
1918 rc = -1;
1919 goto bail;
1920 }
1921
1922 *b_dec = decrypt_part(b, &state, *fp_out, false, &is_signed);
1923 if (*b_dec)
1924 {
1925 rewind(*fp_out);
1926 if (is_signed > 0)
1927 first_part->goodsig = true;
1928 }
1929 else
1930 {
1931 rc = -1;
1932 mutt_file_fclose(fp_out);
1933 }
1934
1935bail:
1936 if (need_decode)
1937 {
1938 b->length = saved_length;
1939 b->offset = saved_offset;
1940 mutt_file_fclose(&fp_decoded);
1941 }
1942
1943 return rc;
1944}
1945
1949int smime_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1950{
1951 struct State state = { 0 };
1952 int is_signed;
1953 LOFF_T saved_b_offset;
1954 size_t saved_b_length;
1955
1957 return -1;
1958
1959 if (b->parts)
1960 return -1;
1961
1962 /* Decode the body - we need to pass binary CMS to the
1963 * backend. The backend allows for Base64 encoded data but it does
1964 * not allow for QP which I have seen in some messages. So better
1965 * do it here. */
1966 saved_b_offset = b->offset;
1967 saved_b_length = b->length;
1968 state.fp_in = fp_in;
1969 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1970 {
1971 return -1;
1972 }
1973 FILE *fp_tmp = mutt_file_mkstemp();
1974 if (!fp_tmp)
1975 {
1976 mutt_perror(_("Can't create temporary file"));
1977 return -1;
1978 }
1979
1980 state.fp_out = fp_tmp;
1981 mutt_decode_attachment(b, &state);
1982 fflush(fp_tmp);
1983 b->length = ftello(state.fp_out);
1984 b->offset = 0;
1985 rewind(fp_tmp);
1986
1987 memset(&state, 0, sizeof(state));
1988 state.fp_in = fp_tmp;
1989 state.fp_out = 0;
1991 if (!*fp_out)
1992 {
1993 mutt_perror(_("Can't create temporary file"));
1994 return -1;
1995 }
1996
1997 *b_dec = decrypt_part(b, &state, *fp_out, true, &is_signed);
1998 if (*b_dec)
1999 (*b_dec)->goodsig = is_signed > 0;
2000 b->length = saved_b_length;
2001 b->offset = saved_b_offset;
2002 mutt_file_fclose(&fp_tmp);
2003 rewind(*fp_out);
2004 if (*b_dec && !is_signed && !(*b_dec)->parts && mutt_is_application_smime(*b_dec))
2005 {
2006 /* Assume that this is a opaque signed s/mime message. This is an ugly way
2007 * of doing it but we have anyway a problem with arbitrary encoded S/MIME
2008 * messages: Only the outer part may be encrypted. The entire mime parsing
2009 * should be revamped, probably by keeping the temporary files so that we
2010 * don't need to decrypt them all the time. Inner parts of an encrypted
2011 * part can then point into this file and there won't ever be a need to
2012 * decrypt again. This needs a partial rewrite of the MIME engine. */
2013 struct Body *bb = *b_dec;
2014
2015 saved_b_offset = bb->offset;
2016 saved_b_length = bb->length;
2017 memset(&state, 0, sizeof(state));
2018 state.fp_in = *fp_out;
2019 if (!mutt_file_seek(state.fp_in, bb->offset, SEEK_SET))
2020 {
2021 return -1;
2022 }
2023 FILE *fp_tmp2 = mutt_file_mkstemp();
2024 if (!fp_tmp2)
2025 {
2026 mutt_perror(_("Can't create temporary file"));
2027 return -1;
2028 }
2029
2030 state.fp_out = fp_tmp2;
2031 mutt_decode_attachment(bb, &state);
2032 fflush(fp_tmp2);
2033 bb->length = ftello(state.fp_out);
2034 bb->offset = 0;
2035 rewind(fp_tmp2);
2036 mutt_file_fclose(fp_out);
2037
2038 memset(&state, 0, sizeof(state));
2039 state.fp_in = fp_tmp2;
2040 state.fp_out = 0;
2041 *fp_out = mutt_file_mkstemp();
2042 if (!*fp_out)
2043 {
2044 mutt_perror(_("Can't create temporary file"));
2045 return -1;
2046 }
2047
2048 struct Body *b_tmp = decrypt_part(bb, &state, *fp_out, true, &is_signed);
2049 if (b_tmp)
2050 b_tmp->goodsig = is_signed > 0;
2051 bb->length = saved_b_length;
2052 bb->offset = saved_b_offset;
2053 mutt_file_fclose(&fp_tmp2);
2054 rewind(*fp_out);
2055 mutt_body_free(b_dec);
2056 *b_dec = b_tmp;
2057 }
2058 return *b_dec ? 0 : -1;
2059}
2060
2068static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
2069{
2070 gpgme_ctx_t tmpctx = NULL;
2071 gpgme_error_t err;
2072 gpgme_key_t key = NULL;
2073 gpgme_user_id_t uid = NULL;
2074 gpgme_subkey_t subkey = NULL;
2075 const char *shortid = NULL;
2076 size_t len;
2077 char date[256] = { 0 };
2078 bool more;
2079 int rc = -1;
2080 time_t tt;
2081
2082 *fp = mutt_file_mkstemp();
2083 if (!*fp)
2084 {
2085 mutt_perror(_("Can't create temporary file"));
2086 return -1;
2087 }
2088
2089 tmpctx = create_gpgme_context(false);
2090
2091 err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2092 while (err == 0)
2093 {
2094 err = gpgme_op_keylist_next(tmpctx, &key);
2095 if (err != 0)
2096 break;
2097 uid = key->uids;
2098 subkey = key->subkeys;
2099 more = false;
2100 while (subkey)
2101 {
2102 shortid = subkey->keyid;
2103 len = mutt_str_len(subkey->keyid);
2104 if (len > 8)
2105 shortid += len - 8;
2106 tt = subkey->timestamp;
2107 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2108
2109 if (more)
2110 {
2111 fprintf(*fp, "sub %5.5s %u/%8s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2112 subkey->length, shortid, date);
2113 }
2114 else
2115 {
2116 fprintf(*fp, "pub %5.5s %u/%8s %s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2117 subkey->length, shortid, date, (uid ? uid->uid : ""));
2118 }
2119 subkey = subkey->next;
2120 more = true;
2121 }
2122 gpgme_key_unref(key);
2123 }
2124 if (gpg_err_code(err) != GPG_ERR_EOF)
2125 {
2126 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2127 goto err_fp;
2128 }
2129
2130 rc = 0;
2131
2132err_fp:
2133 if (rc)
2134 mutt_file_fclose(fp);
2135
2136 gpgme_release(tmpctx);
2137
2138 return rc;
2139}
2140
2152static int line_compare(const char *a, size_t n, const char *b)
2153{
2154 if (mutt_strn_equal(a, b, n))
2155 {
2156 /* at this point we know that 'b' is at least 'n' chars long */
2157 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2158 return true;
2159 }
2160 return false;
2161}
2162
2170static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
2171{
2172 char buf[8192] = { 0 };
2173 bool rc = false;
2174
2175 bool sgn = false;
2176 bool enc = false;
2177
2178 if (b->type != TYPE_TEXT)
2179 return 0;
2180
2181 struct Buffer *tempfile = buf_pool_get();
2182 buf_mktemp(tempfile);
2184 MUTT_SAVE_NO_FLAGS) != 0)
2185 {
2186 unlink(buf_string(tempfile));
2187 goto cleanup;
2188 }
2189
2190 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2191 if (!fp_tmp)
2192 {
2193 unlink(buf_string(tempfile));
2194 goto cleanup;
2195 }
2196
2197 while (fgets(buf, sizeof(buf), fp_tmp))
2198 {
2199 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2200 if (plen != 0)
2201 {
2202 if (MESSAGE(buf + plen))
2203 {
2204 enc = true;
2205 break;
2206 }
2207 else if (SIGNED_MESSAGE(buf + plen))
2208 {
2209 sgn = true;
2210 break;
2211 }
2212 }
2213 }
2214 mutt_file_fclose(&fp_tmp);
2215 unlink(buf_string(tempfile));
2216
2217 if (!enc && !sgn)
2218 goto cleanup;
2219
2220 /* fix the content type */
2221
2222 mutt_param_set(&b->parameter, "format", "fixed");
2223 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2224
2225 rc = true;
2226
2227cleanup:
2228 buf_pool_release(&tempfile);
2229 return rc;
2230}
2231
2235bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2236{
2237 bool rc = false;
2238 for (; b; b = b->next)
2239 {
2240 if (!just_one && is_multipart(b))
2241 {
2242 rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2243 }
2244 else if (b->type == TYPE_TEXT)
2245 {
2247 if (r)
2248 rc = (rc || r);
2249 else
2250 rc = (pgp_check_traditional_one_body(fp, b) || rc);
2251 }
2252
2253 if (just_one)
2254 break;
2255 }
2256 return rc;
2257}
2258
2262void pgp_gpgme_invoke_import(const char *fname)
2263{
2264 gpgme_ctx_t ctx = create_gpgme_context(false);
2265 gpgme_data_t keydata = NULL;
2266 gpgme_import_result_t impres = NULL;
2267 gpgme_import_status_t st = NULL;
2268 bool any;
2269
2270 FILE *fp_in = mutt_file_fopen(fname, "r");
2271 if (!fp_in)
2272 {
2273 mutt_perror("%s", fname);
2274 goto leave;
2275 }
2276 /* Note that the stream, "fp_in", needs to be kept open while the keydata
2277 * is used. */
2278 gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2279 if (err != GPG_ERR_NO_ERROR)
2280 {
2281 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2282 goto leave;
2283 }
2284
2285 err = gpgme_op_import(ctx, keydata);
2286 if (err != 0)
2287 {
2288 mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2289 goto leave;
2290 }
2291
2292 /* Print infos about the imported keys to stdout. */
2293 impres = gpgme_op_import_result(ctx);
2294 if (!impres)
2295 {
2296 fputs("oops: no import result returned\n", stdout);
2297 goto leave;
2298 }
2299
2300 for (st = impres->imports; st; st = st->next)
2301 {
2302 if (st->result)
2303 continue;
2304 printf("key %s imported (", NONULL(st->fpr));
2305 /* Note that we use the singular even if it is possible that
2306 * several uids etc are new. This simply looks better. */
2307 any = false;
2308 if (st->status & GPGME_IMPORT_SECRET)
2309 {
2310 printf("secret parts");
2311 any = true;
2312 }
2313 if ((st->status & GPGME_IMPORT_NEW))
2314 {
2315 printf("%snew key", any ? ", " : "");
2316 any = true;
2317 }
2318 if ((st->status & GPGME_IMPORT_UID))
2319 {
2320 printf("%snew uid", any ? ", " : "");
2321 any = true;
2322 }
2323 if ((st->status & GPGME_IMPORT_SIG))
2324 {
2325 printf("%snew sig", any ? ", " : "");
2326 any = true;
2327 }
2328 if ((st->status & GPGME_IMPORT_SUBKEY))
2329 {
2330 printf("%snew subkey", any ? ", " : "");
2331 any = true;
2332 }
2333 printf("%s)\n", any ? "" : "not changed");
2334 /* Fixme: Should we lookup each imported key and print more infos? */
2335 }
2336 /* Now print keys which failed the import. Unfortunately in most
2337 * cases gpg will bail out early and not tell GPGME about. */
2338 /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2339 * the actual gpg diagnostics. But I fear that would clutter the
2340 * output too much. Maybe a dedicated prompt or option to do this
2341 * would be helpful. */
2342 for (st = impres->imports; st; st = st->next)
2343 {
2344 if (st->result == 0)
2345 continue;
2346 printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2347 }
2348 fflush(stdout);
2349
2350leave:
2351 gpgme_release(ctx);
2352 gpgme_data_release(keydata);
2353 mutt_file_fclose(&fp_in);
2354}
2355
2371static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
2372{
2373 char buf[8192] = { 0 };
2374 bool complete, armor_header;
2375 FILE *fp = NULL;
2376
2377 char *fname = data_object_to_tempfile(data, &fp);
2378 if (!fname)
2379 {
2380 mutt_file_fclose(&fp);
2381 return;
2382 }
2383 unlink(fname);
2384 FREE(&fname);
2385
2386 /* fromcode comes from the MIME Content-Type charset label. It might
2387 * be a wrong label, so we want the ability to do corrections via
2388 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2390
2391 for (complete = true, armor_header = true;
2392 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2393 {
2394 if (!complete)
2395 {
2396 if (!armor_header)
2397 state_puts(state, buf);
2398 continue;
2399 }
2400
2401 if (BEGIN_PGP_SIGNATURE(buf))
2402 break;
2403
2404 if (armor_header)
2405 {
2406 if (buf[0] == '\n')
2407 armor_header = false;
2408 continue;
2409 }
2410
2411 if (state->prefix)
2412 state_puts(state, state->prefix);
2413
2414 if ((buf[0] == '-') && (buf[1] == ' '))
2415 state_puts(state, buf + 2);
2416 else
2417 state_puts(state, buf);
2418 }
2419
2422}
2423
2427int pgp_gpgme_application_handler(struct Body *b, struct State *state)
2428{
2429 int needpass = -1;
2430 bool pgp_keyblock = false;
2431 bool clearsign = false;
2432 long bytes;
2433 LOFF_T last_pos;
2434 char buf[8192] = { 0 };
2435 FILE *fp_out = NULL;
2436
2437 gpgme_error_t err = 0;
2438 gpgme_data_t armored_data = NULL;
2439
2440 bool maybe_goodsig = true;
2441 bool have_any_sigs = false;
2442
2443 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2444
2445 mutt_debug(LL_DEBUG2, "Entering handler\n");
2446
2447 /* For clearsigned messages we won't be able to get a character set
2448 * but we know that this may only be text thus we assume Latin-1 here. */
2449 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2450 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2451
2452 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2453 {
2454 return -1;
2455 }
2456 last_pos = b->offset;
2457
2458 for (bytes = b->length; bytes > 0;)
2459 {
2460 if (!fgets(buf, sizeof(buf), state->fp_in))
2461 break;
2462
2463 LOFF_T offset = ftello(state->fp_in);
2464 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2465 last_pos = offset;
2466
2467 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2468 if (plen != 0)
2469 {
2470 clearsign = false;
2471
2472 if (MESSAGE(buf + plen))
2473 {
2474 needpass = 1;
2475 }
2476 else if (SIGNED_MESSAGE(buf + plen))
2477 {
2478 clearsign = true;
2479 needpass = 0;
2480 }
2481 else if (PUBLIC_KEY_BLOCK(buf + plen))
2482 {
2483 needpass = 0;
2484 pgp_keyblock = true;
2485 }
2486 else
2487 {
2488 /* XXX we may wish to recode here */
2489 if (state->prefix)
2490 state_puts(state, state->prefix);
2491 state_puts(state, buf);
2492 continue;
2493 }
2494
2495 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2496
2497 /* Copy PGP material to an data container */
2498 armored_data = file_to_data_object(state->fp_in, b->offset, b->length);
2499 /* Invoke PGP if needed */
2500 if (pgp_keyblock)
2501 {
2502 pgp_gpgme_extract_keys(armored_data, &fp_out);
2503 }
2504 else if (!clearsign || (state->flags & STATE_VERIFY))
2505 {
2506 gpgme_data_t plaintext = create_gpgme_data();
2507 gpgme_ctx_t ctx = create_gpgme_context(false);
2508
2509 if (clearsign)
2510 {
2511 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2512 }
2513 else
2514 {
2515 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2516 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2517 {
2518 /* Decrypt verify can't handle signed only messages. */
2519 gpgme_data_seek(armored_data, 0, SEEK_SET);
2520 /* Must release plaintext so that we supply an uninitialized object. */
2521 gpgme_data_release(plaintext);
2522 plaintext = create_gpgme_data();
2523 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2524 }
2525 }
2526 redraw_if_needed(ctx);
2527
2528 if (err != 0)
2529 {
2530 char errbuf[200] = { 0 };
2531
2532 snprintf(errbuf, sizeof(errbuf) - 1,
2533 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2534 state_puts(state, errbuf);
2535 }
2536 else
2537 {
2538 /* Decryption/Verification succeeded */
2539
2540 mutt_message(_("PGP message successfully decrypted"));
2541
2542 bool sig_stat = false;
2543 char *tmpfname = NULL;
2544
2545 /* Check whether signatures have been verified. */
2546 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2547 if (verify_result->signatures)
2548 sig_stat = true;
2549
2550 have_any_sigs = false;
2551 maybe_goodsig = false;
2552 if ((state->flags & STATE_DISPLAY) && sig_stat)
2553 {
2554 int res, idx;
2555 bool anybad = false;
2556
2557 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2558 have_any_sigs = true;
2559 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2560 {
2561 if (res == 1)
2562 anybad = true;
2563 }
2564 if (!anybad && idx)
2565 maybe_goodsig = true;
2566
2567 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2568 }
2569
2570 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2571 if (tmpfname)
2572 {
2573 unlink(tmpfname);
2574 FREE(&tmpfname);
2575 }
2576 else
2577 {
2578 mutt_file_fclose(&fp_out);
2579 state_puts(state, _("Error: copy data failed\n"));
2580 }
2581 }
2582 gpgme_data_release(plaintext);
2583 gpgme_release(ctx);
2584 }
2585
2586 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2587 * outputs utf-8 cleartext. This may not always be true, but it
2588 * seems to be a reasonable guess. */
2589 if (state->flags & STATE_DISPLAY)
2590 {
2591 if (needpass)
2592 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2593 else if (pgp_keyblock)
2594 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2595 else
2596 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2597 }
2598
2599 if (clearsign)
2600 {
2601 copy_clearsigned(armored_data, state, body_charset);
2602 }
2603 else if (fp_out)
2604 {
2605 int c;
2606 rewind(fp_out);
2607 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, "utf-8", cc_charset(),
2609 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2610 {
2611 state_putc(state, c);
2612 if ((c == '\n') && state->prefix)
2613 state_puts(state, state->prefix);
2614 }
2616 }
2617
2618 if (state->flags & STATE_DISPLAY)
2619 {
2620 state_putc(state, '\n');
2621 if (needpass)
2622 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2623 else if (pgp_keyblock)
2624 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2625 else
2626 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2627 }
2628
2629 gpgme_data_release(armored_data);
2630 mutt_file_fclose(&fp_out);
2631 }
2632 else
2633 {
2634 /* A traditional PGP part may mix signed and unsigned content */
2635 /* XXX we may wish to recode here */
2636 if (state->prefix)
2637 state_puts(state, state->prefix);
2638 state_puts(state, buf);
2639 }
2640 }
2641
2642 b->goodsig = (maybe_goodsig && have_any_sigs);
2643
2644 if (needpass == -1)
2645 {
2646 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2647 return 1;
2648 }
2649 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2650
2651 return err;
2652}
2653
2660int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
2661{
2662 int is_signed;
2663 int rc = 0;
2664
2665 mutt_debug(LL_DEBUG2, "Entering handler\n");
2666
2667 FILE *fp_out = mutt_file_mkstemp();
2668 if (!fp_out)
2669 {
2670 mutt_perror(_("Can't create temporary file"));
2671 if (state->flags & STATE_DISPLAY)
2672 {
2673 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2674 }
2675 return -1;
2676 }
2677
2678 struct Body *tattach = decrypt_part(b, state, fp_out, false, &is_signed);
2679 if (tattach)
2680 {
2681 tattach->goodsig = is_signed > 0;
2682
2683 if (state->flags & STATE_DISPLAY)
2684 {
2685 state_attach_puts(state, is_signed ?
2686 _("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
2687 _("[-- The following data is PGP/MIME encrypted --]\n\n"));
2688 mutt_protected_headers_handler(tattach, state);
2689 }
2690
2691 /* Store any protected headers in the parent so they can be
2692 * accessed for index updates after the handler recursion is done.
2693 * This is done before the handler to prevent a nested encrypted
2694 * handler from freeing the headers. */
2696 b->mime_headers = tattach->mime_headers;
2697 tattach->mime_headers = NULL;
2698
2699 FILE *fp_save = state->fp_in;
2700 state->fp_in = fp_out;
2701 rc = mutt_body_handler(tattach, state);
2702 state->fp_in = fp_save;
2703
2704 /* Embedded multipart signed protected headers override the
2705 * encrypted headers. We need to do this after the handler so
2706 * they can be printed in the pager. */
2707 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2708 {
2710 b->mime_headers = tattach->parts->mime_headers;
2711 tattach->parts->mime_headers = NULL;
2712 }
2713
2714 /* if a multipart/signed is the _only_ sub-part of a
2715 * multipart/encrypted, cache signature verification
2716 * status. */
2717 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2718 b->goodsig |= tattach->goodsig;
2719
2720 if (state->flags & STATE_DISPLAY)
2721 {
2722 state_puts(state, "\n");
2723 state_attach_puts(state, is_signed ?
2724 _("[-- End of PGP/MIME signed and encrypted data --]\n") :
2725 _("[-- End of PGP/MIME encrypted data --]\n"));
2726 }
2727
2728 mutt_body_free(&tattach);
2729 mutt_message(_("PGP message successfully decrypted"));
2730 }
2731 else
2732 {
2733#ifdef USE_AUTOCRYPT
2734 if (!OptAutocryptGpgme)
2735#endif
2736 {
2737 mutt_error(_("Could not decrypt PGP message"));
2738 }
2739 rc = -1;
2740 }
2741
2742 mutt_file_fclose(&fp_out);
2743 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2744
2745 return rc;
2746}
2747
2751int smime_gpgme_application_handler(struct Body *b, struct State *state)
2752{
2753 int is_signed = 0;
2754 int rc = 0;
2755
2756 mutt_debug(LL_DEBUG2, "Entering handler\n");
2757
2758 /* clear out any mime headers before the handler, so they can't be spoofed. */
2760 b->warnsig = false;
2761 FILE *fp_out = mutt_file_mkstemp();
2762 if (!fp_out)
2763 {
2764 mutt_perror(_("Can't create temporary file"));
2765 if (state->flags & STATE_DISPLAY)
2766 {
2767 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2768 }
2769 return -1;
2770 }
2771
2772 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2773 if (tattach)
2774 {
2775 tattach->goodsig = is_signed > 0;
2776
2777 if (state->flags & STATE_DISPLAY)
2778 {
2779 state_attach_puts(state, is_signed ?
2780 _("[-- The following data is S/MIME signed --]\n\n") :
2781 _("[-- The following data is S/MIME encrypted --]\n\n"));
2782 mutt_protected_headers_handler(tattach, state);
2783 }
2784
2785 /* Store any protected headers in the parent so they can be
2786 * accessed for index updates after the handler recursion is done.
2787 * This is done before the handler to prevent a nested encrypted
2788 * handler from freeing the headers. */
2790 b->mime_headers = tattach->mime_headers;
2791 tattach->mime_headers = NULL;
2792
2793 FILE *fp_save = state->fp_in;
2794 state->fp_in = fp_out;
2795 rc = mutt_body_handler(tattach, state);
2796 state->fp_in = fp_save;
2797
2798 /* Embedded multipart signed protected headers override the
2799 * encrypted headers. We need to do this after the handler so
2800 * they can be printed in the pager. */
2801 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2802 {
2804 b->mime_headers = tattach->parts->mime_headers;
2805 tattach->parts->mime_headers = NULL;
2806 }
2807
2808 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2809 * cache signature verification status. */
2810 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2811 {
2812 b->goodsig = tattach->goodsig;
2813 if (!b->goodsig)
2814 b->warnsig = tattach->warnsig;
2815 }
2816 else if (tattach->goodsig)
2817 {
2818 b->goodsig = true;
2819 b->warnsig = tattach->warnsig;
2820 }
2821
2822 if (state->flags & STATE_DISPLAY)
2823 {
2824 state_puts(state, "\n");
2825 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2826 _("[-- End of S/MIME encrypted data --]\n"));
2827 }
2828
2829 mutt_body_free(&tattach);
2830 }
2831
2832 mutt_file_fclose(&fp_out);
2833 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2834
2835 return rc;
2836}
2837
2844unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
2845{
2846 unsigned int rc = 0;
2847
2848 switch (cap)
2849 {
2851 rc = key->can_encrypt;
2852 if (rc == 0)
2853 {
2854 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2855 {
2856 rc = subkey->can_encrypt;
2857 if (rc != 0)
2858 break;
2859 }
2860 }
2861 break;
2862 case KEY_CAP_CAN_SIGN:
2863 rc = key->can_sign;
2864 if (rc == 0)
2865 {
2866 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2867 {
2868 rc = subkey->can_sign;
2869 if (rc != 0)
2870 break;
2871 }
2872 }
2873 break;
2875 rc = key->can_certify;
2876 if (rc == 0)
2877 {
2878 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2879 {
2880 rc = subkey->can_certify;
2881 if (rc != 0)
2882 break;
2883 }
2884 }
2885 break;
2886 }
2887
2888 return rc;
2889}
2890
2900static char *list_to_pattern(struct ListHead *list)
2901{
2902 char *pattern = NULL, *p = NULL;
2903 const char *s = NULL;
2904 size_t n;
2905
2906 n = 0;
2907 struct ListNode *np = NULL;
2908 STAILQ_FOREACH(np, list, entries)
2909 {
2910 for (s = np->data; *s; s++)
2911 {
2912 if ((*s == '%') || (*s == '+'))
2913 n += 2;
2914 n++;
2915 }
2916 n++; /* delimiter or end of string */
2917 }
2918 n++; /* make sure to allocate at least one byte */
2919 p = mutt_mem_calloc(1, n);
2920 pattern = p;
2921 STAILQ_FOREACH(np, list, entries)
2922 {
2923 s = np->data;
2924 if (*s)
2925 {
2926 if (np != STAILQ_FIRST(list))
2927 *p++ = ' ';
2928 for (s = np->data; *s; s++)
2929 {
2930 if (*s == '%')
2931 {
2932 *p++ = '%';
2933 *p++ = '2';
2934 *p++ = '5';
2935 }
2936 else if (*s == '+')
2937 {
2938 *p++ = '%';
2939 *p++ = '2';
2940 *p++ = 'B';
2941 }
2942 else if (*s == ' ')
2943 {
2944 *p++ = '+';
2945 }
2946 else
2947 {
2948 *p++ = *s;
2949 }
2950 }
2951 }
2952 }
2953 *p = '\0';
2954 return pattern;
2955}
2956
2967static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
2968{
2969 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
2970 gpgme_error_t err;
2971 gpgme_ctx_t ctx = NULL;
2972 gpgme_key_t key = NULL;
2973 int idx;
2974 gpgme_user_id_t uid = NULL;
2975
2976 char *pattern = list_to_pattern(hints);
2977 if (!pattern)
2978 return NULL;
2979
2980 ctx = create_gpgme_context(0);
2981 db = NULL;
2982 kend = &db;
2983
2984 if ((app & APPLICATION_PGP))
2985 {
2986 /* It's all a mess. That old GPGME expects different things depending on
2987 * the protocol. For gpg we don't need percent escaped pappert but simple
2988 * strings passed in an array to the keylist_ext_start function. */
2989 size_t n = 0;
2990 struct ListNode *np = NULL;
2991 STAILQ_FOREACH(np, hints, entries)
2992 {
2993 if (np->data && *np->data)
2994 n++;
2995 }
2996 if (n == 0)
2997 goto no_pgphints;
2998
2999 char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
3000 n = 0;
3001 STAILQ_FOREACH(np, hints, entries)
3002 {
3003 if (np->data && *np->data)
3004 patarr[n++] = mutt_str_dup(np->data);
3005 }
3006 patarr[n] = NULL;
3007 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3008 for (n = 0; patarr[n]; n++)
3009 FREE(&patarr[n]);
3010 FREE(&patarr);
3011 if (err != 0)
3012 {
3013 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3014 gpgme_release(ctx);
3015 FREE(&pattern);
3016 return NULL;
3017 }
3018
3019 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3020 {
3021 KeyFlags flags = KEYFLAG_NO_FLAGS;
3022
3024 flags |= KEYFLAG_CANENCRYPT;
3026 flags |= KEYFLAG_CANSIGN;
3027
3028 if (key->revoked)
3029 flags |= KEYFLAG_REVOKED;
3030 if (key->expired)
3031 flags |= KEYFLAG_EXPIRED;
3032 if (key->disabled)
3033 flags |= KEYFLAG_DISABLED;
3034
3035 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3036 {
3037 k = mutt_mem_calloc(1, sizeof(*k));
3038 k->kobj = key;
3039 gpgme_key_ref(k->kobj);
3040 k->idx = idx;
3041 k->uid = uid->uid;
3042 k->flags = flags;
3043 if (uid->revoked)
3044 k->flags |= KEYFLAG_REVOKED;
3045 k->validity = uid->validity;
3046 *kend = k;
3047 kend = &k->next;
3048 }
3049 gpgme_key_unref(key);
3050 }
3051 if (gpg_err_code(err) != GPG_ERR_EOF)
3052 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3053 gpgme_op_keylist_end(ctx);
3054 no_pgphints:;
3055 }
3056
3057 if ((app & APPLICATION_SMIME))
3058 {
3059 /* and now look for x509 certificates */
3060 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3061 err = gpgme_op_keylist_start(ctx, pattern, 0);
3062 if (err != 0)
3063 {
3064 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3065 gpgme_release(ctx);
3066 FREE(&pattern);
3067 return NULL;
3068 }
3069
3070 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3071 {
3072 KeyFlags flags = KEYFLAG_ISX509;
3073
3075 flags |= KEYFLAG_CANENCRYPT;
3077 flags |= KEYFLAG_CANSIGN;
3078
3079 if (key->revoked)
3080 flags |= KEYFLAG_REVOKED;
3081 if (key->expired)
3082 flags |= KEYFLAG_EXPIRED;
3083 if (key->disabled)
3084 flags |= KEYFLAG_DISABLED;
3085
3086 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3087 {
3088 k = mutt_mem_calloc(1, sizeof(*k));
3089 k->kobj = key;
3090 gpgme_key_ref(k->kobj);
3091 k->idx = idx;
3092 k->uid = uid->uid;
3093 k->flags = flags;
3094 if (uid->revoked)
3095 k->flags |= KEYFLAG_REVOKED;
3096 k->validity = uid->validity;
3097 *kend = k;
3098 kend = &k->next;
3099 }
3100 gpgme_key_unref(key);
3101 }
3102 if (gpg_err_code(err) != GPG_ERR_EOF)
3103 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3104 gpgme_op_keylist_end(ctx);
3105 }
3106
3107 gpgme_release(ctx);
3108 FREE(&pattern);
3109 return db;
3110}
3111
3120static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
3121{
3122 char *scratch = mutt_str_dup(str);
3123 if (!scratch)
3124 return;
3125
3126 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3127 {
3128 if (strlen(t) > 3)
3130 }
3131
3132 FREE(&scratch);
3133}
3134
3144static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
3145 KeyFlags abilities, unsigned int app,
3146 bool *forced_valid, bool oppenc_mode)
3147{
3148 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3149
3150 int multi = false;
3151 int this_key_has_strong = false;
3152 int this_key_has_addr_match = false;
3153 int match = false;
3154
3155 struct CryptKeyInfo *keys = NULL, *k = NULL;
3156 struct CryptKeyInfo *the_strong_valid_key = NULL;
3157 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3158 struct CryptKeyInfo *matches = NULL;
3159 struct CryptKeyInfo **matches_endp = &matches;
3160
3161 if (a && a->mailbox)
3163 if (a && a->personal)
3165
3166 if (!oppenc_mode)
3167 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3168 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3169
3170 mutt_list_free(&hints);
3171
3172 if (!keys)
3173 return NULL;
3174
3175 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3176 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3177
3178 for (k = keys; k; k = k->next)
3179 {
3180 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3181
3182 if (abilities && !(k->flags & abilities))
3183 {
3184 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3185 continue;
3186 }
3187
3188 this_key_has_strong = false; /* strong and valid match */
3189 this_key_has_addr_match = false;
3190 match = false; /* any match */
3191
3192 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3193 mutt_addrlist_parse(&alist, k->uid);
3194 struct Address *ka = NULL;
3195 TAILQ_FOREACH(ka, &alist, entries)
3196 {
3197 int validity = crypt_id_matches_addr(a, ka, k);
3198
3199 if (validity & CRYPT_KV_MATCH) /* something matches */
3200 {
3201 match = true;
3202
3203 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3204 {
3205 if (validity & CRYPT_KV_STRONGID)
3206 {
3207 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3208 multi = true;
3209 this_key_has_strong = true;
3210 }
3211 else
3212 {
3213 this_key_has_addr_match = true;
3214 }
3215 }
3216 }
3217 }
3218 mutt_addrlist_clear(&alist);
3219
3220 if (match)
3221 {
3222 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3223 *matches_endp = tmp;
3224 matches_endp = &tmp->next;
3225
3226 if (this_key_has_strong)
3227 the_strong_valid_key = tmp;
3228 else if (this_key_has_addr_match)
3229 a_valid_addrmatch_key = tmp;
3230 }
3231 }
3232
3233 crypt_key_free(&keys);
3234
3235 if (matches)
3236 {
3237 if (oppenc_mode || !isatty(STDIN_FILENO))
3238 {
3239 const bool c_crypt_opportunistic_encrypt_strong_keys =
3240 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3241 if (the_strong_valid_key)
3242 k = crypt_copy_key(the_strong_valid_key);
3243 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3244 k = crypt_copy_key(a_valid_addrmatch_key);
3245 else
3246 k = NULL;
3247 }
3248 else if (the_strong_valid_key && !multi)
3249 {
3250 /* There was precisely one strong match on a valid ID.
3251 * Proceed without asking the user. */
3252 k = crypt_copy_key(the_strong_valid_key);
3253 }
3254 else
3255 {
3256 /* Else: Ask the user. */
3257 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3258 }
3259
3260 crypt_key_free(&matches);
3261 }
3262 else
3263 {
3264 k = NULL;
3265 }
3266
3267 return k;
3268}
3269
3278static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
3279 unsigned int app, bool *forced_valid)
3280{
3281 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3282 struct CryptKeyInfo *matches = NULL;
3283 struct CryptKeyInfo **matches_endp = &matches;
3284 struct CryptKeyInfo *k = NULL;
3285 const char *ps = NULL, *pl = NULL, *phint = NULL;
3286
3287 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3288
3289 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3290 crypt_add_string_to_hints(phint, &hints);
3291 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3292 mutt_list_free(&hints);
3293
3294 if (!keys)
3295 {
3296 FREE(&pfcopy);
3297 return NULL;
3298 }
3299
3300 for (k = keys; k; k = k->next)
3301 {
3302 if (abilities && !(k->flags & abilities))
3303 continue;
3304
3305 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3306 crypt_long_keyid(k), k->uid);
3307
3308 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3309 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3310 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3311 {
3312 mutt_debug(LL_DEBUG5, "match\n");
3313
3314 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3315 *matches_endp = tmp;
3316 matches_endp = &tmp->next;
3317 }
3318 else
3319 {
3320 mutt_debug(LL_DEBUG5, "no match\n");
3321 }
3322 }
3323
3324 FREE(&pfcopy);
3325 crypt_key_free(&keys);
3326
3327 if (matches)
3328 {
3329 if (isatty(STDIN_FILENO))
3330 {
3331 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3332
3333 crypt_key_free(&matches);
3334 return k;
3335 }
3336 else
3337 {
3338 if (crypt_keys_are_valid(matches))
3339 return matches;
3340
3341 crypt_key_free(&matches);
3342 return NULL;
3343 }
3344 }
3345
3346 return NULL;
3347}
3348
3361static struct CryptKeyInfo *crypt_ask_for_key(const char *tag, const char *whatfor,
3362 KeyFlags abilities,
3363 unsigned int app, bool *forced_valid)
3364{
3365 struct CryptKeyInfo *key = NULL;
3366 struct CryptCache *l = NULL;
3367 struct Buffer *resp = buf_pool_get();
3368
3370
3371 if (whatfor)
3372 {
3373 for (l = IdDefaults; l; l = l->next)
3374 {
3375 if (mutt_istr_equal(whatfor, l->what))
3376 {
3377 buf_strcpy(resp, l->dflt);
3378 break;
3379 }
3380 }
3381 }
3382
3383 while (true)
3384 {
3385 buf_reset(resp);
3386 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3387 {
3388 goto done;
3389 }
3390
3391 if (whatfor)
3392 {
3393 if (l)
3394 {
3395 mutt_str_replace(&l->dflt, buf_string(resp));
3396 }
3397 else
3398 {
3399 l = mutt_mem_malloc(sizeof(struct CryptCache));
3400 l->next = IdDefaults;
3401 IdDefaults = l;
3402 l->what = mutt_str_dup(whatfor);
3403 l->dflt = buf_strdup(resp);
3404 }
3405 }
3406
3407 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3408 if (key)
3409 goto done;
3410
3411 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3412 }
3413
3414done:
3415 buf_pool_release(&resp);
3416 return key;
3417}
3418
3430static char *find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
3431{
3432 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3433 struct ListNode *crypt_hook = NULL;
3434 const char *keyid = NULL;
3435 char *keylist = NULL;
3436 size_t keylist_size = 0;
3437 size_t keylist_used = 0;
3438 struct Address *p = NULL;
3439 struct CryptKeyInfo *k_info = NULL;
3440 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3441 char buf[1024] = { 0 };
3442 bool forced_valid = false;
3443 bool key_selected;
3444 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3445
3446 struct Address *a = NULL;
3447 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3448 TAILQ_FOREACH(a, addrlist, entries)
3449 {
3450 key_selected = false;
3451 mutt_crypt_hook(&crypt_hook_list, a);
3452 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3453 do
3454 {
3455 p = a;
3456 forced_valid = false;
3457 k_info = NULL;
3458
3459 if (crypt_hook)
3460 {
3461 keyid = crypt_hook->data;
3462 enum QuadOption ans = MUTT_YES;
3463 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3464 {
3465 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3466 buf_string(p->mailbox));
3467 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3468 }
3469 if (ans == MUTT_YES)
3470 {
3471 if (crypt_is_numerical_keyid(keyid))
3472 {
3473 if (mutt_strn_equal(keyid, "0x", 2))
3474 keyid += 2;
3475 goto bypass_selection; /* you don't see this. */
3476 }
3477
3478 /* check for e-mail address */
3479 mutt_addrlist_clear(&hookal);
3480 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3481 {
3482 mutt_addrlist_qualify(&hookal, fqdn);
3483 p = TAILQ_FIRST(&hookal);
3484 }
3485 else if (!oppenc_mode)
3486 {
3487 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3488 }
3489 }
3490 else if (ans == MUTT_NO)
3491 {
3492 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3493 {
3494 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3495 continue;
3496 }
3497 }
3498 else if (ans == MUTT_ABORT)
3499 {
3500 FREE(&keylist);
3501 mutt_addrlist_clear(&hookal);
3502 mutt_list_free(&crypt_hook_list);
3503 return NULL;
3504 }
3505 }
3506
3507 if (!k_info)
3508 {
3509 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3510 }
3511
3512 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3513 {
3514 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3515
3516 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3517 KEYFLAG_CANENCRYPT, app, &forced_valid);
3518 }
3519
3520 if (!k_info)
3521 {
3522 FREE(&keylist);
3523 mutt_addrlist_clear(&hookal);
3524 mutt_list_free(&crypt_hook_list);
3525 return NULL;
3526 }
3527
3528 keyid = crypt_fpr_or_lkeyid(k_info);
3529
3530 bypass_selection:
3531 keylist_size += mutt_str_len(keyid) + 4 + 1;
3532 mutt_mem_realloc(&keylist, keylist_size);
3533 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3534 keyid, forced_valid ? "!" : "");
3535 keylist_used = mutt_str_len(keylist);
3536
3537 key_selected = true;
3538
3539 crypt_key_free(&k_info);
3540 mutt_addrlist_clear(&hookal);
3541
3542 if (crypt_hook)
3543 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3544
3545 } while (crypt_hook);
3546
3547 mutt_list_free(&crypt_hook_list);
3548 }
3549 return keylist;
3550}
3551
3555char *pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3556{
3557 return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
3558}
3559
3563char *smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3564{
3565 return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
3566}
3567
3568#ifdef USE_AUTOCRYPT
3582{
3583 int rc = -1;
3584 gpgme_error_t err;
3585 gpgme_key_t key = NULL;
3586 gpgme_user_id_t uid = NULL;
3587 struct CryptKeyInfo *results = NULL, *k = NULL;
3588 struct CryptKeyInfo **kend = NULL;
3589 struct CryptKeyInfo *choice = NULL;
3590
3591 gpgme_ctx_t ctx = create_gpgme_context(false);
3592
3593 /* list all secret keys */
3594 if (gpgme_op_keylist_start(ctx, NULL, 1))
3595 goto cleanup;
3596
3597 kend = &results;
3598
3599 while (!(err = gpgme_op_keylist_next(ctx, &key)))
3600 {
3602
3607
3608 if (key->revoked)
3610 if (key->expired)
3612 if (key->disabled)
3614
3615 int idx;
3616 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3617 {
3618 k = mutt_mem_calloc(1, sizeof(*k));
3619 k->kobj = key;
3620 gpgme_key_ref(k->kobj);
3621 k->idx = idx;
3622 k->uid = uid->uid;
3623 k->flags = flags;
3624 if (uid->revoked)
3625 k->flags |= KEYFLAG_REVOKED;
3626 k->validity = uid->validity;
3627 *kend = k;
3628 kend = &k->next;
3629 }
3630 gpgme_key_unref(key);
3631 }
3632 if (gpg_err_code(err) != GPG_ERR_EOF)
3633 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3634 gpgme_op_keylist_end(ctx);
3635
3636 if (!results)
3637 {
3638 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3639 from. This error is displayed if no results were found. */
3640 mutt_error(_("No secret keys found"));
3641 goto cleanup;
3642 }
3643
3644 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3645 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3646 goto cleanup;
3647 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3648
3649 rc = 0;
3650
3651cleanup:
3652 crypt_key_free(&choice);
3653 crypt_key_free(&results);
3654 gpgme_release(ctx);
3655 return rc;
3656}
3657#endif
3658
3663{
3664 gpgme_ctx_t context = NULL;
3665 gpgme_key_t export_keys[2] = { 0 };
3666 gpgme_data_t keydata = NULL;
3667 gpgme_error_t err;
3668 struct Body *att = NULL;
3669 char buf[1024] = { 0 };
3670
3671 OptPgpCheckTrust = false;
3672
3673 struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
3675 if (!key)
3676 goto bail;
3677 export_keys[0] = key->kobj;
3678 export_keys[1] = NULL;
3679
3680 context = create_gpgme_context(false);
3681 gpgme_set_armor(context, 1);
3682 keydata = create_gpgme_data();
3683 err = gpgme_op_export_keys(context, export_keys, 0, keydata);
3684 if (err != GPG_ERR_NO_ERROR)
3685 {
3686 mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
3687 goto bail;
3688 }
3689
3690 char *tempf = data_object_to_tempfile(keydata, NULL);
3691 if (!tempf)
3692 goto bail;
3693
3694 att = mutt_body_new();
3695 /* tempf is a newly allocated string, so this is correct: */
3696 att->filename = tempf;
3697 att->unlink = true;
3698 att->use_disp = false;
3699 att->type = TYPE_APPLICATION;
3700 att->subtype = mutt_str_dup("pgp-keys");
3701 /* L10N: MIME description for exported (attached) keys.
3702 You can translate this entry to a non-ASCII string (it will be encoded),
3703 but it may be safer to keep it untranslated. */
3704 snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
3705 att->description = mutt_str_dup(buf);
3707
3708 att->length = mutt_file_get_size(tempf);
3709
3710bail:
3711 crypt_key_free(&key);
3712 gpgme_data_release(keydata);
3713 gpgme_release(context);
3714
3715 return att;
3716}
3717
3721static void init_common(void)
3722{
3723 /* this initialization should only run one time, but it may be called by
3724 * either pgp_gpgme_init or smime_gpgme_init */
3725 static bool has_run = false;
3726 if (has_run)
3727 return;
3728
3729 gpgme_check_version(NULL);
3730 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3731#ifdef ENABLE_NLS
3732 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3733#endif
3734 has_run = true;
3735}
3736
3740static void init_pgp(void)
3741{
3742 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3743 {
3744 mutt_error(_("GPGME: OpenPGP protocol not available"));
3745 }
3746}
3747
3751static void init_smime(void)
3752{
3753 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3754 {
3755 mutt_error(_("GPGME: CMS protocol not available"));
3756 }
3757}
3758
3763{
3764 init_common();
3765 init_pgp();
3766}
3767
3772{
3773 init_common();
3774 init_smime();
3775}
3776
3783static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
3784{
3785 struct CryptKeyInfo *p = NULL;
3786 const char *prompt = NULL;
3787 const char *letters = NULL;
3788 const char *choices = NULL;
3789 int choice;
3790
3791 if (is_smime)
3793 else
3795
3796 /* Opportunistic encrypt is controlling encryption.
3797 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3798 * letter choices for those.
3799 */
3800 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3801 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3802 {
3803 if (is_smime)
3804 {
3805 /* L10N: S/MIME options (opportunistic encryption is on) */
3806 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3807 /* L10N: S/MIME options (opportunistic encryption is on) */
3808 letters = _("sapco");
3809 choices = "SapCo";
3810 }
3811 else
3812 {
3813 /* L10N: PGP options (opportunistic encryption is on) */
3814 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3815 /* L10N: PGP options (opportunistic encryption is on) */
3816 letters = _("samco");
3817 choices = "SamCo";
3818 }
3819 }
3820 else if (c_crypt_opportunistic_encrypt)
3821 {
3822 /* Opportunistic encryption option is set, but is toggled off for this message. */
3823 if (is_smime)
3824 {
3825 /* L10N: S/MIME options (opportunistic encryption is off) */
3826 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3827 /* L10N: S/MIME options (opportunistic encryption is off) */
3828 letters = _("esabpco");
3829 choices = "esabpcO";
3830 }
3831 else
3832 {
3833 /* L10N: PGP options (opportunistic encryption is off) */
3834 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3835 /* L10N: PGP options (opportunistic encryption is off) */
3836 letters = _("esabmco");
3837 choices = "esabmcO";
3838 }
3839 }
3840 else
3841 {
3842 /* Opportunistic encryption is unset */
3843 if (is_smime)
3844 {
3845 /* L10N: S/MIME options */
3846 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3847 /* L10N: S/MIME options */
3848 letters = _("esabpc");
3849 choices = "esabpc";
3850 }
3851 else
3852 {
3853 /* L10N: PGP options */
3854 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3855 /* L10N: PGP options */
3856 letters = _("esabmc");
3857 choices = "esabmc";
3858 }
3859 }
3860
3861 choice = mw_multi_choice(prompt, letters);
3862 if (choice > 0)
3863 {
3864 switch (choices[choice - 1])
3865 {
3866 case 'a': /* sign (a)s */
3867 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3868 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3869 if (p)
3870 {
3871 char input_signas[128] = { 0 };
3872 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3873
3874 if (is_smime)
3875 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3876 else
3877 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3878
3879 crypt_key_free(&p);
3880
3881 e->security |= SEC_SIGN;
3882 }
3883 break;
3884
3885 case 'b': /* (b)oth */
3886 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3887 break;
3888
3889 case 'C':
3890 e->security &= ~SEC_SIGN;
3891 break;
3892
3893 case 'c': /* (c)lear */
3894 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3895 break;
3896
3897 case 'e': /* (e)ncrypt */
3898 e->security |= SEC_ENCRYPT;
3899 e->security &= ~SEC_SIGN;
3900 break;
3901
3902 case 'm': /* (p)gp or s/(m)ime */
3903 case 'p':
3904 is_smime = !is_smime;
3905 if (is_smime)
3906 {
3907 e->security &= ~APPLICATION_PGP;
3909 }
3910 else
3911 {
3912 e->security &= ~APPLICATION_SMIME;
3914 }
3916 break;
3917
3918 case 'O': /* oppenc mode on */
3921 break;
3922
3923 case 'o': /* oppenc mode off */
3924 e->security &= ~SEC_OPPENCRYPT;
3925 break;
3926
3927 case 'S': /* (s)ign in oppenc mode */
3928 e->security |= SEC_SIGN;
3929 break;
3930
3931 case 's': /* (s)ign */
3932 e->security &= ~SEC_ENCRYPT;
3933 e->security |= SEC_SIGN;
3934 break;
3935 }
3936 }
3937
3938 return e->security;
3939}
3940
3945{
3946 return gpgme_send_menu(e, false);
3947}
3948
3953{
3954 return gpgme_send_menu(e, true);
3955}
3956
3962static bool verify_sender(struct Email *e)
3963{
3964 struct Address *sender = NULL;
3965 bool rc = true;
3966
3967 if (!TAILQ_EMPTY(&e->env->from))
3968 {
3970 sender = TAILQ_FIRST(&e->env->from);
3971 }
3972 else if (!TAILQ_EMPTY(&e->env->sender))
3973 {
3975 sender = TAILQ_FIRST(&e->env->sender);
3976 }
3977
3978 if (sender)
3979 {
3980 if (SignatureKey)
3981 {
3982 gpgme_key_t key = SignatureKey;
3983 gpgme_user_id_t uid = NULL;
3984 int sender_length = buf_len(sender->mailbox);
3985 for (uid = key->uids; uid && rc; uid = uid->next)
3986 {
3987 int uid_length = strlen(uid->email);
3988 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
3989 (uid_length == (sender_length + 2)))
3990 {
3991 const char *at_sign = strchr(uid->email + 1, '@');
3992 if (at_sign)
3993 {
3994 /* Assume address is 'mailbox@domainname'.
3995 * The mailbox part is case-sensitive,
3996 * the domainname is not. (RFC2821) */
3997 const char *tmp_email = uid->email + 1;
3998 const char *tmp_sender = buf_string(sender->mailbox);
3999 /* length of mailbox part including '@' */
4000 int mailbox_length = at_sign - tmp_email + 1;
4001 int domainname_length = sender_length - mailbox_length;
4002 int mailbox_match, domainname_match;
4003
4004 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4005 tmp_email += mailbox_length;
4006 tmp_sender += mailbox_length;
4007 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4008 if (mailbox_match && domainname_match)
4009 rc = false;
4010 }
4011 else
4012 {
4013 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4014 rc = false;
4015 }
4016 }
4017 }
4018 }
4019 else
4020 {
4021 mutt_any_key_to_continue(_("Failed to verify sender"));
4022 }
4023 }
4024 else
4025 {
4026 mutt_any_key_to_continue(_("Failed to figure out sender"));
4027 }
4028
4029 if (SignatureKey)
4030 {
4031 gpgme_key_unref(SignatureKey);
4032 SignatureKey = NULL;
4033 }
4034
4035 return rc;
4036}
4037
4041int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
4042{
4043 return verify_sender(e);
4044}
4045
4049void pgp_gpgme_set_sender(const char *sender)
4050{
4051 mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
4053 CurrentSender = mutt_str_dup(sender);
4054}
4055
4061{
4062 return GPGME_VERSION;
4063}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:680
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1464
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:480
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
GUI display the mailboxes in a side panel.
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:35
Autocrypt end-to-end encryption.
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:714
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:508
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:308
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:588
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
Convenience wrapper for the core headers.
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:534
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1031
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1364
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:394
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:595
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:453
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1275
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:490
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition: crypt.c:795
Signing/encryption multiplexor.
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
Definition: crypt_gpgme.c:180
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:756
static struct CryptKeyInfo * crypt_getkeybyaddr(struct Address *a, KeyFlags abilities, unsigned int app, bool *forced_valid, bool oppenc_mode)
Find a key by email address.
Definition: crypt_gpgme.c:3144
static char * find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
Find keys of the recipients of the message.
Definition: crypt_gpgme.c:3430
static bool verify_sender(struct Email *e)
Verify the sender of a message.
Definition: crypt_gpgme.c:3962
static void init_common(void)
Initialise code common to PGP and SMIME parts of GPGME.
Definition: crypt_gpgme.c:3721
static struct CryptCache * IdDefaults
Cache of GPGME keys.
Definition: crypt_gpgme.c:92
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:234
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:76
static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
Do the actual verification step.
Definition: crypt_gpgme.c:1542
static char * CurrentSender
Email address of the sender.
Definition: crypt_gpgme.c:96
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
Definition: crypt_gpgme.c:3581
const char * mutt_gpgme_print_version(void)
Get version of GPGME.
Definition: crypt_gpgme.c:4060
static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
Create GPGME object from the mail body.
Definition: crypt_gpgme.c:419
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:310
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:400
static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, struct State *state, gpgme_signature_t sig)
Show a signature summary.
Definition: crypt_gpgme.c:1128
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key's fingerprint.
Definition: crypt_gpgme.c:1252
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:361
static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
Create a string of recipients.
Definition: crypt_gpgme.c:618
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3278
static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig, gpgme_key_t key, struct State *state)
Print key info about an SMIME key.
Definition: crypt_gpgme.c:1346
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
Definition: crypt_gpgme.c:328
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:275
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: crypt_gpgme.c:3120
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:214
static char * encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime, bool combined_signed, const struct AddressList *from)
Encrypt the GPGPME data object.
Definition: crypt_gpgme.c:776
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:104
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:102
#define PKA_NOTATION_NAME
Definition: crypt_gpgme.c:98
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:2900
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:74
static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
Find the "micalg" parameter from the last GPGME operation.
Definition: crypt_gpgme.c:848
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
Definition: crypt_gpgme.c:514
static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check one inline PGP body part.
Definition: crypt_gpgme.c:2170
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:163
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:77
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
Definition: crypt_gpgme.c:2967
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
Definition: crypt_gpgme.c:493
static struct Body * decrypt_part(struct Body *b, struct State *state, FILE *fp_out, bool is_smime, int *r_is_signed)
Decrypt a PGP or SMIME message.
Definition: crypt_gpgme.c:1693
#define PUBLIC_KEY_BLOCK(_y)
Definition: crypt_gpgme.c:103
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
Definition: crypt_gpgme.c:712
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:561
static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
Show the validity of a key used for one signature.
Definition: crypt_gpgme.c:1307
static void init_smime(void)
Initialise the SMIME crypto backend.
Definition: crypt_gpgme.c:3751
static struct CryptKeyInfo * crypt_ask_for_key(const char *tag, const char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3361
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:2844
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:199
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:138
static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
Show the user the encryption/signing menu.
Definition: crypt_gpgme.c:3783
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:75
static struct Body * sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
Sign a message.
Definition: crypt_gpgme.c:901
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
Definition: crypt_gpgme.c:112
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
Definition: crypt_gpgme.c:121
static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
Write PGP keys to a file.
Definition: crypt_gpgme.c:2068
static int line_compare(const char *a, size_t n, const char *b)
Compare two strings ignore line endings.
Definition: crypt_gpgme.c:2152
static gpgme_key_t SignatureKey
PGP Key to sign with.
Definition: crypt_gpgme.c:94
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:253
static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
Try to set the context's signer from the address.
Definition: crypt_gpgme.c:654
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:78
static void init_pgp(void)
Initialise the PGP crypto backend.
Definition: crypt_gpgme.c:3740
static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
Copy a clearsigned message.
Definition: crypt_gpgme.c:2371
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
Show information about one signature.
Definition: crypt_gpgme.c:1419
static void print_time(time_t t, struct State *state)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:886
#define MESSAGE(_y)
Definition: crypt_gpgme.c:101
Wrapper for PGP/SMIME calls to GPGME.
KeyCap
PGP/SMIME Key Capabilities.
Definition: crypt_gpgme.h:75
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition: crypt_gpgme.h:78
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition: crypt_gpgme.h:76
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition: crypt_gpgme.h:77
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:175
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:100
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:445
Edit a string.
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:132
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1748
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1318
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1578
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:771
long mutt_file_get_size(const char *path)
Get the size of a file.
Definition: file.c:1560
#define mutt_file_fclose(FP)
Definition: file.h:148
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:147
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: globals.c:62
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:73
bool crypt_keys_are_valid(struct CryptKeyInfo *keys)
Are all these keys valid?
Gpgme functions.
int pgp_gpgme_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition: crypt_gpgme.c:2427
int smime_gpgme_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition: crypt_gpgme.c:2751
int smime_gpgme_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: crypt_gpgme.c:1949
int pgp_gpgme_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: crypt_gpgme.c:1852
int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
Definition: crypt_gpgme.c:2660
char * smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition: crypt_gpgme.c:3563
char * pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition: crypt_gpgme.c:3555
void smime_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
Definition: crypt_gpgme.c:3771
void pgp_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
Definition: crypt_gpgme.c:3762
bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
Look for inline (non-MIME) PGP content - Implements CryptModuleSpecs::pgp_check_traditional() -.
Definition: crypt_gpgme.c:2235
struct Body * pgp_gpgme_encrypt_message(struct Body *b, char *keylist, bool sign, const struct AddressList *from)
PGP encrypt an email - Implements CryptModuleSpecs::pgp_encrypt_message() -.
Definition: crypt_gpgme.c:1038
void pgp_gpgme_invoke_import(const char *fname)
Import a key from a message into the user's public key ring - Implements CryptModuleSpecs::pgp_invoke...
Definition: crypt_gpgme.c:2262
struct Body * pgp_gpgme_make_key_attachment(void)
Generate a public key attachment - Implements CryptModuleSpecs::pgp_make_key_attachment() -.
Definition: crypt_gpgme.c:3662
SecurityFlags pgp_gpgme_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition: crypt_gpgme.c:3944
SecurityFlags smime_gpgme_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition: crypt_gpgme.c:3952
void pgp_gpgme_set_sender(const char *sender)
Set the sender of the email - Implements CryptModuleSpecs::set_sender() -.
Definition: crypt_gpgme.c:4049
struct Body * smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition: crypt_gpgme.c:1030
struct Body * pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition: crypt_gpgme.c:1022
struct Body * smime_gpgme_build_smime_entity(struct Body *b, char *keylist)
Encrypt the email body to all recipients - Implements CryptModuleSpecs::smime_build_smime_entity() -.
Definition: crypt_gpgme.c:1084
int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
Does the sender match the certificate? - Implements CryptModuleSpecs::smime_verify_sender() -.
Definition: crypt_gpgme.c:4041
int pgp_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition: crypt_gpgme.c:1667
int smime_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition: crypt_gpgme.c:1675
struct CryptKeyInfo * dlg_gpgme(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key -.
Definition: dlg_gpgme.c:625
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:274
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:64
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition: crypt.c:1103
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
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:1631
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1905
Decide how to display email content.
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:756
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:848
Parse and execute user-defined hooks.
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:231
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:45
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ 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)
Definition: mime.h:82
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition: charset.c:982
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:932
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:1044
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:964
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:73
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:72
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:953
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition: state.c:103
#define state_puts(STATE, STR)
Definition: state.h:58
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:33
#define state_putc(STATE, STR)
Definition: state.h:59
#define STATE_VERIFY
Perform signature verification.
Definition: state.h:34
#define STATE_NO_FLAGS
No flags are set.
Definition: state.h:32
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:488
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:721
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:362
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
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:474
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:570
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
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:630
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1039
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:58
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:131
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:129
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:125
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:128
#define KEYFLAG_CANTUSE
Definition: lib.h:139
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:126
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:133
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:132
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:127
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:111
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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:349
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:300
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:421
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:706
GUI display the mailboxes in a side panel.
Key value store.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
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:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:43
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
char * description
content-description
Definition: body.h:55
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
bool goodsig
Good cryptographic signature.
Definition: body.h:45
bool warnsig
Maybe good signature.
Definition: body.h:48
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:58
String manipulation buffer.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:37
Internal cache for GPGME.
Definition: crypt_gpgme.c:85
char * what
Definition: crypt_gpgme.c:86
char * dflt
Definition: crypt_gpgme.c:87
struct CryptCache * next
Definition: crypt_gpgme.c:88
A stored PGP key.
Definition: crypt_gpgme.h:44
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:50
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:49
int idx
and the user ID at this index
Definition: crypt_gpgme.h:47
struct CryptKeyInfo * next
Linked list.
Definition: crypt_gpgme.h:45
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:48
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
The envelope/body of an email.
Definition: email.h:39
struct Envelope * env
Envelope information.
Definition: email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
Cursor for converting a file's encoding.
Definition: charset.h:42
FILE * fp
Definition: charset.h:43
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
A local copy of an email.
Definition: message.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
Keep track when processing files.
Definition: state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:52
FILE * fp_out
File to write to.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition: state.h:51
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:386
#define buf_mktemp(buf)
Definition: tmp.h:33
#define mutt_file_mkstemp()
Definition: tmp.h:36