NeoMutt  2025-01-09-41-g086358
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
smime.c
Go to the documentation of this file.
1
34#include "config.h"
35#include <limits.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <string.h>
39#include <sys/types.h>
40#include <unistd.h>
41#include "private.h"
42#include "mutt/lib.h"
43#include "address/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "alias/lib.h"
48#include "gui/lib.h"
49#include "mutt.h"
50#include "lib.h"
51#include "editor/lib.h"
52#include "expando/lib.h"
53#include "history/lib.h"
54#include "question/lib.h"
55#include "send/lib.h"
56#include "copy.h"
57#include "crypt.h"
58#include "cryptglue.h"
59#include "expando_smime.h"
60#include "globals.h"
61#include "handler.h"
62#include "mutt_logging.h"
63#ifdef CRYPT_BACKEND_CLASSIC_SMIME
64#include "smime.h"
65#endif
66
68static char SmimePass[256];
70static time_t SmimeExpTime = 0; /* when does the cached passphrase expire? */
71
73static struct Buffer SmimeKeyToUse = { 0 };
75static struct Buffer SmimeCertToUse = { 0 };
77static struct Buffer SmimeIntermediateToUse = { 0 };
78
82void smime_init(void)
83{
87}
88
92void smime_cleanup(void)
93{
97}
98
103static void smime_key_free(struct SmimeKey **keylist)
104{
105 if (!keylist)
106 return;
107
108 struct SmimeKey *key = NULL;
109
110 while (*keylist)
111 {
112 key = *keylist;
113 *keylist = (*keylist)->next;
114
115 FREE(&key->email);
116 FREE(&key->hash);
117 FREE(&key->label);
118 FREE(&key->issuer);
119 FREE(&key);
120 }
121}
122
128static struct SmimeKey *smime_copy_key(struct SmimeKey *key)
129{
130 if (!key)
131 return NULL;
132
133 struct SmimeKey *copy = NULL;
134
135 copy = MUTT_MEM_CALLOC(1, struct SmimeKey);
136 copy->email = mutt_str_dup(key->email);
137 copy->hash = mutt_str_dup(key->hash);
138 copy->label = mutt_str_dup(key->label);
139 copy->issuer = mutt_str_dup(key->issuer);
140 copy->trust = key->trust;
141 copy->flags = key->flags;
142
143 return copy;
144}
145
150{
151 memset(SmimePass, 0, sizeof(SmimePass));
152 SmimeExpTime = 0;
153}
154
159{
160 const time_t now = mutt_date_now();
161 if (now < SmimeExpTime)
162 {
163 /* Use cached copy. */
164 return true;
165 }
166
168
169 struct Buffer *buf = buf_pool_get();
170 const int rc = mw_get_field(_("Enter S/MIME passphrase:"), buf,
173 buf_pool_release(&buf);
174
175 if (rc == 0)
176 {
177 const short c_smime_timeout = cs_subset_number(NeoMutt->sub, "smime_timeout");
178 SmimeExpTime = mutt_date_add_timeout(now, c_smime_timeout);
179 return true;
180 }
181 else
182 {
183 SmimeExpTime = 0;
184 }
185
186 return false;
187}
188
195static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx,
196 const struct Expando *exp)
197{
199 buf->dsize, buf);
200 mutt_debug(LL_DEBUG2, "%s\n", buf_string(buf));
201}
202
225static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err,
226 int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd,
227 const char *fname, const char *sig_fname, const char *cryptalg,
228 const char *digestalg, const char *key, const char *certificates,
229 const char *intermediates, const struct Expando *exp)
230{
231 struct SmimeCommandContext cctx = { 0 };
232
233 if (!exp)
234 return (pid_t) -1;
235
236 cctx.fname = fname;
237 cctx.sig_fname = sig_fname;
238 cctx.key = key;
239 cctx.cryptalg = cryptalg;
240 cctx.digestalg = digestalg;
243
244 struct Buffer *cmd = buf_pool_get();
245 smime_command(cmd, &cctx, exp);
246
247 pid_t pid = filter_create_fd(buf_string(cmd), fp_smime_in, fp_smime_out, fp_smime_err,
248 fp_smime_infd, fp_smime_outfd, fp_smime_errfd, EnvList);
249 buf_pool_release(&cmd);
250 return pid;
251}
252
259static struct SmimeKey *smime_parse_key(char *buf)
260{
261 char *pend = NULL, *p = NULL;
262 int field = 0;
263
264 struct SmimeKey *key = MUTT_MEM_CALLOC(1, struct SmimeKey);
265
266 for (p = buf; p; p = pend)
267 {
268 /* Some users manually maintain their .index file, and use a tab
269 * as a delimiter, which the old parsing code (using fscanf)
270 * happened to allow. smime_keys uses a space, so search for both. */
271 if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
272 *pend++ = 0;
273
274 /* For backward compatibility, don't count consecutive delimiters
275 * as an empty field. */
276 if (*p == '\0')
277 continue;
278
279 field++;
280
281 switch (field)
282 {
283 case 1: /* mailbox */
284 key->email = mutt_str_dup(p);
285 break;
286 case 2: /* hash */
287 key->hash = mutt_str_dup(p);
288 break;
289 case 3: /* label */
290 key->label = mutt_str_dup(p);
291 break;
292 case 4: /* issuer */
293 key->issuer = mutt_str_dup(p);
294 break;
295 case 5: /* trust */
296 key->trust = *p;
297 break;
298 case 6: /* purpose */
299 while (*p)
300 {
301 switch (*p++)
302 {
303 case 'e':
305 break;
306
307 case 's':
308 key->flags |= KEYFLAG_CANSIGN;
309 break;
310 }
311 }
312 break;
313 }
314 }
315
316 /* Old index files could be missing issuer, trust, and purpose,
317 * but anything less than that is an error. */
318 if (field < 3)
319 {
320 smime_key_free(&key);
321 return NULL;
322 }
323
324 if (field < 4)
325 key->issuer = mutt_str_dup("?");
326
327 if (field < 5)
328 key->trust = 't';
329
330 if (field < 6)
332
333 return key;
334}
335
342static struct SmimeKey *smime_get_candidates(const char *search, bool only_public_key)
343{
344 char buf[1024] = { 0 };
345 struct SmimeKey *key = NULL, *results = NULL;
346 struct SmimeKey **results_end = &results;
347
348 struct Buffer *index_file = buf_pool_get();
349 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
350 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
351 buf_printf(index_file, "%s/.index",
352 only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
353
354 FILE *fp = mutt_file_fopen(buf_string(index_file), "r");
355 if (!fp)
356 {
357 mutt_perror("%s", buf_string(index_file));
358 buf_pool_release(&index_file);
359 return NULL;
360 }
361 buf_pool_release(&index_file);
362
363 while (fgets(buf, sizeof(buf), fp))
364 {
365 if (((*search == '\0')) || mutt_istr_find(buf, search))
366 {
367 key = smime_parse_key(buf);
368 if (key)
369 {
370 *results_end = key;
371 results_end = &key->next;
372 }
373 }
374 }
375
376 mutt_file_fclose(&fp);
377
378 return results;
379}
380
390static struct SmimeKey *smime_get_key_by_hash(const char *hash, bool only_public_key)
391{
392 struct SmimeKey *match = NULL;
393 struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
394 for (struct SmimeKey *result = results; result; result = result->next)
395 {
396 if (mutt_istr_equal(hash, result->hash))
397 {
398 match = smime_copy_key(result);
399 break;
400 }
401 }
402
403 smime_key_free(&results);
404
405 return match;
406}
407
416static struct SmimeKey *smime_get_key_by_addr(const char *mailbox, KeyFlags abilities,
417 bool only_public_key, bool oppenc_mode)
418{
419 if (!mailbox)
420 return NULL;
421
422 struct SmimeKey *results = NULL, *result = NULL;
423 struct SmimeKey *matches = NULL;
424 struct SmimeKey **matches_end = &matches;
425 struct SmimeKey *match = NULL;
426 struct SmimeKey *trusted_match = NULL;
427 struct SmimeKey *valid_match = NULL;
428 struct SmimeKey *return_key = NULL;
429 bool multi_trusted_matches = false;
430
431 results = smime_get_candidates(mailbox, only_public_key);
432 for (result = results; result; result = result->next)
433 {
434 if (abilities && !(result->flags & abilities))
435 {
436 continue;
437 }
438
439 if (mutt_istr_equal(mailbox, result->email))
440 {
441 match = smime_copy_key(result);
442 *matches_end = match;
443 matches_end = &match->next;
444
445 if (match->trust == 't')
446 {
447 if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
448 {
449 multi_trusted_matches = true;
450 }
451 trusted_match = match;
452 }
453 else if ((match->trust == 'u') || (match->trust == 'v'))
454 {
455 valid_match = match;
456 }
457 }
458 }
459
460 smime_key_free(&results);
461
462 if (matches)
463 {
464 if (oppenc_mode || !isatty(STDIN_FILENO))
465 {
466 const bool c_crypt_opportunistic_encrypt_strong_keys =
467 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
468 if (trusted_match)
469 return_key = smime_copy_key(trusted_match);
470 else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
471 return_key = smime_copy_key(valid_match);
472 else
473 return_key = NULL;
474 }
475 else if (trusted_match && !multi_trusted_matches)
476 {
477 return_key = smime_copy_key(trusted_match);
478 }
479 else
480 {
481 return_key = smime_copy_key(dlg_smime(matches, mailbox));
482 }
483
484 smime_key_free(&matches);
485 }
486
487 return return_key;
488}
489
497static struct SmimeKey *smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
498{
499 if (!str)
500 return NULL;
501
502 struct SmimeKey *results = NULL, *result = NULL;
503 struct SmimeKey *matches = NULL;
504 struct SmimeKey **matches_end = &matches;
505 struct SmimeKey *match = NULL;
506 struct SmimeKey *return_key = NULL;
507
508 results = smime_get_candidates(str, only_public_key);
509 for (result = results; result; result = result->next)
510 {
511 if (abilities && !(result->flags & abilities))
512 {
513 continue;
514 }
515
516 if (mutt_istr_equal(str, result->hash) ||
517 mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
518 {
519 match = smime_copy_key(result);
520 *matches_end = match;
521 matches_end = &match->next;
522 }
523 }
524
525 smime_key_free(&results);
526
527 if (matches)
528 {
529 return_key = smime_copy_key(dlg_smime(matches, str));
530 smime_key_free(&matches);
531 }
532
533 return return_key;
534}
535
543static struct SmimeKey *smime_ask_for_key(const char *prompt, KeyFlags abilities, bool only_public_key)
544{
545 if (!prompt)
546 return NULL;
547
548 struct SmimeKey *key = NULL;
549 struct Buffer *resp = buf_pool_get();
550
552
553 while (true)
554 {
555 buf_reset(resp);
556 if (mw_get_field(prompt, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
557 {
558 goto done;
559 }
560
561 key = smime_get_key_by_str(buf_string(resp), abilities, only_public_key);
562 if (key)
563 goto done;
564
565 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
566 }
567
568done:
569 buf_pool_release(&resp);
570 return key;
571}
572
580static void getkeys(const char *mailbox)
581{
582 const char *k = NULL;
583
584 struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
585
586 if (!key)
587 {
588 struct Buffer *prompt = buf_pool_get();
589 buf_printf(prompt, _("Enter keyID for %s: "), mailbox);
590 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, false);
591 buf_pool_release(&prompt);
592 }
593
594 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
595 size_t smime_keys_len = mutt_str_len(c_smime_keys);
596
597 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
598 k = key ? key->hash : NONULL(c_smime_default_key);
599
600 /* if the key is different from last time */
601 if ((buf_len(&SmimeKeyToUse) <= smime_keys_len) ||
602 !mutt_istr_equal(k, SmimeKeyToUse.data + smime_keys_len + 1))
603 {
605 buf_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), k);
606 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
607 buf_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), k);
608 }
609
610 smime_key_free(&key);
611}
612
617{
618 const bool c_smime_decrypt_use_default_key = cs_subset_bool(NeoMutt->sub, "smime_decrypt_use_default_key");
619 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
620 if (c_smime_decrypt_use_default_key && c_smime_default_key)
621 {
622 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
623 buf_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), c_smime_default_key);
624 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
625 buf_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), c_smime_default_key);
626 return;
627 }
628
629 struct Address *a = NULL;
630 TAILQ_FOREACH(a, &env->to, entries)
631 {
632 if (mutt_addr_is_user(a))
633 {
635 return;
636 }
637 }
638
639 TAILQ_FOREACH(a, &env->cc, entries)
640 {
641 if (mutt_addr_is_user(a))
642 {
644 return;
645 }
646 }
647
648 struct Address *f = mutt_default_from(NeoMutt->sub);
650 mutt_addr_free(&f);
651}
652
656char *smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
657{
658 struct SmimeKey *key = NULL;
659 char *keyid = NULL, *keylist = NULL;
660 size_t keylist_size = 0;
661 size_t keylist_used = 0;
662
663 struct Address *a = NULL;
664 TAILQ_FOREACH(a, al, entries)
665 {
666 key = smime_get_key_by_addr(buf_string(a->mailbox), KEYFLAG_CANENCRYPT, true, oppenc_mode);
667 if (!key && !oppenc_mode && isatty(STDIN_FILENO))
668 {
669 struct Buffer *prompt = buf_pool_get();
670 buf_printf(prompt, _("Enter keyID for %s: "), buf_string(a->mailbox));
671 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, true);
672 buf_pool_release(&prompt);
673 }
674 if (!key)
675 {
676 if (!oppenc_mode)
677 mutt_message(_("No (valid) certificate found for %s"), buf_string(a->mailbox));
678 FREE(&keylist);
679 return NULL;
680 }
681
682 keyid = key->hash;
683 keylist_size += mutt_str_len(keyid) + 2;
684 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
685 sprintf(keylist + keylist_used, "%s%s", keylist_used ? " " : "", keyid);
686 keylist_used = mutt_str_len(keylist);
687
688 smime_key_free(&key);
689 }
690 return keylist;
691}
692
704static int smime_handle_cert_email(const char *certificate, const char *mailbox,
705 bool copy, char ***buffer, int *num)
706{
707 char email[256] = { 0 };
708 int rc = -1, count = 0;
709 pid_t pid;
710
711 FILE *fp_err = mutt_file_mkstemp();
712 if (!fp_err)
713 {
714 mutt_perror(_("Can't create temporary file"));
715 return 1;
716 }
717
718 FILE *fp_out = mutt_file_mkstemp();
719 if (!fp_out)
720 {
721 mutt_file_fclose(&fp_err);
722 mutt_perror(_("Can't create temporary file"));
723 return 1;
724 }
725
726 const struct Expando *c_smime_get_cert_email_command =
727 cs_subset_expando(NeoMutt->sub, "smime_get_cert_email_command");
728 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
729 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
730 if (pid == -1)
731 {
732 mutt_message(_("Error: unable to create OpenSSL subprocess"));
733 mutt_file_fclose(&fp_err);
734 mutt_file_fclose(&fp_out);
735 return 1;
736 }
737
738 filter_wait(pid);
739
740 fflush(fp_out);
741 rewind(fp_out);
742 fflush(fp_err);
743 rewind(fp_err);
744
745 while ((fgets(email, sizeof(email), fp_out)))
746 {
747 size_t len = mutt_str_len(email);
748 if (len && (email[len - 1] == '\n'))
749 email[len - 1] = '\0';
750 if (mutt_istr_startswith(email, mailbox))
751 rc = 1;
752
753 rc = (rc < 0) ? 0 : rc;
754 count++;
755 }
756
757 if (rc == -1)
758 {
759 mutt_endwin();
760 mutt_file_copy_stream(fp_err, stdout);
761 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
762 rc = 1;
763 }
764 else if (rc == 0)
765 {
766 rc = 1;
767 }
768 else
769 {
770 rc = 0;
771 }
772
773 if (copy && buffer && num)
774 {
775 (*num) = count;
776 *buffer = MUTT_MEM_CALLOC(count, char *);
777 count = 0;
778
779 rewind(fp_out);
780 while ((fgets(email, sizeof(email), fp_out)))
781 {
782 size_t len = mutt_str_len(email);
783 if (len && (email[len - 1] == '\n'))
784 email[len - 1] = '\0';
785 (*buffer)[count] = MUTT_MEM_CALLOC(mutt_str_len(email) + 1, char);
786 strncpy((*buffer)[count], email, mutt_str_len(email));
787 count++;
788 }
789 }
790 else if (copy)
791 {
792 rc = 2;
793 }
794
795 mutt_file_fclose(&fp_out);
796 mutt_file_fclose(&fp_err);
797
798 return rc;
799}
800
806static char *smime_extract_certificate(const char *infile)
807{
808 FILE *fp_err = NULL;
809 FILE *fp_out = NULL;
810 FILE *fp_cert = NULL;
811 char *rc = NULL;
812 pid_t pid;
813 int empty;
814
815 struct Buffer *pk7out = buf_pool_get();
816 struct Buffer *certfile = buf_pool_get();
817
818 fp_err = mutt_file_mkstemp();
819 if (!fp_err)
820 {
821 mutt_perror(_("Can't create temporary file"));
822 goto cleanup;
823 }
824
825 buf_mktemp(pk7out);
826 fp_out = mutt_file_fopen(buf_string(pk7out), "w+");
827 if (!fp_out)
828 {
829 mutt_perror("%s", buf_string(pk7out));
830 goto cleanup;
831 }
832
833 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
834 * extract the full set of certificates directly. */
835 const struct Expando *c_smime_pk7out_command = cs_subset_expando(NeoMutt->sub, "smime_pk7out_command");
836 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
837 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_pk7out_command);
838 if (pid == -1)
839 {
840 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
841 goto cleanup;
842 }
843
844 filter_wait(pid);
845
846 fflush(fp_out);
847 rewind(fp_out);
848 fflush(fp_err);
849 rewind(fp_err);
850 empty = (fgetc(fp_out) == EOF);
851 if (empty)
852 {
853 mutt_perror("%s", buf_string(pk7out));
854 mutt_file_copy_stream(fp_err, stdout);
855 goto cleanup;
856 }
857 mutt_file_fclose(&fp_out);
858
859 buf_mktemp(certfile);
860 fp_cert = mutt_file_fopen(buf_string(certfile), "w+");
861 if (!fp_cert)
862 {
863 mutt_perror("%s", buf_string(certfile));
865 goto cleanup;
866 }
867
868 // Step 2: Extract the certificates from a PKCS#7 structure.
869 const struct Expando *c_smime_get_cert_command = cs_subset_expando(NeoMutt->sub, "smime_get_cert_command");
870 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
871 buf_string(pk7out), NULL, NULL, NULL, NULL, NULL, NULL,
872 c_smime_get_cert_command);
873 if (pid == -1)
874 {
875 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
877 goto cleanup;
878 }
879
880 filter_wait(pid);
881
883
884 fflush(fp_cert);
885 rewind(fp_cert);
886 fflush(fp_err);
887 rewind(fp_err);
888 empty = (fgetc(fp_cert) == EOF);
889 if (empty)
890 {
891 mutt_file_copy_stream(fp_err, stdout);
892 goto cleanup;
893 }
894
895 mutt_file_fclose(&fp_cert);
896
897 rc = buf_strdup(certfile);
898
899cleanup:
900 mutt_file_fclose(&fp_err);
901 if (fp_out)
902 {
903 mutt_file_fclose(&fp_out);
905 }
906 if (fp_cert)
907 {
908 mutt_file_fclose(&fp_cert);
909 mutt_file_unlink(buf_string(certfile));
910 }
911 buf_pool_release(&pk7out);
912 buf_pool_release(&certfile);
913 return rc;
914}
915
921static char *smime_extract_signer_certificate(const char *infile)
922{
923 char *cert = NULL;
924 struct Buffer *certfile = NULL;
925 pid_t pid;
926 int empty;
927
928 FILE *fp_err = mutt_file_mkstemp();
929 if (!fp_err)
930 {
931 mutt_perror(_("Can't create temporary file"));
932 return NULL;
933 }
934
935 certfile = buf_pool_get();
936 buf_mktemp(certfile);
937 FILE *fp_out = mutt_file_fopen(buf_string(certfile), "w+");
938 if (!fp_out)
939 {
940 mutt_file_fclose(&fp_err);
941 mutt_perror("%s", buf_string(certfile));
942 goto cleanup;
943 }
944
945 /* Extract signer's certificate
946 */
947 const struct Expando *c_smime_get_signer_cert_command =
948 cs_subset_expando(NeoMutt->sub, "smime_get_signer_cert_command");
949 pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL, NULL, NULL,
950 NULL, buf_string(certfile), NULL, c_smime_get_signer_cert_command);
951 if (pid == -1)
952 {
953 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
954 goto cleanup;
955 }
956
957 filter_wait(pid);
958
959 fflush(fp_out);
960 rewind(fp_out);
961 fflush(fp_err);
962 rewind(fp_err);
963 empty = (fgetc(fp_out) == EOF);
964 if (empty)
965 {
966 mutt_endwin();
967 mutt_file_copy_stream(fp_err, stdout);
969 goto cleanup;
970 }
971
972 mutt_file_fclose(&fp_out);
973 cert = buf_strdup(certfile);
974
975cleanup:
976 mutt_file_fclose(&fp_err);
977 if (fp_out)
978 {
979 mutt_file_fclose(&fp_out);
980 mutt_file_unlink(buf_string(certfile));
981 }
982 buf_pool_release(&certfile);
983 return cert;
984}
985
989void smime_class_invoke_import(const char *infile, const char *mailbox)
990{
991 char *certfile = NULL;
992 struct Buffer *buf = NULL;
993
994 FILE *fp_out = NULL;
995 FILE *fp_err = mutt_file_mkstemp();
996 if (!fp_err)
997 {
998 mutt_perror(_("Can't create temporary file"));
999 goto done;
1000 }
1001
1002 fp_out = mutt_file_mkstemp();
1003 if (!fp_out)
1004 {
1005 mutt_perror(_("Can't create temporary file"));
1006 goto done;
1007 }
1008
1009 buf = buf_pool_get();
1010 const bool c_smime_ask_cert_label = cs_subset_bool(NeoMutt->sub, "smime_ask_cert_label");
1011 if (c_smime_ask_cert_label)
1012 {
1013 if ((mw_get_field(_("Label for certificate: "), buf, MUTT_COMP_NO_FLAGS,
1014 HC_OTHER, NULL, NULL) != 0) ||
1015 buf_is_empty(buf))
1016 {
1017 goto done;
1018 }
1019 }
1020
1021 mutt_endwin();
1022 certfile = smime_extract_certificate(infile);
1023 if (certfile)
1024 {
1025 mutt_endwin();
1026
1027 const struct Expando *c_smime_import_cert_command =
1028 cs_subset_expando(NeoMutt->sub, "smime_import_cert_command");
1029 FILE *fp_smime_in = NULL;
1030 pid_t pid = smime_invoke(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1031 fileno(fp_err), certfile, NULL, NULL, NULL, NULL,
1032 NULL, NULL, c_smime_import_cert_command);
1033 if (pid == -1)
1034 {
1035 mutt_message(_("Error: unable to create OpenSSL subprocess"));
1036 goto done;
1037 }
1038 fputs(buf_string(buf), fp_smime_in);
1039 fputc('\n', fp_smime_in);
1040 mutt_file_fclose(&fp_smime_in);
1041
1042 filter_wait(pid);
1043
1044 mutt_file_unlink(certfile);
1045 FREE(&certfile);
1046 }
1047
1048 fflush(fp_out);
1049 rewind(fp_out);
1050 fflush(fp_err);
1051 rewind(fp_err);
1052
1053 mutt_file_copy_stream(fp_out, stdout);
1054 mutt_file_copy_stream(fp_err, stdout);
1055
1056done:
1057 mutt_file_fclose(&fp_out);
1058 mutt_file_fclose(&fp_err);
1059 buf_pool_release(&buf);
1060}
1061
1065int smime_class_verify_sender(struct Email *e, struct Message *msg)
1066{
1067 const char *mbox = NULL, *certfile = NULL;
1068 int rc = 1;
1069
1070 struct Buffer *tempfname = buf_pool_get();
1071 buf_mktemp(tempfname);
1072 FILE *fp_out = mutt_file_fopen(buf_string(tempfname), "w");
1073 if (!fp_out)
1074 {
1075 mutt_perror("%s", buf_string(tempfname));
1076 goto cleanup;
1077 }
1078
1079 const bool encrypt = e->security & SEC_ENCRYPT;
1080 mutt_copy_message(fp_out, e, msg,
1082 encrypt ? (CH_MIME | CH_WEED | CH_NONEWLINE) : CH_NO_FLAGS, 0);
1083
1084 fflush(fp_out);
1085 mutt_file_fclose(&fp_out);
1086
1087 if (!TAILQ_EMPTY(&e->env->from))
1088 {
1090 mbox = buf_string(TAILQ_FIRST(&e->env->from)->mailbox);
1091 }
1092 else if (!TAILQ_EMPTY(&e->env->sender))
1093 {
1095 mbox = buf_string(TAILQ_FIRST(&e->env->sender)->mailbox);
1096 }
1097
1098 if (mbox)
1099 {
1100 certfile = smime_extract_signer_certificate(buf_string(tempfname));
1101 if (certfile)
1102 {
1103 mutt_file_unlink(buf_string(tempfname));
1104 if (smime_handle_cert_email(certfile, mbox, false, NULL, NULL))
1105 {
1106 if (isendwin())
1108 }
1109 else
1110 {
1111 rc = 0;
1112 }
1113 mutt_file_unlink(certfile);
1114 FREE(&certfile);
1115 }
1116 else
1117 {
1118 mutt_any_key_to_continue(_("no certfile"));
1119 }
1120 }
1121 else
1122 {
1123 mutt_any_key_to_continue(_("no mbox"));
1124 }
1125
1126 mutt_file_unlink(buf_string(tempfname));
1127
1128cleanup:
1129 buf_pool_release(&tempfname);
1130 return rc;
1131}
1132
1149static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1150 FILE **fp_smime_err, int fp_smime_infd,
1151 int fp_smime_outfd, int fp_smime_errfd,
1152 const char *fname, const char *uids)
1153{
1154 const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1155 const struct Expando *c_smime_encrypt_command = cs_subset_expando(NeoMutt->sub, "smime_encrypt_command");
1156 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1157 fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1158 NULL, NULL, uids, NULL, c_smime_encrypt_command);
1159}
1160
1176static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out,
1177 FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1178 int fp_smime_errfd, const char *fname)
1179{
1180 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1181 const struct Expando *c_smime_sign_command = cs_subset_expando(NeoMutt->sub, "smime_sign_command");
1182 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1183 fp_smime_errfd, fname, NULL, NULL, c_smime_sign_digest_alg,
1185 buf_string(&SmimeIntermediateToUse), c_smime_sign_command);
1186}
1187
1191struct Body *smime_class_build_smime_entity(struct Body *b, char *certlist)
1192{
1193 char buf[1024] = { 0 };
1194 char certfile[PATH_MAX] = { 0 };
1195 char *cert_end = NULL;
1196 FILE *fp_smime_in = NULL, *fp_smime_err = NULL, *fp_out = NULL, *fp_tmp = NULL;
1197 struct Body *b_enc = NULL;
1198 bool err = false;
1199 int empty, off;
1200 pid_t pid;
1201
1202 struct Buffer *tempfile = buf_pool_get();
1203 struct Buffer *smime_infile = buf_pool_get();
1204
1205 buf_mktemp(tempfile);
1206 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
1207 if (!fp_out)
1208 {
1209 mutt_perror("%s", buf_string(tempfile));
1210 goto cleanup;
1211 }
1212
1213 fp_smime_err = mutt_file_mkstemp();
1214 if (!fp_smime_err)
1215 {
1216 mutt_perror(_("Can't create temporary file"));
1217 goto cleanup;
1218 }
1219
1220 buf_mktemp(smime_infile);
1221 fp_tmp = mutt_file_fopen(buf_string(smime_infile), "w+");
1222 if (!fp_tmp)
1223 {
1224 mutt_perror("%s", buf_string(smime_infile));
1225 goto cleanup;
1226 }
1227
1228 *certfile = '\0';
1229 for (char *cert_start = certlist; cert_start; cert_start = cert_end)
1230 {
1231 cert_end = strchr(cert_start, ' ');
1232 if (cert_end)
1233 *cert_end = '\0';
1234 if (*cert_start)
1235 {
1236 off = mutt_str_len(certfile);
1237 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1238 snprintf(certfile + off, sizeof(certfile) - off, "%s%s/%s",
1239 (off != 0) ? " " : "", NONULL(c_smime_certificates), cert_start);
1240 }
1241 if (cert_end)
1242 *cert_end++ = ' ';
1243 }
1244
1245 /* write a MIME entity */
1246 mutt_write_mime_header(b, fp_tmp, NeoMutt->sub);
1247 fputc('\n', fp_tmp);
1248 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
1249 mutt_file_fclose(&fp_tmp);
1250
1251 pid = smime_invoke_encrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1252 fileno(fp_smime_err), buf_string(smime_infile), certfile);
1253 if (pid == -1)
1254 {
1255 mutt_file_unlink(buf_string(smime_infile));
1256 goto cleanup;
1257 }
1258
1259 mutt_file_fclose(&fp_smime_in);
1260
1261 filter_wait(pid);
1262 mutt_file_unlink(buf_string(smime_infile));
1263
1264 fflush(fp_out);
1265 rewind(fp_out);
1266 empty = (fgetc(fp_out) == EOF);
1267 mutt_file_fclose(&fp_out);
1268
1269 fflush(fp_smime_err);
1270 rewind(fp_smime_err);
1271 while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1272 {
1273 err = true;
1274 fputs(buf, stdout);
1275 }
1276 mutt_file_fclose(&fp_smime_err);
1277
1278 /* pause if there is any error output from SMIME */
1279 if (err)
1281
1282 if (empty)
1283 {
1284 /* fatal error while trying to encrypt message */
1285 if (!err)
1286 mutt_any_key_to_continue(_("No output from OpenSSL..."));
1287 mutt_file_unlink(buf_string(tempfile));
1288 goto cleanup;
1289 }
1290
1291 b_enc = mutt_body_new();
1292 b_enc->type = TYPE_APPLICATION;
1293 b_enc->subtype = mutt_str_dup("pkcs7-mime");
1294 mutt_param_set(&b_enc->parameter, "name", "smime.p7m");
1295 mutt_param_set(&b_enc->parameter, "smime-type", "enveloped-data");
1296 b_enc->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1297 b_enc->use_disp = true;
1298 b_enc->disposition = DISP_ATTACH;
1299 b_enc->d_filename = mutt_str_dup("smime.p7m");
1300 b_enc->filename = buf_strdup(tempfile);
1301 b_enc->unlink = true; /* delete after sending the message */
1302 b_enc->parts = NULL;
1303 b_enc->next = NULL;
1304
1305cleanup:
1306 if (fp_out)
1307 {
1308 mutt_file_fclose(&fp_out);
1309 mutt_file_unlink(buf_string(tempfile));
1310 }
1311 mutt_file_fclose(&fp_smime_err);
1312 if (fp_tmp)
1313 {
1314 mutt_file_fclose(&fp_tmp);
1315 mutt_file_unlink(buf_string(smime_infile));
1316 }
1317 buf_pool_release(&tempfile);
1318 buf_pool_release(&smime_infile);
1319
1320 return b_enc;
1321}
1322
1335static char *openssl_md_to_smime_micalg(const char *md)
1336{
1337 if (!md)
1338 return NULL;
1339
1340 char *micalg = NULL;
1341 if (mutt_istr_startswith(md, "sha"))
1342 {
1343 mutt_str_asprintf(&micalg, "sha-%s", md + 3);
1344 }
1345 else
1346 {
1347 micalg = mutt_str_dup(md);
1348 }
1349
1350 return micalg;
1351}
1352
1356struct Body *smime_class_sign_message(struct Body *b, const struct AddressList *from)
1357{
1358 struct Body *b_sign = NULL;
1359 struct Body *rc = NULL;
1360 char buf[1024] = { 0 };
1361 struct Buffer *filetosign = NULL, *signedfile = NULL;
1362 FILE *fp_smime_in = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL, *fp_sign = NULL;
1363 bool err = false;
1364 int empty = 0;
1365 pid_t pid;
1366 const char *intermediates = NULL;
1367
1368 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
1369 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1370 const char *signas = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1371 if (!signas || (*signas == '\0'))
1372 {
1373 mutt_error(_("Can't sign: No key specified. Use Sign As."));
1374 return NULL;
1375 }
1376
1377 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
1378
1379 filetosign = buf_pool_get();
1380 signedfile = buf_pool_get();
1381
1382 buf_mktemp(filetosign);
1383 fp_sign = mutt_file_fopen(buf_string(filetosign), "w+");
1384 if (!fp_sign)
1385 {
1386 mutt_perror("%s", buf_string(filetosign));
1387 goto cleanup;
1388 }
1389
1390 buf_mktemp(signedfile);
1391 fp_smime_out = mutt_file_fopen(buf_string(signedfile), "w+");
1392 if (!fp_smime_out)
1393 {
1394 mutt_perror("%s", buf_string(signedfile));
1395 goto cleanup;
1396 }
1397
1398 mutt_write_mime_header(b, fp_sign, NeoMutt->sub);
1399 fputc('\n', fp_sign);
1400 mutt_write_mime_body(b, fp_sign, NeoMutt->sub);
1401 mutt_file_fclose(&fp_sign);
1402
1403 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
1404 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1405 buf_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), signas);
1406 buf_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), signas);
1407
1408 struct SmimeKey *signas_key = smime_get_key_by_hash(signas, 1);
1409 if (!signas_key || mutt_str_equal("?", signas_key->issuer))
1410 intermediates = signas; /* so openssl won't complain in any case */
1411 else
1412 intermediates = signas_key->issuer;
1413
1414 buf_printf(&SmimeIntermediateToUse, "%s/%s", NONULL(c_smime_certificates), intermediates);
1415
1416 smime_key_free(&signas_key);
1417
1418 pid = smime_invoke_sign(&fp_smime_in, NULL, &fp_smime_err, -1,
1419 fileno(fp_smime_out), -1, buf_string(filetosign));
1420 if (pid == -1)
1421 {
1422 mutt_perror(_("Can't open OpenSSL subprocess"));
1423 mutt_file_unlink(buf_string(filetosign));
1424 goto cleanup;
1425 }
1426 fputs(SmimePass, fp_smime_in);
1427 fputc('\n', fp_smime_in);
1428 mutt_file_fclose(&fp_smime_in);
1429
1430 filter_wait(pid);
1431
1432 /* check for errors from OpenSSL */
1433 err = false;
1434 fflush(fp_smime_err);
1435 rewind(fp_smime_err);
1436 while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1437 {
1438 err = true;
1439 fputs(buf, stdout);
1440 }
1441 mutt_file_fclose(&fp_smime_err);
1442
1443 fflush(fp_smime_out);
1444 rewind(fp_smime_out);
1445 empty = (fgetc(fp_smime_out) == EOF);
1446 mutt_file_fclose(&fp_smime_out);
1447
1448 mutt_file_unlink(buf_string(filetosign));
1449
1450 if (err)
1452
1453 if (empty)
1454 {
1455 mutt_any_key_to_continue(_("No output from OpenSSL..."));
1456 mutt_file_unlink(buf_string(signedfile));
1457 goto cleanup; /* fatal error while signing */
1458 }
1459
1460 b_sign = mutt_body_new();
1461 b_sign->type = TYPE_MULTIPART;
1462 b_sign->subtype = mutt_str_dup("signed");
1463 b_sign->encoding = ENC_7BIT;
1464 b_sign->use_disp = false;
1465 b_sign->disposition = DISP_INLINE;
1466
1468
1469 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1470 char *micalg = openssl_md_to_smime_micalg(c_smime_sign_digest_alg);
1471 mutt_param_set(&b_sign->parameter, "micalg", micalg);
1472 FREE(&micalg);
1473
1474 mutt_param_set(&b_sign->parameter, "protocol", "application/pkcs7-signature");
1475
1476 b_sign->parts = b;
1477 rc = b_sign;
1478
1479 b_sign->parts->next = mutt_body_new();
1480 b_sign = b_sign->parts->next;
1481 b_sign->type = TYPE_APPLICATION;
1482 b_sign->subtype = mutt_str_dup("pkcs7-signature");
1483 b_sign->filename = buf_strdup(signedfile);
1484 b_sign->d_filename = mutt_str_dup("smime.p7s");
1485 b_sign->use_disp = true;
1486 b_sign->disposition = DISP_ATTACH;
1487 b_sign->encoding = ENC_BASE64;
1488 b_sign->unlink = true; /* ok to remove this file after sending. */
1489
1490cleanup:
1491 if (fp_sign)
1492 {
1493 mutt_file_fclose(&fp_sign);
1494 mutt_file_unlink(buf_string(filetosign));
1495 }
1496 if (fp_smime_out)
1497 {
1498 mutt_file_fclose(&fp_smime_out);
1499 mutt_file_unlink(buf_string(signedfile));
1500 }
1501 buf_pool_release(&filetosign);
1502 buf_pool_release(&signedfile);
1503 return rc;
1504}
1505
1523static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out,
1524 FILE **fp_smime_err, int fp_smime_infd,
1525 int fp_smime_outfd, int fp_smime_errfd,
1526 const char *fname, const char *sig_fname, int opaque)
1527{
1528 const struct Expando *c_smime_verify_opaque_command =
1529 cs_subset_expando(NeoMutt->sub, "smime_verify_opaque_command");
1530 const struct Expando *c_smime_verify_command = cs_subset_expando(NeoMutt->sub, "smime_verify_command");
1531 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1532 fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1533 (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1534}
1535
1551static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1552 FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1553 int fp_smime_errfd, const char *fname)
1554{
1555 const struct Expando *c_smime_decrypt_command = cs_subset_expando(NeoMutt->sub, "smime_decrypt_command");
1556 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1557 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1559 NULL, c_smime_decrypt_command);
1560}
1561
1565int smime_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
1566{
1567 FILE *fp = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL;
1568 pid_t pid;
1569 int badsig = -1;
1570
1571 LOFF_T tmpoffset = 0;
1572 size_t tmplength = 0;
1573 int orig_type = b->type;
1574
1575 struct Buffer *signedfile = buf_pool_get();
1576
1577 buf_printf(signedfile, "%s.sig", tempfile);
1578
1579 /* decode to a tempfile, saving the original destination */
1580 fp = state->fp_out;
1581 state->fp_out = mutt_file_fopen(buf_string(signedfile), "w");
1582 if (!state->fp_out)
1583 {
1584 mutt_perror("%s", buf_string(signedfile));
1585 goto cleanup;
1586 }
1587 /* decoding the attachment changes the size and offset, so save a copy
1588 * of the "real" values now, and restore them after processing */
1589 tmplength = b->length;
1590 tmpoffset = b->offset;
1591
1592 /* if we are decoding binary bodies, we don't want to prefix each
1593 * line with the prefix or else the data will get corrupted. */
1594 const char *save_prefix = state->prefix;
1595 state->prefix = NULL;
1596
1597 mutt_decode_attachment(b, state);
1598
1599 b->length = ftello(state->fp_out);
1600 b->offset = 0;
1601 mutt_file_fclose(&state->fp_out);
1602
1603 /* restore final destination and substitute the tempfile for input */
1604 state->fp_out = fp;
1605 fp = state->fp_in;
1606 state->fp_in = mutt_file_fopen(buf_string(signedfile), "r");
1607
1608 /* restore the prefix */
1609 state->prefix = save_prefix;
1610
1611 b->type = orig_type;
1612
1613 fp_smime_err = mutt_file_mkstemp();
1614 if (!fp_smime_err)
1615 {
1616 mutt_perror(_("Can't create temporary file"));
1617 goto cleanup;
1618 }
1619
1620 crypt_current_time(state, "OpenSSL");
1621
1622 pid = smime_invoke_verify(NULL, &fp_smime_out, NULL, -1, -1, fileno(fp_smime_err),
1623 tempfile, buf_string(signedfile), 0);
1624 if (pid != -1)
1625 {
1626 fflush(fp_smime_out);
1627 mutt_file_fclose(&fp_smime_out);
1628
1629 if (filter_wait(pid))
1630 {
1631 badsig = -1;
1632 }
1633 else
1634 {
1635 char *line = NULL;
1636 size_t linelen;
1637
1638 fflush(fp_smime_err);
1639 rewind(fp_smime_err);
1640
1641 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
1642 if (linelen && mutt_istr_equal(line, "verification successful"))
1643 badsig = 0;
1644
1645 FREE(&line);
1646 }
1647 }
1648
1649 fflush(fp_smime_err);
1650 rewind(fp_smime_err);
1651 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1652 mutt_file_fclose(&fp_smime_err);
1653
1654 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1655
1656 mutt_file_unlink(buf_string(signedfile));
1657
1658 b->length = tmplength;
1659 b->offset = tmpoffset;
1660
1661 /* restore the original source stream */
1662 mutt_file_fclose(&state->fp_in);
1663 state->fp_in = fp;
1664
1665cleanup:
1666 buf_pool_release(&signedfile);
1667 return badsig;
1668}
1669
1679static struct Body *smime_handle_entity(struct Body *b, struct State *state, FILE *fp_out_file)
1680{
1681 struct Buffer *tmpfname = buf_pool_get();
1682 FILE *fp_smime_out = NULL, *fp_smime_in = NULL, *fp_smime_err = NULL;
1683 FILE *fp_tmp = NULL, *fp_out = NULL;
1684 struct Body *p = NULL;
1685 pid_t pid = -1;
1687
1688 if (!(type & APPLICATION_SMIME))
1689 return NULL;
1690
1691 /* Because of the mutt_body_handler() we avoid the buffer pool. */
1692 fp_smime_out = mutt_file_mkstemp();
1693 if (!fp_smime_out)
1694 {
1695 mutt_perror(_("Can't create temporary file"));
1696 goto cleanup;
1697 }
1698
1699 fp_smime_err = mutt_file_mkstemp();
1700 if (!fp_smime_err)
1701 {
1702 mutt_perror(_("Can't create temporary file"));
1703 goto cleanup;
1704 }
1705
1706 buf_mktemp(tmpfname);
1707 fp_tmp = mutt_file_fopen(buf_string(tmpfname), "w+");
1708 if (!fp_tmp)
1709 {
1710 mutt_perror("%s", buf_string(tmpfname));
1711 goto cleanup;
1712 }
1713
1714 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1715 {
1716 goto cleanup;
1717 }
1718
1719 mutt_file_copy_bytes(state->fp_in, fp_tmp, b->length);
1720
1721 fflush(fp_tmp);
1722 mutt_file_fclose(&fp_tmp);
1723
1724 if ((type & SEC_ENCRYPT) &&
1725 ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_smime_out),
1726 fileno(fp_smime_err), buf_string(tmpfname))) == -1))
1727 {
1728 mutt_file_unlink(buf_string(tmpfname));
1729 if (state->flags & STATE_DISPLAY)
1730 {
1731 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1732 }
1733 goto cleanup;
1734 }
1735 else if ((type & SEC_SIGNOPAQUE) &&
1736 ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1737 fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1738 buf_string(tmpfname), SEC_SIGNOPAQUE)) == -1))
1739 {
1740 mutt_file_unlink(buf_string(tmpfname));
1741 if (state->flags & STATE_DISPLAY)
1742 {
1743 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1744 }
1745 goto cleanup;
1746 }
1747
1748 if (type & SEC_ENCRYPT)
1749 {
1752 fputs(SmimePass, fp_smime_in);
1753 fputc('\n', fp_smime_in);
1754 }
1755
1756 mutt_file_fclose(&fp_smime_in);
1757
1758 filter_wait(pid);
1759 mutt_file_unlink(buf_string(tmpfname));
1760
1761 if (state->flags & STATE_DISPLAY)
1762 {
1763 fflush(fp_smime_err);
1764 rewind(fp_smime_err);
1765
1766 const int c = fgetc(fp_smime_err);
1767 if (c != EOF)
1768 {
1769 ungetc(c, fp_smime_err);
1770
1771 crypt_current_time(state, "OpenSSL");
1772 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1773 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1774 }
1775
1776 if (type & SEC_ENCRYPT)
1777 {
1778 state_attach_puts(state, _("[-- The following data is S/MIME encrypted --]\n"));
1779 }
1780 else
1781 {
1782 state_attach_puts(state, _("[-- The following data is S/MIME signed --]\n"));
1783 }
1784 }
1785
1786 fflush(fp_smime_out);
1787 rewind(fp_smime_out);
1788
1789 if (type & SEC_ENCRYPT)
1790 {
1791 /* void the passphrase, even if that wasn't the problem */
1792 if (fgetc(fp_smime_out) == EOF)
1793 {
1794 mutt_error(_("Decryption failed"));
1796 }
1797 rewind(fp_smime_out);
1798 }
1799
1800 if (fp_out_file)
1801 {
1802 fp_out = fp_out_file;
1803 }
1804 else
1805 {
1806 fp_out = mutt_file_mkstemp();
1807 if (!fp_out)
1808 {
1809 mutt_perror(_("Can't create temporary file"));
1810 goto cleanup;
1811 }
1812 }
1813 char buf[8192] = { 0 };
1814 while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1815 {
1816 const size_t len = mutt_str_len(buf);
1817 if ((len > 1) && (buf[len - 2] == '\r'))
1818 {
1819 buf[len - 2] = '\n';
1820 buf[len - 1] = '\0';
1821 }
1822 fputs(buf, fp_out);
1823 }
1824 fflush(fp_out);
1825 rewind(fp_out);
1826
1827 const long size = mutt_file_get_size_fp(fp_out);
1828 if (size == 0)
1829 {
1830 goto cleanup;
1831 }
1832 p = mutt_read_mime_header(fp_out, 0);
1833 if (p)
1834 {
1835 p->length = size - p->offset;
1836
1837 mutt_parse_part(fp_out, p);
1838
1839 if (state->flags & STATE_DISPLAY)
1841
1842 /* Store any protected headers in the parent so they can be
1843 * accessed for index updates after the handler recursion is done.
1844 * This is done before the handler to prevent a nested encrypted
1845 * handler from freeing the headers. */
1847 b->mime_headers = p->mime_headers;
1848 p->mime_headers = NULL;
1849
1850 if (state->fp_out)
1851 {
1852 rewind(fp_out);
1853 FILE *fp_tmp_buffer = state->fp_in;
1854 state->fp_in = fp_out;
1855 mutt_body_handler(p, state);
1856 state->fp_in = fp_tmp_buffer;
1857 }
1858
1859 /* Embedded multipart signed protected headers override the
1860 * encrypted headers. We need to do this after the handler so
1861 * they can be printed in the pager. */
1862 if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
1863 p->parts->mime_headers)
1864 {
1867 p->parts->mime_headers = NULL;
1868 }
1869 }
1870 mutt_file_fclose(&fp_smime_out);
1871
1872 if (!fp_out_file)
1873 {
1874 mutt_file_fclose(&fp_out);
1875 mutt_file_unlink(buf_string(tmpfname));
1876 }
1877 fp_out = NULL;
1878
1879 if (state->flags & STATE_DISPLAY)
1880 {
1881 if (type & SEC_ENCRYPT)
1882 state_attach_puts(state, _("[-- End of S/MIME encrypted data --]\n"));
1883 else
1884 state_attach_puts(state, _("[-- End of S/MIME signed data --]\n"));
1885 }
1886
1887 if (type & SEC_SIGNOPAQUE)
1888 {
1889 char *line = NULL;
1890 size_t linelen;
1891
1892 rewind(fp_smime_err);
1893
1894 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
1895 if (linelen && mutt_istr_equal(line, "verification successful"))
1896 b->goodsig = true;
1897 FREE(&line);
1898 }
1899 else if (p)
1900 {
1901 b->goodsig = p->goodsig;
1902 b->badsig = p->badsig;
1903 }
1904
1905cleanup:
1906 mutt_file_fclose(&fp_smime_out);
1907 mutt_file_fclose(&fp_smime_err);
1908 mutt_file_fclose(&fp_tmp);
1909 mutt_file_fclose(&fp_out);
1910 buf_pool_release(&tmpfname);
1911 return p;
1912}
1913
1917int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1918{
1919 struct State state = { 0 };
1920 LOFF_T tmpoffset = b->offset;
1921 size_t tmplength = b->length;
1922 int rc = -1;
1923
1925 return -1;
1926
1927 if (b->parts)
1928 return -1;
1929
1930 state.fp_in = fp_in;
1931 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1932 {
1933 return -1;
1934 }
1935
1936 FILE *fp_tmp = mutt_file_mkstemp();
1937 if (!fp_tmp)
1938 {
1939 mutt_perror(_("Can't create temporary file"));
1940 return -1;
1941 }
1942
1943 state.fp_out = fp_tmp;
1944 mutt_decode_attachment(b, &state);
1945 fflush(fp_tmp);
1946 b->length = ftello(state.fp_out);
1947 b->offset = 0;
1948 rewind(fp_tmp);
1949 state.fp_in = fp_tmp;
1950 state.fp_out = 0;
1951
1953 if (!*fp_out)
1954 {
1955 mutt_perror(_("Can't create temporary file"));
1956 goto bail;
1957 }
1958
1959 *b_dec = smime_handle_entity(b, &state, *fp_out);
1960 if (!*b_dec)
1961 goto bail;
1962
1963 (*b_dec)->goodsig = b->goodsig;
1964 (*b_dec)->badsig = b->badsig;
1965 rc = 0;
1966
1967bail:
1968 b->length = tmplength;
1969 b->offset = tmpoffset;
1970 mutt_file_fclose(&fp_tmp);
1971 if (*fp_out)
1972 rewind(*fp_out);
1973
1974 return rc;
1975}
1976
1980int smime_class_application_handler(struct Body *b, struct State *state)
1981{
1982 int rc = -1;
1983
1984 /* clear out any mime headers before the handler, so they can't be spoofed. */
1986
1987 struct Body *tattach = smime_handle_entity(b, state, NULL);
1988 if (tattach)
1989 {
1990 rc = 0;
1991 mutt_body_free(&tattach);
1992 }
1993 return rc;
1994}
1995
2000{
2001 struct SmimeKey *key = NULL;
2002 const char *prompt = NULL;
2003 const char *letters = NULL;
2004 const char *choices = NULL;
2005 int choice;
2006
2008 return e->security;
2009
2011
2012 /* Opportunistic encrypt is controlling encryption.
2013 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
2014 * letter choices for those. */
2015 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
2016 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
2017 {
2018 /* L10N: S/MIME options (opportunistic encryption is on) */
2019 prompt = _("S/MIME (s)ign, encrypt (w)ith, sign (a)s, (c)lear, or (o)ppenc mode off?");
2020 /* L10N: S/MIME options (opportunistic encryption is on) */
2021 letters = _("swaco");
2022 choices = "SwaCo";
2023 }
2024 else if (c_crypt_opportunistic_encrypt)
2025 {
2026 /* Opportunistic encryption option is set, but is toggled off
2027 * for this message. */
2028 /* L10N: S/MIME options (opportunistic encryption is off) */
2029 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode?");
2030 /* L10N: S/MIME options (opportunistic encryption is off) */
2031 letters = _("eswabco");
2032 choices = "eswabcO";
2033 }
2034 else
2035 {
2036 /* Opportunistic encryption is unset */
2037 /* L10N: S/MIME options */
2038 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear?");
2039 /* L10N: S/MIME options */
2040 letters = _("eswabc");
2041 choices = "eswabc";
2042 }
2043
2044 choice = mw_multi_choice(prompt, letters);
2045 if (choice > 0)
2046 {
2047 switch (choices[choice - 1])
2048 {
2049 case 'a': /* sign (a)s */
2050 key = smime_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, false);
2051 if (key)
2052 {
2053 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", key->hash, NULL);
2054 smime_key_free(&key);
2055
2056 e->security |= SEC_SIGN;
2057
2058 /* probably need a different passphrase */
2060 }
2061
2062 break;
2063
2064 case 'b': /* (b)oth */
2065 e->security |= (SEC_ENCRYPT | SEC_SIGN);
2066 break;
2067
2068 case 'c': /* (c)lear */
2069 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2070 break;
2071
2072 case 'C':
2073 e->security &= ~SEC_SIGN;
2074 break;
2075
2076 case 'e': /* (e)ncrypt */
2077 e->security |= SEC_ENCRYPT;
2078 e->security &= ~SEC_SIGN;
2079 break;
2080
2081 case 'O': /* oppenc mode on */
2084 break;
2085
2086 case 'o': /* oppenc mode off */
2087 e->security &= ~SEC_OPPENCRYPT;
2088 break;
2089
2090 case 'S': /* (s)ign in oppenc mode */
2091 e->security |= SEC_SIGN;
2092 break;
2093
2094 case 's': /* (s)ign */
2095 e->security &= ~SEC_ENCRYPT;
2096 e->security |= SEC_SIGN;
2097 break;
2098
2099 case 'w': /* encrypt (w)ith */
2100 {
2101 e->security |= SEC_ENCRYPT;
2102 do
2103 {
2104 struct Buffer *errmsg = buf_pool_get();
2105 int rc = CSR_SUCCESS;
2106 switch (mw_multi_choice(_("Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?"),
2107 // L10N: Options for: Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?
2108 _("123c")))
2109 {
2110 case 1:
2111 switch (choice = mw_multi_choice(_("(1) DES, (2) Triple-DES?"),
2112 // L10N: Options for: (1) DES, (2) Triple-DES
2113 _("12")))
2114 {
2115 case 1:
2116 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2117 "des", errmsg);
2118 break;
2119 case 2:
2120 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2121 "des3", errmsg);
2122 break;
2123 }
2124 break;
2125
2126 case 2:
2127 switch (choice = mw_multi_choice(_("(1) RC2-40, (2) RC2-64, (3) RC2-128?"),
2128 // L10N: Options for: (1) RC2-40, (2) RC2-64, (3) RC2-128
2129 _("123")))
2130 {
2131 case 1:
2132 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2133 "rc2-40", errmsg);
2134 break;
2135 case 2:
2136 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2137 "rc2-64", errmsg);
2138 break;
2139 case 3:
2140 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2141 "rc2-128", errmsg);
2142 break;
2143 }
2144 break;
2145
2146 case 3:
2147 switch (choice = mw_multi_choice(_("(1) AES128, (2) AES192, (3) AES256?"),
2148 // L10N: Options for: (1) AES128, (2) AES192, (3) AES256
2149 _("123")))
2150 {
2151 case 1:
2152 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2153 "aes128", errmsg);
2154 break;
2155 case 2:
2156 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2157 "aes192", errmsg);
2158 break;
2159 case 3:
2160 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2161 "aes256", errmsg);
2162 break;
2163 }
2164 break;
2165
2166 case 4:
2167 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with", NULL, errmsg);
2168 /* (c)lear */
2170
2171 case -1: /* Ctrl-G or Enter */
2172 choice = 0;
2173 break;
2174 }
2175
2176 if ((CSR_RESULT(rc) != CSR_SUCCESS) && !buf_is_empty(errmsg))
2177 mutt_error("%s", buf_string(errmsg));
2178
2179 buf_pool_release(&errmsg);
2180 } while (choice == -1);
2181 break;
2182 }
2183 }
2184 }
2185
2186 return e->security;
2187}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:462
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:596
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:377
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
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
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:143
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
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
Definition: config_type.c:357
Convenience wrapper for the config headers.
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
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.c:911
Duplicate the structure of an entire email.
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:62
#define CH_WEED
Weed the headers?
Definition: copy.h:55
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:48
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:63
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:50
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:53
Convenience wrapper for the core headers.
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1045
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
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition: crypt.c:65
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition: crypt.c:809
Signing/encryption multiplexor.
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:412
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:173
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:151
Edit a string.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:44
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1822
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1362
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
int expando_render(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition: expando.c:118
Parse Expando string.
const struct ExpandoRenderCallback SmimeCommandRenderCallbacks[]
Callbacks for Smime Command Expandos.
Ncrypt Smime Expando definitions.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:225
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:685
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:195
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1430
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:655
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:159
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:40
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
int smime_class_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition: smime.c:1980
int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Decrypt an encrypted MIME part - Implements CryptModuleSpecs::decrypt_mime() -.
Definition: smime.c:1917
char * smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition: smime.c:656
SecurityFlags smime_class_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition: smime.c:1999
struct Body * smime_class_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition: smime.c:1356
struct Body * smime_class_build_smime_entity(struct Body *b, char *certlist)
Encrypt the email body to all recipients - Implements CryptModuleSpecs::smime_build_smime_entity() -.
Definition: smime.c:1191
void smime_class_getkeys(struct Envelope *env)
Get the S/MIME keys required to encrypt this email - Implements CryptModuleSpecs::smime_getkeys() -.
Definition: smime.c:616
void smime_class_invoke_import(const char *infile, const char *mailbox)
Add a certificate and update index file (externally) - Implements CryptModuleSpecs::smime_invoke_impo...
Definition: smime.c:989
int smime_class_verify_sender(struct Email *e, struct Message *msg)
Does the sender match the certificate? - Implements CryptModuleSpecs::smime_verify_sender() -.
Definition: smime.c:1065
bool smime_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition: smime.c:158
int smime_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition: smime.c:1565
void smime_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition: smime.c:149
struct SmimeKey * dlg_smime(struct SmimeKey *keys, const char *query)
Get the user to select a key -.
Definition: dlg_smime.c:194
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:273
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition: crypt.c:1117
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
Convenience wrapper for the gui headers.
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1632
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1906
Decide how to display email content.
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:756
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:43
static int search(struct Menu *menu, int op)
Search a menu.
Definition: functions.c:58
@ 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
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
time_t mutt_date_add_timeout(time_t now, time_t timeout)
Safely add a timeout to a given time_t value.
Definition: date.c:890
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:62
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition: lib.h:111
#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
#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:672
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:803
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:521
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
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:581
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:242
Many unsorted constants and some structs.
#define MUTT_COMP_PASS
Password mode (no echo)
Definition: mutt.h:58
#define MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition: mutt.h:59
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
#define PATH_MAX
Definition: mutt.h:42
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:82
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:92
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:131
#define SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition: lib.h:89
#define SMIME_SIGN
Definition: lib.h:109
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:134
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:97
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:84
#define WithCrypto
Definition: lib.h:122
#define SEC_SIGN
Email is signed.
Definition: lib.h:85
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:133
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
Ask the user a question.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:782
#define TAILQ_FIRST(head)
Definition: queue.h:780
#define TAILQ_EMPTY(head)
Definition: queue.h:778
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: render.h:33
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:300
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1392
GUI display the mailboxes in a side panel.
static struct Buffer SmimeIntermediateToUse
Smime intermediate certificate to use.
Definition: smime.c:77
static struct SmimeKey * smime_get_key_by_hash(const char *hash, bool only_public_key)
Find a key by its hash.
Definition: smime.c:390
static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
Use SMIME to sign a file.
Definition: smime.c:1176
static char SmimePass[256]
Cached Smime Passphrase.
Definition: smime.c:68
static time_t SmimeExpTime
Unix time when SmimePass expires.
Definition: smime.c:70
static void getkeys(const char *mailbox)
Get the keys for a mailbox.
Definition: smime.c:580
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition: smime.c:128
static struct SmimeKey * smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
Find an SMIME key by string.
Definition: smime.c:497
void smime_init(void)
Initialise smime globals.
Definition: smime.c:82
static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, int opaque)
Use SMIME to verify a file.
Definition: smime.c:1523
void smime_cleanup(void)
Clean up smime globals.
Definition: smime.c:92
static char * smime_extract_signer_certificate(const char *infile)
Extract the signer's certificate.
Definition: smime.c:921
static struct Body * smime_handle_entity(struct Body *b, struct State *state, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition: smime.c:1679
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition: smime.c:259
static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
Use SMIME to decrypt a file.
Definition: smime.c:1551
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition: smime.c:342
static struct Buffer SmimeKeyToUse
Smime key to use.
Definition: smime.c:73
static char * smime_extract_certificate(const char *infile)
Extract an SMIME certificate from a file.
Definition: smime.c:806
static int smime_handle_cert_email(const char *certificate, const char *mailbox, bool copy, char ***buffer, int *num)
Process an email containing certificates.
Definition: smime.c:704
static struct SmimeKey * smime_get_key_by_addr(const char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition: smime.c:416
static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const struct Expando *exp)
Run an SMIME command.
Definition: smime.c:225
static struct Buffer SmimeCertToUse
Smime certificate to use.
Definition: smime.c:75
static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *uids)
Use SMIME to encrypt a file.
Definition: smime.c:1149
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition: smime.c:103
static char * openssl_md_to_smime_micalg(const char *md)
Change the algorithm names.
Definition: smime.c:1335
static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
Format an SMIME command string.
Definition: smime.c:195
static struct SmimeKey * smime_ask_for_key(const char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition: smime.c:543
SMIME helper routines.
Key value store.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
The body of an email.
Definition: body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h: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
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
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
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
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
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
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
The header of an Email.
Definition: envelope.h:57
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
Parsed Expando trees.
Definition: expando.h:41
A local copy of an email.
Definition: message.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
Data for a SIME command.
Definition: smime.h:58
const char * sig_fname
s
Definition: smime.h:63
const char * intermediates
i
Definition: smime.h:65
const char * digestalg
d
Definition: smime.h:61
const char * cryptalg
a
Definition: smime.h:60
const char * key
k
Definition: smime.h:59
const char * fname
f
Definition: smime.h:62
const char * certificates
c
Definition: smime.h:64
An SIME key.
Definition: smime.h:43
KeyFlags flags
Definition: smime.h:49
char * hash
Definition: smime.h:45
struct SmimeKey * next
Definition: smime.h:50
char * issuer
Definition: smime.h:47
char * email
Definition: smime.h:44
char * label
Definition: smime.h:46
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition: smime.h:48
Keep track when processing files.
Definition: state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:52
FILE * fp_out
File to write to.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition: state.h:51
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:386
#define buf_mktemp(buf)
Definition: tmp.h:33
#define mutt_file_mkstemp()
Definition: tmp.h:36