NeoMutt  2025-12-11-949-g4870ee
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 false;
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 {
2237 unlink(buf_string(tempfile));
2238 goto cleanup;
2239 }
2240
2241 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2242 if (!fp_tmp)
2243 {
2244 unlink(buf_string(tempfile));
2245 goto cleanup;
2246 }
2247
2248 while (fgets(buf, sizeof(buf), fp_tmp))
2249 {
2250 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2251 if (plen != 0)
2252 {
2253 if (MESSAGE(buf + plen))
2254 {
2255 enc = true;
2256 break;
2257 }
2258 else if (SIGNED_MESSAGE(buf + plen))
2259 {
2260 sgn = true;
2261 break;
2262 }
2263 }
2264 }
2265 mutt_file_fclose(&fp_tmp);
2266 unlink(buf_string(tempfile));
2267
2268 if (!enc && !sgn)
2269 goto cleanup;
2270
2271 /* fix the content type */
2272
2273 mutt_param_set(&b->parameter, "format", "fixed");
2274 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2275
2276 rc = true;
2277
2278cleanup:
2279 buf_pool_release(&tempfile);
2280 return rc;
2281}
2282
2286bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2287{
2288 bool rc = false;
2289 for (; b; b = b->next)
2290 {
2291 if (!just_one && is_multipart(b))
2292 {
2293 rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2294 }
2295 else if (b->type == TYPE_TEXT)
2296 {
2298 if (r)
2299 rc = (rc || r);
2300 else
2301 rc = (pgp_check_traditional_one_body(fp, b) || rc);
2302 }
2303
2304 if (just_one)
2305 break;
2306 }
2307 return rc;
2308}
2309
2313void pgp_gpgme_invoke_import(const char *fname)
2314{
2315 gpgme_ctx_t ctx = create_gpgme_context(false);
2316 gpgme_data_t keydata = NULL;
2317 gpgme_import_result_t impres = NULL;
2318 gpgme_import_status_t st = NULL;
2319 bool any;
2320
2321 FILE *fp_in = mutt_file_fopen(fname, "r");
2322 if (!fp_in)
2323 {
2324 mutt_perror("%s", fname);
2325 goto leave;
2326 }
2327 /* Note that the stream, "fp_in", needs to be kept open while the keydata
2328 * is used. */
2329 gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2330 if (err != GPG_ERR_NO_ERROR)
2331 {
2332 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2333 goto leave;
2334 }
2335
2336 err = gpgme_op_import(ctx, keydata);
2337 if (err != GPG_ERR_NO_ERROR)
2338 {
2339 mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2340 goto leave;
2341 }
2342
2343 /* Print infos about the imported keys to stdout. */
2344 impres = gpgme_op_import_result(ctx);
2345 if (!impres)
2346 {
2347 fputs("oops: no import result returned\n", stdout);
2348 goto leave;
2349 }
2350
2351 for (st = impres->imports; st; st = st->next)
2352 {
2353 if (st->result)
2354 continue;
2355 printf("key %s imported (", NONULL(st->fpr));
2356 /* Note that we use the singular even if it is possible that
2357 * several uids etc are new. This simply looks better. */
2358 any = false;
2359 if (st->status & GPGME_IMPORT_SECRET)
2360 {
2361 printf("secret parts");
2362 any = true;
2363 }
2364 if ((st->status & GPGME_IMPORT_NEW))
2365 {
2366 printf("%snew key", any ? ", " : "");
2367 any = true;
2368 }
2369 if ((st->status & GPGME_IMPORT_UID))
2370 {
2371 printf("%snew uid", any ? ", " : "");
2372 any = true;
2373 }
2374 if ((st->status & GPGME_IMPORT_SIG))
2375 {
2376 printf("%snew sig", any ? ", " : "");
2377 any = true;
2378 }
2379 if ((st->status & GPGME_IMPORT_SUBKEY))
2380 {
2381 printf("%snew subkey", any ? ", " : "");
2382 any = true;
2383 }
2384 printf("%s)\n", any ? "" : "not changed");
2385 /* Fixme: Should we lookup each imported key and print more infos? */
2386 }
2387 /* Now print keys which failed the import. Unfortunately in most
2388 * cases gpg will bail out early and not tell GPGME about. */
2389 /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2390 * the actual gpg diagnostics. But I fear that would clutter the
2391 * output too much. Maybe a dedicated prompt or option to do this
2392 * would be helpful. */
2393 for (st = impres->imports; st; st = st->next)
2394 {
2395 if (st->result == 0)
2396 continue;
2397 printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2398 }
2399 fflush(stdout);
2400
2401leave:
2402 gpgme_release(ctx);
2403 gpgme_data_release(keydata);
2404 mutt_file_fclose(&fp_in);
2405}
2406
2422static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
2423{
2424 char buf[8192] = { 0 };
2425 bool complete, armor_header;
2426 FILE *fp = NULL;
2427
2428 char *fname = data_object_to_tempfile(data, &fp);
2429 if (!fname)
2430 {
2431 mutt_file_fclose(&fp);
2432 return;
2433 }
2434 unlink(fname);
2435 FREE(&fname);
2436
2437 /* fromcode comes from the MIME Content-Type charset label. It might
2438 * be a wrong label, so we want the ability to do corrections via
2439 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2441
2442 for (complete = true, armor_header = true;
2443 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2444 {
2445 if (!complete)
2446 {
2447 if (!armor_header)
2448 state_puts(state, buf);
2449 continue;
2450 }
2451
2452 if (BEGIN_PGP_SIGNATURE(buf))
2453 break;
2454
2455 if (armor_header)
2456 {
2457 if (buf[0] == '\n')
2458 armor_header = false;
2459 continue;
2460 }
2461
2462 if (state->prefix)
2463 state_puts(state, state->prefix);
2464
2465 if ((buf[0] == '-') && (buf[1] == ' '))
2466 state_puts(state, buf + 2);
2467 else
2468 state_puts(state, buf);
2469 }
2470
2473}
2474
2478int pgp_gpgme_application_handler(struct Body *b, struct State *state)
2479{
2480 int needpass = -1;
2481 bool pgp_keyblock = false;
2482 bool clearsign = false;
2483 long bytes;
2484 LOFF_T last_pos;
2485 LOFF_T block_begin;
2486 LOFF_T block_end;
2487 char buf[8192] = { 0 };
2488 FILE *fp_out = NULL;
2489
2490 gpgme_error_t err = GPG_ERR_NO_ERROR;
2491 gpgme_data_t armored_data = NULL;
2492
2493 bool maybe_goodsig = true;
2494 bool have_any_sigs = false;
2495
2496 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2497 char *gpgcharset = NULL;
2498
2499 mutt_debug(LL_DEBUG2, "Entering handler\n");
2500
2501 /* For clearsigned messages we won't be able to get a character set
2502 * but we know that this may only be text thus we assume Latin-1 here. */
2503 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2504 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2505
2506 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2507 {
2508 return -1;
2509 }
2510 last_pos = b->offset;
2511
2512 for (bytes = b->length; bytes > 0;)
2513 {
2514 // record before the fgets in case it is a BEGIN block
2515 block_begin = last_pos;
2516
2517 if (!fgets(buf, sizeof(buf), state->fp_in))
2518 break;
2519
2520 LOFF_T offset = ftello(state->fp_in);
2521 if (offset < 0)
2522 {
2523 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2524 offset = 0;
2525 }
2526 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2527 last_pos = offset;
2528
2529 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2530 if (plen != 0)
2531 {
2532 needpass = 0;
2533 clearsign = false;
2534 pgp_keyblock = false;
2535
2536 if (MESSAGE(buf + plen))
2537 {
2538 needpass = 1;
2539 }
2540 else if (SIGNED_MESSAGE(buf + plen))
2541 {
2542 clearsign = true;
2543 }
2544 else if (PUBLIC_KEY_BLOCK(buf + plen))
2545 {
2546 pgp_keyblock = true;
2547 }
2548 else
2549 {
2550 /* XXX we may wish to recode here */
2551 if (state->prefix)
2552 state_puts(state, state->prefix);
2553 state_puts(state, buf);
2554 continue;
2555 }
2556
2557 /* Find the end of armored block. */
2558 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2559 {
2560 offset = ftello(state->fp_in);
2561 if (offset < 0)
2562 {
2563 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2564 offset = 0;
2565 }
2566 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2567 last_pos = offset;
2568
2569 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2570 {
2571 break;
2572 }
2573
2574 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2575 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2576 {
2577 break;
2578 }
2579
2580 // remember optional Charset: armor header as defined by rfc4880
2581 if (mutt_strn_equal("Charset: ", buf, 9))
2582 {
2583 size_t l = 0;
2584 FREE(&gpgcharset);
2585 gpgcharset = mutt_str_dup(buf + 9);
2586 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2587 gpgcharset[l - 1] = 0;
2588 if (!mutt_ch_check_charset(gpgcharset, 0))
2589 mutt_str_replace(&gpgcharset, "UTF-8");
2590 }
2591 }
2592 block_end = ftello(state->fp_in);
2593 if (block_end < 0)
2594 {
2595 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2596 block_end = 0;
2597 }
2598
2599 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2600
2601 /* Copy PGP material to an data container */
2602 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2603 fseeko(state->fp_in, block_end, 0);
2604
2605 /* Invoke PGP if needed */
2606 if (pgp_keyblock)
2607 {
2608 pgp_gpgme_extract_keys(armored_data, &fp_out);
2609 }
2610 else if (!clearsign || (state->flags & STATE_VERIFY))
2611 {
2612 gpgme_data_t plaintext = create_gpgme_data();
2613 gpgme_ctx_t ctx = create_gpgme_context(false);
2614
2615 if (clearsign)
2616 {
2617 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2618 }
2619 else
2620 {
2621 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2622 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2623 {
2624 /* Decrypt verify can't handle signed only messages. */
2625 gpgme_data_seek(armored_data, 0, SEEK_SET);
2626 /* Must release plaintext so that we supply an uninitialized object. */
2627 gpgme_data_release(plaintext);
2628 plaintext = create_gpgme_data();
2629 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2630 }
2631 }
2632 redraw_if_needed(ctx);
2633
2634 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2635 if (result && (state->flags & STATE_DISPLAY))
2636 show_encryption_info(state, result);
2637
2638 if (err != GPG_ERR_NO_ERROR)
2639 {
2640 char errbuf[200] = { 0 };
2641
2642 snprintf(errbuf, sizeof(errbuf) - 1,
2643 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2644 state_puts(state, errbuf);
2645 }
2646 else
2647 {
2648 /* Decryption/Verification succeeded */
2649
2650 mutt_message(_("PGP message successfully decrypted"));
2651
2652 bool sig_stat = false;
2653 char *tmpfname = NULL;
2654
2655 /* Check whether signatures have been verified. */
2656 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2657 if (verify_result->signatures)
2658 sig_stat = true;
2659
2660 have_any_sigs = false;
2661 maybe_goodsig = false;
2662 if ((state->flags & STATE_DISPLAY) && sig_stat)
2663 {
2664 int res, idx;
2665 bool anybad = false;
2666
2667 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2668 have_any_sigs = true;
2669 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2670 {
2671 if (res == 1)
2672 anybad = true;
2673 }
2674 if (!anybad && idx)
2675 maybe_goodsig = true;
2676
2677 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2678 }
2679
2680 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2681 if (tmpfname)
2682 {
2683 unlink(tmpfname);
2684 FREE(&tmpfname);
2685 }
2686 else
2687 {
2688 mutt_file_fclose(&fp_out);
2689 state_puts(state, _("Error: copy data failed\n"));
2690 }
2691 }
2692 gpgme_data_release(plaintext);
2693 gpgme_release(ctx);
2694 }
2695
2696 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2697 * outputs utf-8 cleartext. This may not always be true, but it
2698 * seems to be a reasonable guess. */
2699 if (state->flags & STATE_DISPLAY)
2700 {
2701 if (needpass)
2702 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2703 else if (pgp_keyblock)
2704 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2705 else
2706 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2707 }
2708
2709 if (clearsign)
2710 {
2711 copy_clearsigned(armored_data, state, body_charset);
2712 }
2713 else if (fp_out)
2714 {
2715 int c;
2716 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2717 rewind(fp_out);
2718 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2720 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2721 {
2722 state_putc(state, c);
2723 if ((c == '\n') && state->prefix)
2724 state_puts(state, state->prefix);
2725 }
2727 }
2728
2729 if (state->flags & STATE_DISPLAY)
2730 {
2731 state_putc(state, '\n');
2732 if (needpass)
2733 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2734 else if (pgp_keyblock)
2735 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2736 else
2737 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2738 }
2739
2740 // Multiple PGP blocks can exist, so clean these up in each loop
2741 gpgme_data_release(armored_data);
2742 mutt_file_fclose(&fp_out);
2743 }
2744 else
2745 {
2746 /* A traditional PGP part may mix signed and unsigned content */
2747 /* XXX we may wish to recode here */
2748 if (state->prefix)
2749 state_puts(state, state->prefix);
2750 state_puts(state, buf);
2751 }
2752 }
2753 FREE(&gpgcharset);
2754
2755 b->goodsig = (maybe_goodsig && have_any_sigs);
2756
2757 if (needpass == -1)
2758 {
2759 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2760 return 1;
2761 }
2762 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2763
2764 return err;
2765}
2766
2773int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
2774{
2775 int is_signed;
2776 int rc = 0;
2777
2778 mutt_debug(LL_DEBUG2, "Entering handler\n");
2779
2780 FILE *fp_out = mutt_file_mkstemp();
2781 if (!fp_out)
2782 {
2783 mutt_perror(_("Can't create temporary file"));
2784 if (state->flags & STATE_DISPLAY)
2785 {
2786 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2787 }
2788 return -1;
2789 }
2790
2791 struct Body *tattach = decrypt_part(b, state, fp_out, false, &is_signed);
2792 if (tattach)
2793 {
2794 tattach->goodsig = is_signed > 0;
2795
2796 if (state->flags & STATE_DISPLAY)
2797 {
2798 state_attach_puts(state, is_signed ?
2799 _("[-- The following data is PGP/MIME signed and encrypted --]\n") :
2800 _("[-- The following data is PGP/MIME encrypted --]\n"));
2801 mutt_protected_headers_handler(tattach, state);
2802 }
2803
2804 /* Store any protected headers in the parent so they can be
2805 * accessed for index updates after the handler recursion is done.
2806 * This is done before the handler to prevent a nested encrypted
2807 * handler from freeing the headers. */
2809 b->mime_headers = tattach->mime_headers;
2810 tattach->mime_headers = NULL;
2811
2812 FILE *fp_save = state->fp_in;
2813 state->fp_in = fp_out;
2814 rc = mutt_body_handler(tattach, state);
2815 state->fp_in = fp_save;
2816
2817 /* Embedded multipart signed protected headers override the
2818 * encrypted headers. We need to do this after the handler so
2819 * they can be printed in the pager. */
2820 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2821 {
2823 b->mime_headers = tattach->parts->mime_headers;
2824 tattach->parts->mime_headers = NULL;
2825 }
2826
2827 /* if a multipart/signed is the _only_ sub-part of a
2828 * multipart/encrypted, cache signature verification
2829 * status. */
2830 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2831 b->goodsig |= tattach->goodsig;
2832
2833 if (state->flags & STATE_DISPLAY)
2834 {
2835 state_attach_puts(state, is_signed ?
2836 _("[-- End of PGP/MIME signed and encrypted data --]\n") :
2837 _("[-- End of PGP/MIME encrypted data --]\n"));
2838 }
2839
2840 mutt_body_free(&tattach);
2841 mutt_message(_("PGP message successfully decrypted"));
2842 }
2843 else
2844 {
2845#ifdef USE_AUTOCRYPT
2846 if (!OptAutocryptGpgme)
2847#endif
2848 {
2849 mutt_error(_("Could not decrypt PGP message"));
2850 }
2851 rc = -1;
2852 }
2853
2854 mutt_file_fclose(&fp_out);
2855 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2856
2857 return rc;
2858}
2859
2863int smime_gpgme_application_handler(struct Body *b, struct State *state)
2864{
2865 int is_signed = 0;
2866 int rc = 0;
2867
2868 mutt_debug(LL_DEBUG2, "Entering handler\n");
2869
2870 /* clear out any mime headers before the handler, so they can't be spoofed. */
2872 b->warnsig = false;
2873 FILE *fp_out = mutt_file_mkstemp();
2874 if (!fp_out)
2875 {
2876 mutt_perror(_("Can't create temporary file"));
2877 if (state->flags & STATE_DISPLAY)
2878 {
2879 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2880 }
2881 return -1;
2882 }
2883
2884 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2885 if (tattach)
2886 {
2887 tattach->goodsig = is_signed > 0;
2888
2889 if (state->flags & STATE_DISPLAY)
2890 {
2891 state_attach_puts(state, is_signed ?
2892 _("[-- The following data is S/MIME signed --]\n") :
2893 _("[-- The following data is S/MIME encrypted --]\n"));
2894 mutt_protected_headers_handler(tattach, state);
2895 }
2896
2897 /* Store any protected headers in the parent so they can be
2898 * accessed for index updates after the handler recursion is done.
2899 * This is done before the handler to prevent a nested encrypted
2900 * handler from freeing the headers. */
2902 b->mime_headers = tattach->mime_headers;
2903 tattach->mime_headers = NULL;
2904
2905 FILE *fp_save = state->fp_in;
2906 state->fp_in = fp_out;
2907 rc = mutt_body_handler(tattach, state);
2908 state->fp_in = fp_save;
2909
2910 /* Embedded multipart signed protected headers override the
2911 * encrypted headers. We need to do this after the handler so
2912 * they can be printed in the pager. */
2913 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2914 {
2916 b->mime_headers = tattach->parts->mime_headers;
2917 tattach->parts->mime_headers = NULL;
2918 }
2919
2920 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2921 * cache signature verification status. */
2922 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2923 {
2924 b->goodsig = tattach->goodsig;
2925 if (!b->goodsig)
2926 b->warnsig = tattach->warnsig;
2927 }
2928 else if (tattach->goodsig)
2929 {
2930 b->goodsig = true;
2931 b->warnsig = tattach->warnsig;
2932 }
2933
2934 if (state->flags & STATE_DISPLAY)
2935 {
2936 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2937 _("[-- End of S/MIME encrypted data --]\n"));
2938 }
2939
2940 mutt_body_free(&tattach);
2941 }
2942
2943 mutt_file_fclose(&fp_out);
2944 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2945
2946 return rc;
2947}
2948
2955unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
2956{
2957 unsigned int rc = 0;
2958
2959 switch (cap)
2960 {
2962 rc = key->can_encrypt;
2963 if (rc == 0)
2964 {
2965 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2966 {
2967 rc = subkey->can_encrypt;
2968 if (rc != 0)
2969 break;
2970 }
2971 }
2972 break;
2973 case KEY_CAP_CAN_SIGN:
2974 rc = key->can_sign;
2975 if (rc == 0)
2976 {
2977 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2978 {
2979 rc = subkey->can_sign;
2980 if (rc != 0)
2981 break;
2982 }
2983 }
2984 break;
2986 rc = key->can_certify;
2987 if (rc == 0)
2988 {
2989 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2990 {
2991 rc = subkey->can_certify;
2992 if (rc != 0)
2993 break;
2994 }
2995 }
2996 break;
2997 }
2998
2999 return rc;
3000}
3001
3011static char *list_to_pattern(struct ListHead *list)
3012{
3013 char *pattern = NULL, *p = NULL;
3014 const char *s = NULL;
3015 size_t n;
3016
3017 n = 0;
3018 struct ListNode *np = NULL;
3019 STAILQ_FOREACH(np, list, entries)
3020 {
3021 for (s = np->data; *s; s++)
3022 {
3023 if ((*s == '%') || (*s == '+'))
3024 n += 2;
3025 n++;
3026 }
3027 n++; /* delimiter or end of string */
3028 }
3029 n++; /* make sure to allocate at least one byte */
3030 p = MUTT_MEM_CALLOC(n, char);
3031 pattern = p;
3032 STAILQ_FOREACH(np, list, entries)
3033 {
3034 s = np->data;
3035 if (*s)
3036 {
3037 if (np != STAILQ_FIRST(list))
3038 *p++ = ' ';
3039 for (s = np->data; *s; s++)
3040 {
3041 if (*s == '%')
3042 {
3043 *p++ = '%';
3044 *p++ = '2';
3045 *p++ = '5';
3046 }
3047 else if (*s == '+')
3048 {
3049 *p++ = '%';
3050 *p++ = '2';
3051 *p++ = 'B';
3052 }
3053 else if (*s == ' ')
3054 {
3055 *p++ = '+';
3056 }
3057 else
3058 {
3059 *p++ = *s;
3060 }
3061 }
3062 }
3063 }
3064 *p = '\0';
3065 return pattern;
3066}
3067
3078static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
3079{
3080 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3081 gpgme_error_t err = GPG_ERR_NO_ERROR;
3082 gpgme_ctx_t ctx = NULL;
3083 gpgme_key_t key = NULL;
3084 int idx;
3085 gpgme_user_id_t uid = NULL;
3086
3087 char *pattern = list_to_pattern(hints);
3088 if (!pattern)
3089 return NULL;
3090
3091 ctx = create_gpgme_context(0);
3092 db = NULL;
3093 kend = &db;
3094
3095 if ((app & APPLICATION_PGP))
3096 {
3097 /* It's all a mess. That old GPGME expects different things depending on
3098 * the protocol. For gpg we don't need percent escaped pappert but simple
3099 * strings passed in an array to the keylist_ext_start function. */
3100 size_t n = 0;
3101 struct ListNode *np = NULL;
3102 STAILQ_FOREACH(np, hints, entries)
3103 {
3104 if (np->data && *np->data)
3105 n++;
3106 }
3107 if (n == 0)
3108 goto no_pgphints;
3109
3110 char **patarr = MUTT_MEM_CALLOC(n + 1, char *);
3111 n = 0;
3112 STAILQ_FOREACH(np, hints, entries)
3113 {
3114 if (np->data && *np->data)
3115 patarr[n++] = mutt_str_dup(np->data);
3116 }
3117 patarr[n] = NULL;
3118 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3119 for (n = 0; patarr[n]; n++)
3120 FREE(&patarr[n]);
3121 FREE(&patarr);
3122 if (err != GPG_ERR_NO_ERROR)
3123 {
3124 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3125 gpgme_release(ctx);
3126 FREE(&pattern);
3127 return NULL;
3128 }
3129
3130 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3131 {
3132 KeyFlags flags = KEYFLAG_NONE;
3133
3135 flags |= KEYFLAG_CANENCRYPT;
3137 flags |= KEYFLAG_CANSIGN;
3138
3139 if (key->revoked)
3140 flags |= KEYFLAG_REVOKED;
3141 if (key->expired)
3142 flags |= KEYFLAG_EXPIRED;
3143 if (key->disabled)
3144 flags |= KEYFLAG_DISABLED;
3145
3146 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3147 {
3148 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3149 k->kobj = key;
3150 gpgme_key_ref(k->kobj);
3151 k->idx = idx;
3152 k->uid = uid->uid;
3153 k->flags = flags;
3154 if (uid->revoked)
3155 k->flags |= KEYFLAG_REVOKED;
3156 k->validity = uid->validity;
3157 *kend = k;
3158 kend = &k->next;
3159 }
3160 gpgme_key_unref(key);
3161 }
3162 if (gpg_err_code(err) != GPG_ERR_EOF)
3163 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3164 gpgme_op_keylist_end(ctx);
3165 no_pgphints:;
3166 }
3167
3168 if ((app & APPLICATION_SMIME))
3169 {
3170 /* and now look for x509 certificates */
3171 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3172 err = gpgme_op_keylist_start(ctx, pattern, 0);
3173 if (err != GPG_ERR_NO_ERROR)
3174 {
3175 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3176 gpgme_release(ctx);
3177 FREE(&pattern);
3178 return NULL;
3179 }
3180
3181 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3182 {
3183 KeyFlags flags = KEYFLAG_ISX509;
3184
3186 flags |= KEYFLAG_CANENCRYPT;
3188 flags |= KEYFLAG_CANSIGN;
3189
3190 if (key->revoked)
3191 flags |= KEYFLAG_REVOKED;
3192 if (key->expired)
3193 flags |= KEYFLAG_EXPIRED;
3194 if (key->disabled)
3195 flags |= KEYFLAG_DISABLED;
3196
3197 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3198 {
3199 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3200 k->kobj = key;
3201 gpgme_key_ref(k->kobj);
3202 k->idx = idx;
3203 k->uid = uid->uid;
3204 k->flags = flags;
3205 if (uid->revoked)
3206 k->flags |= KEYFLAG_REVOKED;
3207 k->validity = uid->validity;
3208 *kend = k;
3209 kend = &k->next;
3210 }
3211 gpgme_key_unref(key);
3212 }
3213 if (gpg_err_code(err) != GPG_ERR_EOF)
3214 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3215 gpgme_op_keylist_end(ctx);
3216 }
3217
3218 gpgme_release(ctx);
3219 FREE(&pattern);
3220 return db;
3221}
3222
3231static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
3232{
3233 char *scratch = mutt_str_dup(str);
3234 if (!scratch)
3235 return;
3236
3237 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3238 {
3239 if (strlen(t) > 3)
3241 }
3242
3243 FREE(&scratch);
3244}
3245
3255static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
3256 KeyFlags abilities, unsigned int app,
3257 bool *forced_valid, bool oppenc_mode)
3258{
3259 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3260
3261 int multi = false;
3262 int this_key_has_strong = false;
3263 int this_key_has_addr_match = false;
3264 int match = false;
3265
3266 struct CryptKeyInfo *keys = NULL, *k = NULL;
3267 struct CryptKeyInfo *the_strong_valid_key = NULL;
3268 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3269 struct CryptKeyInfo *matches = NULL;
3270 struct CryptKeyInfo **matches_endp = &matches;
3271
3272 if (a && a->mailbox)
3274 if (a && a->personal)
3276
3277 if (!oppenc_mode)
3278 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3279 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3280
3281 mutt_list_free(&hints);
3282
3283 if (!keys)
3284 return NULL;
3285
3286 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3287 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3288
3289 for (k = keys; k; k = k->next)
3290 {
3291 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3292
3293 if (abilities && !(k->flags & abilities))
3294 {
3295 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3296 continue;
3297 }
3298
3299 this_key_has_strong = false; /* strong and valid match */
3300 this_key_has_addr_match = false;
3301 match = false; /* any match */
3302
3303 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3304 mutt_addrlist_parse(&alist, k->uid);
3305 struct Address *ka = NULL;
3306 TAILQ_FOREACH(ka, &alist, entries)
3307 {
3308 int validity = crypt_id_matches_addr(a, ka, k);
3309
3310 if (validity & CRYPT_KV_MATCH) /* something matches */
3311 {
3312 match = true;
3313
3314 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3315 {
3316 if (validity & CRYPT_KV_STRONGID)
3317 {
3318 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3319 multi = true;
3320 this_key_has_strong = true;
3321 }
3322 else
3323 {
3324 this_key_has_addr_match = true;
3325 }
3326 }
3327 }
3328 }
3329 mutt_addrlist_clear(&alist);
3330
3331 if (match)
3332 {
3333 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3334 *matches_endp = tmp;
3335 matches_endp = &tmp->next;
3336
3337 if (this_key_has_strong)
3338 the_strong_valid_key = tmp;
3339 else if (this_key_has_addr_match)
3340 a_valid_addrmatch_key = tmp;
3341 }
3342 }
3343
3344 crypt_key_free(&keys);
3345
3346 if (matches)
3347 {
3348 if (oppenc_mode || !isatty(STDIN_FILENO))
3349 {
3350 const bool c_crypt_opportunistic_encrypt_strong_keys =
3351 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3352 if (the_strong_valid_key)
3353 k = crypt_copy_key(the_strong_valid_key);
3354 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3355 k = crypt_copy_key(a_valid_addrmatch_key);
3356 else
3357 k = NULL;
3358 }
3359 else if (the_strong_valid_key && !multi)
3360 {
3361 /* There was precisely one strong match on a valid ID.
3362 * Proceed without asking the user. */
3363 k = crypt_copy_key(the_strong_valid_key);
3364 }
3365 else
3366 {
3367 /* Else: Ask the user. */
3368 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3369 }
3370
3371 crypt_key_free(&matches);
3372 }
3373 else
3374 {
3375 k = NULL;
3376 }
3377
3378 return k;
3379}
3380
3389static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
3390 unsigned int app, bool *forced_valid)
3391{
3392 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3393 struct CryptKeyInfo *matches = NULL;
3394 struct CryptKeyInfo **matches_endp = &matches;
3395 struct CryptKeyInfo *k = NULL;
3396 const char *ps = NULL, *pl = NULL, *phint = NULL;
3397
3398 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3399
3400 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3401 crypt_add_string_to_hints(phint, &hints);
3402 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3403 mutt_list_free(&hints);
3404
3405 if (!keys)
3406 {
3407 FREE(&pfcopy);
3408 return NULL;
3409 }
3410
3411 for (k = keys; k; k = k->next)
3412 {
3413 if (abilities && !(k->flags & abilities))
3414 continue;
3415
3416 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3417 crypt_long_keyid(k), k->uid);
3418
3419 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3420 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3421 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3422 {
3423 mutt_debug(LL_DEBUG5, "match\n");
3424
3425 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3426 *matches_endp = tmp;
3427 matches_endp = &tmp->next;
3428 }
3429 else
3430 {
3431 mutt_debug(LL_DEBUG5, "no match\n");
3432 }
3433 }
3434
3435 FREE(&pfcopy);
3436 crypt_key_free(&keys);
3437
3438 if (matches)
3439 {
3440 if (isatty(STDIN_FILENO))
3441 {
3442 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3443
3444 crypt_key_free(&matches);
3445 return k;
3446 }
3447 else
3448 {
3449 if (crypt_keys_are_valid(matches))
3450 return matches;
3451
3452 crypt_key_free(&matches);
3453 return NULL;
3454 }
3455 }
3456
3457 return NULL;
3458}
3459
3472static struct CryptKeyInfo *crypt_ask_for_key(const char *tag, const char *whatfor,
3473 KeyFlags abilities,
3474 unsigned int app, bool *forced_valid)
3475{
3477 struct CryptKeyInfo *key = NULL;
3478 struct CryptCache *l = NULL;
3479 struct Buffer *resp = buf_pool_get();
3480
3482
3483 if (whatfor)
3484 {
3485 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3486 {
3487 if (mutt_istr_equal(whatfor, l->what))
3488 {
3489 buf_strcpy(resp, l->dflt);
3490 break;
3491 }
3492 }
3493 }
3494
3495 while (true)
3496 {
3497 buf_reset(resp);
3498 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3499 {
3500 goto done;
3501 }
3502
3503 if (whatfor)
3504 {
3505 if (l)
3506 {
3507 mutt_str_replace(&l->dflt, buf_string(resp));
3508 }
3509 else
3510 {
3511 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3512 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3513 mod_data->gpgme_id_defaults = l;
3514 l->what = mutt_str_dup(whatfor);
3515 l->dflt = buf_strdup(resp);
3516 }
3517 }
3518
3519 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3520 if (key)
3521 goto done;
3522
3523 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3524 }
3525
3526done:
3527 buf_pool_release(&resp);
3528 return key;
3529}
3530
3542static char *find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
3543{
3544 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3545 struct ListNode *crypt_hook = NULL;
3546 const char *keyid = NULL;
3547 char *keylist = NULL;
3548 size_t keylist_size = 0;
3549 size_t keylist_used = 0;
3550 struct Address *p = NULL;
3551 struct CryptKeyInfo *k_info = NULL;
3552 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3553 char buf[1024] = { 0 };
3554 bool forced_valid = false;
3555 bool key_selected;
3556 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3557
3558 struct Address *a = NULL;
3559 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3560 /* Iterate through each recipient address to find an encryption key */
3561 TAILQ_FOREACH(a, addrlist, entries)
3562 {
3563 key_selected = false;
3564 /* Check for crypt-hook overrides for this recipient */
3565 mutt_crypt_hook(&crypt_hook_list, a);
3566 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3567 do
3568 {
3569 p = a;
3570 forced_valid = false;
3571 k_info = NULL;
3572
3573 /* If a crypt-hook provides a key ID, confirm with the user unless
3574 * in opportunistic encryption mode */
3575 if (crypt_hook)
3576 {
3577 keyid = crypt_hook->data;
3578 enum QuadOption ans = MUTT_YES;
3579 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3580 {
3581 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3582 buf_string(p->mailbox));
3583 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3584 }
3585 if (ans == MUTT_YES)
3586 {
3587 if (crypt_is_numerical_keyid(keyid))
3588 {
3589 if (mutt_strn_equal(keyid, "0x", 2))
3590 keyid += 2;
3591 goto bypass_selection; /* you don't see this. */
3592 }
3593
3594 /* check for e-mail address */
3595 mutt_addrlist_clear(&hookal);
3596 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3597 {
3598 mutt_addrlist_qualify(&hookal, fqdn);
3599 p = TAILQ_FIRST(&hookal);
3600 }
3601 else if (!oppenc_mode)
3602 {
3603 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3604 }
3605 }
3606 else if (ans == MUTT_NO)
3607 {
3608 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3609 {
3610 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3611 continue;
3612 }
3613 }
3614 else if (ans == MUTT_ABORT)
3615 {
3616 FREE(&keylist);
3617 mutt_addrlist_clear(&hookal);
3618 mutt_list_free(&crypt_hook_list);
3619 return NULL;
3620 }
3621 }
3622
3623 /* If no key found yet, try looking up by address in the keyring */
3624 if (!k_info)
3625 {
3626 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3627 }
3628
3629 /* Last resort: prompt the user to enter a key ID interactively */
3630 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3631 {
3632 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3633
3634 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3635 KEYFLAG_CANENCRYPT, app, &forced_valid);
3636 }
3637
3638 if (!k_info)
3639 {
3640 FREE(&keylist);
3641 mutt_addrlist_clear(&hookal);
3642 mutt_list_free(&crypt_hook_list);
3643 return NULL;
3644 }
3645
3646 keyid = crypt_fpr_or_lkeyid(k_info);
3647
3648 bypass_selection:
3649 /* Append the selected key ID to the space-separated keylist string */
3650 keylist_size += mutt_str_len(keyid) + 4 + 1;
3651 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3652 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3653 keyid, forced_valid ? "!" : "");
3654 keylist_used = mutt_str_len(keylist);
3655
3656 key_selected = true;
3657
3658 crypt_key_free(&k_info);
3659 mutt_addrlist_clear(&hookal);
3660
3661 if (crypt_hook)
3662 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3663
3664 } while (crypt_hook);
3665
3666 mutt_list_free(&crypt_hook_list);
3667 }
3668 return keylist;
3669}
3670
3674char *pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3675{
3676 return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
3677}
3678
3682char *smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3683{
3684 return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
3685}
3686
3687#ifdef USE_AUTOCRYPT
3701{
3702 int rc = -1;
3703 gpgme_error_t err = GPG_ERR_NO_ERROR;
3704 gpgme_key_t key = NULL;
3705 gpgme_user_id_t uid = NULL;
3706 struct CryptKeyInfo *results = NULL, *k = NULL;
3707 struct CryptKeyInfo **kend = NULL;
3708 struct CryptKeyInfo *choice = NULL;
3709
3710 gpgme_ctx_t ctx = create_gpgme_context(false);
3711
3712 /* list all secret keys */
3713 if (gpgme_op_keylist_start(ctx, NULL, 1))
3714 goto cleanup;
3715
3716 kend = &results;
3717
3718 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3719 {
3721
3726
3727 if (key->revoked)
3729 if (key->expired)
3731 if (key->disabled)
3733
3734 int idx;
3735 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3736 {
3737 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3738 k->kobj = key;
3739 gpgme_key_ref(k->kobj);
3740 k->idx = idx;
3741 k->uid = uid->uid;
3742 k->flags = flags;
3743 if (uid->revoked)
3744 k->flags |= KEYFLAG_REVOKED;
3745 k->validity = uid->validity;
3746 *kend = k;
3747 kend = &k->next;
3748 }
3749 gpgme_key_unref(key);
3750 }
3751 if (gpg_err_code(err) != GPG_ERR_EOF)
3752 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3753 gpgme_op_keylist_end(ctx);
3754
3755 if (!results)
3756 {
3757 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3758 from. This error is displayed if no results were found. */
3759 mutt_error(_("No secret keys found"));
3760 goto cleanup;
3761 }
3762
3763 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3764 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3765 goto cleanup;
3766 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3767
3768 rc = 0;
3769
3770cleanup:
3771 crypt_key_free(&choice);
3772 crypt_key_free(&results);
3773 gpgme_release(ctx);
3774 return rc;
3775}
3776#endif
3777
3782{
3783 gpgme_ctx_t ctx = NULL;
3784 gpgme_key_t export_keys[2] = { 0 };
3785 gpgme_data_t keydata = NULL;
3786 struct Body *att = NULL;
3787 char buf[1024] = { 0 };
3788
3789 OptPgpCheckTrust = false;
3790
3791 struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
3793 if (!key)
3794 goto bail;
3795 export_keys[0] = key->kobj;
3796 export_keys[1] = NULL;
3797
3798 ctx = create_gpgme_context(false);
3799 gpgme_set_armor(ctx, 1);
3800 keydata = create_gpgme_data();
3801 gpgme_error_t err = gpgme_op_export_keys(ctx, export_keys, 0, keydata);
3802 if (err != GPG_ERR_NO_ERROR)
3803 {
3804 mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
3805 goto bail;
3806 }
3807
3808 char *tempf = data_object_to_tempfile(keydata, NULL);
3809 if (!tempf)
3810 goto bail;
3811
3812 att = mutt_body_new();
3813 /* tempf is a newly allocated string, so this is correct: */
3814 att->filename = tempf;
3815 att->unlink = true;
3816 att->use_disp = false;
3817 att->type = TYPE_APPLICATION;
3818 att->subtype = mutt_str_dup("pgp-keys");
3819 /* L10N: MIME description for exported (attached) keys.
3820 You can translate this entry to a non-ASCII string (it will be encoded),
3821 but it may be safer to keep it untranslated. */
3822 snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
3823 att->description = mutt_str_dup(buf);
3825
3826 att->length = mutt_file_get_size(tempf);
3827
3828bail:
3829 crypt_key_free(&key);
3830 gpgme_data_release(keydata);
3831 gpgme_release(ctx);
3832
3833 return att;
3834}
3835
3839static void init_common(void)
3840{
3841 /* this initialization should only run one time, but it may be called by
3842 * either pgp_gpgme_init or smime_gpgme_init */
3843 static bool has_run = false;
3844 if (has_run)
3845 return;
3846
3847 gpgme_check_version(NULL);
3848 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3849#ifdef ENABLE_NLS
3850 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3851#endif
3852 has_run = true;
3853}
3854
3858static void init_pgp(void)
3859{
3860 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3861 {
3862 mutt_error(_("GPGME: OpenPGP protocol not available"));
3863 }
3864}
3865
3869static void init_smime(void)
3870{
3871 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3872 {
3873 mutt_error(_("GPGME: CMS protocol not available"));
3874 }
3875}
3876
3881{
3882 init_common();
3883 init_pgp();
3884}
3885
3890{
3891 init_common();
3892 init_smime();
3893}
3894
3901static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
3902{
3903 struct CryptKeyInfo *p = NULL;
3904 const char *prompt = NULL;
3905 const char *letters = NULL;
3906 const char *choices = NULL;
3907 int choice;
3908
3909 if (is_smime)
3911 else
3913
3914 /* Opportunistic encrypt is controlling encryption.
3915 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3916 * letter choices for those.
3917 */
3918 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3919 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3920 {
3921 if (is_smime)
3922 {
3923 /* L10N: S/MIME options (opportunistic encryption is on) */
3924 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3925 /* L10N: S/MIME options (opportunistic encryption is on) */
3926 letters = _("sapco");
3927 choices = "SapCo";
3928 }
3929 else
3930 {
3931 /* L10N: PGP options (opportunistic encryption is on) */
3932 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3933 /* L10N: PGP options (opportunistic encryption is on) */
3934 letters = _("samco");
3935 choices = "SamCo";
3936 }
3937 }
3938 else if (c_crypt_opportunistic_encrypt)
3939 {
3940 /* Opportunistic encryption option is set, but is toggled off for this message. */
3941 if (is_smime)
3942 {
3943 /* L10N: S/MIME options (opportunistic encryption is off) */
3944 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3945 /* L10N: S/MIME options (opportunistic encryption is off) */
3946 letters = _("esabpco");
3947 choices = "esabpcO";
3948 }
3949 else
3950 {
3951 /* L10N: PGP options (opportunistic encryption is off) */
3952 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3953 /* L10N: PGP options (opportunistic encryption is off) */
3954 letters = _("esabmco");
3955 choices = "esabmcO";
3956 }
3957 }
3958 else
3959 {
3960 /* Opportunistic encryption is unset */
3961 if (is_smime)
3962 {
3963 /* L10N: S/MIME options */
3964 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3965 /* L10N: S/MIME options */
3966 letters = _("esabpc");
3967 choices = "esabpc";
3968 }
3969 else
3970 {
3971 /* L10N: PGP options */
3972 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3973 /* L10N: PGP options */
3974 letters = _("esabmc");
3975 choices = "esabmc";
3976 }
3977 }
3978
3979 choice = mw_multi_choice(prompt, letters);
3980 if (choice > 0)
3981 {
3982 switch (choices[choice - 1])
3983 {
3984 case 'a': /* sign (a)s */
3985 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3986 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3987 if (p)
3988 {
3989 char input_signas[128] = { 0 };
3990 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3991
3992 if (is_smime)
3993 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3994 else
3995 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3996
3997 crypt_key_free(&p);
3998
3999 e->security |= SEC_SIGN;
4000 }
4001 break;
4002
4003 case 'b': /* (b)oth */
4004 e->security |= (SEC_ENCRYPT | SEC_SIGN);
4005 break;
4006
4007 case 'C':
4008 e->security &= ~SEC_SIGN;
4009 break;
4010
4011 case 'c': /* (c)lear */
4012 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4013 break;
4014
4015 case 'e': /* (e)ncrypt */
4016 e->security |= SEC_ENCRYPT;
4017 e->security &= ~SEC_SIGN;
4018 break;
4019
4020 case 'm': /* (p)gp or s/(m)ime */
4021 case 'p':
4022 is_smime = !is_smime;
4023 if (is_smime)
4024 {
4027 }
4028 else
4029 {
4032 }
4034 break;
4035
4036 case 'O': /* oppenc mode on */
4039 break;
4040
4041 case 'o': /* oppenc mode off */
4043 break;
4044
4045 case 'S': /* (s)ign in oppenc mode */
4046 e->security |= SEC_SIGN;
4047 break;
4048
4049 case 's': /* (s)ign */
4050 e->security &= ~SEC_ENCRYPT;
4051 e->security |= SEC_SIGN;
4052 break;
4053 }
4054 }
4055
4056 return e->security;
4057}
4058
4063{
4064 return gpgme_send_menu(e, false);
4065}
4066
4071{
4072 return gpgme_send_menu(e, true);
4073}
4074
4080static bool verify_sender(struct Email *e)
4081{
4083 struct Address *sender = NULL;
4084 bool rc = true;
4085
4086 if (!TAILQ_EMPTY(&e->env->from))
4087 {
4089 sender = TAILQ_FIRST(&e->env->from);
4090 }
4091 else if (!TAILQ_EMPTY(&e->env->sender))
4092 {
4094 sender = TAILQ_FIRST(&e->env->sender);
4095 }
4096
4097 if (sender)
4098 {
4099 if ((gpgme_key_t) mod_data->signature_key)
4100 {
4101 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4102 gpgme_user_id_t uid = NULL;
4103 int sender_length = buf_len(sender->mailbox);
4104 for (uid = key->uids; uid && rc; uid = uid->next)
4105 {
4106 int uid_length = strlen(uid->email);
4107 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4108 (uid_length == (sender_length + 2)))
4109 {
4110 const char *at_sign = strchr(uid->email + 1, '@');
4111 if (at_sign)
4112 {
4113 /* Assume address is 'mailbox@domainname'.
4114 * The mailbox part is case-sensitive,
4115 * the domainname is not. (RFC2821) */
4116 const char *tmp_email = uid->email + 1;
4117 const char *tmp_sender = buf_string(sender->mailbox);
4118 /* length of mailbox part including '@' */
4119 int mailbox_length = at_sign - tmp_email + 1;
4120 int domainname_length = sender_length - mailbox_length;
4121 int mailbox_match, domainname_match;
4122
4123 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4124 tmp_email += mailbox_length;
4125 tmp_sender += mailbox_length;
4126 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4127 if (mailbox_match && domainname_match)
4128 rc = false;
4129 }
4130 else
4131 {
4132 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4133 rc = false;
4134 }
4135 }
4136 }
4137 }
4138 else
4139 {
4140 mutt_any_key_to_continue(_("Failed to verify sender"));
4141 }
4142 }
4143 else
4144 {
4145 mutt_any_key_to_continue(_("Failed to figure out sender"));
4146 }
4147
4148 if ((gpgme_key_t) mod_data->signature_key)
4149 {
4150 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4151 mod_data->signature_key = NULL;
4152 }
4153
4154 return rc;
4155}
4156
4160int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
4161{
4162 return verify_sender(e);
4163}
4164
4168void pgp_gpgme_set_sender(const char *sender)
4169{
4171 mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
4172 FREE(&mod_data->current_sender);
4173 mod_data->current_sender = mutt_str_dup(sender);
4174}
4175
4181{
4182 return GPGME_VERSION;
4183}
4184
4190{
4191 struct CryptCache *l = mod_data->gpgme_id_defaults;
4192 while (l)
4193 {
4194 struct CryptCache *next = l->next;
4195 FREE(&l->what);
4196 FREE(&l->dflt);
4197 FREE(&l);
4198 l = next;
4199 }
4200 mod_data->gpgme_id_defaults = NULL;
4201
4202 if ((gpgme_key_t) mod_data->signature_key)
4203 {
4204 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4205 mod_data->signature_key = NULL;
4206 }
4207}
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:1470
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:701
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h: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.
void gpgme_id_defaults_cleanup(struct NcryptModuleData *mod_data)
Free the GPGME IdDefaults cache.
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.
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
bool crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
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.
#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:77
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition crypt_gpgme.h:80
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition crypt_gpgme.h:78
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition crypt_gpgme.h:79
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:101
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition curs_lib.c:445
Edit a string.
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
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:1947
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1484
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:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
bool crypt_keys_are_valid(struct CryptKeyInfo *keys)
Are all these keys valid?
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.
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:502
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c: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:1939
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition exec.c:319
Hook Commands.
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:82
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition multipart.c:93
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition charset.c: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:64
#define state_putc(STATE, STR)
Definition state.h:65
@ STATE_NONE
No flags are set.
Definition state.h:36
@ STATE_VERIFY
Perform signature verification.
Definition state.h:38
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
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_NONE
Overwrite existing file (the default)
Definition mutt_attach.h:59
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
NeoMutt Logging.
API for encryption/signing of emails.
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_NONE
No flags are set.
Definition lib.h:91
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
uint16_t KeyFlags
Definition lib.h:159
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:112
#define KEYFLAG_CANTUSE
Definition lib.h:161
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
@ KEYFLAG_REVOKED
Key is revoked.
Definition lib.h:152
@ KEYFLAG_NONE
No flags are set.
Definition lib.h:146
@ KEYFLAG_CANSIGN
Key is suitable for signing.
Definition lib.h:147
@ KEYFLAG_ISX509
Key is an X.509 key.
Definition lib.h:149
@ KEYFLAG_EXPIRED
Key is expired.
Definition lib.h:151
@ KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:148
@ KEYFLAG_DISABLED
Key is marked disabled.
Definition lib.h:153
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:666
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:45
gpgme_validity_t validity
uid validity (cached for convenience)
Definition crypt_gpgme.h:51
KeyFlags flags
global and per uid flags (for convenience)
Definition crypt_gpgme.h:50
int idx
and the user ID at this index
Definition crypt_gpgme.h:48
struct CryptKeyInfo * next
Linked list.
Definition crypt_gpgme.h:46
const char * uid
and for convenience point to this user ID
Definition crypt_gpgme.h:49
gpgme_key_t kobj
GPGME key object.
Definition crypt_gpgme.h:47
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:39
struct CryptCache * gpgme_id_defaults
GPGME IdDefaults cache.
Definition module_data.h:43
gpgme_key_t signature_key
GPGME Signature key.
Definition module_data.h:45
char * current_sender
Current sender for GPGME.
Definition module_data.h:48
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:54
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition subset.c:392
#define buf_mktemp(buf)
Definition tmp.h:33
#define mutt_file_mkstemp()
Definition tmp.h:36