NeoMutt  2025-12-11-769-g906513
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt_gpgme.c
Go to the documentation of this file.
1
29
35
36#include "config.h"
37#include <errno.h>
38#include <gpg-error.h>
39#include <gpgme.h>
40#include <langinfo.h>
41#include <locale.h>
42#include <stdbool.h>
43#include <stdio.h>
44#include <string.h>
45#include <sys/types.h>
46#include <unistd.h>
47#include "private.h"
48#include "mutt/lib.h"
49#include "address/lib.h"
50#include "config/lib.h"
51#include "email/lib.h"
52#include "core/lib.h"
53#include "alias/lib.h"
54#include "gui/lib.h"
55#include "mutt.h"
56#include "crypt_gpgme.h"
57#include "lib.h"
58#include "attach/lib.h"
59#include "editor/lib.h"
60#include "history/lib.h"
61#include "hooks/lib.h"
62#include "question/lib.h"
63#include "send/lib.h"
64#include "crypt.h"
65#include "globals.h"
66#include "gpgme_functions.h"
67#include "module_data.h"
68#include "mutt_logging.h"
69#ifdef USE_AUTOCRYPT
70#include "autocrypt/lib.h"
71#endif
72
73// clang-format off
74/* Values used for comparing addresses. */
75#define CRYPT_KV_VALID (1 << 0)
76#define CRYPT_KV_ADDR (1 << 1)
77#define CRYPT_KV_STRING (1 << 2)
78#define CRYPT_KV_STRONGID (1 << 3)
79#define CRYPT_KV_MATCH (CRYPT_KV_ADDR | CRYPT_KV_STRING)
80// clang-format on
81
86{
87 char *what;
88 char *dflt;
89 struct CryptCache *next;
90};
91
92#define PKA_NOTATION_NAME "pka-address@gnupg.org"
93
94#define _LINE_COMPARE(_x, _y) line_compare(_x, sizeof(_x) - 1, _y)
95#define MESSAGE(_y) _LINE_COMPARE("MESSAGE-----", _y)
96#define SIGNED_MESSAGE(_y) _LINE_COMPARE("SIGNED MESSAGE-----", _y)
97#define PUBLIC_KEY_BLOCK(_y) _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
98#define BEGIN_PGP_SIGNATURE(_y) \
99 _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)
100
106static bool is_pka_notation(gpgme_sig_notation_t notation)
107{
108 return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
109}
110
115static void redraw_if_needed(gpgme_ctx_t ctx)
116{
117 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
118 if (!s /* flag not known */ || *s /* flag true */)
119 {
121 }
122}
123
132const char *crypt_keyid(struct CryptKeyInfo *k)
133{
134 const char *s = "????????";
135
136 if (k->kobj && k->kobj->subkeys)
137 {
138 s = k->kobj->subkeys->keyid;
139 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
140 if ((!c_pgp_long_ids) && (strlen(s) == 16))
141 {
142 /* Return only the short keyID. */
143 s += 8;
144 }
145 }
146
147 return s;
148}
149
157static const char *crypt_long_keyid(struct CryptKeyInfo *k)
158{
159 const char *s = "????????????????";
160
161 if (k->kobj && k->kobj->subkeys)
162 {
163 s = k->kobj->subkeys->keyid;
164 }
165
166 return s;
167}
168
174static const char *crypt_short_keyid(struct CryptKeyInfo *k)
175{
176 const char *s = "????????";
177
178 if (k->kobj && k->kobj->subkeys)
179 {
180 s = k->kobj->subkeys->keyid;
181 if (strlen(s) == 16)
182 s += 8;
183 }
184
185 return s;
186}
187
193static const char *crypt_fpr(struct CryptKeyInfo *k)
194{
195 const char *s = "";
196
197 if (k->kobj && k->kobj->subkeys)
198 s = k->kobj->subkeys->fpr;
199
200 return s;
201}
202
208const char *crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
209{
210 const char *s = "????????????????";
211
212 if (k->kobj && k->kobj->subkeys)
213 {
214 if (k->kobj->subkeys->fpr)
215 s = k->kobj->subkeys->fpr;
216 else
217 s = k->kobj->subkeys->keyid;
218 }
219
220 return s;
221}
222
229{
230 struct CryptKeyInfo *k = NULL;
231
232 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
233 k->kobj = key->kobj;
234 gpgme_key_ref(key->kobj);
235 k->idx = key->idx;
236 k->uid = key->uid;
237 k->flags = key->flags;
238 k->validity = key->validity;
239
240 return k;
241}
242
247static void crypt_key_free(struct CryptKeyInfo **keylist)
248{
249 if (!keylist)
250 return;
251
252 struct CryptKeyInfo *k = NULL;
253
254 while (*keylist)
255 {
256 k = *keylist;
257 *keylist = (*keylist)->next;
258
259 gpgme_key_unref(k->kobj);
260 FREE(&k);
261 }
262}
263
270{
271 if (!key)
272 return false;
273
274 bool is_strong = false;
275
276 if ((key->flags & KEYFLAG_ISX509))
277 return true;
278
279 switch (key->validity)
280 {
281 case GPGME_VALIDITY_MARGINAL:
282 case GPGME_VALIDITY_NEVER:
283 case GPGME_VALIDITY_UNDEFINED:
284 case GPGME_VALIDITY_UNKNOWN:
285 is_strong = false;
286 break;
287
288 case GPGME_VALIDITY_FULL:
289 case GPGME_VALIDITY_ULTIMATE:
290 is_strong = true;
291 break;
292 }
293
294 return is_strong;
295}
296
305{
306 if (!key)
307 return 0;
308
309 return !(key->flags & KEYFLAG_CANTUSE);
310}
311
322static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr,
323 struct CryptKeyInfo *key)
324{
325 int rc = 0;
326
327 if (crypt_id_is_valid(key))
328 rc |= CRYPT_KV_VALID;
329
330 if (crypt_id_is_strong(key))
331 rc |= CRYPT_KV_STRONGID;
332
333 if (addr && u_addr)
334 {
335 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
336 {
337 rc |= CRYPT_KV_ADDR;
338 }
339
340 if (addr->personal && u_addr->personal &&
341 buf_istr_equal(addr->personal, u_addr->personal))
342 {
343 rc |= CRYPT_KV_STRING;
344 }
345 }
346
347 return rc;
348}
349
355gpgme_ctx_t create_gpgme_context(bool for_smime)
356{
357 gpgme_ctx_t ctx = NULL;
358
359 gpgme_error_t err = gpgme_new(&ctx);
360
361#ifdef USE_AUTOCRYPT
362 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
363 if ((err == GPG_ERR_NO_ERROR) && OptAutocryptGpgme)
364 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
365#endif
366
367 if (err != GPG_ERR_NO_ERROR)
368 {
369 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
370 mutt_exit(1);
371 }
372
373 if (for_smime)
374 {
375 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
376 if (err != GPG_ERR_NO_ERROR)
377 {
378 mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
379 mutt_exit(1);
380 }
381 }
382
383 return ctx;
384}
385
394static gpgme_data_t create_gpgme_data(void)
395{
396 gpgme_data_t data = NULL;
397
398 gpgme_error_t err = gpgme_data_new(&data);
399 if (err != GPG_ERR_NO_ERROR)
400 {
401 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
402 mutt_exit(1);
403 }
404 return data;
405}
406
413static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
414{
415 gpgme_error_t err = GPG_ERR_NO_ERROR;
416 gpgme_data_t data = NULL;
417
418 struct Buffer *tempfile = buf_pool_get();
419 buf_mktemp(tempfile);
420 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
421 if (!fp_tmp)
422 {
423 mutt_perror("%s", buf_string(tempfile));
424 goto cleanup;
425 }
426
428 fputc('\n', fp_tmp);
429 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
430
431 if (convert)
432 {
433 int c, hadcr = 0;
434 unsigned char buf[1];
435
437 rewind(fp_tmp);
438 while ((c = fgetc(fp_tmp)) != EOF)
439 {
440 if (c == '\r')
441 {
442 hadcr = 1;
443 }
444 else
445 {
446 if ((c == '\n') && !hadcr)
447 {
448 buf[0] = '\r';
449 gpgme_data_write(data, buf, 1);
450 }
451
452 hadcr = 0;
453 }
454 /* FIXME: This is quite suboptimal */
455 buf[0] = c;
456 gpgme_data_write(data, buf, 1);
457 }
458 mutt_file_fclose(&fp_tmp);
459 gpgme_data_seek(data, 0, SEEK_SET);
460 }
461 else
462 {
463 mutt_file_fclose(&fp_tmp);
464 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
465 if (err != GPG_ERR_NO_ERROR)
466 {
467 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
468 gpgme_data_release(data);
469 data = NULL;
470 /* fall through to unlink the tempfile */
471 }
472 }
473 unlink(buf_string(tempfile));
474
475cleanup:
476 buf_pool_release(&tempfile);
477 return data;
478}
479
487static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
488{
489 gpgme_data_t data = NULL;
490
491 gpgme_error_t err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
492 if (err != GPG_ERR_NO_ERROR)
493 {
494 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
495 return NULL;
496 }
497
498 return data;
499}
500
508static int data_object_to_stream(gpgme_data_t data, FILE *fp)
509{
510 char buf[4096] = { 0 };
511 ssize_t nread;
512
513 gpgme_error_t err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ?
514 gpgme_error_from_errno(errno) :
515 GPG_ERR_NO_ERROR);
516 if (err != GPG_ERR_NO_ERROR)
517 {
518 mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
519 return -1;
520 }
521
522 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
523 {
524 /* fixme: we are not really converting CRLF to LF but just
525 * skipping CR. Doing it correctly needs a more complex logic */
526 for (char *p = buf; nread; p++, nread--)
527 {
528 if (*p != '\r')
529 putc(*p, fp);
530 }
531
532 if (ferror(fp))
533 {
534 mutt_perror(_("[tempfile]"));
535 return -1;
536 }
537 }
538 if (nread == -1)
539 {
540 mutt_error(_("error reading data object: %s"), strerror(errno));
541 return -1;
542 }
543 return 0;
544}
545
557static char *data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
558{
559 ssize_t nread = 0;
560 char *rv = NULL;
561 struct Buffer *tempfile = buf_pool_get();
562
563 buf_mktemp(tempfile);
564
565 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
566 if (!fp)
567 {
568 mutt_perror(_("Can't create temporary file"));
569 goto cleanup;
570 }
571
572 gpgme_error_t err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ?
573 gpgme_error_from_errno(errno) :
574 GPG_ERR_NO_ERROR);
575 if (err == GPG_ERR_NO_ERROR)
576 {
577 char buf[4096] = { 0 };
578
579 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
580 {
581 if (fwrite(buf, nread, 1, fp) != 1)
582 {
583 mutt_perror("%s", buf_string(tempfile));
584 mutt_file_fclose(&fp);
585 unlink(buf_string(tempfile));
586 goto cleanup;
587 }
588 }
589 }
590 if (fp_ret)
591 rewind(fp);
592 else
593 mutt_file_fclose(&fp);
594 if (nread == -1)
595 {
596 mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
597 unlink(buf_string(tempfile));
598 mutt_file_fclose(&fp);
599 goto cleanup;
600 }
601 if (fp_ret)
602 *fp_ret = fp;
603 rv = buf_strdup(tempfile);
604
605cleanup:
606 buf_pool_release(&tempfile);
607 return rv;
608}
609
616static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
617{
618 unsigned int n = 0;
619
620 const char *s = keylist;
621 do
622 {
623 while (*s == ' ')
624 s++;
625 if (*s != '\0')
626 {
627 if (n == 0)
628 {
629 if (!use_smime)
630 buf_addstr(recpstring, "--\n");
631 }
632 else
633 {
634 buf_addch(recpstring, '\n');
635 }
636 n++;
637
638 while ((*s != '\0') && (*s != ' '))
639 buf_addch(recpstring, *s++);
640 }
641 } while (*s != '\0');
642}
643
652static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
653{
654 gpgme_key_t key = NULL;
655 gpgme_key_t key2 = NULL;
656
657 gpgme_ctx_t listctx = create_gpgme_context(for_smime);
658 gpgme_error_t err = gpgme_op_keylist_start(listctx, address, 1);
659 if (err == GPG_ERR_NO_ERROR)
660 err = gpgme_op_keylist_next(listctx, &key);
661 if (err != GPG_ERR_NO_ERROR)
662 {
663 gpgme_release(listctx);
664 mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
665 return false;
666 }
667
668 char *fpr = "fpr1";
669 if (key->subkeys)
670 fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
671 while (gpgme_op_keylist_next(listctx, &key2) == 0)
672 {
673 char *fpr2 = "fpr2";
674 if (key2->subkeys)
675 fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
676 if (!mutt_str_equal(fpr, fpr2))
677 {
678 gpgme_key_unref(key);
679 gpgme_key_unref(key2);
680 gpgme_release(listctx);
681 mutt_error(_("ambiguous specification of secret key '%s'"), address);
682 return false;
683 }
684 else
685 {
686 gpgme_key_unref(key2);
687 }
688 }
689 gpgme_op_keylist_end(listctx);
690 gpgme_release(listctx);
691
692 gpgme_signers_clear(ctx);
693 err = gpgme_signers_add(ctx, key);
694 gpgme_key_unref(key);
695 if (err != GPG_ERR_NO_ERROR)
696 {
697 mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
698 return false;
699 }
700 return true;
701}
702
711static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
712{
713 const char *signid = NULL;
714
715 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
716 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
717 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
718 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
719 if (for_smime)
720 {
721 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
722 }
723#ifdef USE_AUTOCRYPT
724 else if (OptAutocryptGpgme)
725 {
727 ASSERT(mod_data);
728
729 signid = mod_data->autocrypt_sign_as;
730 }
731#endif
732 else
733 {
734 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
735 }
736
737 /* Try getting the signing key from config entries */
738 if (signid && set_signer_from_address(ctx, signid, for_smime))
739 {
740 return 0;
741 }
742
743 /* Try getting the signing key from the From line */
744 if (al)
745 {
746 struct Address *a;
747 TAILQ_FOREACH(a, al, entries)
748 {
749 if (a->mailbox && set_signer_from_address(ctx, buf_string(a->mailbox), for_smime))
750 {
751 return 0;
752 }
753 }
754 }
755
756 return (!signid && !al) ? 0 : -1;
757}
758
764static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
765{
767 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME,
768 mod_data->current_sender, 0);
769 if (err != GPG_ERR_NO_ERROR)
770 {
771 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
772 }
773
774 return err;
775}
776
786static char *encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime,
787 bool combined_signed, const struct AddressList *from)
788{
789 gpgme_error_t err = GPG_ERR_NO_ERROR;
790 gpgme_ctx_t ctx = NULL;
791 gpgme_data_t ciphertext = NULL;
792 char *outfile = NULL;
793
794 struct Buffer *recpstring = buf_pool_get();
795 create_recipient_string(keylist, recpstring, use_smime);
796 if (buf_is_empty(recpstring))
797 {
798 buf_pool_release(&recpstring);
799 return NULL;
800 }
801
802 ctx = create_gpgme_context(use_smime);
803 if (!use_smime)
804 gpgme_set_armor(ctx, 1);
805
806 ciphertext = create_gpgme_data();
807
808 if (combined_signed)
809 {
810 if (set_signer(ctx, from, use_smime))
811 goto cleanup;
812
813 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
814 if (c_crypt_use_pka)
815 {
816 err = set_pka_sig_notation(ctx);
817 if (err != GPG_ERR_NO_ERROR)
818 goto cleanup;
819 }
820
821 err = gpgme_op_encrypt_sign_ext(ctx, NULL, buf_string(recpstring),
822 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
823 }
824 else
825 {
826 err = gpgme_op_encrypt_ext(ctx, NULL, buf_string(recpstring),
827 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
828 }
829
830 redraw_if_needed(ctx);
831 if (err != GPG_ERR_NO_ERROR)
832 {
833 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
834 goto cleanup;
835 }
836
837 outfile = data_object_to_tempfile(ciphertext, NULL);
838
839cleanup:
840 buf_pool_release(&recpstring);
841 gpgme_release(ctx);
842 gpgme_data_release(ciphertext);
843 return outfile;
844}
845
858static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
859{
860 gpgme_sign_result_t result = NULL;
861 const char *algorithm_name = NULL;
862
863 if (buflen < 5)
864 return -1;
865
866 *buf = '\0';
867 result = gpgme_op_sign_result(ctx);
868 if (result && result->signatures)
869 {
870 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
871 if (algorithm_name)
872 {
873 if (use_smime)
874 {
875 /* convert GPGME raw hash name to RFC2633 format */
876 snprintf(buf, buflen, "%s", algorithm_name);
877 mutt_str_lower(buf);
878 }
879 else
880 {
881 /* convert GPGME raw hash name to RFC3156 format */
882 snprintf(buf, buflen, "pgp-%s", algorithm_name);
883 mutt_str_lower(buf + 4);
884 }
885 }
886 }
887
888 return (buf[0] != '\0') ? 0 : -1;
889}
890
896static void print_time(time_t t, struct State *state)
897{
898 char p[256] = { 0 };
899 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
900 state_puts(state, p);
901}
902
911static struct Body *sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
912{
913 struct Body *b_sign = NULL;
914 char *sigfile = NULL;
915 gpgme_error_t err = GPG_ERR_NO_ERROR;
916 char buf[100] = { 0 };
917 gpgme_ctx_t ctx = NULL;
918 gpgme_data_t message = NULL, signature = NULL;
919 gpgme_sign_result_t sigres = NULL;
920
921 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
922
923 message = body_to_data_object(b, true);
924 if (!message)
925 return NULL;
926 signature = create_gpgme_data();
927
928 ctx = create_gpgme_context(use_smime);
929 if (!use_smime)
930 gpgme_set_armor(ctx, 1);
931
932 if (set_signer(ctx, from, use_smime))
933 {
934 gpgme_data_release(signature);
935 gpgme_data_release(message);
936 gpgme_release(ctx);
937 return NULL;
938 }
939
940 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
941 if (c_crypt_use_pka)
942 {
943 err = set_pka_sig_notation(ctx);
944 if (err != GPG_ERR_NO_ERROR)
945 {
946 gpgme_data_release(signature);
947 gpgme_data_release(message);
948 gpgme_release(ctx);
949 return NULL;
950 }
951 }
952
953 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
954 redraw_if_needed(ctx);
955 gpgme_data_release(message);
956 if (err != GPG_ERR_NO_ERROR)
957 {
958 gpgme_data_release(signature);
959 gpgme_release(ctx);
960 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
961 return NULL;
962 }
963 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
964 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
965 sigres = gpgme_op_sign_result(ctx);
966 if (!sigres->signatures)
967 {
968 gpgme_data_release(signature);
969 gpgme_release(ctx);
970 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
971 return NULL;
972 }
973
974 sigfile = data_object_to_tempfile(signature, NULL);
975 gpgme_data_release(signature);
976 if (!sigfile)
977 {
978 gpgme_release(ctx);
979 return NULL;
980 }
981
982 b_sign = mutt_body_new();
983 b_sign->type = TYPE_MULTIPART;
984 b_sign->subtype = mutt_str_dup("signed");
985 b_sign->encoding = ENC_7BIT;
986 b_sign->use_disp = false;
987 b_sign->disposition = DISP_INLINE;
988
990 mutt_param_set(&b_sign->parameter, "protocol",
991 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
992 /* Get the micalg from GPGME. Old gpgme versions don't support this
993 * for S/MIME so we assume sha-1 in this case. */
994 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
995 mutt_param_set(&b_sign->parameter, "micalg", buf);
996 else if (use_smime)
997 mutt_param_set(&b_sign->parameter, "micalg", "sha1");
998 gpgme_release(ctx);
999
1000 b_sign->parts = b;
1001 b = b_sign;
1002
1003 b_sign->parts->next = mutt_body_new();
1004 b_sign = b_sign->parts->next;
1005 b_sign->type = TYPE_APPLICATION;
1006 if (use_smime)
1007 {
1008 b_sign->subtype = mutt_str_dup("pkcs7-signature");
1009 mutt_param_set(&b_sign->parameter, "name", "smime.p7s");
1010 b_sign->encoding = ENC_BASE64;
1011 b_sign->use_disp = true;
1012 b_sign->disposition = DISP_ATTACH;
1013 b_sign->d_filename = mutt_str_dup("smime.p7s");
1014 }
1015 else
1016 {
1017 b_sign->subtype = mutt_str_dup("pgp-signature");
1018 mutt_param_set(&b_sign->parameter, "name", "signature.asc");
1019 b_sign->use_disp = false;
1020 b_sign->disposition = DISP_NONE;
1021 b_sign->encoding = ENC_7BIT;
1022 }
1023 b_sign->filename = sigfile;
1024 b_sign->unlink = true; /* ok to remove this file after sending. */
1025
1026 return b;
1027}
1028
1032struct Body *pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1033{
1034 return sign_message(b, from, false);
1035}
1036
1040struct Body *smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1041{
1042 return sign_message(b, from, true);
1043}
1044
1048struct Body *pgp_gpgme_encrypt_message(struct Body *b, char *keylist, bool sign,
1049 const struct AddressList *from)
1050{
1051 if (sign)
1053 gpgme_data_t plaintext = body_to_data_object(b, false);
1054 if (!plaintext)
1055 return NULL;
1056
1057 char *outfile = encrypt_gpgme_object(plaintext, keylist, false, sign, from);
1058 gpgme_data_release(plaintext);
1059 if (!outfile)
1060 return NULL;
1061
1062 struct Body *b_enc = mutt_body_new();
1063 b_enc->type = TYPE_MULTIPART;
1064 b_enc->subtype = mutt_str_dup("encrypted");
1065 b_enc->encoding = ENC_7BIT;
1066 b_enc->use_disp = false;
1067 b_enc->disposition = DISP_INLINE;
1068
1070 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-encrypted");
1071
1072 b_enc->parts = mutt_body_new();
1073 b_enc->parts->type = TYPE_APPLICATION;
1074 b_enc->parts->subtype = mutt_str_dup("pgp-encrypted");
1075 b_enc->parts->encoding = ENC_7BIT;
1076
1077 b_enc->parts->next = mutt_body_new();
1078 b_enc->parts->next->type = TYPE_APPLICATION;
1079 b_enc->parts->next->subtype = mutt_str_dup("octet-stream");
1080 b_enc->parts->next->encoding = ENC_7BIT;
1081 b_enc->parts->next->filename = outfile;
1082 b_enc->parts->next->use_disp = true;
1083 b_enc->parts->next->disposition = DISP_ATTACH;
1084 b_enc->parts->next->unlink = true; /* delete after sending the message */
1085 b_enc->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime
1086 can save */
1087
1088 return b_enc;
1089}
1090
1094struct Body *smime_gpgme_build_smime_entity(struct Body *b, char *keylist)
1095{
1096 /* OpenSSL converts line endings to crlf when encrypting. Some clients
1097 * depend on this for signed+encrypted messages: they do not convert line
1098 * endings between decrypting and checking the signature. */
1099 gpgme_data_t plaintext = body_to_data_object(b, true);
1100 if (!plaintext)
1101 return NULL;
1102
1103 char *outfile = encrypt_gpgme_object(plaintext, keylist, true, false, NULL);
1104 gpgme_data_release(plaintext);
1105 if (!outfile)
1106 return NULL;
1107
1108 struct Body *b_enc = mutt_body_new();
1109 b_enc->type = TYPE_APPLICATION;
1110 b_enc->subtype = mutt_str_dup("pkcs7-mime");
1111 mutt_param_set(&b_enc->parameter, "name", "smime.p7m");
1112 mutt_param_set(&b_enc->parameter, "smime-type", "enveloped-data");
1113 b_enc->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1114 b_enc->use_disp = true;
1115 b_enc->disposition = DISP_ATTACH;
1116 b_enc->d_filename = mutt_str_dup("smime.p7m");
1117 b_enc->filename = outfile;
1118 b_enc->unlink = true; /* delete after sending the message */
1119 b_enc->parts = 0;
1120 b_enc->next = 0;
1121
1122 return b_enc;
1123}
1124
1138static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key,
1139 int idx, struct State *state, gpgme_signature_t sig)
1140{
1141 if (!key)
1142 return 1;
1143
1144 bool severe = false;
1145
1146 if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1147 {
1148 state_puts(state, _("Warning: One of the keys has been revoked\n"));
1149 severe = true;
1150 }
1151
1152 if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1153 {
1154 time_t at = (key->subkeys && key->subkeys->expires) ? key->subkeys->expires : 0;
1155 if (at)
1156 {
1157 state_puts(state, _("Warning: The key used to create the signature expired at: "));
1158 print_time(at, state);
1159 state_puts(state, "\n");
1160 }
1161 else
1162 {
1163 state_puts(state, _("Warning: At least one certification key has expired\n"));
1164 }
1165 }
1166
1167 if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1168 {
1169 gpgme_signature_t sig2 = NULL;
1170 unsigned int i;
1171
1172 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1173
1174 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1175 ; // do nothing
1176
1177 state_puts(state, _("Warning: The signature expired at: "));
1178 print_time(sig2 ? sig2->exp_timestamp : 0, state);
1179 state_puts(state, "\n");
1180 }
1181
1182 if ((sum & GPGME_SIGSUM_KEY_MISSING))
1183 {
1184 state_puts(state, _("Can't verify due to a missing key or certificate\n"));
1185 }
1186
1187 if ((sum & GPGME_SIGSUM_CRL_MISSING))
1188 {
1189 state_puts(state, _("The CRL is not available\n"));
1190 severe = true;
1191 }
1192
1193 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1194 {
1195 state_puts(state, _("Available CRL is too old\n"));
1196 severe = true;
1197 }
1198
1199 if ((sum & GPGME_SIGSUM_BAD_POLICY))
1200 state_puts(state, _("A policy requirement was not met\n"));
1201
1202 if ((sum & GPGME_SIGSUM_SYS_ERROR))
1203 {
1204 const char *t0 = NULL, *t1 = NULL;
1205 gpgme_verify_result_t result = NULL;
1206 gpgme_signature_t sig2 = NULL;
1207 unsigned int i;
1208
1209 state_puts(state, _("A system error occurred"));
1210
1211 /* Try to figure out some more detailed system error information. */
1212 result = gpgme_op_verify_result(ctx);
1213 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1214 ; // do nothing
1215
1216 if (sig2)
1217 {
1218 t0 = "";
1219 t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1220 }
1221
1222 if (t0 || t1)
1223 {
1224 state_puts(state, ": ");
1225 if (t0)
1226 state_puts(state, t0);
1227 if (t1 && !(t0 && (mutt_str_equal(t0, t1))))
1228 {
1229 if (t0)
1230 state_puts(state, ",");
1231 state_puts(state, t1);
1232 }
1233 }
1234 state_puts(state, "\n");
1235 }
1236
1237 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1238 if (c_crypt_use_pka)
1239 {
1240 if ((sig->pka_trust == 1) && sig->pka_address)
1241 {
1242 state_puts(state, _("WARNING: PKA entry does not match signer's address: "));
1243 state_puts(state, sig->pka_address);
1244 state_puts(state, "\n");
1245 }
1246 else if ((sig->pka_trust == 2) && sig->pka_address)
1247 {
1248 state_puts(state, _("PKA verified signer's address is: "));
1249 state_puts(state, sig->pka_address);
1250 state_puts(state, "\n");
1251 }
1252 }
1253
1254 return severe;
1255}
1256
1262static void show_fingerprint(gpgme_key_t key, struct State *state)
1263{
1264 if (!key)
1265 return;
1266
1267 const char *prefix = _("Fingerprint: ");
1268
1269 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1270 if (!s)
1271 return;
1272 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1273
1274 char *buf = MUTT_MEM_MALLOC(strlen(prefix) + strlen(s) * 4 + 2, char);
1275 strcpy(buf, prefix);
1276 char *p = buf + strlen(buf);
1277 if (is_pgp && (strlen(s) == 40))
1278 { /* PGP v4 style formatted. */
1279 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1280 {
1281 *p++ = s[0];
1282 *p++ = s[1];
1283 *p++ = s[2];
1284 *p++ = s[3];
1285 *p++ = ' ';
1286 if (i == 4)
1287 *p++ = ' ';
1288 }
1289 }
1290 else
1291 {
1292 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1293 {
1294 *p++ = s[0];
1295 *p++ = s[1];
1296 *p++ = is_pgp ? ' ' : ':';
1297 if (is_pgp && (i == 7))
1298 *p++ = ' ';
1299 }
1300 }
1301
1302 /* just in case print remaining odd digits */
1303 for (; *s; s++)
1304 *p++ = *s;
1305 *p++ = '\n';
1306 *p = '\0';
1307 state_puts(state, buf);
1308 FREE(&buf);
1309}
1310
1317static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
1318{
1319 gpgme_signature_t sig = NULL;
1320 const char *txt = NULL;
1321
1322 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1323 if (result)
1324 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1325 ; // do nothing
1326
1327 switch (sig ? sig->validity : 0)
1328 {
1329 case GPGME_VALIDITY_UNKNOWN:
1330 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1331 break;
1332 case GPGME_VALIDITY_UNDEFINED:
1333 break;
1334 case GPGME_VALIDITY_NEVER:
1335 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1336 break;
1337 case GPGME_VALIDITY_MARGINAL:
1338 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1339 break;
1340 case GPGME_VALIDITY_FULL:
1341 case GPGME_VALIDITY_ULTIMATE:
1342 txt = NULL;
1343 break;
1344 }
1345 if (txt)
1346 state_puts(state, txt);
1347}
1348
1356static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig,
1357 gpgme_key_t key, struct State *state)
1358{
1359 int msgwid;
1360
1361 state_puts(state, msg);
1362 state_puts(state, " ");
1363 /* key is NULL when not present in the user's keyring */
1364 if (key)
1365 {
1366 bool aka = false;
1367 for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1368 {
1369 if (uids->revoked)
1370 continue;
1371 if (aka)
1372 {
1373 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1374 if (msgwid < 0)
1375 msgwid = 0;
1376 for (int i = 0; i < msgwid; i++)
1377 state_puts(state, " ");
1378 state_puts(state, _("aka: "));
1379 }
1380 state_puts(state, uids->uid);
1381 state_puts(state, "\n");
1382
1383 aka = true;
1384 }
1385 }
1386 else
1387 {
1388 if (sig->fpr)
1389 {
1390 state_puts(state, _("KeyID "));
1391 state_puts(state, sig->fpr);
1392 }
1393 else
1394 {
1395 /* L10N: You will see this message in place of "KeyID "
1396 if the S/MIME key has no ID. This is quite an error. */
1397 state_puts(state, _("no signature fingerprint available"));
1398 }
1399 state_puts(state, "\n");
1400 }
1401
1402 /* timestamp is 0 when verification failed.
1403 * "Jan 1 1970" is not the created date. */
1404 if (sig->timestamp)
1405 {
1406 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1407 if (msgwid < 0)
1408 msgwid = 0;
1409 for (int i = 0; i < msgwid; i++)
1410 state_puts(state, " ");
1411 state_puts(state, _("created: "));
1412 print_time(sig->timestamp, state);
1413 state_puts(state, "\n");
1414 }
1415}
1416
1422static void show_one_recipient(struct State *state, gpgme_recipient_t r)
1423{
1424 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1425 if (!algo)
1426 algo = "?";
1427
1428 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1429 // Recipient: RSA key, ID 1111111111111111
1430 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1431}
1432
1438static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
1439{
1440 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1441 return;
1442
1443 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1444
1445 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1446 show_one_recipient(state, r);
1447
1448 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1449}
1450
1463static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
1464{
1466 const char *fpr = NULL;
1467 gpgme_key_t key = NULL;
1468 bool anybad = false, anywarn = false;
1469 gpgme_signature_t sig = NULL;
1470 gpgme_error_t err = GPG_ERR_NO_ERROR;
1471
1472 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1473 if (result)
1474 {
1475 /* FIXME: this code should use a static variable and remember
1476 * the current position in the list of signatures, IMHO.
1477 * -moritz. */
1478 int i;
1479 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1480 ; // do nothing
1481
1482 if (!sig)
1483 return -1; /* Signature not found. */
1484
1485 if ((gpgme_key_t) mod_data->signature_key)
1486 {
1487 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
1488 mod_data->signature_key = NULL;
1489 }
1490
1491 fpr = sig->fpr;
1492 const unsigned int sum = sig->summary;
1493
1494 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1495 anybad = true;
1496
1497 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1498 {
1499 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1500 if (err == GPG_ERR_NO_ERROR)
1501 {
1502 /* Only cache the signer key for S/MIME sender verification.
1503 * (For OpenPGP, this cached key isn't used and would leak if left set.) */
1504 if (!mod_data->signature_key && key && (key->protocol == GPGME_PROTOCOL_CMS))
1505 mod_data->signature_key = key;
1506 }
1507 else
1508 {
1509 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1510 error. Do it here to avoid a double free. */
1511 }
1512 }
1513 else
1514 {
1515 /* pubkey not present */
1516 }
1517
1518 if (!state || !state->fp_out || !(state->flags & STATE_DISPLAY))
1519 {
1520 ; /* No state information so no way to print anything. */
1521 }
1522 else if (err != GPG_ERR_NO_ERROR)
1523 {
1524 char buf[1024] = { 0 };
1525 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1526 fpr, gpgme_strerror(err));
1527 state_puts(state, buf);
1528 anybad = true;
1529 }
1530 else if ((sum & GPGME_SIGSUM_GREEN))
1531 {
1532 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1533 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1534 anywarn = true;
1535 show_one_sig_validity(ctx, idx, state);
1536 }
1537 else if ((sum & GPGME_SIGSUM_RED))
1538 {
1539 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, state);
1540 show_sig_summary(sum, ctx, key, idx, state, sig);
1541 }
1542 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1543 { /* We can't decide (yellow) but this is a PGP key with a good
1544 signature, so we display what a PGP user expects: The name,
1545 fingerprint and the key validity (which is neither fully or
1546 ultimate). */
1547 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1548 show_one_sig_validity(ctx, idx, state);
1549 show_fingerprint(key, state);
1550 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1551 anywarn = true;
1552 }
1553 else /* can't decide (yellow) */
1554 {
1555 print_smime_keyinfo(_("Problem signature from:"), sig, key, state);
1556 /* 0 indicates no expiration */
1557 if (sig->exp_timestamp)
1558 {
1559 /* L10N: This is trying to match the width of the
1560 "Problem signature from:" translation just above. */
1561 state_puts(state, _(" expires: "));
1562 print_time(sig->exp_timestamp, state);
1563 state_puts(state, "\n");
1564 }
1565 show_sig_summary(sum, ctx, key, idx, state, sig);
1566 anywarn = true;
1567 }
1568
1569 if (key != (gpgme_key_t) mod_data->signature_key)
1570 gpgme_key_unref(key);
1571 }
1572
1573 return anybad ? 1 : anywarn ? 2 : 0;
1574}
1575
1589static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
1590{
1592 int badsig = -1;
1593 int anywarn = 0;
1594 gpgme_ctx_t ctx = NULL;
1595 gpgme_data_t message = NULL;
1596
1597 gpgme_data_t signature = file_to_data_object(state->fp_in, b->offset, b->length);
1598 if (!signature)
1599 return -1;
1600
1601 /* We need to tell GPGME about the encoding because the backend can't
1602 * auto-detect plain base-64 encoding which is used by S/MIME. */
1603 if (is_smime)
1604 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1605
1606 gpgme_error_t err = gpgme_data_new_from_file(&message, tempfile, 1);
1607 if (err != GPG_ERR_NO_ERROR)
1608 {
1609 gpgme_data_release(signature);
1610 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1611 return -1;
1612 }
1613 ctx = create_gpgme_context(is_smime);
1614
1615 /* Note: We don't need a current time output because GPGME avoids
1616 * such an attack by separating the meta information from the data. */
1617 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1618
1619 err = gpgme_op_verify(ctx, signature, message, NULL);
1620 gpgme_data_release(message);
1621 gpgme_data_release(signature);
1622
1623 redraw_if_needed(ctx);
1624 if (err != GPG_ERR_NO_ERROR)
1625 {
1626 char buf[200] = { 0 };
1627
1628 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1629 gpgme_strerror(err));
1630 state_puts(state, buf);
1631 }
1632 else
1633 { /* Verification succeeded, see what the result is. */
1634 gpgme_verify_result_t verify_result = NULL;
1635
1636 if ((gpgme_key_t) mod_data->signature_key)
1637 {
1638 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
1639 mod_data->signature_key = NULL;
1640 }
1641
1642 verify_result = gpgme_op_verify_result(ctx);
1643 if (verify_result && verify_result->signatures)
1644 {
1645 bool anybad = false;
1646 int res;
1647 for (int idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1648 {
1649 if (res == 1)
1650 anybad = true;
1651 else if (res == 2)
1652 anywarn = 2;
1653 }
1654 if (!anybad)
1655 badsig = 0;
1656 }
1657 }
1658
1659 if (badsig == 0)
1660 {
1661 gpgme_verify_result_t result = NULL;
1662 gpgme_sig_notation_t notation = NULL;
1663 gpgme_signature_t sig = NULL;
1664
1665 result = gpgme_op_verify_result(ctx);
1666 if (result)
1667 {
1668 for (sig = result->signatures; sig; sig = sig->next)
1669 {
1670 int non_pka_notations = 0;
1671 for (notation = sig->notations; notation; notation = notation->next)
1672 if (!is_pka_notation(notation))
1673 non_pka_notations++;
1674
1675 if (non_pka_notations)
1676 {
1677 char buf[128] = { 0 };
1678 snprintf(buf, sizeof(buf),
1679 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1680 state_puts(state, buf);
1681 for (notation = sig->notations; notation; notation = notation->next)
1682 {
1683 if (is_pka_notation(notation))
1684 continue;
1685
1686 if (notation->name)
1687 {
1688 state_puts(state, notation->name);
1689 state_puts(state, "=");
1690 }
1691 if (notation->value)
1692 {
1693 state_puts(state, notation->value);
1694 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1695 state_puts(state, "\n");
1696 }
1697 }
1698 state_puts(state, _("*** End Notation ***\n"));
1699 }
1700 }
1701 }
1702 }
1703
1704 gpgme_release(ctx);
1705
1706 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1707 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1708
1709 return badsig ? 1 : anywarn ? 2 : 0;
1710}
1711
1715int pgp_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1716{
1717 return verify_one(b, state, tempfile, false);
1718}
1719
1723int smime_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1724{
1725 return verify_one(b, state, tempfile, true);
1726}
1727
1741static struct Body *decrypt_part(struct Body *b, struct State *state,
1742 FILE *fp_out, bool is_smime, int *r_is_signed)
1743{
1744 if (!b || !state || !fp_out)
1745 return NULL;
1746
1747 struct Body *tattach = NULL;
1748 gpgme_error_t err = GPG_ERR_NO_ERROR;
1749 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1750 gpgme_decrypt_result_t result = NULL;
1751 bool maybe_signed = false;
1752 bool anywarn = false;
1753 int sig_stat = 0;
1754
1755 if (r_is_signed)
1756 *r_is_signed = 0;
1757
1758 gpgme_ctx_t ctx = NULL;
1759restart:
1760 ctx = create_gpgme_context(is_smime);
1761
1762 if (b->length < 0)
1763 return NULL;
1764 /* Make a data object from the body, create context etc. */
1765 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1766 if (!ciphertext)
1767 goto cleanup;
1768 plaintext = create_gpgme_data();
1769
1770 /* Do the decryption or the verification in case of the S/MIME hack. */
1771 if ((!is_smime) || maybe_signed)
1772 {
1773 if (!is_smime)
1774 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1775 else if (maybe_signed)
1776 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1777
1778 if (err == GPG_ERR_NO_ERROR)
1779 {
1780 /* Check whether signatures have been verified. */
1781 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1782 if (verify_result->signatures)
1783 sig_stat = 1;
1784 }
1785 }
1786 else
1787 {
1788 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1789 }
1790 gpgme_data_release(ciphertext);
1791 ciphertext = NULL;
1792
1793#ifdef USE_AUTOCRYPT
1794 // Abort right away and silently. Autocrypt will retry on the normal keyring.
1795 if (OptAutocryptGpgme && (err != GPG_ERR_NO_ERROR))
1796 goto cleanup;
1797#endif
1798
1799 result = gpgme_op_decrypt_result(ctx);
1800 if (result && (state->flags & STATE_DISPLAY))
1801 show_encryption_info(state, result);
1802
1803 if (err != GPG_ERR_NO_ERROR)
1804 {
1805 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1806 {
1807 /* Check whether this might be a signed message despite what the mime
1808 * header told us. Retry then. gpgsm returns the error information
1809 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1810 * algorithm, thus we test that it has not been set. */
1811 if (result && !result->unsupported_algorithm)
1812 {
1813 maybe_signed = true;
1814 gpgme_data_release(plaintext);
1815 plaintext = NULL;
1816 /* gpgsm ends the session after an error; restart it */
1817 gpgme_release(ctx);
1818 goto restart;
1819 }
1820 }
1821 redraw_if_needed(ctx);
1822 if ((state->flags & STATE_DISPLAY))
1823 {
1824 char buf[200] = { 0 };
1825
1826 snprintf(buf, sizeof(buf) - 1,
1827 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1828 state_attach_puts(state, buf);
1829 }
1830 goto cleanup;
1831 }
1832 redraw_if_needed(ctx);
1833
1834 /* Read the output from GPGME, and make sure to change CRLF to LF,
1835 * otherwise read_mime_header has a hard time parsing the message. */
1836 if (data_object_to_stream(plaintext, fp_out))
1837 {
1838 goto cleanup;
1839 }
1840 gpgme_data_release(plaintext);
1841 plaintext = NULL;
1842
1843 if (sig_stat)
1844 {
1845 int res, idx;
1846 int anybad = 0;
1847
1848 if (r_is_signed)
1849 *r_is_signed = -1; /* A signature exists. */
1850
1851 if ((state->flags & STATE_DISPLAY))
1852 {
1853 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1854 }
1855 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1856 {
1857 if (res == 1)
1858 anybad = 1;
1859 else if (res == 2)
1860 anywarn = true;
1861 }
1862 if (!anybad && idx && r_is_signed && *r_is_signed)
1863 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1864
1865 if ((state->flags & STATE_DISPLAY))
1866 {
1867 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1868 }
1869 }
1870 gpgme_release(ctx);
1871 ctx = NULL;
1872
1873 fflush(fp_out);
1874 rewind(fp_out);
1875 const long size = mutt_file_get_size_fp(fp_out);
1876 if (size == 0)
1877 {
1878 goto cleanup;
1879 }
1880 tattach = mutt_read_mime_header(fp_out, 0);
1881 if (tattach)
1882 {
1883 /* Need to set the length of this body part. */
1884 tattach->length = size - tattach->offset;
1885
1886 tattach->warnsig = anywarn;
1887
1888 /* See if we need to recurse on this MIME part. */
1889 mutt_parse_part(fp_out, tattach);
1890 }
1891
1892cleanup:
1893 gpgme_data_release(ciphertext);
1894 gpgme_data_release(plaintext);
1895 gpgme_release(ctx);
1896
1897 return tattach;
1898}
1899
1903int pgp_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1904{
1905 struct State state = { 0 };
1906 struct Body *first_part = b;
1907 int is_signed = 0;
1908 bool need_decode = false;
1909 LOFF_T saved_offset = 0;
1910 size_t saved_length = 0;
1911 FILE *fp_decoded = NULL;
1912 int rc = 0;
1913
1914 first_part->goodsig = false;
1915 first_part->warnsig = false;
1916
1918 {
1919 b = b->parts->next;
1920 /* Some clients improperly encode the octetstream part. */
1921 if (b->encoding != ENC_7BIT)
1922 need_decode = true;
1923 }
1925 {
1926 b = b->parts->next->next;
1927 need_decode = true;
1928 }
1929 else
1930 {
1931 return -1;
1932 }
1933
1934 state.fp_in = fp_in;
1935
1936 if (need_decode)
1937 {
1938 saved_offset = b->offset;
1939 saved_length = b->length;
1940
1941 fp_decoded = mutt_file_mkstemp();
1942 if (!fp_decoded)
1943 {
1944 mutt_perror(_("Can't create temporary file"));
1945 return -1;
1946 }
1947
1948 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1949 {
1950 rc = -1;
1951 goto bail;
1952 }
1953 state.fp_out = fp_decoded;
1954
1955 mutt_decode_attachment(b, &state);
1956
1957 fflush(fp_decoded);
1958 b->length = ftello(fp_decoded);
1959 b->offset = 0;
1960 rewind(fp_decoded);
1961 state.fp_in = fp_decoded;
1962 state.fp_out = 0;
1963 }
1964
1965 *fp_out = mutt_file_mkstemp();
1966 if (!*fp_out)
1967 {
1968 mutt_perror(_("Can't create temporary file"));
1969 rc = -1;
1970 goto bail;
1971 }
1972
1973 *b_dec = decrypt_part(b, &state, *fp_out, false, &is_signed);
1974 if (*b_dec)
1975 {
1976 rewind(*fp_out);
1977 if (is_signed > 0)
1978 first_part->goodsig = true;
1979 }
1980 else
1981 {
1982 rc = -1;
1983 mutt_file_fclose(fp_out);
1984 }
1985
1986bail:
1987 if (need_decode)
1988 {
1989 b->length = saved_length;
1990 b->offset = saved_offset;
1991 mutt_file_fclose(&fp_decoded);
1992 }
1993
1994 return rc;
1995}
1996
2000int smime_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
2001{
2002 struct State state = { 0 };
2003 int is_signed;
2004 LOFF_T saved_b_offset;
2005 size_t saved_b_length;
2006
2008 return -1;
2009
2010 if (b->parts)
2011 return -1;
2012
2013 /* Decode the body - we need to pass binary CMS to the
2014 * backend. The backend allows for Base64 encoded data but it does
2015 * not allow for QP which I have seen in some messages. So better
2016 * do it here. */
2017 saved_b_offset = b->offset;
2018 saved_b_length = b->length;
2019 state.fp_in = fp_in;
2020 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
2021 {
2022 return -1;
2023 }
2024 FILE *fp_tmp = mutt_file_mkstemp();
2025 if (!fp_tmp)
2026 {
2027 mutt_perror(_("Can't create temporary file"));
2028 return -1;
2029 }
2030
2031 state.fp_out = fp_tmp;
2032 mutt_decode_attachment(b, &state);
2033 fflush(fp_tmp);
2034 b->length = ftello(state.fp_out);
2035 b->offset = 0;
2036 rewind(fp_tmp);
2037
2038 memset(&state, 0, sizeof(state));
2039 state.fp_in = fp_tmp;
2040 state.fp_out = 0;
2042 if (!*fp_out)
2043 {
2044 mutt_perror(_("Can't create temporary file"));
2045 mutt_file_fclose(&fp_tmp);
2046 return -1;
2047 }
2048
2049 *b_dec = decrypt_part(b, &state, *fp_out, true, &is_signed);
2050 if (*b_dec)
2051 (*b_dec)->goodsig = is_signed > 0;
2052 b->length = saved_b_length;
2053 b->offset = saved_b_offset;
2054 mutt_file_fclose(&fp_tmp);
2055 rewind(*fp_out);
2056 if (*b_dec && !is_signed && !(*b_dec)->parts && mutt_is_application_smime(*b_dec))
2057 {
2058 /* Assume that this is a opaque signed s/mime message. This is an ugly way
2059 * of doing it but we have anyway a problem with arbitrary encoded S/MIME
2060 * messages: Only the outer part may be encrypted. The entire mime parsing
2061 * should be revamped, probably by keeping the temporary files so that we
2062 * don't need to decrypt them all the time. Inner parts of an encrypted
2063 * part can then point into this file and there won't ever be a need to
2064 * decrypt again. This needs a partial rewrite of the MIME engine. */
2065 struct Body *bb = *b_dec;
2066
2067 saved_b_offset = bb->offset;
2068 saved_b_length = bb->length;
2069 memset(&state, 0, sizeof(state));
2070 state.fp_in = *fp_out;
2071 if (!mutt_file_seek(state.fp_in, bb->offset, SEEK_SET))
2072 {
2073 return -1;
2074 }
2075 FILE *fp_tmp2 = mutt_file_mkstemp();
2076 if (!fp_tmp2)
2077 {
2078 mutt_perror(_("Can't create temporary file"));
2079 return -1;
2080 }
2081
2082 state.fp_out = fp_tmp2;
2083 mutt_decode_attachment(bb, &state);
2084 fflush(fp_tmp2);
2085 bb->length = ftello(state.fp_out);
2086 bb->offset = 0;
2087 rewind(fp_tmp2);
2088 mutt_file_fclose(fp_out);
2089
2090 memset(&state, 0, sizeof(state));
2091 state.fp_in = fp_tmp2;
2092 state.fp_out = 0;
2093 *fp_out = mutt_file_mkstemp();
2094 if (!*fp_out)
2095 {
2096 mutt_perror(_("Can't create temporary file"));
2097 mutt_file_fclose(&fp_tmp2);
2098 return -1;
2099 }
2100
2101 struct Body *b_tmp = decrypt_part(bb, &state, *fp_out, true, &is_signed);
2102 if (b_tmp)
2103 b_tmp->goodsig = is_signed > 0;
2104 bb->length = saved_b_length;
2105 bb->offset = saved_b_offset;
2106 mutt_file_fclose(&fp_tmp2);
2107 rewind(*fp_out);
2108 mutt_body_free(b_dec);
2109 *b_dec = b_tmp;
2110 }
2111 return *b_dec ? 0 : -1;
2112}
2113
2121static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
2122{
2123 gpgme_ctx_t tmpctx = NULL;
2124 gpgme_key_t key = NULL;
2125 gpgme_user_id_t uid = NULL;
2126 gpgme_subkey_t subkey = NULL;
2127 const char *shortid = NULL;
2128 size_t len;
2129 char date[256] = { 0 };
2130 bool more;
2131 int rc = -1;
2132 time_t tt;
2133
2134 *fp = mutt_file_mkstemp();
2135 if (!*fp)
2136 {
2137 mutt_perror(_("Can't create temporary file"));
2138 return -1;
2139 }
2140
2141 tmpctx = create_gpgme_context(false);
2142
2143 gpgme_error_t err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2144 while (err == GPG_ERR_NO_ERROR)
2145 {
2146 err = gpgme_op_keylist_next(tmpctx, &key);
2147 if (err != GPG_ERR_NO_ERROR)
2148 break;
2149 uid = key->uids;
2150 subkey = key->subkeys;
2151 more = false;
2152 while (subkey)
2153 {
2154 shortid = subkey->keyid;
2155 len = mutt_str_len(subkey->keyid);
2156 if (len > 8)
2157 shortid += len - 8;
2158 tt = subkey->timestamp;
2159 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2160
2161 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2162 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2163 if (!more)
2164 {
2165 while (uid)
2166 {
2167 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2168 uid = uid->next;
2169 }
2170 }
2171 subkey = subkey->next;
2172 more = true;
2173 }
2174 gpgme_key_unref(key);
2175 }
2176 if (gpg_err_code(err) != GPG_ERR_EOF)
2177 {
2178 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2179 goto err_fp;
2180 }
2181
2182 rc = 0;
2183
2184err_fp:
2185 if (rc)
2186 mutt_file_fclose(fp);
2187
2188 gpgme_release(tmpctx);
2189
2190 return rc;
2191}
2192
2204static int line_compare(const char *a, size_t n, const char *b)
2205{
2206 if (mutt_strn_equal(a, b, n))
2207 {
2208 /* at this point we know that 'b' is at least 'n' chars long */
2209 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2210 return true;
2211 }
2212 return false;
2213}
2214
2222static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
2223{
2224 char buf[8192] = { 0 };
2225 bool rc = false;
2226
2227 bool sgn = false;
2228 bool enc = false;
2229
2230 if (b->type != TYPE_TEXT)
2231 return 0;
2232
2233 struct Buffer *tempfile = buf_pool_get();
2234 buf_mktemp(tempfile);
2236 MUTT_SAVE_NO_FLAGS) != 0)
2237 {
2238 unlink(buf_string(tempfile));
2239 goto cleanup;
2240 }
2241
2242 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2243 if (!fp_tmp)
2244 {
2245 unlink(buf_string(tempfile));
2246 goto cleanup;
2247 }
2248
2249 while (fgets(buf, sizeof(buf), fp_tmp))
2250 {
2251 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2252 if (plen != 0)
2253 {
2254 if (MESSAGE(buf + plen))
2255 {
2256 enc = true;
2257 break;
2258 }
2259 else if (SIGNED_MESSAGE(buf + plen))
2260 {
2261 sgn = true;
2262 break;
2263 }
2264 }
2265 }
2266 mutt_file_fclose(&fp_tmp);
2267 unlink(buf_string(tempfile));
2268
2269 if (!enc && !sgn)
2270 goto cleanup;
2271
2272 /* fix the content type */
2273
2274 mutt_param_set(&b->parameter, "format", "fixed");
2275 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2276
2277 rc = true;
2278
2279cleanup:
2280 buf_pool_release(&tempfile);
2281 return rc;
2282}
2283
2287bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2288{
2289 bool rc = false;
2290 for (; b; b = b->next)
2291 {
2292 if (!just_one && is_multipart(b))
2293 {
2294 rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2295 }
2296 else if (b->type == TYPE_TEXT)
2297 {
2299 if (r)
2300 rc = (rc || r);
2301 else
2302 rc = (pgp_check_traditional_one_body(fp, b) || rc);
2303 }
2304
2305 if (just_one)
2306 break;
2307 }
2308 return rc;
2309}
2310
2314void pgp_gpgme_invoke_import(const char *fname)
2315{
2316 gpgme_ctx_t ctx = create_gpgme_context(false);
2317 gpgme_data_t keydata = NULL;
2318 gpgme_import_result_t impres = NULL;
2319 gpgme_import_status_t st = NULL;
2320 bool any;
2321
2322 FILE *fp_in = mutt_file_fopen(fname, "r");
2323 if (!fp_in)
2324 {
2325 mutt_perror("%s", fname);
2326 goto leave;
2327 }
2328 /* Note that the stream, "fp_in", needs to be kept open while the keydata
2329 * is used. */
2330 gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2331 if (err != GPG_ERR_NO_ERROR)
2332 {
2333 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2334 goto leave;
2335 }
2336
2337 err = gpgme_op_import(ctx, keydata);
2338 if (err != GPG_ERR_NO_ERROR)
2339 {
2340 mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2341 goto leave;
2342 }
2343
2344 /* Print infos about the imported keys to stdout. */
2345 impres = gpgme_op_import_result(ctx);
2346 if (!impres)
2347 {
2348 fputs("oops: no import result returned\n", stdout);
2349 goto leave;
2350 }
2351
2352 for (st = impres->imports; st; st = st->next)
2353 {
2354 if (st->result)
2355 continue;
2356 printf("key %s imported (", NONULL(st->fpr));
2357 /* Note that we use the singular even if it is possible that
2358 * several uids etc are new. This simply looks better. */
2359 any = false;
2360 if (st->status & GPGME_IMPORT_SECRET)
2361 {
2362 printf("secret parts");
2363 any = true;
2364 }
2365 if ((st->status & GPGME_IMPORT_NEW))
2366 {
2367 printf("%snew key", any ? ", " : "");
2368 any = true;
2369 }
2370 if ((st->status & GPGME_IMPORT_UID))
2371 {
2372 printf("%snew uid", any ? ", " : "");
2373 any = true;
2374 }
2375 if ((st->status & GPGME_IMPORT_SIG))
2376 {
2377 printf("%snew sig", any ? ", " : "");
2378 any = true;
2379 }
2380 if ((st->status & GPGME_IMPORT_SUBKEY))
2381 {
2382 printf("%snew subkey", any ? ", " : "");
2383 any = true;
2384 }
2385 printf("%s)\n", any ? "" : "not changed");
2386 /* Fixme: Should we lookup each imported key and print more infos? */
2387 }
2388 /* Now print keys which failed the import. Unfortunately in most
2389 * cases gpg will bail out early and not tell GPGME about. */
2390 /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2391 * the actual gpg diagnostics. But I fear that would clutter the
2392 * output too much. Maybe a dedicated prompt or option to do this
2393 * would be helpful. */
2394 for (st = impres->imports; st; st = st->next)
2395 {
2396 if (st->result == 0)
2397 continue;
2398 printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2399 }
2400 fflush(stdout);
2401
2402leave:
2403 gpgme_release(ctx);
2404 gpgme_data_release(keydata);
2405 mutt_file_fclose(&fp_in);
2406}
2407
2423static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
2424{
2425 char buf[8192] = { 0 };
2426 bool complete, armor_header;
2427 FILE *fp = NULL;
2428
2429 char *fname = data_object_to_tempfile(data, &fp);
2430 if (!fname)
2431 {
2432 mutt_file_fclose(&fp);
2433 return;
2434 }
2435 unlink(fname);
2436 FREE(&fname);
2437
2438 /* fromcode comes from the MIME Content-Type charset label. It might
2439 * be a wrong label, so we want the ability to do corrections via
2440 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2442
2443 for (complete = true, armor_header = true;
2444 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2445 {
2446 if (!complete)
2447 {
2448 if (!armor_header)
2449 state_puts(state, buf);
2450 continue;
2451 }
2452
2453 if (BEGIN_PGP_SIGNATURE(buf))
2454 break;
2455
2456 if (armor_header)
2457 {
2458 if (buf[0] == '\n')
2459 armor_header = false;
2460 continue;
2461 }
2462
2463 if (state->prefix)
2464 state_puts(state, state->prefix);
2465
2466 if ((buf[0] == '-') && (buf[1] == ' '))
2467 state_puts(state, buf + 2);
2468 else
2469 state_puts(state, buf);
2470 }
2471
2474}
2475
2479int pgp_gpgme_application_handler(struct Body *b, struct State *state)
2480{
2481 int needpass = -1;
2482 bool pgp_keyblock = false;
2483 bool clearsign = false;
2484 long bytes;
2485 LOFF_T last_pos;
2486 LOFF_T block_begin;
2487 LOFF_T block_end;
2488 char buf[8192] = { 0 };
2489 FILE *fp_out = NULL;
2490
2491 gpgme_error_t err = GPG_ERR_NO_ERROR;
2492 gpgme_data_t armored_data = NULL;
2493
2494 bool maybe_goodsig = true;
2495 bool have_any_sigs = false;
2496
2497 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2498 char *gpgcharset = NULL;
2499
2500 mutt_debug(LL_DEBUG2, "Entering handler\n");
2501
2502 /* For clearsigned messages we won't be able to get a character set
2503 * but we know that this may only be text thus we assume Latin-1 here. */
2504 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2505 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2506
2507 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2508 {
2509 return -1;
2510 }
2511 last_pos = b->offset;
2512
2513 for (bytes = b->length; bytes > 0;)
2514 {
2515 // record before the fgets in case it is a BEGIN block
2516 block_begin = last_pos;
2517
2518 if (!fgets(buf, sizeof(buf), state->fp_in))
2519 break;
2520
2521 LOFF_T offset = ftello(state->fp_in);
2522 if (offset < 0)
2523 {
2524 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2525 offset = 0;
2526 }
2527 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2528 last_pos = offset;
2529
2530 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2531 if (plen != 0)
2532 {
2533 needpass = 0;
2534 clearsign = false;
2535 pgp_keyblock = false;
2536
2537 if (MESSAGE(buf + plen))
2538 {
2539 needpass = 1;
2540 }
2541 else if (SIGNED_MESSAGE(buf + plen))
2542 {
2543 clearsign = true;
2544 }
2545 else if (PUBLIC_KEY_BLOCK(buf + plen))
2546 {
2547 pgp_keyblock = true;
2548 }
2549 else
2550 {
2551 /* XXX we may wish to recode here */
2552 if (state->prefix)
2553 state_puts(state, state->prefix);
2554 state_puts(state, buf);
2555 continue;
2556 }
2557
2558 /* Find the end of armored block. */
2559 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2560 {
2561 offset = ftello(state->fp_in);
2562 if (offset < 0)
2563 {
2564 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2565 offset = 0;
2566 }
2567 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2568 last_pos = offset;
2569
2570 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2571 {
2572 break;
2573 }
2574
2575 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2576 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2577 {
2578 break;
2579 }
2580
2581 // remember optional Charset: armor header as defined by rfc4880
2582 if (mutt_strn_equal("Charset: ", buf, 9))
2583 {
2584 size_t l = 0;
2585 FREE(&gpgcharset);
2586 gpgcharset = mutt_str_dup(buf + 9);
2587 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2588 gpgcharset[l - 1] = 0;
2589 if (!mutt_ch_check_charset(gpgcharset, 0))
2590 mutt_str_replace(&gpgcharset, "UTF-8");
2591 }
2592 }
2593 block_end = ftello(state->fp_in);
2594 if (block_end < 0)
2595 {
2596 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2597 block_end = 0;
2598 }
2599
2600 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2601
2602 /* Copy PGP material to an data container */
2603 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2604 fseeko(state->fp_in, block_end, 0);
2605
2606 /* Invoke PGP if needed */
2607 if (pgp_keyblock)
2608 {
2609 pgp_gpgme_extract_keys(armored_data, &fp_out);
2610 }
2611 else if (!clearsign || (state->flags & STATE_VERIFY))
2612 {
2613 gpgme_data_t plaintext = create_gpgme_data();
2614 gpgme_ctx_t ctx = create_gpgme_context(false);
2615
2616 if (clearsign)
2617 {
2618 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2619 }
2620 else
2621 {
2622 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2623 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2624 {
2625 /* Decrypt verify can't handle signed only messages. */
2626 gpgme_data_seek(armored_data, 0, SEEK_SET);
2627 /* Must release plaintext so that we supply an uninitialized object. */
2628 gpgme_data_release(plaintext);
2629 plaintext = create_gpgme_data();
2630 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2631 }
2632 }
2633 redraw_if_needed(ctx);
2634
2635 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2636 if (result && (state->flags & STATE_DISPLAY))
2637 show_encryption_info(state, result);
2638
2639 if (err != GPG_ERR_NO_ERROR)
2640 {
2641 char errbuf[200] = { 0 };
2642
2643 snprintf(errbuf, sizeof(errbuf) - 1,
2644 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2645 state_puts(state, errbuf);
2646 }
2647 else
2648 {
2649 /* Decryption/Verification succeeded */
2650
2651 mutt_message(_("PGP message successfully decrypted"));
2652
2653 bool sig_stat = false;
2654 char *tmpfname = NULL;
2655
2656 /* Check whether signatures have been verified. */
2657 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2658 if (verify_result->signatures)
2659 sig_stat = true;
2660
2661 have_any_sigs = false;
2662 maybe_goodsig = false;
2663 if ((state->flags & STATE_DISPLAY) && sig_stat)
2664 {
2665 int res, idx;
2666 bool anybad = false;
2667
2668 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2669 have_any_sigs = true;
2670 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2671 {
2672 if (res == 1)
2673 anybad = true;
2674 }
2675 if (!anybad && idx)
2676 maybe_goodsig = true;
2677
2678 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2679 }
2680
2681 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2682 if (tmpfname)
2683 {
2684 unlink(tmpfname);
2685 FREE(&tmpfname);
2686 }
2687 else
2688 {
2689 mutt_file_fclose(&fp_out);
2690 state_puts(state, _("Error: copy data failed\n"));
2691 }
2692 }
2693 gpgme_data_release(plaintext);
2694 gpgme_release(ctx);
2695 }
2696
2697 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2698 * outputs utf-8 cleartext. This may not always be true, but it
2699 * seems to be a reasonable guess. */
2700 if (state->flags & STATE_DISPLAY)
2701 {
2702 if (needpass)
2703 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2704 else if (pgp_keyblock)
2705 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2706 else
2707 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2708 }
2709
2710 if (clearsign)
2711 {
2712 copy_clearsigned(armored_data, state, body_charset);
2713 }
2714 else if (fp_out)
2715 {
2716 int c;
2717 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2718 rewind(fp_out);
2719 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2721 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2722 {
2723 state_putc(state, c);
2724 if ((c == '\n') && state->prefix)
2725 state_puts(state, state->prefix);
2726 }
2728 }
2729
2730 if (state->flags & STATE_DISPLAY)
2731 {
2732 state_putc(state, '\n');
2733 if (needpass)
2734 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2735 else if (pgp_keyblock)
2736 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2737 else
2738 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2739 }
2740
2741 // Multiple PGP blocks can exist, so clean these up in each loop
2742 gpgme_data_release(armored_data);
2743 mutt_file_fclose(&fp_out);
2744 }
2745 else
2746 {
2747 /* A traditional PGP part may mix signed and unsigned content */
2748 /* XXX we may wish to recode here */
2749 if (state->prefix)
2750 state_puts(state, state->prefix);
2751 state_puts(state, buf);
2752 }
2753 }
2754 FREE(&gpgcharset);
2755
2756 b->goodsig = (maybe_goodsig && have_any_sigs);
2757
2758 if (needpass == -1)
2759 {
2760 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2761 return 1;
2762 }
2763 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2764
2765 return err;
2766}
2767
2774int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
2775{
2776 int is_signed;
2777 int rc = 0;
2778
2779 mutt_debug(LL_DEBUG2, "Entering handler\n");
2780
2781 FILE *fp_out = mutt_file_mkstemp();
2782 if (!fp_out)
2783 {
2784 mutt_perror(_("Can't create temporary file"));
2785 if (state->flags & STATE_DISPLAY)
2786 {
2787 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2788 }
2789 return -1;
2790 }
2791
2792 struct Body *tattach = decrypt_part(b, state, fp_out, false, &is_signed);
2793 if (tattach)
2794 {
2795 tattach->goodsig = is_signed > 0;
2796
2797 if (state->flags & STATE_DISPLAY)
2798 {
2799 state_attach_puts(state, is_signed ?
2800 _("[-- The following data is PGP/MIME signed and encrypted --]\n") :
2801 _("[-- The following data is PGP/MIME encrypted --]\n"));
2802 mutt_protected_headers_handler(tattach, state);
2803 }
2804
2805 /* Store any protected headers in the parent so they can be
2806 * accessed for index updates after the handler recursion is done.
2807 * This is done before the handler to prevent a nested encrypted
2808 * handler from freeing the headers. */
2810 b->mime_headers = tattach->mime_headers;
2811 tattach->mime_headers = NULL;
2812
2813 FILE *fp_save = state->fp_in;
2814 state->fp_in = fp_out;
2815 rc = mutt_body_handler(tattach, state);
2816 state->fp_in = fp_save;
2817
2818 /* Embedded multipart signed protected headers override the
2819 * encrypted headers. We need to do this after the handler so
2820 * they can be printed in the pager. */
2821 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2822 {
2824 b->mime_headers = tattach->parts->mime_headers;
2825 tattach->parts->mime_headers = NULL;
2826 }
2827
2828 /* if a multipart/signed is the _only_ sub-part of a
2829 * multipart/encrypted, cache signature verification
2830 * status. */
2831 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2832 b->goodsig |= tattach->goodsig;
2833
2834 if (state->flags & STATE_DISPLAY)
2835 {
2836 state_attach_puts(state, is_signed ?
2837 _("[-- End of PGP/MIME signed and encrypted data --]\n") :
2838 _("[-- End of PGP/MIME encrypted data --]\n"));
2839 }
2840
2841 mutt_body_free(&tattach);
2842 mutt_message(_("PGP message successfully decrypted"));
2843 }
2844 else
2845 {
2846#ifdef USE_AUTOCRYPT
2847 if (!OptAutocryptGpgme)
2848#endif
2849 {
2850 mutt_error(_("Could not decrypt PGP message"));
2851 }
2852 rc = -1;
2853 }
2854
2855 mutt_file_fclose(&fp_out);
2856 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2857
2858 return rc;
2859}
2860
2864int smime_gpgme_application_handler(struct Body *b, struct State *state)
2865{
2866 int is_signed = 0;
2867 int rc = 0;
2868
2869 mutt_debug(LL_DEBUG2, "Entering handler\n");
2870
2871 /* clear out any mime headers before the handler, so they can't be spoofed. */
2873 b->warnsig = false;
2874 FILE *fp_out = mutt_file_mkstemp();
2875 if (!fp_out)
2876 {
2877 mutt_perror(_("Can't create temporary file"));
2878 if (state->flags & STATE_DISPLAY)
2879 {
2880 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2881 }
2882 return -1;
2883 }
2884
2885 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2886 if (tattach)
2887 {
2888 tattach->goodsig = is_signed > 0;
2889
2890 if (state->flags & STATE_DISPLAY)
2891 {
2892 state_attach_puts(state, is_signed ?
2893 _("[-- The following data is S/MIME signed --]\n") :
2894 _("[-- The following data is S/MIME encrypted --]\n"));
2895 mutt_protected_headers_handler(tattach, state);
2896 }
2897
2898 /* Store any protected headers in the parent so they can be
2899 * accessed for index updates after the handler recursion is done.
2900 * This is done before the handler to prevent a nested encrypted
2901 * handler from freeing the headers. */
2903 b->mime_headers = tattach->mime_headers;
2904 tattach->mime_headers = NULL;
2905
2906 FILE *fp_save = state->fp_in;
2907 state->fp_in = fp_out;
2908 rc = mutt_body_handler(tattach, state);
2909 state->fp_in = fp_save;
2910
2911 /* Embedded multipart signed protected headers override the
2912 * encrypted headers. We need to do this after the handler so
2913 * they can be printed in the pager. */
2914 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2915 {
2917 b->mime_headers = tattach->parts->mime_headers;
2918 tattach->parts->mime_headers = NULL;
2919 }
2920
2921 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2922 * cache signature verification status. */
2923 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2924 {
2925 b->goodsig = tattach->goodsig;
2926 if (!b->goodsig)
2927 b->warnsig = tattach->warnsig;
2928 }
2929 else if (tattach->goodsig)
2930 {
2931 b->goodsig = true;
2932 b->warnsig = tattach->warnsig;
2933 }
2934
2935 if (state->flags & STATE_DISPLAY)
2936 {
2937 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2938 _("[-- End of S/MIME encrypted data --]\n"));
2939 }
2940
2941 mutt_body_free(&tattach);
2942 }
2943
2944 mutt_file_fclose(&fp_out);
2945 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2946
2947 return rc;
2948}
2949
2956unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
2957{
2958 unsigned int rc = 0;
2959
2960 switch (cap)
2961 {
2963 rc = key->can_encrypt;
2964 if (rc == 0)
2965 {
2966 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2967 {
2968 rc = subkey->can_encrypt;
2969 if (rc != 0)
2970 break;
2971 }
2972 }
2973 break;
2974 case KEY_CAP_CAN_SIGN:
2975 rc = key->can_sign;
2976 if (rc == 0)
2977 {
2978 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2979 {
2980 rc = subkey->can_sign;
2981 if (rc != 0)
2982 break;
2983 }
2984 }
2985 break;
2987 rc = key->can_certify;
2988 if (rc == 0)
2989 {
2990 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2991 {
2992 rc = subkey->can_certify;
2993 if (rc != 0)
2994 break;
2995 }
2996 }
2997 break;
2998 }
2999
3000 return rc;
3001}
3002
3012static char *list_to_pattern(struct ListHead *list)
3013{
3014 char *pattern = NULL, *p = NULL;
3015 const char *s = NULL;
3016 size_t n;
3017
3018 n = 0;
3019 struct ListNode *np = NULL;
3020 STAILQ_FOREACH(np, list, entries)
3021 {
3022 for (s = np->data; *s; s++)
3023 {
3024 if ((*s == '%') || (*s == '+'))
3025 n += 2;
3026 n++;
3027 }
3028 n++; /* delimiter or end of string */
3029 }
3030 n++; /* make sure to allocate at least one byte */
3031 p = MUTT_MEM_CALLOC(n, char);
3032 pattern = p;
3033 STAILQ_FOREACH(np, list, entries)
3034 {
3035 s = np->data;
3036 if (*s)
3037 {
3038 if (np != STAILQ_FIRST(list))
3039 *p++ = ' ';
3040 for (s = np->data; *s; s++)
3041 {
3042 if (*s == '%')
3043 {
3044 *p++ = '%';
3045 *p++ = '2';
3046 *p++ = '5';
3047 }
3048 else if (*s == '+')
3049 {
3050 *p++ = '%';
3051 *p++ = '2';
3052 *p++ = 'B';
3053 }
3054 else if (*s == ' ')
3055 {
3056 *p++ = '+';
3057 }
3058 else
3059 {
3060 *p++ = *s;
3061 }
3062 }
3063 }
3064 }
3065 *p = '\0';
3066 return pattern;
3067}
3068
3079static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
3080{
3081 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3082 gpgme_error_t err = GPG_ERR_NO_ERROR;
3083 gpgme_ctx_t ctx = NULL;
3084 gpgme_key_t key = NULL;
3085 int idx;
3086 gpgme_user_id_t uid = NULL;
3087
3088 char *pattern = list_to_pattern(hints);
3089 if (!pattern)
3090 return NULL;
3091
3092 ctx = create_gpgme_context(0);
3093 db = NULL;
3094 kend = &db;
3095
3096 if ((app & APPLICATION_PGP))
3097 {
3098 /* It's all a mess. That old GPGME expects different things depending on
3099 * the protocol. For gpg we don't need percent escaped pappert but simple
3100 * strings passed in an array to the keylist_ext_start function. */
3101 size_t n = 0;
3102 struct ListNode *np = NULL;
3103 STAILQ_FOREACH(np, hints, entries)
3104 {
3105 if (np->data && *np->data)
3106 n++;
3107 }
3108 if (n == 0)
3109 goto no_pgphints;
3110
3111 char **patarr = MUTT_MEM_CALLOC(n + 1, char *);
3112 n = 0;
3113 STAILQ_FOREACH(np, hints, entries)
3114 {
3115 if (np->data && *np->data)
3116 patarr[n++] = mutt_str_dup(np->data);
3117 }
3118 patarr[n] = NULL;
3119 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3120 for (n = 0; patarr[n]; n++)
3121 FREE(&patarr[n]);
3122 FREE(&patarr);
3123 if (err != GPG_ERR_NO_ERROR)
3124 {
3125 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3126 gpgme_release(ctx);
3127 FREE(&pattern);
3128 return NULL;
3129 }
3130
3131 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3132 {
3133 KeyFlags flags = KEYFLAG_NO_FLAGS;
3134
3136 flags |= KEYFLAG_CANENCRYPT;
3138 flags |= KEYFLAG_CANSIGN;
3139
3140 if (key->revoked)
3141 flags |= KEYFLAG_REVOKED;
3142 if (key->expired)
3143 flags |= KEYFLAG_EXPIRED;
3144 if (key->disabled)
3145 flags |= KEYFLAG_DISABLED;
3146
3147 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3148 {
3149 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3150 k->kobj = key;
3151 gpgme_key_ref(k->kobj);
3152 k->idx = idx;
3153 k->uid = uid->uid;
3154 k->flags = flags;
3155 if (uid->revoked)
3156 k->flags |= KEYFLAG_REVOKED;
3157 k->validity = uid->validity;
3158 *kend = k;
3159 kend = &k->next;
3160 }
3161 gpgme_key_unref(key);
3162 }
3163 if (gpg_err_code(err) != GPG_ERR_EOF)
3164 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3165 gpgme_op_keylist_end(ctx);
3166 no_pgphints:;
3167 }
3168
3169 if ((app & APPLICATION_SMIME))
3170 {
3171 /* and now look for x509 certificates */
3172 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3173 err = gpgme_op_keylist_start(ctx, pattern, 0);
3174 if (err != GPG_ERR_NO_ERROR)
3175 {
3176 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3177 gpgme_release(ctx);
3178 FREE(&pattern);
3179 return NULL;
3180 }
3181
3182 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3183 {
3184 KeyFlags flags = KEYFLAG_ISX509;
3185
3187 flags |= KEYFLAG_CANENCRYPT;
3189 flags |= KEYFLAG_CANSIGN;
3190
3191 if (key->revoked)
3192 flags |= KEYFLAG_REVOKED;
3193 if (key->expired)
3194 flags |= KEYFLAG_EXPIRED;
3195 if (key->disabled)
3196 flags |= KEYFLAG_DISABLED;
3197
3198 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3199 {
3200 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3201 k->kobj = key;
3202 gpgme_key_ref(k->kobj);
3203 k->idx = idx;
3204 k->uid = uid->uid;
3205 k->flags = flags;
3206 if (uid->revoked)
3207 k->flags |= KEYFLAG_REVOKED;
3208 k->validity = uid->validity;
3209 *kend = k;
3210 kend = &k->next;
3211 }
3212 gpgme_key_unref(key);
3213 }
3214 if (gpg_err_code(err) != GPG_ERR_EOF)
3215 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3216 gpgme_op_keylist_end(ctx);
3217 }
3218
3219 gpgme_release(ctx);
3220 FREE(&pattern);
3221 return db;
3222}
3223
3232static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
3233{
3234 char *scratch = mutt_str_dup(str);
3235 if (!scratch)
3236 return;
3237
3238 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3239 {
3240 if (strlen(t) > 3)
3242 }
3243
3244 FREE(&scratch);
3245}
3246
3256static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
3257 KeyFlags abilities, unsigned int app,
3258 bool *forced_valid, bool oppenc_mode)
3259{
3260 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3261
3262 int multi = false;
3263 int this_key_has_strong = false;
3264 int this_key_has_addr_match = false;
3265 int match = false;
3266
3267 struct CryptKeyInfo *keys = NULL, *k = NULL;
3268 struct CryptKeyInfo *the_strong_valid_key = NULL;
3269 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3270 struct CryptKeyInfo *matches = NULL;
3271 struct CryptKeyInfo **matches_endp = &matches;
3272
3273 if (a && a->mailbox)
3275 if (a && a->personal)
3277
3278 if (!oppenc_mode)
3279 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3280 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3281
3282 mutt_list_free(&hints);
3283
3284 if (!keys)
3285 return NULL;
3286
3287 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3288 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3289
3290 for (k = keys; k; k = k->next)
3291 {
3292 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3293
3294 if (abilities && !(k->flags & abilities))
3295 {
3296 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3297 continue;
3298 }
3299
3300 this_key_has_strong = false; /* strong and valid match */
3301 this_key_has_addr_match = false;
3302 match = false; /* any match */
3303
3304 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3305 mutt_addrlist_parse(&alist, k->uid);
3306 struct Address *ka = NULL;
3307 TAILQ_FOREACH(ka, &alist, entries)
3308 {
3309 int validity = crypt_id_matches_addr(a, ka, k);
3310
3311 if (validity & CRYPT_KV_MATCH) /* something matches */
3312 {
3313 match = true;
3314
3315 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3316 {
3317 if (validity & CRYPT_KV_STRONGID)
3318 {
3319 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3320 multi = true;
3321 this_key_has_strong = true;
3322 }
3323 else
3324 {
3325 this_key_has_addr_match = true;
3326 }
3327 }
3328 }
3329 }
3330 mutt_addrlist_clear(&alist);
3331
3332 if (match)
3333 {
3334 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3335 *matches_endp = tmp;
3336 matches_endp = &tmp->next;
3337
3338 if (this_key_has_strong)
3339 the_strong_valid_key = tmp;
3340 else if (this_key_has_addr_match)
3341 a_valid_addrmatch_key = tmp;
3342 }
3343 }
3344
3345 crypt_key_free(&keys);
3346
3347 if (matches)
3348 {
3349 if (oppenc_mode || !isatty(STDIN_FILENO))
3350 {
3351 const bool c_crypt_opportunistic_encrypt_strong_keys =
3352 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3353 if (the_strong_valid_key)
3354 k = crypt_copy_key(the_strong_valid_key);
3355 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3356 k = crypt_copy_key(a_valid_addrmatch_key);
3357 else
3358 k = NULL;
3359 }
3360 else if (the_strong_valid_key && !multi)
3361 {
3362 /* There was precisely one strong match on a valid ID.
3363 * Proceed without asking the user. */
3364 k = crypt_copy_key(the_strong_valid_key);
3365 }
3366 else
3367 {
3368 /* Else: Ask the user. */
3369 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3370 }
3371
3372 crypt_key_free(&matches);
3373 }
3374 else
3375 {
3376 k = NULL;
3377 }
3378
3379 return k;
3380}
3381
3390static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
3391 unsigned int app, bool *forced_valid)
3392{
3393 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3394 struct CryptKeyInfo *matches = NULL;
3395 struct CryptKeyInfo **matches_endp = &matches;
3396 struct CryptKeyInfo *k = NULL;
3397 const char *ps = NULL, *pl = NULL, *phint = NULL;
3398
3399 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3400
3401 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3402 crypt_add_string_to_hints(phint, &hints);
3403 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3404 mutt_list_free(&hints);
3405
3406 if (!keys)
3407 {
3408 FREE(&pfcopy);
3409 return NULL;
3410 }
3411
3412 for (k = keys; k; k = k->next)
3413 {
3414 if (abilities && !(k->flags & abilities))
3415 continue;
3416
3417 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3418 crypt_long_keyid(k), k->uid);
3419
3420 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3421 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3422 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3423 {
3424 mutt_debug(LL_DEBUG5, "match\n");
3425
3426 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3427 *matches_endp = tmp;
3428 matches_endp = &tmp->next;
3429 }
3430 else
3431 {
3432 mutt_debug(LL_DEBUG5, "no match\n");
3433 }
3434 }
3435
3436 FREE(&pfcopy);
3437 crypt_key_free(&keys);
3438
3439 if (matches)
3440 {
3441 if (isatty(STDIN_FILENO))
3442 {
3443 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3444
3445 crypt_key_free(&matches);
3446 return k;
3447 }
3448 else
3449 {
3450 if (crypt_keys_are_valid(matches))
3451 return matches;
3452
3453 crypt_key_free(&matches);
3454 return NULL;
3455 }
3456 }
3457
3458 return NULL;
3459}
3460
3473static struct CryptKeyInfo *crypt_ask_for_key(const char *tag, const char *whatfor,
3474 KeyFlags abilities,
3475 unsigned int app, bool *forced_valid)
3476{
3478 struct CryptKeyInfo *key = NULL;
3479 struct CryptCache *l = NULL;
3480 struct Buffer *resp = buf_pool_get();
3481
3483
3484 if (whatfor)
3485 {
3486 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3487 {
3488 if (mutt_istr_equal(whatfor, l->what))
3489 {
3490 buf_strcpy(resp, l->dflt);
3491 break;
3492 }
3493 }
3494 }
3495
3496 while (true)
3497 {
3498 buf_reset(resp);
3499 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3500 {
3501 goto done;
3502 }
3503
3504 if (whatfor)
3505 {
3506 if (l)
3507 {
3508 mutt_str_replace(&l->dflt, buf_string(resp));
3509 }
3510 else
3511 {
3512 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3513 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3514 mod_data->gpgme_id_defaults = l;
3515 l->what = mutt_str_dup(whatfor);
3516 l->dflt = buf_strdup(resp);
3517 }
3518 }
3519
3520 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3521 if (key)
3522 goto done;
3523
3524 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3525 }
3526
3527done:
3528 buf_pool_release(&resp);
3529 return key;
3530}
3531
3543static char *find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
3544{
3545 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3546 struct ListNode *crypt_hook = NULL;
3547 const char *keyid = NULL;
3548 char *keylist = NULL;
3549 size_t keylist_size = 0;
3550 size_t keylist_used = 0;
3551 struct Address *p = NULL;
3552 struct CryptKeyInfo *k_info = NULL;
3553 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3554 char buf[1024] = { 0 };
3555 bool forced_valid = false;
3556 bool key_selected;
3557 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3558
3559 struct Address *a = NULL;
3560 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3561 /* Iterate through each recipient address to find an encryption key */
3562 TAILQ_FOREACH(a, addrlist, entries)
3563 {
3564 key_selected = false;
3565 /* Check for crypt-hook overrides for this recipient */
3566 mutt_crypt_hook(&crypt_hook_list, a);
3567 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3568 do
3569 {
3570 p = a;
3571 forced_valid = false;
3572 k_info = NULL;
3573
3574 /* If a crypt-hook provides a key ID, confirm with the user unless
3575 * in opportunistic encryption mode */
3576 if (crypt_hook)
3577 {
3578 keyid = crypt_hook->data;
3579 enum QuadOption ans = MUTT_YES;
3580 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3581 {
3582 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3583 buf_string(p->mailbox));
3584 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3585 }
3586 if (ans == MUTT_YES)
3587 {
3588 if (crypt_is_numerical_keyid(keyid))
3589 {
3590 if (mutt_strn_equal(keyid, "0x", 2))
3591 keyid += 2;
3592 goto bypass_selection; /* you don't see this. */
3593 }
3594
3595 /* check for e-mail address */
3596 mutt_addrlist_clear(&hookal);
3597 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3598 {
3599 mutt_addrlist_qualify(&hookal, fqdn);
3600 p = TAILQ_FIRST(&hookal);
3601 }
3602 else if (!oppenc_mode)
3603 {
3604 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3605 }
3606 }
3607 else if (ans == MUTT_NO)
3608 {
3609 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3610 {
3611 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3612 continue;
3613 }
3614 }
3615 else if (ans == MUTT_ABORT)
3616 {
3617 FREE(&keylist);
3618 mutt_addrlist_clear(&hookal);
3619 mutt_list_free(&crypt_hook_list);
3620 return NULL;
3621 }
3622 }
3623
3624 /* If no key found yet, try looking up by address in the keyring */
3625 if (!k_info)
3626 {
3627 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3628 }
3629
3630 /* Last resort: prompt the user to enter a key ID interactively */
3631 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3632 {
3633 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3634
3635 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3636 KEYFLAG_CANENCRYPT, app, &forced_valid);
3637 }
3638
3639 if (!k_info)
3640 {
3641 FREE(&keylist);
3642 mutt_addrlist_clear(&hookal);
3643 mutt_list_free(&crypt_hook_list);
3644 return NULL;
3645 }
3646
3647 keyid = crypt_fpr_or_lkeyid(k_info);
3648
3649 bypass_selection:
3650 /* Append the selected key ID to the space-separated keylist string */
3651 keylist_size += mutt_str_len(keyid) + 4 + 1;
3652 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3653 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3654 keyid, forced_valid ? "!" : "");
3655 keylist_used = mutt_str_len(keylist);
3656
3657 key_selected = true;
3658
3659 crypt_key_free(&k_info);
3660 mutt_addrlist_clear(&hookal);
3661
3662 if (crypt_hook)
3663 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3664
3665 } while (crypt_hook);
3666
3667 mutt_list_free(&crypt_hook_list);
3668 }
3669 return keylist;
3670}
3671
3675char *pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3676{
3677 return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
3678}
3679
3683char *smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3684{
3685 return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
3686}
3687
3688#ifdef USE_AUTOCRYPT
3702{
3703 int rc = -1;
3704 gpgme_error_t err = GPG_ERR_NO_ERROR;
3705 gpgme_key_t key = NULL;
3706 gpgme_user_id_t uid = NULL;
3707 struct CryptKeyInfo *results = NULL, *k = NULL;
3708 struct CryptKeyInfo **kend = NULL;
3709 struct CryptKeyInfo *choice = NULL;
3710
3711 gpgme_ctx_t ctx = create_gpgme_context(false);
3712
3713 /* list all secret keys */
3714 if (gpgme_op_keylist_start(ctx, NULL, 1))
3715 goto cleanup;
3716
3717 kend = &results;
3718
3719 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3720 {
3722
3727
3728 if (key->revoked)
3730 if (key->expired)
3732 if (key->disabled)
3734
3735 int idx;
3736 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3737 {
3738 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3739 k->kobj = key;
3740 gpgme_key_ref(k->kobj);
3741 k->idx = idx;
3742 k->uid = uid->uid;
3743 k->flags = flags;
3744 if (uid->revoked)
3745 k->flags |= KEYFLAG_REVOKED;
3746 k->validity = uid->validity;
3747 *kend = k;
3748 kend = &k->next;
3749 }
3750 gpgme_key_unref(key);
3751 }
3752 if (gpg_err_code(err) != GPG_ERR_EOF)
3753 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3754 gpgme_op_keylist_end(ctx);
3755
3756 if (!results)
3757 {
3758 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3759 from. This error is displayed if no results were found. */
3760 mutt_error(_("No secret keys found"));
3761 goto cleanup;
3762 }
3763
3764 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3765 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3766 goto cleanup;
3767 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3768
3769 rc = 0;
3770
3771cleanup:
3772 crypt_key_free(&choice);
3773 crypt_key_free(&results);
3774 gpgme_release(ctx);
3775 return rc;
3776}
3777#endif
3778
3783{
3784 gpgme_ctx_t ctx = NULL;
3785 gpgme_key_t export_keys[2] = { 0 };
3786 gpgme_data_t keydata = NULL;
3787 struct Body *att = NULL;
3788 char buf[1024] = { 0 };
3789
3790 OptPgpCheckTrust = false;
3791
3792 struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
3794 if (!key)
3795 goto bail;
3796 export_keys[0] = key->kobj;
3797 export_keys[1] = NULL;
3798
3799 ctx = create_gpgme_context(false);
3800 gpgme_set_armor(ctx, 1);
3801 keydata = create_gpgme_data();
3802 gpgme_error_t err = gpgme_op_export_keys(ctx, export_keys, 0, keydata);
3803 if (err != GPG_ERR_NO_ERROR)
3804 {
3805 mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
3806 goto bail;
3807 }
3808
3809 char *tempf = data_object_to_tempfile(keydata, NULL);
3810 if (!tempf)
3811 goto bail;
3812
3813 att = mutt_body_new();
3814 /* tempf is a newly allocated string, so this is correct: */
3815 att->filename = tempf;
3816 att->unlink = true;
3817 att->use_disp = false;
3818 att->type = TYPE_APPLICATION;
3819 att->subtype = mutt_str_dup("pgp-keys");
3820 /* L10N: MIME description for exported (attached) keys.
3821 You can translate this entry to a non-ASCII string (it will be encoded),
3822 but it may be safer to keep it untranslated. */
3823 snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
3824 att->description = mutt_str_dup(buf);
3826
3827 att->length = mutt_file_get_size(tempf);
3828
3829bail:
3830 crypt_key_free(&key);
3831 gpgme_data_release(keydata);
3832 gpgme_release(ctx);
3833
3834 return att;
3835}
3836
3840static void init_common(void)
3841{
3842 /* this initialization should only run one time, but it may be called by
3843 * either pgp_gpgme_init or smime_gpgme_init */
3844 static bool has_run = false;
3845 if (has_run)
3846 return;
3847
3848 gpgme_check_version(NULL);
3849 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3850#ifdef ENABLE_NLS
3851 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3852#endif
3853 has_run = true;
3854}
3855
3859static void init_pgp(void)
3860{
3861 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3862 {
3863 mutt_error(_("GPGME: OpenPGP protocol not available"));
3864 }
3865}
3866
3870static void init_smime(void)
3871{
3872 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3873 {
3874 mutt_error(_("GPGME: CMS protocol not available"));
3875 }
3876}
3877
3882{
3883 init_common();
3884 init_pgp();
3885}
3886
3891{
3892 init_common();
3893 init_smime();
3894}
3895
3902static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
3903{
3904 struct CryptKeyInfo *p = NULL;
3905 const char *prompt = NULL;
3906 const char *letters = NULL;
3907 const char *choices = NULL;
3908 int choice;
3909
3910 if (is_smime)
3912 else
3914
3915 /* Opportunistic encrypt is controlling encryption.
3916 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3917 * letter choices for those.
3918 */
3919 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3920 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3921 {
3922 if (is_smime)
3923 {
3924 /* L10N: S/MIME options (opportunistic encryption is on) */
3925 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3926 /* L10N: S/MIME options (opportunistic encryption is on) */
3927 letters = _("sapco");
3928 choices = "SapCo";
3929 }
3930 else
3931 {
3932 /* L10N: PGP options (opportunistic encryption is on) */
3933 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3934 /* L10N: PGP options (opportunistic encryption is on) */
3935 letters = _("samco");
3936 choices = "SamCo";
3937 }
3938 }
3939 else if (c_crypt_opportunistic_encrypt)
3940 {
3941 /* Opportunistic encryption option is set, but is toggled off for this message. */
3942 if (is_smime)
3943 {
3944 /* L10N: S/MIME options (opportunistic encryption is off) */
3945 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3946 /* L10N: S/MIME options (opportunistic encryption is off) */
3947 letters = _("esabpco");
3948 choices = "esabpcO";
3949 }
3950 else
3951 {
3952 /* L10N: PGP options (opportunistic encryption is off) */
3953 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3954 /* L10N: PGP options (opportunistic encryption is off) */
3955 letters = _("esabmco");
3956 choices = "esabmcO";
3957 }
3958 }
3959 else
3960 {
3961 /* Opportunistic encryption is unset */
3962 if (is_smime)
3963 {
3964 /* L10N: S/MIME options */
3965 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3966 /* L10N: S/MIME options */
3967 letters = _("esabpc");
3968 choices = "esabpc";
3969 }
3970 else
3971 {
3972 /* L10N: PGP options */
3973 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3974 /* L10N: PGP options */
3975 letters = _("esabmc");
3976 choices = "esabmc";
3977 }
3978 }
3979
3980 choice = mw_multi_choice(prompt, letters);
3981 if (choice > 0)
3982 {
3983 switch (choices[choice - 1])
3984 {
3985 case 'a': /* sign (a)s */
3986 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3987 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3988 if (p)
3989 {
3990 char input_signas[128] = { 0 };
3991 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3992
3993 if (is_smime)
3994 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3995 else
3996 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3997
3998 crypt_key_free(&p);
3999
4000 e->security |= SEC_SIGN;
4001 }
4002 break;
4003
4004 case 'b': /* (b)oth */
4005 e->security |= (SEC_ENCRYPT | SEC_SIGN);
4006 break;
4007
4008 case 'C':
4009 e->security &= ~SEC_SIGN;
4010 break;
4011
4012 case 'c': /* (c)lear */
4013 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4014 break;
4015
4016 case 'e': /* (e)ncrypt */
4017 e->security |= SEC_ENCRYPT;
4018 e->security &= ~SEC_SIGN;
4019 break;
4020
4021 case 'm': /* (p)gp or s/(m)ime */
4022 case 'p':
4023 is_smime = !is_smime;
4024 if (is_smime)
4025 {
4028 }
4029 else
4030 {
4033 }
4035 break;
4036
4037 case 'O': /* oppenc mode on */
4040 break;
4041
4042 case 'o': /* oppenc mode off */
4044 break;
4045
4046 case 'S': /* (s)ign in oppenc mode */
4047 e->security |= SEC_SIGN;
4048 break;
4049
4050 case 's': /* (s)ign */
4051 e->security &= ~SEC_ENCRYPT;
4052 e->security |= SEC_SIGN;
4053 break;
4054 }
4055 }
4056
4057 return e->security;
4058}
4059
4064{
4065 return gpgme_send_menu(e, false);
4066}
4067
4072{
4073 return gpgme_send_menu(e, true);
4074}
4075
4081static bool verify_sender(struct Email *e)
4082{
4084 struct Address *sender = NULL;
4085 bool rc = true;
4086
4087 if (!TAILQ_EMPTY(&e->env->from))
4088 {
4090 sender = TAILQ_FIRST(&e->env->from);
4091 }
4092 else if (!TAILQ_EMPTY(&e->env->sender))
4093 {
4095 sender = TAILQ_FIRST(&e->env->sender);
4096 }
4097
4098 if (sender)
4099 {
4100 if ((gpgme_key_t) mod_data->signature_key)
4101 {
4102 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4103 gpgme_user_id_t uid = NULL;
4104 int sender_length = buf_len(sender->mailbox);
4105 for (uid = key->uids; uid && rc; uid = uid->next)
4106 {
4107 int uid_length = strlen(uid->email);
4108 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4109 (uid_length == (sender_length + 2)))
4110 {
4111 const char *at_sign = strchr(uid->email + 1, '@');
4112 if (at_sign)
4113 {
4114 /* Assume address is 'mailbox@domainname'.
4115 * The mailbox part is case-sensitive,
4116 * the domainname is not. (RFC2821) */
4117 const char *tmp_email = uid->email + 1;
4118 const char *tmp_sender = buf_string(sender->mailbox);
4119 /* length of mailbox part including '@' */
4120 int mailbox_length = at_sign - tmp_email + 1;
4121 int domainname_length = sender_length - mailbox_length;
4122 int mailbox_match, domainname_match;
4123
4124 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4125 tmp_email += mailbox_length;
4126 tmp_sender += mailbox_length;
4127 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4128 if (mailbox_match && domainname_match)
4129 rc = false;
4130 }
4131 else
4132 {
4133 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4134 rc = false;
4135 }
4136 }
4137 }
4138 }
4139 else
4140 {
4141 mutt_any_key_to_continue(_("Failed to verify sender"));
4142 }
4143 }
4144 else
4145 {
4146 mutt_any_key_to_continue(_("Failed to figure out sender"));
4147 }
4148
4149 if ((gpgme_key_t) mod_data->signature_key)
4150 {
4151 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4152 mod_data->signature_key = NULL;
4153 }
4154
4155 return rc;
4156}
4157
4161int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
4162{
4163 return verify_sender(e);
4164}
4165
4169void pgp_gpgme_set_sender(const char *sender)
4170{
4172 mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
4173 FREE(&mod_data->current_sender);
4174 mod_data->current_sender = mutt_str_dup(sender);
4175}
4176
4182{
4183 return GPGME_VERSION;
4184}
4185
4190{
4192 struct CryptCache *l = mod_data->gpgme_id_defaults;
4193 while (l)
4194 {
4195 struct CryptCache *next = l->next;
4196 FREE(&l->what);
4197 FREE(&l->dflt);
4198 FREE(&l);
4199 l = next;
4200 }
4201 mod_data->gpgme_id_defaults = NULL;
4202
4203 if ((gpgme_key_t) mod_data->signature_key)
4204 {
4205 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4206 mod_data->signature_key = NULL;
4207 }
4208}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:685
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
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:296
GUI display the mailboxes in a side panel.
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:695
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Convenience wrapper for the core headers.
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1050
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1484
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:408
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:467
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:1395
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:814
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
Signing/encryption multiplexor.
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
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.
static char * find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
Find keys of the recipients of the message.
static bool verify_sender(struct Email *e)
Verify the sender of a message.
static void init_common(void)
Initialise code common to PGP and SMIME parts of GPGME.
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
#define CRYPT_KV_STRING
Definition crypt_gpgme.c:77
static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
Do the actual verification step.
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
const char * mutt_gpgme_print_version(void)
Get version of GPGME.
static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
Show encryption information.
static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
Create GPGME object from the mail body.
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
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.
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key's fingerprint.
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
Create a string of recipients.
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
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.
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
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.
static void show_one_recipient(struct State *state, gpgme_recipient_t r)
Show information about one encryption recipient.
#define BEGIN_PGP_SIGNATURE(_y)
Definition crypt_gpgme.c:98
#define SIGNED_MESSAGE(_y)
Definition crypt_gpgme.c:96
#define PKA_NOTATION_NAME
Definition crypt_gpgme.c:92
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
#define CRYPT_KV_VALID
Definition crypt_gpgme.c:75
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.
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check one inline PGP body part.
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
#define CRYPT_KV_STRONGID
Definition crypt_gpgme.c:78
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
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.
#define PUBLIC_KEY_BLOCK(_y)
Definition crypt_gpgme.c:97
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
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.
static void init_smime(void)
Initialise the SMIME crypto backend.
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.
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
Show the user the encryption/signing menu.
void gpgme_id_defaults_cleanup(void)
Free the GPGME IdDefaults cache.
#define CRYPT_KV_ADDR
Definition crypt_gpgme.c:76
static struct Body * sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
Sign a message.
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
Write PGP keys to a file.
static int line_compare(const char *a, size_t n, const char *b)
Compare two strings ignore line endings.
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
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.
#define CRYPT_KV_MATCH
Definition crypt_gpgme.c:79
static void init_pgp(void)
Initialise the PGP crypto backend.
static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
Copy a clearsigned message.
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
Show information about one signature.
static void print_time(time_t t, struct State *state)
Print the date/time according to the locale.
#define MESSAGE(_y)
Definition crypt_gpgme.c:95
Wrapper for PGP/SMIME calls to GPGME.
KeyCap
PGP/SMIME Key Capabilities.
Definition crypt_gpgme.h:76
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition crypt_gpgme.h:79
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition crypt_gpgme.h:77
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition crypt_gpgme.h:78
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:102
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition curs_lib.c:446
Edit a string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
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:133
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1794
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1331
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition exit.c:41
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1432
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
long mutt_file_get_size(const char *path)
Get the size of a file.
Definition file.c:1414
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition globals.c:44
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition globals.c:55
Global variables.
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...
int smime_gpgme_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
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() -.
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() -.
int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
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() -.
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() -.
void smime_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
void pgp_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
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() -.
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() -.
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...
struct Body * pgp_gpgme_make_key_attachment(void)
Generate a public key attachment - Implements CryptModuleSpecs::pgp_make_key_attachment() -.
SecurityFlags pgp_gpgme_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
SecurityFlags smime_gpgme_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
void pgp_gpgme_set_sender(const char *sender)
Set the sender of the email - Implements CryptModuleSpecs::set_sender() -.
struct Body * smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
struct Body * pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
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() -.
int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
Does the sender match the certificate?
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() -.
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() -.
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:195
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:467
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1122
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
Convenience wrapper for the gui headers.
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1664
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1938
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition exec.c:319
Hook Commands.
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
@ 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)
Check if a body part is multipart or a message container.
Definition mime.h:85
@ MODULE_ID_AUTOCRYPT
ModuleAutocrypt, Autocrypt
Definition module_api.h:50
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:80
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition multipart.c:93
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition charset.c:880
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition charset.c:966
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:919
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1028
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:948
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition date.c:952
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:104
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition state.c:190
#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:443
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition string.c:317
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition string.c:528
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:586
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
NeoMutt Logging.
API for encryption/signing of emails.
#define KEYFLAG_EXPIRED
Key is expired.
Definition lib.h:140
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:85
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:95
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition lib.h:138
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition lib.h:134
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:99
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:137
#define KEYFLAG_CANTUSE
Definition lib.h:148
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:100
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition lib.h:135
#define SEC_NO_FLAGS
No flags are set.
Definition lib.h:86
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition lib.h:142
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:87
#define KEYFLAG_REVOKED
Key is revoked.
Definition lib.h:141
#define SEC_SIGN
Email is signed.
Definition lib.h:88
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition lib.h:136
Ncrypt private Module data.
Shared constants/structs that are private to libconn.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:665
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:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition question.c:357
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define TAILQ_EMPTY(head)
Definition queue.h:778
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:302
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:757
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:713
#define ASSERT(COND)
Definition signal2.h:59
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
Autocrypt private Module data.
Definition module_data.h:32
char * autocrypt_sign_as
Autocrypt Key id to sign as.
Definition module_data.h:36
The body of an email.
Definition body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
bool use_disp
Content-Disposition uses filename= ?
Definition body.h:47
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:72
char * subtype
content-type subtype
Definition body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
bool goodsig
Good cryptographic signature.
Definition body.h:45
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:59
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
Internal cache for GPGME.
Definition crypt_gpgme.c:86
char * what
Cached key identifier.
Definition crypt_gpgme.c:87
char * dflt
Default key ID.
Definition crypt_gpgme.c:88
struct CryptCache * next
Linked list.
Definition crypt_gpgme.c:89
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
GPGME key object.
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:45
FILE * fp
File to read from.
Definition charset.h:46
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
A local copy of an email.
Definition message.h:34
Ncrypt private Module data.
Definition module_data.h:38
struct CryptCache * gpgme_id_defaults
GPGME IdDefaults cache.
Definition module_data.h:42
gpgme_key_t signature_key
GPGME Signature key.
Definition module_data.h:44
char * current_sender
Current sender for GPGME.
Definition module_data.h:47
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
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:392
#define buf_mktemp(buf)
Definition tmp.h:33
#define mutt_file_mkstemp()
Definition tmp.h:36