NeoMutt  2025-12-11-1009-ga75d9e
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;
434 int hadcr = 0;
435 unsigned char buf[1] = { 0 };
436
438 rewind(fp_tmp);
439 while ((c = fgetc(fp_tmp)) != EOF)
440 {
441 if (c == '\r')
442 {
443 hadcr = 1;
444 }
445 else
446 {
447 if ((c == '\n') && !hadcr)
448 {
449 buf[0] = '\r';
450 gpgme_data_write(data, buf, 1);
451 }
452
453 hadcr = 0;
454 }
455 /* FIXME: This is quite suboptimal */
456 buf[0] = c;
457 gpgme_data_write(data, buf, 1);
458 }
459 mutt_file_fclose(&fp_tmp);
460 gpgme_data_seek(data, 0, SEEK_SET);
461 }
462 else
463 {
464 mutt_file_fclose(&fp_tmp);
465 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
466 if (err != GPG_ERR_NO_ERROR)
467 {
468 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
469 gpgme_data_release(data);
470 data = NULL;
471 /* fall through to unlink the tempfile */
472 }
473 }
474 unlink(buf_string(tempfile));
475
476cleanup:
477 buf_pool_release(&tempfile);
478 return data;
479}
480
488static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
489{
490 gpgme_data_t data = NULL;
491
492 gpgme_error_t err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
493 if (err != GPG_ERR_NO_ERROR)
494 {
495 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
496 return NULL;
497 }
498
499 return data;
500}
501
509static int data_object_to_stream(gpgme_data_t data, FILE *fp)
510{
511 char buf[4096] = { 0 };
512 ssize_t nread;
513
514 gpgme_error_t err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ?
515 gpgme_error_from_errno(errno) :
516 GPG_ERR_NO_ERROR);
517 if (err != GPG_ERR_NO_ERROR)
518 {
519 mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
520 return -1;
521 }
522
523 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
524 {
525 /* fixme: we are not really converting CRLF to LF but just
526 * skipping CR. Doing it correctly needs a more complex logic */
527 for (char *p = buf; nread; p++, nread--)
528 {
529 if (*p != '\r')
530 putc(*p, fp);
531 }
532
533 if (ferror(fp))
534 {
535 mutt_perror(_("[tempfile]"));
536 return -1;
537 }
538 }
539 if (nread == -1)
540 {
541 mutt_error(_("error reading data object: %s"), strerror(errno));
542 return -1;
543 }
544 return 0;
545}
546
558static char *data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
559{
560 ssize_t nread = 0;
561 char *rv = NULL;
562 struct Buffer *tempfile = buf_pool_get();
563
564 buf_mktemp(tempfile);
565
566 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
567 if (!fp)
568 {
569 mutt_perror(_("Can't create temporary file"));
570 goto cleanup;
571 }
572
573 gpgme_error_t err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ?
574 gpgme_error_from_errno(errno) :
575 GPG_ERR_NO_ERROR);
576 if (err == GPG_ERR_NO_ERROR)
577 {
578 char buf[4096] = { 0 };
579
580 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
581 {
582 if (fwrite(buf, nread, 1, fp) != 1)
583 {
584 mutt_perror("%s", buf_string(tempfile));
585 mutt_file_fclose(&fp);
586 unlink(buf_string(tempfile));
587 goto cleanup;
588 }
589 }
590 }
591 if (fp_ret)
592 rewind(fp);
593 else
594 mutt_file_fclose(&fp);
595 if (nread == -1)
596 {
597 mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
598 unlink(buf_string(tempfile));
599 mutt_file_fclose(&fp);
600 goto cleanup;
601 }
602 if (fp_ret)
603 *fp_ret = fp;
604 rv = buf_strdup(tempfile);
605
606cleanup:
607 buf_pool_release(&tempfile);
608 return rv;
609}
610
617static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
618{
619 unsigned int n = 0;
620
621 const char *s = keylist;
622 do
623 {
624 while (*s == ' ')
625 s++;
626 if (*s != '\0')
627 {
628 if (n == 0)
629 {
630 if (!use_smime)
631 buf_addstr(recpstring, "--\n");
632 }
633 else
634 {
635 buf_addch(recpstring, '\n');
636 }
637 n++;
638
639 while ((*s != '\0') && (*s != ' '))
640 buf_addch(recpstring, *s++);
641 }
642 } while (*s != '\0');
643}
644
653static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
654{
655 gpgme_key_t key = NULL;
656 gpgme_key_t key2 = NULL;
657
658 gpgme_ctx_t listctx = create_gpgme_context(for_smime);
659 gpgme_error_t err = gpgme_op_keylist_start(listctx, address, 1);
660 if (err == GPG_ERR_NO_ERROR)
661 err = gpgme_op_keylist_next(listctx, &key);
662 if (err != GPG_ERR_NO_ERROR)
663 {
664 gpgme_release(listctx);
665 mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
666 return false;
667 }
668
669 char *fpr = "fpr1";
670 if (key->subkeys)
671 fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
672 while (gpgme_op_keylist_next(listctx, &key2) == 0)
673 {
674 char *fpr2 = "fpr2";
675 if (key2->subkeys)
676 fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
677 if (!mutt_str_equal(fpr, fpr2))
678 {
679 gpgme_key_unref(key);
680 gpgme_key_unref(key2);
681 gpgme_release(listctx);
682 mutt_error(_("ambiguous specification of secret key '%s'"), address);
683 return false;
684 }
685 else
686 {
687 gpgme_key_unref(key2);
688 }
689 }
690 gpgme_op_keylist_end(listctx);
691 gpgme_release(listctx);
692
693 gpgme_signers_clear(ctx);
694 err = gpgme_signers_add(ctx, key);
695 gpgme_key_unref(key);
696 if (err != GPG_ERR_NO_ERROR)
697 {
698 mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
699 return false;
700 }
701 return true;
702}
703
712static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
713{
714 const char *signid = NULL;
715
716 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
717 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
718 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
719 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
720 if (for_smime)
721 {
722 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
723 }
724#ifdef USE_AUTOCRYPT
725 else if (OptAutocryptGpgme)
726 {
728 ASSERT(mod_data);
729
730 signid = mod_data->autocrypt_sign_as;
731 }
732#endif
733 else
734 {
735 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
736 }
737
738 /* Try getting the signing key from config entries */
739 if (signid && set_signer_from_address(ctx, signid, for_smime))
740 {
741 return 0;
742 }
743
744 /* Try getting the signing key from the From line */
745 if (al)
746 {
747 struct Address *a = NULL;
748 TAILQ_FOREACH(a, al, entries)
749 {
750 if (a->mailbox && set_signer_from_address(ctx, buf_string(a->mailbox), for_smime))
751 {
752 return 0;
753 }
754 }
755 }
756
757 return (!signid && !al) ? 0 : -1;
758}
759
765static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
766{
768 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME,
769 mod_data->current_sender, 0);
770 if (err != GPG_ERR_NO_ERROR)
771 {
772 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
773 }
774
775 return err;
776}
777
787static char *encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime,
788 bool combined_signed, const struct AddressList *from)
789{
790 gpgme_error_t err = GPG_ERR_NO_ERROR;
791 gpgme_ctx_t ctx = NULL;
792 gpgme_data_t ciphertext = NULL;
793 char *outfile = NULL;
794
795 struct Buffer *recpstring = buf_pool_get();
796 create_recipient_string(keylist, recpstring, use_smime);
797 if (buf_is_empty(recpstring))
798 {
799 buf_pool_release(&recpstring);
800 return NULL;
801 }
802
803 ctx = create_gpgme_context(use_smime);
804 if (!use_smime)
805 gpgme_set_armor(ctx, 1);
806
807 ciphertext = create_gpgme_data();
808
809 if (combined_signed)
810 {
811 if (set_signer(ctx, from, use_smime))
812 goto cleanup;
813
814 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
815 if (c_crypt_use_pka)
816 {
817 err = set_pka_sig_notation(ctx);
818 if (err != GPG_ERR_NO_ERROR)
819 goto cleanup;
820 }
821
822 err = gpgme_op_encrypt_sign_ext(ctx, NULL, buf_string(recpstring),
823 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
824 }
825 else
826 {
827 err = gpgme_op_encrypt_ext(ctx, NULL, buf_string(recpstring),
828 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
829 }
830
831 redraw_if_needed(ctx);
832 if (err != GPG_ERR_NO_ERROR)
833 {
834 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
835 goto cleanup;
836 }
837
838 outfile = data_object_to_tempfile(ciphertext, NULL);
839
840cleanup:
841 buf_pool_release(&recpstring);
842 gpgme_release(ctx);
843 gpgme_data_release(ciphertext);
844 return outfile;
845}
846
859static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
860{
861 gpgme_sign_result_t result = NULL;
862 const char *algorithm_name = NULL;
863
864 if (buflen < 5)
865 return -1;
866
867 *buf = '\0';
868 result = gpgme_op_sign_result(ctx);
869 if (result && result->signatures)
870 {
871 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
872 if (algorithm_name)
873 {
874 if (use_smime)
875 {
876 /* convert GPGME raw hash name to RFC2633 format */
877 snprintf(buf, buflen, "%s", algorithm_name);
878 mutt_str_lower(buf);
879 }
880 else
881 {
882 /* convert GPGME raw hash name to RFC3156 format */
883 snprintf(buf, buflen, "pgp-%s", algorithm_name);
884 mutt_str_lower(buf + 4);
885 }
886 }
887 }
888
889 return (buf[0] != '\0') ? 0 : -1;
890}
891
897static void print_time(time_t t, struct State *state)
898{
899 char p[256] = { 0 };
900 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
901 state_puts(state, p);
902}
903
912static struct Body *sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
913{
914 struct Body *b_sign = NULL;
915 char *sigfile = NULL;
916 gpgme_error_t err = GPG_ERR_NO_ERROR;
917 char buf[100] = { 0 };
918 gpgme_ctx_t ctx = NULL;
919 gpgme_data_t message = NULL;
920 gpgme_data_t signature = NULL;
921 gpgme_sign_result_t sigres = NULL;
922
923 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
924
925 message = body_to_data_object(b, true);
926 if (!message)
927 return NULL;
928 signature = create_gpgme_data();
929
930 ctx = create_gpgme_context(use_smime);
931 if (!use_smime)
932 gpgme_set_armor(ctx, 1);
933
934 if (set_signer(ctx, from, use_smime))
935 {
936 gpgme_data_release(signature);
937 gpgme_data_release(message);
938 gpgme_release(ctx);
939 return NULL;
940 }
941
942 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
943 if (c_crypt_use_pka)
944 {
945 err = set_pka_sig_notation(ctx);
946 if (err != GPG_ERR_NO_ERROR)
947 {
948 gpgme_data_release(signature);
949 gpgme_data_release(message);
950 gpgme_release(ctx);
951 return NULL;
952 }
953 }
954
955 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
956 redraw_if_needed(ctx);
957 gpgme_data_release(message);
958 if (err != GPG_ERR_NO_ERROR)
959 {
960 gpgme_data_release(signature);
961 gpgme_release(ctx);
962 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
963 return NULL;
964 }
965 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
966 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
967 sigres = gpgme_op_sign_result(ctx);
968 if (!sigres->signatures)
969 {
970 gpgme_data_release(signature);
971 gpgme_release(ctx);
972 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
973 return NULL;
974 }
975
976 sigfile = data_object_to_tempfile(signature, NULL);
977 gpgme_data_release(signature);
978 if (!sigfile)
979 {
980 gpgme_release(ctx);
981 return NULL;
982 }
983
984 b_sign = mutt_body_new();
985 b_sign->type = TYPE_MULTIPART;
986 b_sign->subtype = mutt_str_dup("signed");
987 b_sign->encoding = ENC_7BIT;
988 b_sign->use_disp = false;
989 b_sign->disposition = DISP_INLINE;
990
992 mutt_param_set(&b_sign->parameter, "protocol",
993 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
994 /* Get the micalg from GPGME. Old gpgme versions don't support this
995 * for S/MIME so we assume sha-1 in this case. */
996 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
997 mutt_param_set(&b_sign->parameter, "micalg", buf);
998 else if (use_smime)
999 mutt_param_set(&b_sign->parameter, "micalg", "sha1");
1000 gpgme_release(ctx);
1001
1002 b_sign->parts = b;
1003 b = b_sign;
1004
1005 b_sign->parts->next = mutt_body_new();
1006 b_sign = b_sign->parts->next;
1007 b_sign->type = TYPE_APPLICATION;
1008 if (use_smime)
1009 {
1010 b_sign->subtype = mutt_str_dup("pkcs7-signature");
1011 mutt_param_set(&b_sign->parameter, "name", "smime.p7s");
1012 b_sign->encoding = ENC_BASE64;
1013 b_sign->use_disp = true;
1014 b_sign->disposition = DISP_ATTACH;
1015 b_sign->d_filename = mutt_str_dup("smime.p7s");
1016 }
1017 else
1018 {
1019 b_sign->subtype = mutt_str_dup("pgp-signature");
1020 mutt_param_set(&b_sign->parameter, "name", "signature.asc");
1021 b_sign->use_disp = false;
1022 b_sign->disposition = DISP_NONE;
1023 b_sign->encoding = ENC_7BIT;
1024 }
1025 b_sign->filename = sigfile;
1026 b_sign->unlink = true; /* ok to remove this file after sending. */
1027
1028 return b;
1029}
1030
1034struct Body *pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1035{
1036 return sign_message(b, from, false);
1037}
1038
1042struct Body *smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1043{
1044 return sign_message(b, from, true);
1045}
1046
1050struct Body *pgp_gpgme_encrypt_message(struct Body *b, char *keylist, bool sign,
1051 const struct AddressList *from)
1052{
1053 if (sign)
1055 gpgme_data_t plaintext = body_to_data_object(b, false);
1056 if (!plaintext)
1057 return NULL;
1058
1059 char *outfile = encrypt_gpgme_object(plaintext, keylist, false, sign, from);
1060 gpgme_data_release(plaintext);
1061 if (!outfile)
1062 return NULL;
1063
1064 struct Body *b_enc = mutt_body_new();
1065 b_enc->type = TYPE_MULTIPART;
1066 b_enc->subtype = mutt_str_dup("encrypted");
1067 b_enc->encoding = ENC_7BIT;
1068 b_enc->use_disp = false;
1069 b_enc->disposition = DISP_INLINE;
1070
1072 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-encrypted");
1073
1074 b_enc->parts = mutt_body_new();
1075 b_enc->parts->type = TYPE_APPLICATION;
1076 b_enc->parts->subtype = mutt_str_dup("pgp-encrypted");
1077 b_enc->parts->encoding = ENC_7BIT;
1078
1079 b_enc->parts->next = mutt_body_new();
1080 b_enc->parts->next->type = TYPE_APPLICATION;
1081 b_enc->parts->next->subtype = mutt_str_dup("octet-stream");
1082 b_enc->parts->next->encoding = ENC_7BIT;
1083 b_enc->parts->next->filename = outfile;
1084 b_enc->parts->next->use_disp = true;
1085 b_enc->parts->next->disposition = DISP_ATTACH;
1086 b_enc->parts->next->unlink = true; /* delete after sending the message */
1087 b_enc->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime
1088 can save */
1089
1090 return b_enc;
1091}
1092
1096struct Body *smime_gpgme_build_smime_entity(struct Body *b, char *keylist)
1097{
1098 /* OpenSSL converts line endings to crlf when encrypting. Some clients
1099 * depend on this for signed+encrypted messages: they do not convert line
1100 * endings between decrypting and checking the signature. */
1101 gpgme_data_t plaintext = body_to_data_object(b, true);
1102 if (!plaintext)
1103 return NULL;
1104
1105 char *outfile = encrypt_gpgme_object(plaintext, keylist, true, false, NULL);
1106 gpgme_data_release(plaintext);
1107 if (!outfile)
1108 return NULL;
1109
1110 struct Body *b_enc = mutt_body_new();
1111 b_enc->type = TYPE_APPLICATION;
1112 b_enc->subtype = mutt_str_dup("pkcs7-mime");
1113 mutt_param_set(&b_enc->parameter, "name", "smime.p7m");
1114 mutt_param_set(&b_enc->parameter, "smime-type", "enveloped-data");
1115 b_enc->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1116 b_enc->use_disp = true;
1117 b_enc->disposition = DISP_ATTACH;
1118 b_enc->d_filename = mutt_str_dup("smime.p7m");
1119 b_enc->filename = outfile;
1120 b_enc->unlink = true; /* delete after sending the message */
1121 b_enc->parts = 0;
1122 b_enc->next = 0;
1123
1124 return b_enc;
1125}
1126
1140static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key,
1141 int idx, struct State *state, gpgme_signature_t sig)
1142{
1143 if (!key)
1144 return 1;
1145
1146 bool severe = false;
1147
1148 if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1149 {
1150 state_puts(state, _("Warning: One of the keys has been revoked\n"));
1151 severe = true;
1152 }
1153
1154 if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1155 {
1156 time_t at = (key->subkeys && key->subkeys->expires) ? key->subkeys->expires : 0;
1157 if (at)
1158 {
1159 state_puts(state, _("Warning: The key used to create the signature expired at: "));
1160 print_time(at, state);
1161 state_puts(state, "\n");
1162 }
1163 else
1164 {
1165 state_puts(state, _("Warning: At least one certification key has expired\n"));
1166 }
1167 }
1168
1169 if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1170 {
1171 gpgme_signature_t sig2 = NULL;
1172 unsigned int i;
1173
1174 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1175
1176 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1177 ; // do nothing
1178
1179 state_puts(state, _("Warning: The signature expired at: "));
1180 print_time(sig2 ? sig2->exp_timestamp : 0, state);
1181 state_puts(state, "\n");
1182 }
1183
1184 if ((sum & GPGME_SIGSUM_KEY_MISSING))
1185 {
1186 state_puts(state, _("Can't verify due to a missing key or certificate\n"));
1187 }
1188
1189 if ((sum & GPGME_SIGSUM_CRL_MISSING))
1190 {
1191 state_puts(state, _("The CRL is not available\n"));
1192 severe = true;
1193 }
1194
1195 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1196 {
1197 state_puts(state, _("Available CRL is too old\n"));
1198 severe = true;
1199 }
1200
1201 if ((sum & GPGME_SIGSUM_BAD_POLICY))
1202 state_puts(state, _("A policy requirement was not met\n"));
1203
1204 if ((sum & GPGME_SIGSUM_SYS_ERROR))
1205 {
1206 const char *t0 = NULL;
1207 const char *t1 = NULL;
1208 gpgme_verify_result_t result = NULL;
1209 gpgme_signature_t sig2 = NULL;
1210 unsigned int i;
1211
1212 state_puts(state, _("A system error occurred"));
1213
1214 /* Try to figure out some more detailed system error information. */
1215 result = gpgme_op_verify_result(ctx);
1216 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1217 ; // do nothing
1218
1219 if (sig2)
1220 {
1221 t0 = "";
1222 t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1223 }
1224
1225 if (t0 || t1)
1226 {
1227 state_puts(state, ": ");
1228 if (t0)
1229 state_puts(state, t0);
1230 if (t1 && !(t0 && (mutt_str_equal(t0, t1))))
1231 {
1232 if (t0)
1233 state_puts(state, ",");
1234 state_puts(state, t1);
1235 }
1236 }
1237 state_puts(state, "\n");
1238 }
1239
1240 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1241 if (c_crypt_use_pka)
1242 {
1243 if ((sig->pka_trust == 1) && sig->pka_address)
1244 {
1245 state_puts(state, _("WARNING: PKA entry does not match signer's address: "));
1246 state_puts(state, sig->pka_address);
1247 state_puts(state, "\n");
1248 }
1249 else if ((sig->pka_trust == 2) && sig->pka_address)
1250 {
1251 state_puts(state, _("PKA verified signer's address is: "));
1252 state_puts(state, sig->pka_address);
1253 state_puts(state, "\n");
1254 }
1255 }
1256
1257 return severe;
1258}
1259
1265static void show_fingerprint(gpgme_key_t key, struct State *state)
1266{
1267 if (!key)
1268 return;
1269
1270 const char *prefix = _("Fingerprint: ");
1271
1272 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1273 if (!s)
1274 return;
1275 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1276
1277 char *buf = MUTT_MEM_MALLOC(strlen(prefix) + strlen(s) * 4 + 2, char);
1278 strcpy(buf, prefix);
1279 char *p = buf + strlen(buf);
1280 if (is_pgp && (strlen(s) == 40))
1281 { /* PGP v4 style formatted. */
1282 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1283 {
1284 *p++ = s[0];
1285 *p++ = s[1];
1286 *p++ = s[2];
1287 *p++ = s[3];
1288 *p++ = ' ';
1289 if (i == 4)
1290 *p++ = ' ';
1291 }
1292 }
1293 else
1294 {
1295 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1296 {
1297 *p++ = s[0];
1298 *p++ = s[1];
1299 *p++ = is_pgp ? ' ' : ':';
1300 if (is_pgp && (i == 7))
1301 *p++ = ' ';
1302 }
1303 }
1304
1305 /* just in case print remaining odd digits */
1306 for (; *s; s++)
1307 *p++ = *s;
1308 *p++ = '\n';
1309 *p = '\0';
1310 state_puts(state, buf);
1311 FREE(&buf);
1312}
1313
1320static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
1321{
1322 gpgme_signature_t sig = NULL;
1323 const char *txt = NULL;
1324
1325 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1326 if (result)
1327 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1328 ; // do nothing
1329
1330 switch (sig ? sig->validity : 0)
1331 {
1332 case GPGME_VALIDITY_UNKNOWN:
1333 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1334 break;
1335 case GPGME_VALIDITY_UNDEFINED:
1336 break;
1337 case GPGME_VALIDITY_NEVER:
1338 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1339 break;
1340 case GPGME_VALIDITY_MARGINAL:
1341 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1342 break;
1343 case GPGME_VALIDITY_FULL:
1344 case GPGME_VALIDITY_ULTIMATE:
1345 txt = NULL;
1346 break;
1347 }
1348 if (txt)
1349 state_puts(state, txt);
1350}
1351
1359static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig,
1360 gpgme_key_t key, struct State *state)
1361{
1362 int msgwid;
1363
1364 state_puts(state, msg);
1365 state_puts(state, " ");
1366 /* key is NULL when not present in the user's keyring */
1367 if (key)
1368 {
1369 bool aka = false;
1370 for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1371 {
1372 if (uids->revoked)
1373 continue;
1374 if (aka)
1375 {
1376 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1377 if (msgwid < 0)
1378 msgwid = 0;
1379 for (int i = 0; i < msgwid; i++)
1380 state_puts(state, " ");
1381 state_puts(state, _("aka: "));
1382 }
1383 state_puts(state, uids->uid);
1384 state_puts(state, "\n");
1385
1386 aka = true;
1387 }
1388 }
1389 else
1390 {
1391 if (sig->fpr)
1392 {
1393 state_puts(state, _("KeyID "));
1394 state_puts(state, sig->fpr);
1395 }
1396 else
1397 {
1398 /* L10N: You will see this message in place of "KeyID "
1399 if the S/MIME key has no ID. This is quite an error. */
1400 state_puts(state, _("no signature fingerprint available"));
1401 }
1402 state_puts(state, "\n");
1403 }
1404
1405 /* timestamp is 0 when verification failed.
1406 * "Jan 1 1970" is not the created date. */
1407 if (sig->timestamp)
1408 {
1409 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1410 if (msgwid < 0)
1411 msgwid = 0;
1412 for (int i = 0; i < msgwid; i++)
1413 state_puts(state, " ");
1414 state_puts(state, _("created: "));
1415 print_time(sig->timestamp, state);
1416 state_puts(state, "\n");
1417 }
1418}
1419
1425static void show_one_recipient(struct State *state, gpgme_recipient_t r)
1426{
1427 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1428 if (!algo)
1429 algo = "?";
1430
1431 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1432 // Recipient: RSA key, ID 1111111111111111
1433 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1434}
1435
1441static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
1442{
1443 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1444 return;
1445
1446 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1447
1448 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1449 show_one_recipient(state, r);
1450
1451 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1452}
1453
1466static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
1467{
1469 const char *fpr = NULL;
1470 gpgme_key_t key = NULL;
1471 bool anybad = false, anywarn = false;
1472 gpgme_signature_t sig = NULL;
1473 gpgme_error_t err = GPG_ERR_NO_ERROR;
1474
1475 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1476 if (result)
1477 {
1478 /* FIXME: this code should use a static variable and remember
1479 * the current position in the list of signatures, IMHO.
1480 * -moritz. */
1481 int i;
1482 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1483 ; // do nothing
1484
1485 if (!sig)
1486 return -1; /* Signature not found. */
1487
1488 if ((gpgme_key_t) mod_data->signature_key)
1489 {
1490 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
1491 mod_data->signature_key = NULL;
1492 }
1493
1494 fpr = sig->fpr;
1495 const unsigned int sum = sig->summary;
1496
1497 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1498 anybad = true;
1499
1500 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1501 {
1502 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1503 if (err == GPG_ERR_NO_ERROR)
1504 {
1505 /* Only cache the signer key for S/MIME sender verification.
1506 * (For OpenPGP, this cached key isn't used and would leak if left set.) */
1507 if (!mod_data->signature_key && key && (key->protocol == GPGME_PROTOCOL_CMS))
1508 mod_data->signature_key = key;
1509 }
1510 else
1511 {
1512 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1513 error. Do it here to avoid a double free. */
1514 }
1515 }
1516 else
1517 {
1518 /* pubkey not present */
1519 }
1520
1521 if (!state || !state->fp_out || !(state->flags & STATE_DISPLAY))
1522 {
1523 ; /* No state information so no way to print anything. */
1524 }
1525 else if (err != GPG_ERR_NO_ERROR)
1526 {
1527 char buf[1024] = { 0 };
1528 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1529 fpr, gpgme_strerror(err));
1530 state_puts(state, buf);
1531 anybad = true;
1532 }
1533 else if ((sum & GPGME_SIGSUM_GREEN))
1534 {
1535 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1536 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1537 anywarn = true;
1538 show_one_sig_validity(ctx, idx, state);
1539 }
1540 else if ((sum & GPGME_SIGSUM_RED))
1541 {
1542 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, state);
1543 show_sig_summary(sum, ctx, key, idx, state, sig);
1544 }
1545 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1546 { /* We can't decide (yellow) but this is a PGP key with a good
1547 signature, so we display what a PGP user expects: The name,
1548 fingerprint and the key validity (which is neither fully or
1549 ultimate). */
1550 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1551 show_one_sig_validity(ctx, idx, state);
1552 show_fingerprint(key, state);
1553 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1554 anywarn = true;
1555 }
1556 else /* can't decide (yellow) */
1557 {
1558 print_smime_keyinfo(_("Problem signature from:"), sig, key, state);
1559 /* 0 indicates no expiration */
1560 if (sig->exp_timestamp)
1561 {
1562 /* L10N: This is trying to match the width of the
1563 "Problem signature from:" translation just above. */
1564 state_puts(state, _(" expires: "));
1565 print_time(sig->exp_timestamp, state);
1566 state_puts(state, "\n");
1567 }
1568 show_sig_summary(sum, ctx, key, idx, state, sig);
1569 anywarn = true;
1570 }
1571
1572 if (key != (gpgme_key_t) mod_data->signature_key)
1573 gpgme_key_unref(key);
1574 }
1575
1576 return anybad ? 1 : anywarn ? 2 : 0;
1577}
1578
1592static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
1593{
1595 int badsig = -1;
1596 int anywarn = 0;
1597 gpgme_ctx_t ctx = NULL;
1598 gpgme_data_t message = NULL;
1599
1600 gpgme_data_t signature = file_to_data_object(state->fp_in, b->offset, b->length);
1601 if (!signature)
1602 return -1;
1603
1604 /* We need to tell GPGME about the encoding because the backend can't
1605 * auto-detect plain base-64 encoding which is used by S/MIME. */
1606 if (is_smime)
1607 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1608
1609 gpgme_error_t err = gpgme_data_new_from_file(&message, tempfile, 1);
1610 if (err != GPG_ERR_NO_ERROR)
1611 {
1612 gpgme_data_release(signature);
1613 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1614 return -1;
1615 }
1616 ctx = create_gpgme_context(is_smime);
1617
1618 /* Note: We don't need a current time output because GPGME avoids
1619 * such an attack by separating the meta information from the data. */
1620 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1621
1622 err = gpgme_op_verify(ctx, signature, message, NULL);
1623 gpgme_data_release(message);
1624 gpgme_data_release(signature);
1625
1626 redraw_if_needed(ctx);
1627 if (err != GPG_ERR_NO_ERROR)
1628 {
1629 char buf[200] = { 0 };
1630
1631 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1632 gpgme_strerror(err));
1633 state_puts(state, buf);
1634 }
1635 else
1636 { /* Verification succeeded, see what the result is. */
1637 gpgme_verify_result_t verify_result = NULL;
1638
1639 if ((gpgme_key_t) mod_data->signature_key)
1640 {
1641 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
1642 mod_data->signature_key = NULL;
1643 }
1644
1645 verify_result = gpgme_op_verify_result(ctx);
1646 if (verify_result && verify_result->signatures)
1647 {
1648 bool anybad = false;
1649 int res;
1650 for (int idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1651 {
1652 if (res == 1)
1653 anybad = true;
1654 else if (res == 2)
1655 anywarn = 2;
1656 }
1657 if (!anybad)
1658 badsig = 0;
1659 }
1660 }
1661
1662 if (badsig == 0)
1663 {
1664 gpgme_verify_result_t result = NULL;
1665 gpgme_sig_notation_t notation = NULL;
1666 gpgme_signature_t sig = NULL;
1667
1668 result = gpgme_op_verify_result(ctx);
1669 if (result)
1670 {
1671 for (sig = result->signatures; sig; sig = sig->next)
1672 {
1673 int non_pka_notations = 0;
1674 for (notation = sig->notations; notation; notation = notation->next)
1675 if (!is_pka_notation(notation))
1676 non_pka_notations++;
1677
1678 if (non_pka_notations)
1679 {
1680 char buf[128] = { 0 };
1681 snprintf(buf, sizeof(buf),
1682 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1683 state_puts(state, buf);
1684 for (notation = sig->notations; notation; notation = notation->next)
1685 {
1686 if (is_pka_notation(notation))
1687 continue;
1688
1689 if (notation->name)
1690 {
1691 state_puts(state, notation->name);
1692 state_puts(state, "=");
1693 }
1694 if (notation->value)
1695 {
1696 state_puts(state, notation->value);
1697 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1698 state_puts(state, "\n");
1699 }
1700 }
1701 state_puts(state, _("*** End Notation ***\n"));
1702 }
1703 }
1704 }
1705 }
1706
1707 gpgme_release(ctx);
1708
1709 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1710 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1711
1712 return badsig ? 1 : anywarn ? 2 : 0;
1713}
1714
1718int pgp_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1719{
1720 return verify_one(b, state, tempfile, false);
1721}
1722
1726int smime_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1727{
1728 return verify_one(b, state, tempfile, true);
1729}
1730
1744static struct Body *decrypt_part(struct Body *b, struct State *state,
1745 FILE *fp_out, bool is_smime, int *r_is_signed)
1746{
1747 if (!b || !state || !fp_out)
1748 return NULL;
1749
1750 struct Body *tattach = NULL;
1751 gpgme_error_t err = GPG_ERR_NO_ERROR;
1752 gpgme_data_t ciphertext = NULL;
1753 gpgme_data_t plaintext = NULL;
1754 gpgme_decrypt_result_t result = NULL;
1755 bool maybe_signed = false;
1756 bool anywarn = false;
1757 int sig_stat = 0;
1758
1759 if (r_is_signed)
1760 *r_is_signed = 0;
1761
1762 gpgme_ctx_t ctx = NULL;
1763restart:
1764 ctx = create_gpgme_context(is_smime);
1765
1766 if (b->length < 0)
1767 return NULL;
1768 /* Make a data object from the body, create context etc. */
1769 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1770 if (!ciphertext)
1771 goto cleanup;
1772 plaintext = create_gpgme_data();
1773
1774 /* Do the decryption or the verification in case of the S/MIME hack. */
1775 if ((!is_smime) || maybe_signed)
1776 {
1777 if (!is_smime)
1778 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1779 else if (maybe_signed)
1780 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1781
1782 if (err == GPG_ERR_NO_ERROR)
1783 {
1784 /* Check whether signatures have been verified. */
1785 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1786 if (verify_result->signatures)
1787 sig_stat = 1;
1788 }
1789 }
1790 else
1791 {
1792 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1793 }
1794 gpgme_data_release(ciphertext);
1795 ciphertext = NULL;
1796
1797#ifdef USE_AUTOCRYPT
1798 // Abort right away and silently. Autocrypt will retry on the normal keyring.
1799 if (OptAutocryptGpgme && (err != GPG_ERR_NO_ERROR))
1800 goto cleanup;
1801#endif
1802
1803 result = gpgme_op_decrypt_result(ctx);
1804 if (result && (state->flags & STATE_DISPLAY))
1805 show_encryption_info(state, result);
1806
1807 if (err != GPG_ERR_NO_ERROR)
1808 {
1809 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1810 {
1811 /* Check whether this might be a signed message despite what the mime
1812 * header told us. Retry then. gpgsm returns the error information
1813 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1814 * algorithm, thus we test that it has not been set. */
1815 if (result && !result->unsupported_algorithm)
1816 {
1817 maybe_signed = true;
1818 gpgme_data_release(plaintext);
1819 plaintext = NULL;
1820 /* gpgsm ends the session after an error; restart it */
1821 gpgme_release(ctx);
1822 goto restart;
1823 }
1824 }
1825 redraw_if_needed(ctx);
1826 if ((state->flags & STATE_DISPLAY))
1827 {
1828 char buf[200] = { 0 };
1829
1830 snprintf(buf, sizeof(buf) - 1,
1831 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1832 state_attach_puts(state, buf);
1833 }
1834 goto cleanup;
1835 }
1836 redraw_if_needed(ctx);
1837
1838 /* Read the output from GPGME, and make sure to change CRLF to LF,
1839 * otherwise read_mime_header has a hard time parsing the message. */
1840 if (data_object_to_stream(plaintext, fp_out))
1841 {
1842 goto cleanup;
1843 }
1844 gpgme_data_release(plaintext);
1845 plaintext = NULL;
1846
1847 if (sig_stat)
1848 {
1849 int res;
1850 int idx;
1851 int anybad = 0;
1852
1853 if (r_is_signed)
1854 *r_is_signed = -1; /* A signature exists. */
1855
1856 if ((state->flags & STATE_DISPLAY))
1857 {
1858 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1859 }
1860 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1861 {
1862 if (res == 1)
1863 anybad = 1;
1864 else if (res == 2)
1865 anywarn = true;
1866 }
1867 if (!anybad && idx && r_is_signed && *r_is_signed)
1868 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1869
1870 if ((state->flags & STATE_DISPLAY))
1871 {
1872 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1873 }
1874 }
1875 gpgme_release(ctx);
1876 ctx = NULL;
1877
1878 fflush(fp_out);
1879 rewind(fp_out);
1880 const long size = mutt_file_get_size_fp(fp_out);
1881 if (size == 0)
1882 {
1883 goto cleanup;
1884 }
1885 tattach = mutt_read_mime_header(fp_out, 0);
1886 if (tattach)
1887 {
1888 /* Need to set the length of this body part. */
1889 tattach->length = size - tattach->offset;
1890
1891 tattach->warnsig = anywarn;
1892
1893 /* See if we need to recurse on this MIME part. */
1894 mutt_parse_part(fp_out, tattach);
1895 }
1896
1897cleanup:
1898 gpgme_data_release(ciphertext);
1899 gpgme_data_release(plaintext);
1900 gpgme_release(ctx);
1901
1902 return tattach;
1903}
1904
1908int pgp_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1909{
1910 struct State state = { 0 };
1911 struct Body *first_part = b;
1912 int is_signed = 0;
1913 bool need_decode = false;
1914 LOFF_T saved_offset = 0;
1915 size_t saved_length = 0;
1916 FILE *fp_decoded = NULL;
1917 int rc = 0;
1918
1919 first_part->goodsig = false;
1920 first_part->warnsig = false;
1921
1923 {
1924 b = b->parts->next;
1925 /* Some clients improperly encode the octetstream part. */
1926 if (b->encoding != ENC_7BIT)
1927 need_decode = true;
1928 }
1930 {
1931 b = b->parts->next->next;
1932 need_decode = true;
1933 }
1934 else
1935 {
1936 return -1;
1937 }
1938
1939 state.fp_in = fp_in;
1940
1941 if (need_decode)
1942 {
1943 saved_offset = b->offset;
1944 saved_length = b->length;
1945
1946 fp_decoded = mutt_file_mkstemp();
1947 if (!fp_decoded)
1948 {
1949 mutt_perror(_("Can't create temporary file"));
1950 return -1;
1951 }
1952
1953 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1954 {
1955 rc = -1;
1956 goto bail;
1957 }
1958 state.fp_out = fp_decoded;
1959
1960 mutt_decode_attachment(b, &state);
1961
1962 fflush(fp_decoded);
1963 b->length = ftello(fp_decoded);
1964 b->offset = 0;
1965 rewind(fp_decoded);
1966 state.fp_in = fp_decoded;
1967 state.fp_out = 0;
1968 }
1969
1970 *fp_out = mutt_file_mkstemp();
1971 if (!*fp_out)
1972 {
1973 mutt_perror(_("Can't create temporary file"));
1974 rc = -1;
1975 goto bail;
1976 }
1977
1978 *b_dec = decrypt_part(b, &state, *fp_out, false, &is_signed);
1979 if (*b_dec)
1980 {
1981 rewind(*fp_out);
1982 if (is_signed > 0)
1983 first_part->goodsig = true;
1984 }
1985 else
1986 {
1987 rc = -1;
1988 mutt_file_fclose(fp_out);
1989 }
1990
1991bail:
1992 if (need_decode)
1993 {
1994 b->length = saved_length;
1995 b->offset = saved_offset;
1996 mutt_file_fclose(&fp_decoded);
1997 }
1998
1999 return rc;
2000}
2001
2005int smime_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
2006{
2007 struct State state = { 0 };
2008 int is_signed = 0;
2009 LOFF_T saved_b_offset;
2010 size_t saved_b_length;
2011
2013 return -1;
2014
2015 if (b->parts)
2016 return -1;
2017
2018 /* Decode the body - we need to pass binary CMS to the
2019 * backend. The backend allows for Base64 encoded data but it does
2020 * not allow for QP which I have seen in some messages. So better
2021 * do it here. */
2022 saved_b_offset = b->offset;
2023 saved_b_length = b->length;
2024 state.fp_in = fp_in;
2025 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
2026 {
2027 return -1;
2028 }
2029 FILE *fp_tmp = mutt_file_mkstemp();
2030 if (!fp_tmp)
2031 {
2032 mutt_perror(_("Can't create temporary file"));
2033 return -1;
2034 }
2035
2036 state.fp_out = fp_tmp;
2037 mutt_decode_attachment(b, &state);
2038 fflush(fp_tmp);
2039 b->length = ftello(state.fp_out);
2040 b->offset = 0;
2041 rewind(fp_tmp);
2042
2043 memset(&state, 0, sizeof(state));
2044 state.fp_in = fp_tmp;
2045 state.fp_out = 0;
2047 if (!*fp_out)
2048 {
2049 mutt_perror(_("Can't create temporary file"));
2050 mutt_file_fclose(&fp_tmp);
2051 return -1;
2052 }
2053
2054 *b_dec = decrypt_part(b, &state, *fp_out, true, &is_signed);
2055 if (*b_dec)
2056 (*b_dec)->goodsig = is_signed > 0;
2057 b->length = saved_b_length;
2058 b->offset = saved_b_offset;
2059 mutt_file_fclose(&fp_tmp);
2060 rewind(*fp_out);
2061 if (*b_dec && !is_signed && !(*b_dec)->parts && mutt_is_application_smime(*b_dec))
2062 {
2063 /* Assume that this is a opaque signed s/mime message. This is an ugly way
2064 * of doing it but we have anyway a problem with arbitrary encoded S/MIME
2065 * messages: Only the outer part may be encrypted. The entire mime parsing
2066 * should be revamped, probably by keeping the temporary files so that we
2067 * don't need to decrypt them all the time. Inner parts of an encrypted
2068 * part can then point into this file and there won't ever be a need to
2069 * decrypt again. This needs a partial rewrite of the MIME engine. */
2070 struct Body *bb = *b_dec;
2071
2072 saved_b_offset = bb->offset;
2073 saved_b_length = bb->length;
2074 memset(&state, 0, sizeof(state));
2075 state.fp_in = *fp_out;
2076 if (!mutt_file_seek(state.fp_in, bb->offset, SEEK_SET))
2077 {
2078 return -1;
2079 }
2080 FILE *fp_tmp2 = mutt_file_mkstemp();
2081 if (!fp_tmp2)
2082 {
2083 mutt_perror(_("Can't create temporary file"));
2084 return -1;
2085 }
2086
2087 state.fp_out = fp_tmp2;
2088 mutt_decode_attachment(bb, &state);
2089 fflush(fp_tmp2);
2090 bb->length = ftello(state.fp_out);
2091 bb->offset = 0;
2092 rewind(fp_tmp2);
2093 mutt_file_fclose(fp_out);
2094
2095 memset(&state, 0, sizeof(state));
2096 state.fp_in = fp_tmp2;
2097 state.fp_out = 0;
2098 *fp_out = mutt_file_mkstemp();
2099 if (!*fp_out)
2100 {
2101 mutt_perror(_("Can't create temporary file"));
2102 mutt_file_fclose(&fp_tmp2);
2103 return -1;
2104 }
2105
2106 struct Body *b_tmp = decrypt_part(bb, &state, *fp_out, true, &is_signed);
2107 if (b_tmp)
2108 b_tmp->goodsig = is_signed > 0;
2109 bb->length = saved_b_length;
2110 bb->offset = saved_b_offset;
2111 mutt_file_fclose(&fp_tmp2);
2112 rewind(*fp_out);
2113 mutt_body_free(b_dec);
2114 *b_dec = b_tmp;
2115 }
2116 return *b_dec ? 0 : -1;
2117}
2118
2126static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
2127{
2128 gpgme_ctx_t tmpctx = NULL;
2129 gpgme_key_t key = NULL;
2130 gpgme_user_id_t uid = NULL;
2131 gpgme_subkey_t subkey = NULL;
2132 const char *shortid = NULL;
2133 size_t len;
2134 char date[256] = { 0 };
2135 bool more;
2136 int rc = -1;
2137 time_t tt;
2138
2139 *fp = mutt_file_mkstemp();
2140 if (!*fp)
2141 {
2142 mutt_perror(_("Can't create temporary file"));
2143 return -1;
2144 }
2145
2146 tmpctx = create_gpgme_context(false);
2147
2148 gpgme_error_t err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2149 while (err == GPG_ERR_NO_ERROR)
2150 {
2151 err = gpgme_op_keylist_next(tmpctx, &key);
2152 if (err != GPG_ERR_NO_ERROR)
2153 break;
2154 uid = key->uids;
2155 subkey = key->subkeys;
2156 more = false;
2157 while (subkey)
2158 {
2159 shortid = subkey->keyid;
2160 len = mutt_str_len(subkey->keyid);
2161 if (len > 8)
2162 shortid += len - 8;
2163 tt = subkey->timestamp;
2164 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2165
2166 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2167 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2168 if (!more)
2169 {
2170 while (uid)
2171 {
2172 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2173 uid = uid->next;
2174 }
2175 }
2176 subkey = subkey->next;
2177 more = true;
2178 }
2179 gpgme_key_unref(key);
2180 }
2181 if (gpg_err_code(err) != GPG_ERR_EOF)
2182 {
2183 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2184 goto err_fp;
2185 }
2186
2187 rc = 0;
2188
2189err_fp:
2190 if (rc)
2191 mutt_file_fclose(fp);
2192
2193 gpgme_release(tmpctx);
2194
2195 return rc;
2196}
2197
2209static int line_compare(const char *a, size_t n, const char *b)
2210{
2211 if (mutt_strn_equal(a, b, n))
2212 {
2213 /* at this point we know that 'b' is at least 'n' chars long */
2214 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2215 return true;
2216 }
2217 return false;
2218}
2219
2227static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
2228{
2229 char buf[8192] = { 0 };
2230 bool rc = false;
2231
2232 bool sgn = false;
2233 bool enc = false;
2234
2235 if (b->type != TYPE_TEXT)
2236 return 0;
2237
2238 struct Buffer *tempfile = buf_pool_get();
2239 buf_mktemp(tempfile);
2241 {
2242 unlink(buf_string(tempfile));
2243 goto cleanup;
2244 }
2245
2246 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2247 if (!fp_tmp)
2248 {
2249 unlink(buf_string(tempfile));
2250 goto cleanup;
2251 }
2252
2253 while (fgets(buf, sizeof(buf), fp_tmp))
2254 {
2255 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2256 if (plen != 0)
2257 {
2258 if (MESSAGE(buf + plen))
2259 {
2260 enc = true;
2261 break;
2262 }
2263 else if (SIGNED_MESSAGE(buf + plen))
2264 {
2265 sgn = true;
2266 break;
2267 }
2268 }
2269 }
2270 mutt_file_fclose(&fp_tmp);
2271 unlink(buf_string(tempfile));
2272
2273 if (!enc && !sgn)
2274 goto cleanup;
2275
2276 /* fix the content type */
2277
2278 mutt_param_set(&b->parameter, "format", "fixed");
2279 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2280
2281 rc = true;
2282
2283cleanup:
2284 buf_pool_release(&tempfile);
2285 return rc;
2286}
2287
2291bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2292{
2293 bool rc = false;
2294 for (; b; b = b->next)
2295 {
2296 if (!just_one && is_multipart(b))
2297 {
2298 rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2299 }
2300 else if (b->type == TYPE_TEXT)
2301 {
2303 if (r)
2304 rc = (rc || r);
2305 else
2306 rc = (pgp_check_traditional_one_body(fp, b) || rc);
2307 }
2308
2309 if (just_one)
2310 break;
2311 }
2312 return rc;
2313}
2314
2318void pgp_gpgme_invoke_import(const char *fname)
2319{
2320 gpgme_ctx_t ctx = create_gpgme_context(false);
2321 gpgme_data_t keydata = NULL;
2322 gpgme_import_result_t impres = NULL;
2323 gpgme_import_status_t st = NULL;
2324 bool any;
2325
2326 FILE *fp_in = mutt_file_fopen(fname, "r");
2327 if (!fp_in)
2328 {
2329 mutt_perror("%s", fname);
2330 goto leave;
2331 }
2332 /* Note that the stream, "fp_in", needs to be kept open while the keydata
2333 * is used. */
2334 gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2335 if (err != GPG_ERR_NO_ERROR)
2336 {
2337 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2338 goto leave;
2339 }
2340
2341 err = gpgme_op_import(ctx, keydata);
2342 if (err != GPG_ERR_NO_ERROR)
2343 {
2344 mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2345 goto leave;
2346 }
2347
2348 /* Print infos about the imported keys to stdout. */
2349 impres = gpgme_op_import_result(ctx);
2350 if (!impres)
2351 {
2352 fputs("oops: no import result returned\n", stdout);
2353 goto leave;
2354 }
2355
2356 for (st = impres->imports; st; st = st->next)
2357 {
2358 if (st->result)
2359 continue;
2360 printf("key %s imported (", NONULL(st->fpr));
2361 /* Note that we use the singular even if it is possible that
2362 * several uids etc are new. This simply looks better. */
2363 any = false;
2364 if (st->status & GPGME_IMPORT_SECRET)
2365 {
2366 printf("secret parts");
2367 any = true;
2368 }
2369 if ((st->status & GPGME_IMPORT_NEW))
2370 {
2371 printf("%snew key", any ? ", " : "");
2372 any = true;
2373 }
2374 if ((st->status & GPGME_IMPORT_UID))
2375 {
2376 printf("%snew uid", any ? ", " : "");
2377 any = true;
2378 }
2379 if ((st->status & GPGME_IMPORT_SIG))
2380 {
2381 printf("%snew sig", any ? ", " : "");
2382 any = true;
2383 }
2384 if ((st->status & GPGME_IMPORT_SUBKEY))
2385 {
2386 printf("%snew subkey", any ? ", " : "");
2387 any = true;
2388 }
2389 printf("%s)\n", any ? "" : "not changed");
2390 /* Fixme: Should we lookup each imported key and print more infos? */
2391 }
2392 /* Now print keys which failed the import. Unfortunately in most
2393 * cases gpg will bail out early and not tell GPGME about. */
2394 /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2395 * the actual gpg diagnostics. But I fear that would clutter the
2396 * output too much. Maybe a dedicated prompt or option to do this
2397 * would be helpful. */
2398 for (st = impres->imports; st; st = st->next)
2399 {
2400 if (st->result == 0)
2401 continue;
2402 printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2403 }
2404 fflush(stdout);
2405
2406leave:
2407 gpgme_release(ctx);
2408 gpgme_data_release(keydata);
2409 mutt_file_fclose(&fp_in);
2410}
2411
2427static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
2428{
2429 char buf[8192] = { 0 };
2430 bool complete, armor_header;
2431 FILE *fp = NULL;
2432
2433 char *fname = data_object_to_tempfile(data, &fp);
2434 if (!fname)
2435 {
2436 mutt_file_fclose(&fp);
2437 return;
2438 }
2439 unlink(fname);
2440 FREE(&fname);
2441
2442 /* fromcode comes from the MIME Content-Type charset label. It might
2443 * be a wrong label, so we want the ability to do corrections via
2444 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2446
2447 for (complete = true, armor_header = true;
2448 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2449 {
2450 if (!complete)
2451 {
2452 if (!armor_header)
2453 state_puts(state, buf);
2454 continue;
2455 }
2456
2457 if (BEGIN_PGP_SIGNATURE(buf))
2458 break;
2459
2460 if (armor_header)
2461 {
2462 if (buf[0] == '\n')
2463 armor_header = false;
2464 continue;
2465 }
2466
2467 if (state->prefix)
2468 state_puts(state, state->prefix);
2469
2470 if ((buf[0] == '-') && (buf[1] == ' '))
2471 state_puts(state, buf + 2);
2472 else
2473 state_puts(state, buf);
2474 }
2475
2478}
2479
2483int pgp_gpgme_application_handler(struct Body *b, struct State *state)
2484{
2485 int needpass = -1;
2486 bool pgp_keyblock = false;
2487 bool clearsign = false;
2488 long bytes;
2489 LOFF_T last_pos;
2490 LOFF_T block_begin;
2491 LOFF_T block_end;
2492 char buf[8192] = { 0 };
2493 FILE *fp_out = NULL;
2494
2495 gpgme_error_t err = GPG_ERR_NO_ERROR;
2496 gpgme_data_t armored_data = NULL;
2497
2498 bool maybe_goodsig = true;
2499 bool have_any_sigs = false;
2500
2501 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2502 char *gpgcharset = NULL;
2503
2504 mutt_debug(LL_DEBUG2, "Entering handler\n");
2505
2506 /* For clearsigned messages we won't be able to get a character set
2507 * but we know that this may only be text thus we assume Latin-1 here. */
2508 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2509 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2510
2511 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2512 {
2513 return -1;
2514 }
2515 last_pos = b->offset;
2516
2517 for (bytes = b->length; bytes > 0;)
2518 {
2519 // record before the fgets in case it is a BEGIN block
2520 block_begin = last_pos;
2521
2522 if (!fgets(buf, sizeof(buf), state->fp_in))
2523 break;
2524
2525 LOFF_T offset = ftello(state->fp_in);
2526 if (offset < 0)
2527 {
2528 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2529 offset = 0;
2530 }
2531 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2532 last_pos = offset;
2533
2534 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2535 if (plen != 0)
2536 {
2537 needpass = 0;
2538 clearsign = false;
2539 pgp_keyblock = false;
2540
2541 if (MESSAGE(buf + plen))
2542 {
2543 needpass = 1;
2544 }
2545 else if (SIGNED_MESSAGE(buf + plen))
2546 {
2547 clearsign = true;
2548 }
2549 else if (PUBLIC_KEY_BLOCK(buf + plen))
2550 {
2551 pgp_keyblock = true;
2552 }
2553 else
2554 {
2555 /* XXX we may wish to recode here */
2556 if (state->prefix)
2557 state_puts(state, state->prefix);
2558 state_puts(state, buf);
2559 continue;
2560 }
2561
2562 /* Find the end of armored block. */
2563 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2564 {
2565 offset = ftello(state->fp_in);
2566 if (offset < 0)
2567 {
2568 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2569 offset = 0;
2570 }
2571 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2572 last_pos = offset;
2573
2574 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2575 {
2576 break;
2577 }
2578
2579 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2580 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2581 {
2582 break;
2583 }
2584
2585 // remember optional Charset: armor header as defined by rfc4880
2586 if (mutt_strn_equal("Charset: ", buf, 9))
2587 {
2588 size_t l = 0;
2589 FREE(&gpgcharset);
2590 gpgcharset = mutt_str_dup(buf + 9);
2591 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2592 gpgcharset[l - 1] = 0;
2593 if (!mutt_ch_check_charset(gpgcharset, 0))
2594 mutt_str_replace(&gpgcharset, "UTF-8");
2595 }
2596 }
2597 block_end = ftello(state->fp_in);
2598 if (block_end < 0)
2599 {
2600 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2601 block_end = 0;
2602 }
2603
2604 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2605
2606 /* Copy PGP material to an data container */
2607 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2608 fseeko(state->fp_in, block_end, 0);
2609
2610 /* Invoke PGP if needed */
2611 if (pgp_keyblock)
2612 {
2613 pgp_gpgme_extract_keys(armored_data, &fp_out);
2614 }
2615 else if (!clearsign || (state->flags & STATE_VERIFY))
2616 {
2617 gpgme_data_t plaintext = create_gpgme_data();
2618 gpgme_ctx_t ctx = create_gpgme_context(false);
2619
2620 if (clearsign)
2621 {
2622 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2623 }
2624 else
2625 {
2626 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2627 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2628 {
2629 /* Decrypt verify can't handle signed only messages. */
2630 gpgme_data_seek(armored_data, 0, SEEK_SET);
2631 /* Must release plaintext so that we supply an uninitialized object. */
2632 gpgme_data_release(plaintext);
2633 plaintext = create_gpgme_data();
2634 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2635 }
2636 }
2637 redraw_if_needed(ctx);
2638
2639 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2640 if (result && (state->flags & STATE_DISPLAY))
2641 show_encryption_info(state, result);
2642
2643 if (err != GPG_ERR_NO_ERROR)
2644 {
2645 char errbuf[200] = { 0 };
2646
2647 snprintf(errbuf, sizeof(errbuf) - 1,
2648 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2649 state_puts(state, errbuf);
2650 }
2651 else
2652 {
2653 /* Decryption/Verification succeeded */
2654
2655 mutt_message(_("PGP message successfully decrypted"));
2656
2657 bool sig_stat = false;
2658 char *tmpfname = NULL;
2659
2660 /* Check whether signatures have been verified. */
2661 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2662 if (verify_result->signatures)
2663 sig_stat = true;
2664
2665 have_any_sigs = false;
2666 maybe_goodsig = false;
2667 if ((state->flags & STATE_DISPLAY) && sig_stat)
2668 {
2669 int res;
2670 int idx;
2671 bool anybad = false;
2672
2673 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2674 have_any_sigs = true;
2675 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2676 {
2677 if (res == 1)
2678 anybad = true;
2679 }
2680 if (!anybad && idx)
2681 maybe_goodsig = true;
2682
2683 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2684 }
2685
2686 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2687 if (tmpfname)
2688 {
2689 unlink(tmpfname);
2690 FREE(&tmpfname);
2691 }
2692 else
2693 {
2694 mutt_file_fclose(&fp_out);
2695 state_puts(state, _("Error: copy data failed\n"));
2696 }
2697 }
2698 gpgme_data_release(plaintext);
2699 gpgme_release(ctx);
2700 }
2701
2702 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2703 * outputs utf-8 cleartext. This may not always be true, but it
2704 * seems to be a reasonable guess. */
2705 if (state->flags & STATE_DISPLAY)
2706 {
2707 if (needpass)
2708 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2709 else if (pgp_keyblock)
2710 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2711 else
2712 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2713 }
2714
2715 if (clearsign)
2716 {
2717 copy_clearsigned(armored_data, state, body_charset);
2718 }
2719 else if (fp_out)
2720 {
2721 int c;
2722 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2723 rewind(fp_out);
2724 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2726 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2727 {
2728 state_putc(state, c);
2729 if ((c == '\n') && state->prefix)
2730 state_puts(state, state->prefix);
2731 }
2733 }
2734
2735 if (state->flags & STATE_DISPLAY)
2736 {
2737 state_putc(state, '\n');
2738 if (needpass)
2739 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2740 else if (pgp_keyblock)
2741 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2742 else
2743 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2744 }
2745
2746 // Multiple PGP blocks can exist, so clean these up in each loop
2747 gpgme_data_release(armored_data);
2748 mutt_file_fclose(&fp_out);
2749 }
2750 else
2751 {
2752 /* A traditional PGP part may mix signed and unsigned content */
2753 /* XXX we may wish to recode here */
2754 if (state->prefix)
2755 state_puts(state, state->prefix);
2756 state_puts(state, buf);
2757 }
2758 }
2759 FREE(&gpgcharset);
2760
2761 b->goodsig = (maybe_goodsig && have_any_sigs);
2762
2763 if (needpass == -1)
2764 {
2765 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2766 return 1;
2767 }
2768 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2769
2770 return err;
2771}
2772
2779int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
2780{
2781 int is_signed = 0;
2782 int rc = 0;
2783
2784 mutt_debug(LL_DEBUG2, "Entering handler\n");
2785
2786 FILE *fp_out = mutt_file_mkstemp();
2787 if (!fp_out)
2788 {
2789 mutt_perror(_("Can't create temporary file"));
2790 if (state->flags & STATE_DISPLAY)
2791 {
2792 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2793 }
2794 return -1;
2795 }
2796
2797 struct Body *tattach = decrypt_part(b, state, fp_out, false, &is_signed);
2798 if (tattach)
2799 {
2800 tattach->goodsig = is_signed > 0;
2801
2802 if (state->flags & STATE_DISPLAY)
2803 {
2804 state_attach_puts(state, is_signed ?
2805 _("[-- The following data is PGP/MIME signed and encrypted --]\n") :
2806 _("[-- The following data is PGP/MIME encrypted --]\n"));
2807 mutt_protected_headers_handler(tattach, state);
2808 }
2809
2810 /* Store any protected headers in the parent so they can be
2811 * accessed for index updates after the handler recursion is done.
2812 * This is done before the handler to prevent a nested encrypted
2813 * handler from freeing the headers. */
2815 b->mime_headers = tattach->mime_headers;
2816 tattach->mime_headers = NULL;
2817
2818 FILE *fp_save = state->fp_in;
2819 state->fp_in = fp_out;
2820 rc = mutt_body_handler(tattach, state);
2821 state->fp_in = fp_save;
2822
2823 /* Embedded multipart signed protected headers override the
2824 * encrypted headers. We need to do this after the handler so
2825 * they can be printed in the pager. */
2826 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2827 {
2829 b->mime_headers = tattach->parts->mime_headers;
2830 tattach->parts->mime_headers = NULL;
2831 }
2832
2833 /* if a multipart/signed is the _only_ sub-part of a
2834 * multipart/encrypted, cache signature verification
2835 * status. */
2836 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2837 b->goodsig |= tattach->goodsig;
2838
2839 if (state->flags & STATE_DISPLAY)
2840 {
2841 state_attach_puts(state, is_signed ?
2842 _("[-- End of PGP/MIME signed and encrypted data --]\n") :
2843 _("[-- End of PGP/MIME encrypted data --]\n"));
2844 }
2845
2846 mutt_body_free(&tattach);
2847 mutt_message(_("PGP message successfully decrypted"));
2848 }
2849 else
2850 {
2851#ifdef USE_AUTOCRYPT
2852 if (!OptAutocryptGpgme)
2853#endif
2854 {
2855 mutt_error(_("Could not decrypt PGP message"));
2856 }
2857 rc = -1;
2858 }
2859
2860 mutt_file_fclose(&fp_out);
2861 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2862
2863 return rc;
2864}
2865
2869int smime_gpgme_application_handler(struct Body *b, struct State *state)
2870{
2871 int is_signed = 0;
2872 int rc = 0;
2873
2874 mutt_debug(LL_DEBUG2, "Entering handler\n");
2875
2876 /* clear out any mime headers before the handler, so they can't be spoofed. */
2878 b->warnsig = false;
2879 FILE *fp_out = mutt_file_mkstemp();
2880 if (!fp_out)
2881 {
2882 mutt_perror(_("Can't create temporary file"));
2883 if (state->flags & STATE_DISPLAY)
2884 {
2885 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2886 }
2887 return -1;
2888 }
2889
2890 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2891 if (tattach)
2892 {
2893 tattach->goodsig = is_signed > 0;
2894
2895 if (state->flags & STATE_DISPLAY)
2896 {
2897 state_attach_puts(state, is_signed ?
2898 _("[-- The following data is S/MIME signed --]\n") :
2899 _("[-- The following data is S/MIME encrypted --]\n"));
2900 mutt_protected_headers_handler(tattach, state);
2901 }
2902
2903 /* Store any protected headers in the parent so they can be
2904 * accessed for index updates after the handler recursion is done.
2905 * This is done before the handler to prevent a nested encrypted
2906 * handler from freeing the headers. */
2908 b->mime_headers = tattach->mime_headers;
2909 tattach->mime_headers = NULL;
2910
2911 FILE *fp_save = state->fp_in;
2912 state->fp_in = fp_out;
2913 rc = mutt_body_handler(tattach, state);
2914 state->fp_in = fp_save;
2915
2916 /* Embedded multipart signed protected headers override the
2917 * encrypted headers. We need to do this after the handler so
2918 * they can be printed in the pager. */
2919 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2920 {
2922 b->mime_headers = tattach->parts->mime_headers;
2923 tattach->parts->mime_headers = NULL;
2924 }
2925
2926 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2927 * cache signature verification status. */
2928 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2929 {
2930 b->goodsig = tattach->goodsig;
2931 if (!b->goodsig)
2932 b->warnsig = tattach->warnsig;
2933 }
2934 else if (tattach->goodsig)
2935 {
2936 b->goodsig = true;
2937 b->warnsig = tattach->warnsig;
2938 }
2939
2940 if (state->flags & STATE_DISPLAY)
2941 {
2942 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2943 _("[-- End of S/MIME encrypted data --]\n"));
2944 }
2945
2946 mutt_body_free(&tattach);
2947 }
2948
2949 mutt_file_fclose(&fp_out);
2950 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2951
2952 return rc;
2953}
2954
2961unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
2962{
2963 unsigned int rc = 0;
2964
2965 switch (cap)
2966 {
2968 rc = key->can_encrypt;
2969 if (rc == 0)
2970 {
2971 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2972 {
2973 rc = subkey->can_encrypt;
2974 if (rc != 0)
2975 break;
2976 }
2977 }
2978 break;
2979 case KEY_CAP_CAN_SIGN:
2980 rc = key->can_sign;
2981 if (rc == 0)
2982 {
2983 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2984 {
2985 rc = subkey->can_sign;
2986 if (rc != 0)
2987 break;
2988 }
2989 }
2990 break;
2992 rc = key->can_certify;
2993 if (rc == 0)
2994 {
2995 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2996 {
2997 rc = subkey->can_certify;
2998 if (rc != 0)
2999 break;
3000 }
3001 }
3002 break;
3003 }
3004
3005 return rc;
3006}
3007
3017static char *list_to_pattern(struct ListHead *list)
3018{
3019 char *pattern = NULL;
3020 char *p = NULL;
3021 const char *s = NULL;
3022 size_t n;
3023
3024 n = 0;
3025 struct ListNode *np = NULL;
3026 STAILQ_FOREACH(np, list, entries)
3027 {
3028 for (s = np->data; *s; s++)
3029 {
3030 if ((*s == '%') || (*s == '+'))
3031 n += 2;
3032 n++;
3033 }
3034 n++; /* delimiter or end of string */
3035 }
3036 n++; /* make sure to allocate at least one byte */
3037 p = MUTT_MEM_CALLOC(n, char);
3038 pattern = p;
3039 STAILQ_FOREACH(np, list, entries)
3040 {
3041 s = np->data;
3042 if (*s)
3043 {
3044 if (np != STAILQ_FIRST(list))
3045 *p++ = ' ';
3046 for (s = np->data; *s; s++)
3047 {
3048 if (*s == '%')
3049 {
3050 *p++ = '%';
3051 *p++ = '2';
3052 *p++ = '5';
3053 }
3054 else if (*s == '+')
3055 {
3056 *p++ = '%';
3057 *p++ = '2';
3058 *p++ = 'B';
3059 }
3060 else if (*s == ' ')
3061 {
3062 *p++ = '+';
3063 }
3064 else
3065 {
3066 *p++ = *s;
3067 }
3068 }
3069 }
3070 }
3071 *p = '\0';
3072 return pattern;
3073}
3074
3085static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
3086{
3087 struct CryptKeyInfo *db = NULL;
3088 struct CryptKeyInfo *k = NULL;
3089 struct CryptKeyInfo **kend = NULL;
3090 gpgme_error_t err = GPG_ERR_NO_ERROR;
3091 gpgme_ctx_t ctx = NULL;
3092 gpgme_key_t key = NULL;
3093 int idx;
3094 gpgme_user_id_t uid = NULL;
3095
3096 char *pattern = list_to_pattern(hints);
3097 if (!pattern)
3098 return NULL;
3099
3100 ctx = create_gpgme_context(0);
3101 db = NULL;
3102 kend = &db;
3103
3104 if ((app & APPLICATION_PGP))
3105 {
3106 /* It's all a mess. That old GPGME expects different things depending on
3107 * the protocol. For gpg we don't need percent escaped pappert but simple
3108 * strings passed in an array to the keylist_ext_start function. */
3109 size_t n = 0;
3110 struct ListNode *np = NULL;
3111 STAILQ_FOREACH(np, hints, entries)
3112 {
3113 if (np->data && *np->data)
3114 n++;
3115 }
3116 if (n == 0)
3117 goto no_pgphints;
3118
3119 char **patarr = MUTT_MEM_CALLOC(n + 1, char *);
3120 n = 0;
3121 STAILQ_FOREACH(np, hints, entries)
3122 {
3123 if (np->data && *np->data)
3124 patarr[n++] = mutt_str_dup(np->data);
3125 }
3126 patarr[n] = NULL;
3127 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3128 for (n = 0; patarr[n]; n++)
3129 FREE(&patarr[n]);
3130 FREE(&patarr);
3131 if (err != GPG_ERR_NO_ERROR)
3132 {
3133 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3134 gpgme_release(ctx);
3135 FREE(&pattern);
3136 return NULL;
3137 }
3138
3139 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3140 {
3141 KeyFlags flags = KEYFLAG_NONE;
3142
3144 flags |= KEYFLAG_CANENCRYPT;
3146 flags |= KEYFLAG_CANSIGN;
3147
3148 if (key->revoked)
3149 flags |= KEYFLAG_REVOKED;
3150 if (key->expired)
3151 flags |= KEYFLAG_EXPIRED;
3152 if (key->disabled)
3153 flags |= KEYFLAG_DISABLED;
3154
3155 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3156 {
3157 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3158 k->kobj = key;
3159 gpgme_key_ref(k->kobj);
3160 k->idx = idx;
3161 k->uid = uid->uid;
3162 k->flags = flags;
3163 if (uid->revoked)
3164 k->flags |= KEYFLAG_REVOKED;
3165 k->validity = uid->validity;
3166 *kend = k;
3167 kend = &k->next;
3168 }
3169 gpgme_key_unref(key);
3170 }
3171 if (gpg_err_code(err) != GPG_ERR_EOF)
3172 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3173 gpgme_op_keylist_end(ctx);
3174 no_pgphints:;
3175 }
3176
3177 if ((app & APPLICATION_SMIME))
3178 {
3179 /* and now look for x509 certificates */
3180 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3181 err = gpgme_op_keylist_start(ctx, pattern, 0);
3182 if (err != GPG_ERR_NO_ERROR)
3183 {
3184 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3185 gpgme_release(ctx);
3186 FREE(&pattern);
3187 return NULL;
3188 }
3189
3190 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3191 {
3192 KeyFlags flags = KEYFLAG_ISX509;
3193
3195 flags |= KEYFLAG_CANENCRYPT;
3197 flags |= KEYFLAG_CANSIGN;
3198
3199 if (key->revoked)
3200 flags |= KEYFLAG_REVOKED;
3201 if (key->expired)
3202 flags |= KEYFLAG_EXPIRED;
3203 if (key->disabled)
3204 flags |= KEYFLAG_DISABLED;
3205
3206 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3207 {
3208 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3209 k->kobj = key;
3210 gpgme_key_ref(k->kobj);
3211 k->idx = idx;
3212 k->uid = uid->uid;
3213 k->flags = flags;
3214 if (uid->revoked)
3215 k->flags |= KEYFLAG_REVOKED;
3216 k->validity = uid->validity;
3217 *kend = k;
3218 kend = &k->next;
3219 }
3220 gpgme_key_unref(key);
3221 }
3222 if (gpg_err_code(err) != GPG_ERR_EOF)
3223 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3224 gpgme_op_keylist_end(ctx);
3225 }
3226
3227 gpgme_release(ctx);
3228 FREE(&pattern);
3229 return db;
3230}
3231
3240static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
3241{
3242 char *scratch = mutt_str_dup(str);
3243 if (!scratch)
3244 return;
3245
3246 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3247 {
3248 if (strlen(t) > 3)
3250 }
3251
3252 FREE(&scratch);
3253}
3254
3264static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
3265 KeyFlags abilities, unsigned int app,
3266 bool *forced_valid, bool oppenc_mode)
3267{
3268 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3269
3270 int multi = false;
3271 int this_key_has_strong = false;
3272 int this_key_has_addr_match = false;
3273 int match = false;
3274
3275 struct CryptKeyInfo *keys = NULL;
3276 struct CryptKeyInfo *k = NULL;
3277 struct CryptKeyInfo *the_strong_valid_key = NULL;
3278 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3279 struct CryptKeyInfo *matches = NULL;
3280 struct CryptKeyInfo **matches_endp = &matches;
3281
3282 if (a && a->mailbox)
3284 if (a && a->personal)
3286
3287 if (!oppenc_mode)
3288 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3289 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3290
3291 mutt_list_free(&hints);
3292
3293 if (!keys)
3294 return NULL;
3295
3296 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3297 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3298
3299 for (k = keys; k; k = k->next)
3300 {
3301 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3302
3303 if (abilities && !(k->flags & abilities))
3304 {
3305 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3306 continue;
3307 }
3308
3309 this_key_has_strong = false; /* strong and valid match */
3310 this_key_has_addr_match = false;
3311 match = false; /* any match */
3312
3313 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3314 mutt_addrlist_parse(&alist, k->uid);
3315 struct Address *ka = NULL;
3316 TAILQ_FOREACH(ka, &alist, entries)
3317 {
3318 int validity = crypt_id_matches_addr(a, ka, k);
3319
3320 if (validity & CRYPT_KV_MATCH) /* something matches */
3321 {
3322 match = true;
3323
3324 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3325 {
3326 if (validity & CRYPT_KV_STRONGID)
3327 {
3328 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3329 multi = true;
3330 this_key_has_strong = true;
3331 }
3332 else
3333 {
3334 this_key_has_addr_match = true;
3335 }
3336 }
3337 }
3338 }
3339 mutt_addrlist_clear(&alist);
3340
3341 if (match)
3342 {
3343 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3344 *matches_endp = tmp;
3345 matches_endp = &tmp->next;
3346
3347 if (this_key_has_strong)
3348 the_strong_valid_key = tmp;
3349 else if (this_key_has_addr_match)
3350 a_valid_addrmatch_key = tmp;
3351 }
3352 }
3353
3354 crypt_key_free(&keys);
3355
3356 if (matches)
3357 {
3358 if (oppenc_mode || !isatty(STDIN_FILENO))
3359 {
3360 const bool c_crypt_opportunistic_encrypt_strong_keys =
3361 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3362 if (the_strong_valid_key)
3363 k = crypt_copy_key(the_strong_valid_key);
3364 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3365 k = crypt_copy_key(a_valid_addrmatch_key);
3366 else
3367 k = NULL;
3368 }
3369 else if (the_strong_valid_key && !multi)
3370 {
3371 /* There was precisely one strong match on a valid ID.
3372 * Proceed without asking the user. */
3373 k = crypt_copy_key(the_strong_valid_key);
3374 }
3375 else
3376 {
3377 /* Else: Ask the user. */
3378 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3379 }
3380
3381 crypt_key_free(&matches);
3382 }
3383 else
3384 {
3385 k = NULL;
3386 }
3387
3388 return k;
3389}
3390
3399static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
3400 unsigned int app, bool *forced_valid)
3401{
3402 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3403 struct CryptKeyInfo *matches = NULL;
3404 struct CryptKeyInfo **matches_endp = &matches;
3405 struct CryptKeyInfo *k = NULL;
3406 const char *ps = NULL;
3407 const char *pl = NULL;
3408 const char *phint = NULL;
3409
3410 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3411
3412 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3413 crypt_add_string_to_hints(phint, &hints);
3414 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3415 mutt_list_free(&hints);
3416
3417 if (!keys)
3418 {
3419 FREE(&pfcopy);
3420 return NULL;
3421 }
3422
3423 for (k = keys; k; k = k->next)
3424 {
3425 if (abilities && !(k->flags & abilities))
3426 continue;
3427
3428 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3429 crypt_long_keyid(k), k->uid);
3430
3431 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3432 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3433 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3434 {
3435 mutt_debug(LL_DEBUG5, "match\n");
3436
3437 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3438 *matches_endp = tmp;
3439 matches_endp = &tmp->next;
3440 }
3441 else
3442 {
3443 mutt_debug(LL_DEBUG5, "no match\n");
3444 }
3445 }
3446
3447 FREE(&pfcopy);
3448 crypt_key_free(&keys);
3449
3450 if (matches)
3451 {
3452 if (isatty(STDIN_FILENO))
3453 {
3454 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3455
3456 crypt_key_free(&matches);
3457 return k;
3458 }
3459 else
3460 {
3461 if (crypt_keys_are_valid(matches))
3462 return matches;
3463
3464 crypt_key_free(&matches);
3465 return NULL;
3466 }
3467 }
3468
3469 return NULL;
3470}
3471
3484static struct CryptKeyInfo *crypt_ask_for_key(const char *tag, const char *whatfor,
3485 KeyFlags abilities,
3486 unsigned int app, bool *forced_valid)
3487{
3489 struct CryptKeyInfo *key = NULL;
3490 struct CryptCache *l = NULL;
3491 struct Buffer *resp = buf_pool_get();
3492
3494
3495 if (whatfor)
3496 {
3497 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3498 {
3499 if (mutt_istr_equal(whatfor, l->what))
3500 {
3501 buf_strcpy(resp, l->dflt);
3502 break;
3503 }
3504 }
3505 }
3506
3507 while (true)
3508 {
3509 buf_reset(resp);
3510 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3511 {
3512 goto done;
3513 }
3514
3515 if (buf_is_empty(resp))
3516 goto done;
3517
3518 if (whatfor)
3519 {
3520 if (l)
3521 {
3522 mutt_str_replace(&l->dflt, buf_string(resp));
3523 }
3524 else
3525 {
3526 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3527 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3528 mod_data->gpgme_id_defaults = l;
3529 l->what = mutt_str_dup(whatfor);
3530 l->dflt = buf_strdup(resp);
3531 }
3532 }
3533
3534 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3535 if (key)
3536 goto done;
3537
3538 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3539 }
3540
3541done:
3542 buf_pool_release(&resp);
3543 return key;
3544}
3545
3557static char *find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
3558{
3559 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3560 struct ListNode *crypt_hook = NULL;
3561 const char *keyid = NULL;
3562 char *keylist = NULL;
3563 size_t keylist_size = 0;
3564 size_t keylist_used = 0;
3565 struct Address *p = NULL;
3566 struct CryptKeyInfo *k_info = NULL;
3567 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3568 char buf[1024] = { 0 };
3569 bool forced_valid = false;
3570 bool key_selected;
3571 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3572
3573 struct Address *a = NULL;
3574 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3575 /* Iterate through each recipient address to find an encryption key */
3576 TAILQ_FOREACH(a, addrlist, entries)
3577 {
3578 key_selected = false;
3579 /* Check for crypt-hook overrides for this recipient */
3580 mutt_crypt_hook(&crypt_hook_list, a);
3581 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3582 do
3583 {
3584 p = a;
3585 forced_valid = false;
3586 k_info = NULL;
3587
3588 /* If a crypt-hook provides a key ID, confirm with the user unless
3589 * in opportunistic encryption mode */
3590 if (crypt_hook)
3591 {
3592 keyid = crypt_hook->data;
3593 enum QuadOption ans = MUTT_YES;
3594 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3595 {
3596 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3597 buf_string(p->mailbox));
3598 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3599 }
3600 if (ans == MUTT_YES)
3601 {
3602 if (crypt_is_numerical_keyid(keyid))
3603 {
3604 if (mutt_strn_equal(keyid, "0x", 2))
3605 keyid += 2;
3606 goto bypass_selection; /* you don't see this. */
3607 }
3608
3609 /* check for e-mail address */
3610 mutt_addrlist_clear(&hookal);
3611 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3612 {
3613 mutt_addrlist_qualify(&hookal, fqdn);
3614 p = TAILQ_FIRST(&hookal);
3615 }
3616 else if (!oppenc_mode)
3617 {
3618 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3619 }
3620 }
3621 else if (ans == MUTT_NO)
3622 {
3623 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3624 {
3625 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3626 continue;
3627 }
3628 }
3629 else if (ans == MUTT_ABORT)
3630 {
3631 FREE(&keylist);
3632 mutt_addrlist_clear(&hookal);
3633 mutt_list_free(&crypt_hook_list);
3634 return NULL;
3635 }
3636 }
3637
3638 /* If no key found yet, try looking up by address in the keyring */
3639 if (!k_info)
3640 {
3641 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3642 }
3643
3644 /* Last resort: prompt the user to enter a key ID interactively */
3645 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3646 {
3647 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3648
3649 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3650 KEYFLAG_CANENCRYPT, app, &forced_valid);
3651 }
3652
3653 if (!k_info)
3654 {
3655 FREE(&keylist);
3656 mutt_addrlist_clear(&hookal);
3657 mutt_list_free(&crypt_hook_list);
3658 return NULL;
3659 }
3660
3661 keyid = crypt_fpr_or_lkeyid(k_info);
3662
3663 bypass_selection:
3664 /* Append the selected key ID to the space-separated keylist string */
3665 keylist_size += mutt_str_len(keyid) + 4 + 1;
3666 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3667 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3668 keyid, forced_valid ? "!" : "");
3669 keylist_used = mutt_str_len(keylist);
3670
3671 key_selected = true;
3672
3673 crypt_key_free(&k_info);
3674 mutt_addrlist_clear(&hookal);
3675
3676 if (crypt_hook)
3677 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3678
3679 } while (crypt_hook);
3680
3681 mutt_list_free(&crypt_hook_list);
3682 }
3683 return keylist;
3684}
3685
3689char *pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3690{
3691 return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
3692}
3693
3697char *smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3698{
3699 return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
3700}
3701
3702#ifdef USE_AUTOCRYPT
3716{
3717 int rc = -1;
3718 gpgme_error_t err = GPG_ERR_NO_ERROR;
3719 gpgme_key_t key = NULL;
3720 gpgme_user_id_t uid = NULL;
3721 struct CryptKeyInfo *results = NULL;
3722 struct CryptKeyInfo *k = NULL;
3723 struct CryptKeyInfo **kend = NULL;
3724 struct CryptKeyInfo *choice = NULL;
3725
3726 gpgme_ctx_t ctx = create_gpgme_context(false);
3727
3728 /* list all secret keys */
3729 if (gpgme_op_keylist_start(ctx, NULL, 1))
3730 goto cleanup;
3731
3732 kend = &results;
3733
3734 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3735 {
3737
3742
3743 if (key->revoked)
3745 if (key->expired)
3747 if (key->disabled)
3749
3750 int idx;
3751 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3752 {
3753 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3754 k->kobj = key;
3755 gpgme_key_ref(k->kobj);
3756 k->idx = idx;
3757 k->uid = uid->uid;
3758 k->flags = flags;
3759 if (uid->revoked)
3760 k->flags |= KEYFLAG_REVOKED;
3761 k->validity = uid->validity;
3762 *kend = k;
3763 kend = &k->next;
3764 }
3765 gpgme_key_unref(key);
3766 }
3767 if (gpg_err_code(err) != GPG_ERR_EOF)
3768 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3769 gpgme_op_keylist_end(ctx);
3770
3771 if (!results)
3772 {
3773 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3774 from. This error is displayed if no results were found. */
3775 mutt_error(_("No secret keys found"));
3776 goto cleanup;
3777 }
3778
3779 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3780 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3781 goto cleanup;
3782 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3783
3784 rc = 0;
3785
3786cleanup:
3787 crypt_key_free(&choice);
3788 crypt_key_free(&results);
3789 gpgme_release(ctx);
3790 return rc;
3791}
3792#endif
3793
3798{
3799 gpgme_ctx_t ctx = NULL;
3800 gpgme_key_t export_keys[2] = { 0 };
3801 gpgme_data_t keydata = NULL;
3802 struct Body *att = NULL;
3803 char buf[1024] = { 0 };
3804
3805 OptPgpCheckTrust = false;
3806
3807 struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
3809 if (!key)
3810 goto bail;
3811 export_keys[0] = key->kobj;
3812 export_keys[1] = NULL;
3813
3814 ctx = create_gpgme_context(false);
3815 gpgme_set_armor(ctx, 1);
3816 keydata = create_gpgme_data();
3817 gpgme_error_t err = gpgme_op_export_keys(ctx, export_keys, 0, keydata);
3818 if (err != GPG_ERR_NO_ERROR)
3819 {
3820 mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
3821 goto bail;
3822 }
3823
3824 char *tempf = data_object_to_tempfile(keydata, NULL);
3825 if (!tempf)
3826 goto bail;
3827
3828 att = mutt_body_new();
3829 /* tempf is a newly allocated string, so this is correct: */
3830 att->filename = tempf;
3831 att->unlink = true;
3832 att->use_disp = false;
3833 att->type = TYPE_APPLICATION;
3834 att->subtype = mutt_str_dup("pgp-keys");
3835 /* L10N: MIME description for exported (attached) keys.
3836 You can translate this entry to a non-ASCII string (it will be encoded),
3837 but it may be safer to keep it untranslated. */
3838 snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
3839 att->description = mutt_str_dup(buf);
3841
3842 att->length = mutt_file_get_size(tempf);
3843
3844bail:
3845 crypt_key_free(&key);
3846 gpgme_data_release(keydata);
3847 gpgme_release(ctx);
3848
3849 return att;
3850}
3851
3855static void init_common(void)
3856{
3857 /* this initialization should only run one time, but it may be called by
3858 * either pgp_gpgme_init or smime_gpgme_init */
3859 static bool has_run = false;
3860 if (has_run)
3861 return;
3862
3863 gpgme_check_version(NULL);
3864 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3865#ifdef ENABLE_NLS
3866 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3867#endif
3868 has_run = true;
3869}
3870
3874static void init_pgp(void)
3875{
3876 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3877 {
3878 mutt_error(_("GPGME: OpenPGP protocol not available"));
3879 }
3880}
3881
3885static void init_smime(void)
3886{
3887 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3888 {
3889 mutt_error(_("GPGME: CMS protocol not available"));
3890 }
3891}
3892
3897{
3898 init_common();
3899 init_pgp();
3900}
3901
3906{
3907 init_common();
3908 init_smime();
3909}
3910
3917static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
3918{
3919 struct CryptKeyInfo *p = NULL;
3920 const char *prompt = NULL;
3921 const char *letters = NULL;
3922 const char *choices = NULL;
3923 int choice;
3924
3925 if (is_smime)
3927 else
3929
3930 /* Opportunistic encrypt is controlling encryption.
3931 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3932 * letter choices for those.
3933 */
3934 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3935 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3936 {
3937 if (is_smime)
3938 {
3939 /* L10N: S/MIME options (opportunistic encryption is on) */
3940 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3941 /* L10N: S/MIME options (opportunistic encryption is on) */
3942 letters = _("sapco");
3943 choices = "SapCo";
3944 }
3945 else
3946 {
3947 /* L10N: PGP options (opportunistic encryption is on) */
3948 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3949 /* L10N: PGP options (opportunistic encryption is on) */
3950 letters = _("samco");
3951 choices = "SamCo";
3952 }
3953 }
3954 else if (c_crypt_opportunistic_encrypt)
3955 {
3956 /* Opportunistic encryption option is set, but is toggled off for this message. */
3957 if (is_smime)
3958 {
3959 /* L10N: S/MIME options (opportunistic encryption is off) */
3960 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3961 /* L10N: S/MIME options (opportunistic encryption is off) */
3962 letters = _("esabpco");
3963 choices = "esabpcO";
3964 }
3965 else
3966 {
3967 /* L10N: PGP options (opportunistic encryption is off) */
3968 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3969 /* L10N: PGP options (opportunistic encryption is off) */
3970 letters = _("esabmco");
3971 choices = "esabmcO";
3972 }
3973 }
3974 else
3975 {
3976 /* Opportunistic encryption is unset */
3977 if (is_smime)
3978 {
3979 /* L10N: S/MIME options */
3980 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3981 /* L10N: S/MIME options */
3982 letters = _("esabpc");
3983 choices = "esabpc";
3984 }
3985 else
3986 {
3987 /* L10N: PGP options */
3988 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3989 /* L10N: PGP options */
3990 letters = _("esabmc");
3991 choices = "esabmc";
3992 }
3993 }
3994
3995 choice = mw_multi_choice(prompt, letters);
3996 if (choice > 0)
3997 {
3998 switch (choices[choice - 1])
3999 {
4000 case 'a': /* sign (a)s */
4001 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
4002 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
4003 if (p)
4004 {
4005 char input_signas[128] = { 0 };
4006 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
4007
4008 if (is_smime)
4009 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
4010 else
4011 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
4012
4013 crypt_key_free(&p);
4014
4015 e->security |= SEC_SIGN;
4016 }
4017 break;
4018
4019 case 'b': /* (b)oth */
4020 e->security |= (SEC_ENCRYPT | SEC_SIGN);
4021 break;
4022
4023 case 'C':
4024 e->security &= ~SEC_SIGN;
4025 break;
4026
4027 case 'c': /* (c)lear */
4028 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4029 break;
4030
4031 case 'e': /* (e)ncrypt */
4032 e->security |= SEC_ENCRYPT;
4033 e->security &= ~SEC_SIGN;
4034 break;
4035
4036 case 'm': /* (p)gp or s/(m)ime */
4037 case 'p':
4038 is_smime = !is_smime;
4039 if (is_smime)
4040 {
4043 }
4044 else
4045 {
4048 }
4050 break;
4051
4052 case 'O': /* oppenc mode on */
4055 break;
4056
4057 case 'o': /* oppenc mode off */
4059 break;
4060
4061 case 'S': /* (s)ign in oppenc mode */
4062 e->security |= SEC_SIGN;
4063 break;
4064
4065 case 's': /* (s)ign */
4066 e->security &= ~SEC_ENCRYPT;
4067 e->security |= SEC_SIGN;
4068 break;
4069 }
4070 }
4071
4072 return e->security;
4073}
4074
4079{
4080 return gpgme_send_menu(e, false);
4081}
4082
4087{
4088 return gpgme_send_menu(e, true);
4089}
4090
4096static bool verify_sender(struct Email *e)
4097{
4099 struct Address *sender = NULL;
4100 bool rc = true;
4101
4102 if (!TAILQ_EMPTY(&e->env->from))
4103 {
4105 sender = TAILQ_FIRST(&e->env->from);
4106 }
4107 else if (!TAILQ_EMPTY(&e->env->sender))
4108 {
4110 sender = TAILQ_FIRST(&e->env->sender);
4111 }
4112
4113 if (sender)
4114 {
4115 if ((gpgme_key_t) mod_data->signature_key)
4116 {
4117 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4118 gpgme_user_id_t uid = NULL;
4119 int sender_length = buf_len(sender->mailbox);
4120 for (uid = key->uids; uid && rc; uid = uid->next)
4121 {
4122 int uid_length = strlen(uid->email);
4123 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4124 (uid_length == (sender_length + 2)))
4125 {
4126 const char *at_sign = strchr(uid->email + 1, '@');
4127 if (at_sign)
4128 {
4129 /* Assume address is 'mailbox@domainname'.
4130 * The mailbox part is case-sensitive,
4131 * the domainname is not. (RFC2821) */
4132 const char *tmp_email = uid->email + 1;
4133 const char *tmp_sender = buf_string(sender->mailbox);
4134 /* length of mailbox part including '@' */
4135 int mailbox_length = at_sign - tmp_email + 1;
4136 int domainname_length = sender_length - mailbox_length;
4137 int mailbox_match;
4138 int domainname_match;
4139
4140 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4141 tmp_email += mailbox_length;
4142 tmp_sender += mailbox_length;
4143 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4144 if (mailbox_match && domainname_match)
4145 rc = false;
4146 }
4147 else
4148 {
4149 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4150 rc = false;
4151 }
4152 }
4153 }
4154 }
4155 else
4156 {
4157 mutt_any_key_to_continue(_("Failed to verify sender"));
4158 }
4159 }
4160 else
4161 {
4162 mutt_any_key_to_continue(_("Failed to figure out sender"));
4163 }
4164
4165 if ((gpgme_key_t) mod_data->signature_key)
4166 {
4167 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4168 mod_data->signature_key = NULL;
4169 }
4170
4171 return rc;
4172}
4173
4177int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
4178{
4179 return verify_sender(e);
4180}
4181
4185void pgp_gpgme_set_sender(const char *sender)
4186{
4188 mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
4189 FREE(&mod_data->current_sender);
4190 mod_data->current_sender = mutt_str_dup(sender);
4191}
4192
4198{
4199 return GPGME_VERSION;
4200}
4201
4207{
4208 struct CryptCache *l = mod_data->gpgme_id_defaults;
4209 while (l)
4210 {
4211 struct CryptCache *next = l->next;
4212 FREE(&l->what);
4213 FREE(&l->dflt);
4214 FREE(&l);
4215 l = next;
4216 }
4217 mod_data->gpgme_id_defaults = NULL;
4218
4219 if ((gpgme_key_t) mod_data->signature_key)
4220 {
4221 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4222 mod_data->signature_key = NULL;
4223 }
4224}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:687
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1475
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:481
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:297
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:1051
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1489
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:409
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:468
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:1396
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:505
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:815
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:549
Signing/encryption multiplexor.
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:449
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:134
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1981
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1516
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:1433
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:1415
#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:1123
#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:1668
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1943
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:882
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition charset.c:968
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition charset.c:921
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1030
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:950
#define MUTT_ICONV_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:957
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:678
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:666
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
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:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NONE
Overwrite existing file (the default).
Definition mutt_attach.h:59
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:304
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:763
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:424
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:717
#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