NeoMutt  2025-12-11-769-g906513
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt.c
Go to the documentation of this file.
1
26
32
33#include "config.h"
34#include <stdbool.h>
35#include <stdio.h>
36#include <string.h>
37#include "mutt/lib.h"
38#include "address/lib.h"
39#include "config/lib.h"
40#include "email/lib.h"
41#include "core/lib.h"
42#include "alias/lib.h"
43#include "gui/lib.h"
44#include "mutt.h"
45#include "crypt.h"
46#include "lib.h"
47#include "attach/lib.h"
48#include "question/lib.h"
49#include "send/lib.h"
50#include "cryptglue.h"
51#include "globals.h"
52#include "mx.h"
53#ifdef USE_AUTOCRYPT
54#include "autocrypt/lib.h"
55#endif
56
64void crypt_current_time(struct State *state, const char *app_name)
65{
66 char p[256] = { 0 };
67 char tmp[512] = { 0 };
68
69 if (!WithCrypto)
70 return;
71
72 const bool c_crypt_timestamp = cs_subset_bool(NeoMutt->sub, "crypt_timestamp");
73 if (c_crypt_timestamp)
74 {
75 mutt_date_localtime_format(p, sizeof(p), _(" (current time: %c)"), mutt_date_now());
76 }
77 else
78 {
79 *p = '\0';
80 }
81
82 snprintf(tmp, sizeof(tmp), _("[-- %s output follows%s --]\n"), NONULL(app_name), p);
83 state_attach_puts(state, tmp);
84}
85
90{
93
96
97 if (WithCrypto)
98 {
99 /* L10N: Due to the implementation details (e.g. some passwords are managed
100 by gpg-agent) we can't know whether we forgot zero, 1, 12, ...
101 passwords. So in English we use "Passphrases". Your language might
102 have other means to express this. */
103 mutt_message(_("Passphrases forgotten"));
104 }
105}
106
107#ifndef DEBUG
108#include <sys/resource.h>
112static void disable_coredumps(void)
113{
114 struct rlimit rl = { 0, 0 };
115 static bool done = false;
116
117 if (!done)
118 {
119 setrlimit(RLIMIT_CORE, &rl);
120 done = true;
121 }
122}
123#endif
124
132{
133 bool rc = false;
134
135#ifndef DEBUG
136 disable_coredumps();
137#endif
138
139 if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & APPLICATION_PGP))
141
142 if (((WithCrypto & APPLICATION_SMIME) != 0) && (flags & APPLICATION_SMIME))
144
145 return rc;
146}
147
156int mutt_protect(struct Email *e, char *keylist, bool postpone)
157{
158 struct Body *pbody = NULL, *tmp_pbody = NULL;
159 struct Body *tmp_smime_pbody = NULL;
160 struct Body *tmp_pgp_pbody = NULL;
161 bool has_retainable_sig = false;
162
163 if (!WithCrypto)
164 return -1;
165
166 SecurityFlags security = e->security;
167 int sign = security & (SEC_AUTOCRYPT | SEC_SIGN);
168 if (postpone)
169 {
170 sign = SEC_NO_FLAGS;
171 security &= ~SEC_SIGN;
172 }
173
174 if (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) && !sign)
175 return 0;
176
177 if (sign && !(security & SEC_AUTOCRYPT) && !crypt_valid_passphrase(security))
178 return -1;
179
180 if (((WithCrypto & APPLICATION_PGP) != 0) && !(security & SEC_AUTOCRYPT) &&
181 ((security & PGP_INLINE) == PGP_INLINE))
182 {
183 if ((e->body->type != TYPE_TEXT) || !mutt_istr_equal(e->body->subtype, "plain"))
184 {
185 if (query_quadoption(_("Inline PGP can't be used with attachments. Revert to PGP/MIME?"),
186 NeoMutt->sub, "pgp_mime_auto") != MUTT_YES)
187 {
188 mutt_error(_("Mail not sent: inline PGP can't be used with attachments"));
189 return -1;
190 }
191 }
192 else if (mutt_istr_equal("flowed", mutt_param_get(&e->body->parameter, "format")))
193 {
194 if ((query_quadoption(_("Inline PGP can't be used with format=flowed. Revert to PGP/MIME?"),
195 NeoMutt->sub, "pgp_mime_auto")) != MUTT_YES)
196 {
197 mutt_error(_("Mail not sent: inline PGP can't be used with format=flowed"));
198 return -1;
199 }
200 }
201 else
202 {
203 /* they really want to send it inline... go for it */
204 if (!isendwin())
205 {
206 mutt_endwin();
207 puts(_("Invoking PGP..."));
208 }
209 pbody = crypt_pgp_traditional_encryptsign(e->body, security, keylist);
210 if (pbody)
211 {
212 e->body = pbody;
213 return 0;
214 }
215
216 /* otherwise inline won't work...ask for revert */
217 if (query_quadoption(_("Message can't be sent inline. Revert to using PGP/MIME?"),
218 NeoMutt->sub, "pgp_mime_auto") != MUTT_YES)
219 {
220 mutt_error(_("Mail not sent"));
221 return -1;
222 }
223 }
224
225 /* go ahead with PGP/MIME */
226 }
227
228 if (!isendwin())
229 mutt_endwin();
230
232 tmp_smime_pbody = e->body;
234 tmp_pgp_pbody = e->body;
235
236#ifdef CRYPT_BACKEND_GPGME
237 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
238 if (sign && c_crypt_use_pka)
239#else
240 if (sign)
241#endif
242 {
243 /* Set sender (necessary for e.g. PKA). */
244 const char *mailbox = NULL;
245 struct Address *from = TAILQ_FIRST(&e->env->from);
246 bool free_from = false;
247
248 if (!from)
249 {
250 free_from = true;
252 }
253
254 mailbox = buf_string(from->mailbox);
255 const struct Address *c_envelope_from_address = cs_subset_address(NeoMutt->sub, "envelope_from_address");
256 if (!mailbox && c_envelope_from_address)
257 mailbox = buf_string(c_envelope_from_address->mailbox);
258
259 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
261 else if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
263
264 if (free_from)
265 mutt_addr_free(&from);
266 }
267
268 const bool c_crypt_protected_headers_write = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_write");
269 if (c_crypt_protected_headers_write)
270 {
271 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
272 struct Envelope *protected_headers = mutt_env_new();
273 mutt_env_set_subject(protected_headers, e->env->subject);
274 if (c_devel_security)
275 {
276 mutt_addrlist_copy(&protected_headers->return_path, &e->env->return_path, false);
277 mutt_addrlist_copy(&protected_headers->from, &e->env->from, false);
278 mutt_addrlist_copy(&protected_headers->to, &e->env->to, false);
279 mutt_addrlist_copy(&protected_headers->cc, &e->env->cc, false);
280 mutt_addrlist_copy(&protected_headers->sender, &e->env->sender, false);
281 mutt_addrlist_copy(&protected_headers->reply_to, &e->env->reply_to, false);
282 mutt_addrlist_copy(&protected_headers->mail_followup_to,
283 &e->env->mail_followup_to, false);
284 mutt_addrlist_copy(&protected_headers->x_original_to, &e->env->x_original_to, false);
285 mutt_str_replace(&protected_headers->message_id, e->env->message_id);
286 mutt_list_copy_tail(&protected_headers->references, &e->env->references);
287 mutt_list_copy_tail(&protected_headers->in_reply_to, &e->env->in_reply_to);
288 mutt_env_to_intl(protected_headers, NULL, NULL);
289 }
290 mutt_prepare_envelope(protected_headers, 0, NeoMutt->sub);
291
293 e->body->mime_headers = protected_headers;
294 mutt_param_set(&e->body->parameter, "protected-headers", "v1");
295 }
296
297#ifdef USE_AUTOCRYPT
298 /* A note about e->body->mime_headers. If postpone or send
299 * fails, the mime_headers is cleared out before returning to the
300 * compose menu. So despite the "robustness" code above and in the
301 * gen_gossip_list function below, mime_headers will not be set when
302 * entering mutt_protect().
303 *
304 * This is important to note because the user could toggle
305 * $crypt_protected_headers_write or $autocrypt off back in the
306 * compose menu. We don't want mutt_rfc822_write_header() to write
307 * stale data from one option if the other is set.
308 */
309 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
310 if (c_autocrypt && !postpone && (security & SEC_AUTOCRYPT))
311 {
313 }
314#endif
315
316 if (sign)
317 {
318 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
319 {
320 tmp_pbody = crypt_smime_sign_message(e->body, &e->env->from);
321 if (!tmp_pbody)
322 goto bail;
323 pbody = tmp_pbody;
324 tmp_smime_pbody = tmp_pbody;
325 }
326
327 const bool c_pgp_retainable_sigs = cs_subset_bool(NeoMutt->sub, "pgp_retainable_sigs");
328 if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP) &&
329 (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) || c_pgp_retainable_sigs))
330 {
331 tmp_pbody = crypt_pgp_sign_message(e->body, &e->env->from);
332 if (!tmp_pbody)
333 goto bail;
334
335 has_retainable_sig = true;
336 sign = SEC_NO_FLAGS;
337 pbody = tmp_pbody;
338 tmp_pgp_pbody = tmp_pbody;
339 }
340 }
341
342 if (security & (SEC_ENCRYPT | SEC_AUTOCRYPT))
343 {
344 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
345 {
346 tmp_pbody = crypt_smime_build_smime_entity(tmp_smime_pbody, keylist);
347 if (!tmp_pbody)
348 {
349 /* signed ? free it! */
350 goto bail;
351 }
352 /* free tmp_body if messages was signed AND encrypted ... */
353 if ((tmp_smime_pbody != e->body) && (tmp_smime_pbody != tmp_pbody))
354 {
355 /* detach and don't delete e->body,
356 * which tmp_smime_pbody->parts after signing. */
357 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
358 e->body->next = NULL;
359 mutt_body_free(&tmp_smime_pbody);
360 }
361 pbody = tmp_pbody;
362 }
363
364 if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
365 {
366 pbody = crypt_pgp_encrypt_message(e, tmp_pgp_pbody, keylist, sign, &e->env->from);
367 if (!pbody)
368 {
369 /* did we perform a retainable signature? */
370 if (has_retainable_sig)
371 {
372 /* remove the outer multipart layer */
373 tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
374 /* get rid of the signature */
375 mutt_body_free(&tmp_pgp_pbody->next);
376 }
377
378 goto bail;
379 }
380
381 // destroy temporary signature envelope when doing retainable signatures.
382 if (has_retainable_sig)
383 {
384 tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
385 mutt_body_free(&tmp_pgp_pbody->next);
386 }
387 }
388 }
389
390 if (pbody)
391 {
392 e->body = pbody;
393 return 0;
394 }
395
396bail:
398 mutt_param_delete(&e->body->parameter, "protected-headers");
399 return -1;
400}
401
409{
410 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype || !mutt_istr_equal(b->subtype, "signed"))
411 {
412 return SEC_NO_FLAGS;
413 }
414
415 char *p = mutt_param_get(&b->parameter, "protocol");
416 if (!p)
417 return SEC_NO_FLAGS;
418
419 if (mutt_istr_equal(p, "multipart/mixed"))
420 return SEC_SIGN;
421
422 if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_istr_equal(p, "application/pgp-signature"))
423 {
424 return PGP_SIGN;
425 }
426
427 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
428 (mutt_istr_equal(p, "application/x-pkcs7-signature") ||
429 mutt_istr_equal(p, "application/pkcs7-signature")))
430 {
431 return SMIME_SIGN;
432 }
433
434 return SEC_NO_FLAGS;
435}
436
444{
445 if ((WithCrypto & APPLICATION_PGP) == 0)
446 return SEC_NO_FLAGS;
447
448 char *p = NULL;
449
450 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype ||
451 !mutt_istr_equal(b->subtype, "encrypted") ||
452 !(p = mutt_param_get(&b->parameter, "protocol")) ||
453 !mutt_istr_equal(p, "application/pgp-encrypted"))
454 {
455 return SEC_NO_FLAGS;
456 }
457
458 return PGP_ENCRYPT;
459}
460
468{
470 return 0;
471
472 b = b->parts;
473 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
474 !mutt_istr_equal(b->subtype, "pgp-encrypted"))
475 {
476 return 0;
477 }
478
479 b = b->next;
480 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
481 !mutt_istr_equal(b->subtype, "octet-stream"))
482 {
483 return 0;
484 }
485
486 return PGP_ENCRYPT;
487}
488
505{
507 return SEC_NO_FLAGS;
508
509 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype || !mutt_istr_equal(b->subtype, "mixed"))
510 {
511 return SEC_NO_FLAGS;
512 }
513
514 b = b->parts;
515 if (!b || (b->type != TYPE_TEXT) || !b->subtype ||
516 !mutt_istr_equal(b->subtype, "plain") || (b->length != 0))
517 {
518 return SEC_NO_FLAGS;
519 }
520
521 b = b->next;
522 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
523 !mutt_istr_equal(b->subtype, "pgp-encrypted"))
524 {
525 return SEC_NO_FLAGS;
526 }
527
528 b = b->next;
529 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
530 !mutt_istr_equal(b->subtype, "octet-stream"))
531 {
532 return SEC_NO_FLAGS;
533 }
534
535 b = b->next;
536 if (b)
537 return SEC_NO_FLAGS;
538
539 return PGP_ENCRYPT;
540}
541
549{
551 char *p = NULL;
552
553 if (b->type == TYPE_APPLICATION)
554 {
555 if (mutt_istr_equal(b->subtype, "pgp") || mutt_istr_equal(b->subtype, "x-pgp-message"))
556 {
557 p = mutt_param_get(&b->parameter, "x-action");
558 if (p && (mutt_istr_equal(p, "sign") || mutt_istr_equal(p, "signclear")))
559 {
560 t |= PGP_SIGN;
561 }
562
563 p = mutt_param_get(&b->parameter, "format");
564 if (p && mutt_istr_equal(p, "keys-only"))
565 {
566 t |= PGP_KEY;
567 }
568
569 if (t == SEC_NO_FLAGS)
570 t |= PGP_ENCRYPT; /* not necessarily correct, but... */
571 }
572
573 if (mutt_istr_equal(b->subtype, "pgp-signed"))
574 t |= PGP_SIGN;
575
576 if (mutt_istr_equal(b->subtype, "pgp-keys"))
577 t |= PGP_KEY;
578 }
579 else if ((b->type == TYPE_TEXT) && mutt_istr_equal("plain", b->subtype))
580 {
581 if (((p = mutt_param_get(&b->parameter, "x-mutt-action")) ||
582 (p = mutt_param_get(&b->parameter, "x-action")) ||
583 (p = mutt_param_get(&b->parameter, "action"))) &&
584 mutt_istr_startswith(p, "pgp-sign"))
585 {
586 t |= PGP_SIGN;
587 }
588 else if (p && mutt_istr_startswith(p, "pgp-encrypt"))
589 {
590 t |= PGP_ENCRYPT;
591 }
592 else if (p && mutt_istr_startswith(p, "pgp-keys"))
593 {
594 t |= PGP_KEY;
595 }
596 }
597 if (t)
598 t |= PGP_INLINE;
599
600 return t;
601}
602
610{
611 if (!b)
612 return SEC_NO_FLAGS;
613
614 if (((b->type & TYPE_APPLICATION) == 0) || !b->subtype)
615 return SEC_NO_FLAGS;
616
617 char *t = NULL;
618 bool complain = false;
619 /* S/MIME MIME types don't need x- anymore, see RFC2311 */
620 if (mutt_istr_equal(b->subtype, "x-pkcs7-mime") || mutt_istr_equal(b->subtype, "pkcs7-mime"))
621 {
622 t = mutt_param_get(&b->parameter, "smime-type");
623 if (t)
624 {
625 if (mutt_istr_equal(t, "enveloped-data"))
626 return SMIME_ENCRYPT;
627 if (mutt_istr_equal(t, "signed-data"))
628 return SMIME_SIGN | SMIME_OPAQUE;
629 return SEC_NO_FLAGS;
630 }
631 /* Netscape 4.7 uses
632 * Content-Description: S/MIME Encrypted Message
633 * instead of Content-Type parameter */
634 if (mutt_istr_equal(b->description, "S/MIME Encrypted Message"))
635 return SMIME_ENCRYPT;
636 complain = true;
637 }
638 else if (!mutt_istr_equal(b->subtype, "octet-stream"))
639 {
640 return SEC_NO_FLAGS;
641 }
642
643 t = mutt_param_get(&b->parameter, "name");
644
645 if (!t)
646 t = b->d_filename;
647 if (!t)
648 t = b->filename;
649 if (!t)
650 {
651 if (complain)
652 {
653 mutt_message(_("S/MIME messages with no hints on content are unsupported"));
654 }
655 return SEC_NO_FLAGS;
656 }
657
658 /* no .p7c, .p10 support yet. */
659
660 int len = mutt_str_len(t) - 4;
661 if ((len > 0) && (*(t + len) == '.'))
662 {
663 len++;
664 if (mutt_istr_equal((t + len), "p7m"))
665 {
666 const char *const c_smime_pkcs7_default_smime_type =
667 cs_subset_string(NeoMutt->sub, "smime_pkcs7_default_smime_type");
668 if (mutt_istr_equal(c_smime_pkcs7_default_smime_type, "signed"))
669 return SMIME_SIGN | SMIME_OPAQUE;
670 else if (mutt_istr_equal(c_smime_pkcs7_default_smime_type, "enveloped"))
671 return SMIME_ENCRYPT;
672 else
673 return SEC_NO_FLAGS;
674 }
675 else if (mutt_istr_equal((t + len), "p7s"))
676 {
677 return SMIME_SIGN | SMIME_OPAQUE;
678 }
679 }
680
681 return SEC_NO_FLAGS;
682}
683
693{
694 if (!WithCrypto || !b)
695 return SEC_NO_FLAGS;
696
698
699 if (b->type == TYPE_APPLICATION)
700 {
703
705 {
707 if (rc && b->goodsig)
708 rc |= SEC_GOODSIGN;
709 if (rc && b->badsig)
710 rc |= SEC_BADSIGN;
711 }
712 }
713 else if (((WithCrypto & APPLICATION_PGP) != 0) && (b->type == TYPE_TEXT))
714 {
716 if (rc && b->goodsig)
717 rc |= SEC_GOODSIGN;
718 }
719
720 if (b->type == TYPE_MULTIPART)
721 {
725
726 if (rc && b->goodsig)
727 rc |= SEC_GOODSIGN;
728#ifdef USE_AUTOCRYPT
729 if (rc && b->is_autocrypt)
730 rc |= SEC_AUTOCRYPT;
731#endif
732 }
733
734 if ((b->type == TYPE_MULTIPART) || (b->type == TYPE_MESSAGE))
735 {
736 SecurityFlags u = b->parts ? SEC_ALL_FLAGS : SEC_NO_FLAGS; /* Bits set in all parts */
737 SecurityFlags w = SEC_NO_FLAGS; /* Bits set in any part */
738
739 for (b = b->parts; b; b = b->next)
740 {
741 const SecurityFlags v = crypt_query(b);
742 u &= v;
743 w |= v;
744 }
745 rc |= u | (w & ~SEC_GOODSIGN);
746
747 if ((w & SEC_GOODSIGN) && !(u & SEC_GOODSIGN))
748 rc |= SEC_PARTSIGN;
749 }
750
751 return rc;
752}
753
764int crypt_write_signed(struct Body *b, struct State *state, const char *tempfile)
765{
766 if (!WithCrypto)
767 return -1;
768
769 FILE *fp = mutt_file_fopen(tempfile, "w");
770 if (!fp)
771 {
772 mutt_perror("%s", tempfile);
773 return -1;
774 }
775
776 if (!mutt_file_seek(state->fp_in, b->hdr_offset, SEEK_SET))
777 {
778 mutt_file_fclose(&fp);
779 return -1;
780 }
781 size_t bytes = b->length + b->offset - b->hdr_offset;
782 bool hadcr = false;
783 while (bytes > 0)
784 {
785 const int c = fgetc(state->fp_in);
786 if (c == EOF)
787 break;
788
789 bytes--;
790
791 if (c == '\r')
792 {
793 hadcr = true;
794 }
795 else
796 {
797 if ((c == '\n') && !hadcr)
798 fputc('\r', fp);
799
800 hadcr = false;
801 }
802
803 fputc(c, fp);
804 }
805 mutt_file_fclose(&fp);
806
807 return 0;
808}
809
815{
816 if (!WithCrypto)
817 return;
818
819 const bool c_pgp_strict_enc = cs_subset_bool(NeoMutt->sub, "pgp_strict_enc");
820 while (b)
821 {
822 if (b->type == TYPE_MULTIPART)
823 {
824 if (b->encoding != ENC_7BIT)
825 {
826 b->encoding = ENC_7BIT;
828 }
829 else if (((WithCrypto & APPLICATION_PGP) != 0) && c_pgp_strict_enc)
830 {
832 }
833 }
834 else if ((b->type == TYPE_MESSAGE) && !mutt_istr_equal(b->subtype, "delivery-status"))
835 {
836 if (b->encoding != ENC_7BIT)
838 }
839 else if (b->encoding == ENC_8BIT)
840 {
842 }
843 else if (b->encoding == ENC_BINARY)
844 {
845 b->encoding = ENC_BASE64;
846 }
847 else if (b->content && (b->encoding != ENC_BASE64) &&
848 (b->content->from || (b->content->space && c_pgp_strict_enc)))
849 {
851 }
852 b = b->next;
853 }
854}
855
863void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
864{
865 if (!WithCrypto)
866 return;
867
868 struct Buffer *tempfile = buf_pool_get();
869 buf_mktemp(tempfile);
870 FILE *fp_out = mutt_file_fopen(buf_string(tempfile), "w");
871 if (!fp_out)
872 {
873 mutt_perror("%s", buf_string(tempfile));
874 goto cleanup;
875 }
876
879
880 struct Email **ep = NULL;
881 ARRAY_FOREACH(ep, ea)
882 {
883 struct Email *e = *ep;
884 struct Message *msg = mx_msg_open(m, e);
885 if (!msg)
886 {
887 continue;
888 }
891 {
892 mx_msg_close(m, &msg);
893 mutt_file_fclose(&fp_out);
894 break;
895 }
896
897 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
898 {
900 fflush(fp_out);
901
902 mutt_endwin();
903 puts(_("Trying to extract PGP keys...\n"));
905 }
906
908 {
909 const bool encrypt = e->security & SEC_ENCRYPT;
910 mutt_copy_message(fp_out, e, msg,
913 CH_NO_FLAGS, 0);
914 fflush(fp_out);
915
916 const char *mbox = NULL;
917 if (!TAILQ_EMPTY(&e->env->from))
918 {
920 mbox = buf_string(TAILQ_FIRST(&e->env->from)->mailbox);
921 }
922 else if (!TAILQ_EMPTY(&e->env->sender))
923 {
925 mbox = buf_string(TAILQ_FIRST(&e->env->sender)->mailbox);
926 }
927 if (mbox)
928 {
929 mutt_endwin();
930 puts(_("Trying to extract S/MIME certificates..."));
931 crypt_smime_invoke_import(buf_string(tempfile), mbox);
932 }
933 }
934 mx_msg_close(m, &msg);
935
936 rewind(fp_out);
937 }
938
939 mutt_file_fclose(&fp_out);
940 if (isendwin())
942
943 mutt_file_unlink(buf_string(tempfile));
944
946 OptDontHandlePgpKeys = false;
947
948cleanup:
949 buf_pool_release(&tempfile);
950}
951
966int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
967{
968 if (!WithCrypto)
969 return 0;
970
971 struct AddressList addrlist = TAILQ_HEAD_INITIALIZER(addrlist);
972 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
973 const char *self_encrypt = NULL;
974
975 /* Do a quick check to make sure that we can find all of the encryption
976 * keys if the user has requested this service. */
977
978 *keylist = NULL;
979
980#ifdef USE_AUTOCRYPT
981 if (!oppenc_mode && (e->security & SEC_AUTOCRYPT))
982 {
984 return -1;
985 return 0;
986 }
987#endif
988
990 OptPgpCheckTrust = true;
991
992 mutt_addrlist_copy(&addrlist, &e->env->to, false);
993 mutt_addrlist_copy(&addrlist, &e->env->cc, false);
994 mutt_addrlist_copy(&addrlist, &e->env->bcc, false);
995 mutt_addrlist_qualify(&addrlist, fqdn);
996 mutt_addrlist_dedupe(&addrlist);
997
998 if (oppenc_mode || (e->security & SEC_ENCRYPT))
999 {
1000 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
1001 {
1002 *keylist = crypt_pgp_find_keys(&addrlist, oppenc_mode);
1003 if (!*keylist)
1004 {
1005 mutt_addrlist_clear(&addrlist);
1006 return -1;
1007 }
1008 OptPgpCheckTrust = false;
1009 const bool c_pgp_self_encrypt = cs_subset_bool(NeoMutt->sub, "pgp_self_encrypt");
1010 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
1011 const enum QuadOption c_pgp_encrypt_self = cs_subset_quad(NeoMutt->sub, "pgp_encrypt_self");
1012 if (c_pgp_self_encrypt || (c_pgp_encrypt_self == MUTT_YES))
1013 self_encrypt = c_pgp_default_key;
1014 }
1015 if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
1016 {
1017 *keylist = crypt_smime_find_keys(&addrlist, oppenc_mode);
1018 if (!*keylist)
1019 {
1020 mutt_addrlist_clear(&addrlist);
1021 return -1;
1022 }
1023 const bool c_smime_self_encrypt = cs_subset_bool(NeoMutt->sub, "smime_self_encrypt");
1024 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1025 const enum QuadOption c_smime_encrypt_self = cs_subset_quad(NeoMutt->sub, "smime_encrypt_self");
1026 if (c_smime_self_encrypt || (c_smime_encrypt_self == MUTT_YES))
1027 self_encrypt = c_smime_default_key;
1028 }
1029 }
1030
1031 if (!oppenc_mode && self_encrypt)
1032 {
1033 const size_t keylist_size = mutt_str_len(*keylist);
1034 MUTT_MEM_REALLOC(keylist, keylist_size + mutt_str_len(self_encrypt) + 2, char);
1035 sprintf(*keylist + keylist_size, " %s", self_encrypt);
1036 }
1037
1038 mutt_addrlist_clear(&addrlist);
1039
1040 return 0;
1041}
1042
1051{
1052 if (!WithCrypto)
1053 return;
1054
1055 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
1056 if (!(c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT)))
1057 return;
1058
1059 char *pgpkeylist = NULL;
1060
1061 crypt_get_keys(e, &pgpkeylist, true);
1062 if (pgpkeylist)
1063 {
1064 e->security |= SEC_ENCRYPT;
1065 FREE(&pgpkeylist);
1066 }
1067 else
1068 {
1069 e->security &= ~SEC_ENCRYPT;
1070 }
1071}
1072
1079static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
1080{
1081 if (!WithCrypto)
1082 return;
1083
1084 for (; b; b = b->next)
1085 {
1086 if (b->type == TYPE_MULTIPART)
1087 {
1088 crypt_fetch_signatures(b_sigs, b->parts, n);
1089 }
1090 else
1091 {
1092 if ((*n % 5) == 0)
1093 MUTT_MEM_REALLOC(b_sigs, *n + 6, struct Body *);
1094
1095 (*b_sigs)[(*n)++] = b;
1096 }
1097 }
1098}
1099
1106{
1107 const bool c_crypt_protected_headers_write = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_write");
1108 const char *const c_crypt_protected_headers_subject =
1109 cs_subset_string(NeoMutt->sub, "crypt_protected_headers_subject");
1110 if (c_crypt_protected_headers_write && (e->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) &&
1111 !(e->security & SEC_INLINE) && c_crypt_protected_headers_subject)
1112 {
1113 return true;
1114 }
1115
1116 return false;
1117}
1118
1122int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
1123{
1124 if (!cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read"))
1125 return 0;
1126
1128
1129 if (!b_email->mime_headers)
1130 goto blank;
1131
1132 /* Load display preferences: weeding, wrapping, and security debug flags */
1133 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
1134 const bool display = (state->flags & STATE_DISPLAY);
1135 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1136 const bool c_crypt_protected_headers_weed = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_weed");
1137 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
1138 const int wraplen = display ? mutt_window_wrap_cols(state->wraplen, c_wrap) : 0;
1139 const CopyHeaderFlags chflags = display ? CH_DISPLAY : CH_NO_FLAGS;
1140 struct Buffer *buf = buf_pool_get();
1141 bool weed = (display && c_weed && c_crypt_protected_headers_weed);
1142
1143 /* When devel_security is enabled, output all protected envelope headers
1144 * (Date, From, To, Cc, etc.) subject to weed rules */
1145 if (c_devel_security)
1146 {
1147 if (b_email->mime_headers->date && (!display || !c_weed || !mutt_matches_ignore("date")))
1148 {
1149 mutt_write_one_header(state->fp_out, "Date", b_email->mime_headers->date,
1150 state->prefix, wraplen, chflags, NeoMutt->sub);
1151 }
1152
1153 if (!weed || !mutt_matches_ignore("return-path"))
1154 {
1155 mutt_addrlist_write(&b_email->mime_headers->return_path, buf, display);
1156 mutt_write_one_header(state->fp_out, "Return-Path", buf_string(buf),
1157 state->prefix, wraplen, chflags, NeoMutt->sub);
1158 }
1159 if (!weed || !mutt_matches_ignore("from"))
1160 {
1161 buf_reset(buf);
1162 mutt_addrlist_write(&b_email->mime_headers->from, buf, display);
1163 mutt_write_one_header(state->fp_out, "From", buf_string(buf),
1164 state->prefix, wraplen, chflags, NeoMutt->sub);
1165 }
1166 if (!weed || !mutt_matches_ignore("to"))
1167 {
1168 buf_reset(buf);
1169 mutt_addrlist_write(&b_email->mime_headers->to, buf, display);
1170 mutt_write_one_header(state->fp_out, "To", buf_string(buf), state->prefix,
1171 wraplen, chflags, NeoMutt->sub);
1172 }
1173 if (!weed || !mutt_matches_ignore("cc"))
1174 {
1175 buf_reset(buf);
1176 mutt_addrlist_write(&b_email->mime_headers->cc, buf, display);
1177 mutt_write_one_header(state->fp_out, "Cc", buf_string(buf), state->prefix,
1178 wraplen, chflags, NeoMutt->sub);
1179 }
1180 if (!weed || !mutt_matches_ignore("sender"))
1181 {
1182 buf_reset(buf);
1183 mutt_addrlist_write(&b_email->mime_headers->sender, buf, display);
1184 mutt_write_one_header(state->fp_out, "Sender", buf_string(buf),
1185 state->prefix, wraplen, chflags, NeoMutt->sub);
1186 }
1187 if (!weed || !mutt_matches_ignore("reply-to"))
1188 {
1189 buf_reset(buf);
1190 mutt_addrlist_write(&b_email->mime_headers->reply_to, buf, display);
1191 mutt_write_one_header(state->fp_out, "Reply-To", buf_string(buf),
1192 state->prefix, wraplen, chflags, NeoMutt->sub);
1193 }
1194 if (!weed || !mutt_matches_ignore("mail-followup-to"))
1195 {
1196 buf_reset(buf);
1197 mutt_addrlist_write(&b_email->mime_headers->mail_followup_to, buf, display);
1198 mutt_write_one_header(state->fp_out, "Mail-Followup-To", buf_string(buf),
1199 state->prefix, wraplen, chflags, NeoMutt->sub);
1200 }
1201 if (!weed || !mutt_matches_ignore("x-original-to"))
1202 {
1203 buf_reset(buf);
1204 mutt_addrlist_write(&b_email->mime_headers->x_original_to, buf, display);
1205 mutt_write_one_header(state->fp_out, "X-Original-To", buf_string(buf),
1206 state->prefix, wraplen, chflags, NeoMutt->sub);
1207 }
1208 }
1209
1210 if (b_email->mime_headers->subject && (!weed || !mutt_matches_ignore("subject")))
1211 {
1212 mutt_write_one_header(state->fp_out, "Subject", b_email->mime_headers->subject,
1213 state->prefix, wraplen, chflags, NeoMutt->sub);
1214 }
1215
1216 if (c_devel_security)
1217 {
1218 if (b_email->mime_headers->message_id && (!weed || !mutt_matches_ignore("message-id")))
1219 {
1220 mutt_write_one_header(state->fp_out, "Message-ID", b_email->mime_headers->message_id,
1221 state->prefix, wraplen, chflags, NeoMutt->sub);
1222 }
1223 if (!weed || !mutt_matches_ignore("references"))
1224 {
1225 buf_reset(buf);
1226 mutt_list_write(&b_email->mime_headers->references, buf);
1227 mutt_write_one_header(state->fp_out, "References", buf_string(buf),
1228 state->prefix, wraplen, chflags, NeoMutt->sub);
1229 }
1230 if (!weed || !mutt_matches_ignore("in-reply-to"))
1231 {
1232 buf_reset(buf);
1233 mutt_list_write(&b_email->mime_headers->in_reply_to, buf);
1234 mutt_write_one_header(state->fp_out, "In-Reply-To", buf_string(buf),
1235 state->prefix, wraplen, chflags, NeoMutt->sub);
1236 }
1237 }
1238
1239 buf_pool_release(&buf);
1240
1241blank:
1242 state_puts(state, "\n");
1243 return 0;
1244}
1245
1249int mutt_signed_handler(struct Body *b_email, struct State *state)
1250{
1251 if (!WithCrypto)
1252 return -1;
1253
1254 bool inconsistent = false;
1255 struct Body *top = b_email;
1256 struct Body **signatures = NULL;
1257 int sigcnt = 0;
1258 int rc = 0;
1259 struct Buffer *tempfile = NULL;
1260
1261 /* Identify the signature type from the multipart/signed protocol parameter */
1262 b_email = b_email->parts;
1263 SecurityFlags signed_type = mutt_is_multipart_signed(top);
1264 if (signed_type == SEC_NO_FLAGS)
1265 {
1266 /* A null protocol value is already checked for in mutt_body_handler() */
1267 state_printf(state, _("[-- Error: Unknown multipart/signed protocol %s --]\n\n"),
1268 mutt_param_get(&top->parameter, "protocol"));
1269 return mutt_body_handler(b_email, state);
1270 }
1271
1272 /* Validate that the second MIME part matches the expected signature type */
1273 if (!(b_email && b_email->next))
1274 {
1275 inconsistent = true;
1276 }
1277 else
1278 {
1279 switch (signed_type)
1280 {
1281 case SEC_SIGN:
1282 if ((b_email->next->type != TYPE_MULTIPART) ||
1283 !mutt_istr_equal(b_email->next->subtype, "mixed"))
1284 {
1285 inconsistent = true;
1286 }
1287 break;
1288 case PGP_SIGN:
1289 if ((b_email->next->type != TYPE_APPLICATION) ||
1290 !mutt_istr_equal(b_email->next->subtype, "pgp-signature"))
1291 {
1292 inconsistent = true;
1293 }
1294 break;
1295 case SMIME_SIGN:
1296 if ((b_email->next->type != TYPE_APPLICATION) ||
1297 (!mutt_istr_equal(b_email->next->subtype, "x-pkcs7-signature") &&
1298 !mutt_istr_equal(b_email->next->subtype, "pkcs7-signature")))
1299 {
1300 inconsistent = true;
1301 }
1302 break;
1303 default:
1304 inconsistent = true;
1305 }
1306 }
1307 if (inconsistent)
1308 {
1309 state_attach_puts(state, _("[-- Error: Missing or bad-format multipart/signed signature --]\n\n"));
1310 return mutt_body_handler(b_email, state);
1311 }
1312
1313 if (state->flags & STATE_DISPLAY)
1314 {
1315 /* Verify each signature part (PGP or S/MIME) against the signed body
1316 * written to a temporary file */
1317 crypt_fetch_signatures(&signatures, b_email->next, &sigcnt);
1318
1319 if (sigcnt != 0)
1320 {
1321 tempfile = buf_pool_get();
1322 buf_mktemp(tempfile);
1323 bool goodsig = true;
1324 if (crypt_write_signed(b_email, state, buf_string(tempfile)) == 0)
1325 {
1326 for (int i = 0; i < sigcnt; i++)
1327 {
1328 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1329 (signatures[i]->type == TYPE_APPLICATION) &&
1330 mutt_istr_equal(signatures[i]->subtype, "pgp-signature"))
1331 {
1332 if (crypt_pgp_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1333 goodsig = false;
1334
1335 continue;
1336 }
1337
1338 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1339 (signatures[i]->type == TYPE_APPLICATION) &&
1340 (mutt_istr_equal(signatures[i]->subtype, "x-pkcs7-signature") ||
1341 mutt_istr_equal(signatures[i]->subtype, "pkcs7-signature")))
1342 {
1343 if (crypt_smime_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1344 goodsig = false;
1345
1346 continue;
1347 }
1348
1349 state_printf(state, _("[-- Warning: We can't verify %s/%s signatures --]\n\n"),
1350 BODY_TYPE(signatures[i]), signatures[i]->subtype);
1351 }
1352 }
1353
1354 mutt_file_unlink(buf_string(tempfile));
1355 buf_pool_release(&tempfile);
1356
1357 top->goodsig = goodsig;
1358 top->badsig = !goodsig;
1359
1360 /* Now display the signed body */
1361 state_attach_puts(state, _("[-- The following data is signed --]\n"));
1362
1363 mutt_protected_headers_handler(b_email, state);
1364
1365 FREE(&signatures);
1366 }
1367 else
1368 {
1369 state_attach_puts(state, _("[-- Warning: Can't find any signatures --]\n\n"));
1370 }
1371 }
1372
1373 rc = mutt_body_handler(b_email, state);
1374
1375 if ((state->flags & STATE_DISPLAY) && (sigcnt != 0))
1376 state_attach_puts(state, _("[-- End of signed data --]\n"));
1377
1378 return rc;
1379}
1380
1395const char *crypt_get_fingerprint_or_id(const char *p, const char **pphint,
1396 const char **ppl, const char **pps)
1397{
1398 const char *ps = NULL, *pl = NULL, *phint = NULL;
1399 char *pfcopy = NULL, *s1 = NULL, *s2 = NULL;
1400 char c;
1401 int isid;
1402 size_t hexdigits;
1403
1404 /* User input may be partial name, fingerprint or short or long key ID,
1405 * independent of `$pgp_long_ids`.
1406 * Fingerprint without spaces is 40 hex digits (SHA-1) or 32 hex digits (MD5).
1407 * Strip leading "0x" for key ID detection and prepare pl and ps to indicate
1408 * if an ID was found and to simplify logic in the key loop's inner
1409 * condition of the caller. */
1410
1411 char *pf = mutt_str_skip_whitespace(p);
1412 if (mutt_istr_startswith(pf, "0x"))
1413 pf += 2;
1414
1415 /* Check if a fingerprint is given, must be hex digits only, blanks
1416 * separating groups of 4 hex digits are allowed. Also pre-check for ID. */
1417 isid = 2; /* unknown */
1418 hexdigits = 0;
1419 s1 = pf;
1420 do
1421 {
1422 c = *(s1++);
1423 if ((('0' <= c) && (c <= '9')) || (('A' <= c) && (c <= 'F')) ||
1424 (('a' <= c) && (c <= 'f')))
1425 {
1426 hexdigits++;
1427 if (isid == 2)
1428 isid = 1; /* it is an ID so far */
1429 }
1430 else if (c)
1431 {
1432 isid = 0; /* not an ID */
1433 if ((c == ' ') && ((hexdigits % 4) == 0))
1434 ; /* skip blank before or after 4 hex digits */
1435 else
1436 break; /* any other character or position */
1437 }
1438 } while (c);
1439
1440 /* If at end of input, check for correct fingerprint length and copy if. */
1441 pfcopy = (!c && ((hexdigits == 40) || (hexdigits == 32)) ? mutt_str_dup(pf) : NULL);
1442
1443 if (pfcopy)
1444 {
1445 /* Use pfcopy to strip all spaces from fingerprint and as hint. */
1446 s1 = pfcopy;
1447 s2 = pfcopy;
1448 do
1449 {
1450 *(s1++) = *(s2 = mutt_str_skip_whitespace(s2));
1451 } while (*(s2++));
1452
1453 phint = pfcopy;
1454 ps = NULL;
1455 pl = NULL;
1456 }
1457 else
1458 {
1459 phint = p;
1460 ps = NULL;
1461 pl = NULL;
1462 if (isid == 1)
1463 {
1464 if (mutt_str_len(pf) == 16)
1465 pl = pf; /* long key ID */
1466 else if (mutt_str_len(pf) == 8)
1467 ps = pf; /* short key ID */
1468 }
1469 }
1470
1471 *pphint = phint;
1472 *ppl = pl;
1473 *pps = ps;
1474 return pfcopy;
1475}
1476
1484bool crypt_is_numerical_keyid(const char *s)
1485{
1486 /* or should we require the "0x"? */
1487 if (mutt_strn_equal(s, "0x", 2))
1488 s += 2;
1489 if (strlen(s) % 8)
1490 return false;
1491 while (*s)
1492 if (!strchr("0123456789ABCDEFabcdef", *s++))
1493 return false;
1494
1495 return true;
1496}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:685
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition address.c:462
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1215
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition address.c:1406
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:296
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:627
GUI display the mailboxes in a side panel.
Autocrypt end-to-end encryption.
@ AUTOCRYPT_REC_NO
Do no use Autocrypt.
Definition lib.h:168
int mutt_autocrypt_generate_gossip_list(struct Email *e)
Create the gossip list headers.
Definition autocrypt.c:843
enum AutocryptRec mutt_autocrypt_ui_recommendation(const struct Email *e, char **keylist)
Get the recommended action for an Email.
Definition autocrypt.c:577
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
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
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
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.
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition copy_email.c:917
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:40
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:44
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:48
#define CH_DISPLAY
Display result to user.
Definition copy_email.h:74
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition copy_email.h:54
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition copy_email.h:37
#define MUTT_CM_DECODE_CRYPT
Combination flag for decoding any kind of cryptography (PGP or S/MIME)
Definition copy_email.h:52
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition copy_email.h:38
#define CH_NO_FLAGS
No flags are set.
Definition copy_email.h:55
Convenience wrapper for the core headers.
static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
Create an array of an emails parts.
Definition crypt.c:1079
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1050
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1484
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:408
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:467
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition crypt.c:1105
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition crypt.c:863
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:443
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition crypt.c:156
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition crypt.c:89
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition crypt.c:1395
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
int crypt_write_signed(struct Body *b, struct State *state, const char *tempfile)
Write the message body/part.
Definition crypt.c:764
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition crypt.c:966
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition crypt.c:64
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:814
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition crypt.c:692
Signing/encryption multiplexor.
char * crypt_smime_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Wrapper for CryptModuleSpecs::find_keys()
Definition cryptglue.c:487
struct Body * crypt_smime_build_smime_entity(struct Body *b, char *certlist)
Wrapper for CryptModuleSpecs::smime_build_smime_entity()
Definition cryptglue.c:509
struct Body * crypt_smime_sign_message(struct Body *b, const struct AddressList *from)
Wrapper for CryptModuleSpecs::sign_message()
Definition cryptglue.c:498
struct Body * crypt_pgp_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
Wrapper for CryptModuleSpecs::pgp_traditional_encryptsign()
Definition cryptglue.c:306
char * crypt_pgp_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Wrapper for CryptModuleSpecs::find_keys()
Definition cryptglue.c:328
struct Body * crypt_pgp_sign_message(struct Body *b, const struct AddressList *from)
Wrapper for CryptModuleSpecs::sign_message()
Definition cryptglue.c:339
bool crypt_smime_valid_passphrase(void)
Wrapper for CryptModuleSpecs::valid_passphrase()
Definition cryptglue.c:434
void crypt_pgp_invoke_import(const char *fname)
Wrapper for CryptModuleSpecs::pgp_invoke_import()
Definition cryptglue.c:376
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition cryptglue.c:425
void crypt_smime_invoke_import(const char *infile, const char *mailbox)
Wrapper for CryptModuleSpecs::smime_invoke_import()
Definition cryptglue.c:520
void crypt_pgp_set_sender(const char *sender)
Wrapper for CryptModuleSpecs::set_sender()
Definition cryptglue.c:416
void crypt_smime_set_sender(const char *sender)
Wrapper for CryptModuleSpecs::set_sender()
Definition cryptglue.c:551
int crypt_smime_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition cryptglue.c:529
void crypt_pgp_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition cryptglue.c:203
bool crypt_pgp_valid_passphrase(void)
Wrapper for CryptModuleSpecs::valid_passphrase()
Definition cryptglue.c:212
int crypt_pgp_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition cryptglue.c:385
struct Body * crypt_pgp_encrypt_message(struct Email *e, struct Body *b, char *keylist, int sign, const struct AddressList *from)
Wrapper for CryptModuleSpecs::pgp_encrypt_message()
Definition cryptglue.c:350
Wrapper around crypto functions.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:175
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:153
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
Structs that make up an email.
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition parse.c:320
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
Definition envelope.c:350
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition envelope.c:68
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition globals.c:46
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition globals.c:55
Global variables.
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1122
int mutt_signed_handler(struct Body *b_email, struct State *state)
Handler for "multipart/signed" - Implements handler_t -.
Definition crypt.c:1249
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_perror(...)
Definition logging2.h:95
Convenience wrapper for the gui headers.
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1664
void mutt_list_copy_tail(struct ListHead *dst, const struct ListHead *src)
Copy a list into another list.
Definition list.c:275
size_t mutt_list_write(const struct ListHead *h, struct Buffer *buf)
Write a list to a buffer.
Definition list.c:293
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
@ ENC_7BIT
7-bit text
Definition mime.h:49
@ ENC_BINARY
Binary.
Definition mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition mime.h:52
@ ENC_8BIT
8-bit text
Definition mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition mime.h:51
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
#define BODY_TYPE(body)
Get the type name of a body part.
Definition mime.h:93
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition multipart.c:133
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition date.c:952
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
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
void state_mark_protected_header(struct State *state)
Write a unique marker around protected headers.
Definition state.c:88
#define state_puts(STATE, STR)
Definition state.h:58
#define STATE_DISPLAY
Output is displayed to the user.
Definition state.h:33
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
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
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:556
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
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_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
API for mailboxes.
API for encryption/signing of emails.
#define SEC_INLINE
Email has an inline signature.
Definition lib.h:94
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:96
#define PGP_SIGN
Email is PGP signed.
Definition lib.h:106
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:85
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:95
#define SEC_ALL_FLAGS
Mask for all security flags.
Definition lib.h:103
#define SEC_GOODSIGN
Email has a valid signature.
Definition lib.h:89
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:99
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:105
#define SMIME_SIGN
Email is S/MIME signed.
Definition lib.h:112
#define PGP_INLINE
Email is inline PGP encrypted/signed.
Definition lib.h:109
#define SEC_BADSIGN
Email has a bad signature.
Definition lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:100
#define SEC_NO_FLAGS
No flags are set.
Definition lib.h:86
#define SEC_PARTSIGN
Not all parts of the email is signed.
Definition lib.h:91
#define SMIME_OPAQUE
Email has an opaque S/MIME signature.
Definition lib.h:115
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:87
#define PGP_KEY
Email contains a PGP key.
Definition lib.h:108
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:111
#define WithCrypto
Definition lib.h:125
#define SEC_SIGN
Email is signed.
Definition lib.h:88
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition parameter.c:85
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition parameter.c:143
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_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#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
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags, struct ConfigSubset *sub)
Write one header line to a file.
Definition header.c:424
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1405
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:713
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:746
void mutt_message_to_7bit(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition sendlib.c:258
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
The body of an email.
Definition body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition body.h:43
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
bool is_autocrypt
Flag autocrypt-decrypted messages for replying.
Definition body.h:50
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
char * description
content-description
Definition body.h:55
struct Content * content
Detailed info about the content of the attachment.
Definition body.h:70
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
long hdr_offset
Offset in stream where the headers begin.
Definition body.h:81
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
bool space
Whitespace at the end of lines?
Definition content.h:42
bool from
Has a line beginning with "From "?
Definition content.h:44
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 Body * body
List of MIME parts.
Definition email.h:69
The header of an Email.
Definition envelope.h:57
struct AddressList return_path
Return path for the Email.
Definition envelope.h:58
char *const subject
Email's subject.
Definition envelope.h:70
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition envelope.h:64
char * message_id
Message ID.
Definition envelope.h:73
struct AddressList x_original_to
Email's 'X-Original-to'.
Definition envelope.h:66
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
struct AddressList sender
Email's sender.
Definition envelope.h:63
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
struct AddressList bcc
Email's 'Bcc' list.
Definition envelope.h:62
char * date
Sent date.
Definition envelope.h:75
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
A mailbox.
Definition mailbox.h:78
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Keep track when processing files.
Definition state.h:48
int wraplen
Width to wrap lines to (when flags & STATE_DISPLAY)
Definition state.h:53
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
FILE * fp_out
File to write to.
Definition state.h:50
FILE * fp_in
File to read from.
Definition state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition state.h:51
#define buf_mktemp(buf)
Definition tmp.h:33