NeoMutt  2022-04-29-323-g5fcc6c
Teaching an old dog new tricks
DOXYGEN
smime.c
Go to the documentation of this file.
1
32#include "config.h"
33#include <limits.h>
34#include <stdbool.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <time.h>
40#include "private.h"
41#include "mutt/lib.h"
42#include "address/lib.h"
43#include "config/lib.h"
44#include "email/lib.h"
45#include "core/lib.h"
46#include "alias/lib.h"
47#include "gui/lib.h"
48#include "mutt.h"
49#include "lib.h"
50#include "enter/lib.h"
51#include "question/lib.h"
52#include "send/lib.h"
53#include "copy.h"
54#include "crypt.h"
55#include "cryptglue.h"
56#include "format_flags.h"
57#include "handler.h"
58#include "mutt_logging.h"
59#include "muttlib.h"
60#ifdef CRYPT_BACKEND_CLASSIC_SMIME
61#include "smime.h"
62#endif
63
68{
69 const char *key;
70 const char *cryptalg;
71 const char *digestalg;
72 const char *fname;
73 const char *sig_fname;
74 const char *certificates;
75 const char *intermediates;
76};
77
78char SmimePass[256];
79time_t SmimeExpTime = 0; /* when does the cached passphrase expire? */
80
81static struct Buffer SmimeKeyToUse = { 0 };
82static struct Buffer SmimeCertToUse = { 0 };
83static struct Buffer SmimeIntermediateToUse = { 0 };
84
88void smime_init(void)
89{
93}
94
98void smime_cleanup(void)
99{
103}
104
109static void smime_key_free(struct SmimeKey **keylist)
110{
111 if (!keylist)
112 return;
113
114 struct SmimeKey *key = NULL;
115
116 while (*keylist)
117 {
118 key = *keylist;
119 *keylist = (*keylist)->next;
120
121 FREE(&key->email);
122 FREE(&key->hash);
123 FREE(&key->label);
124 FREE(&key->issuer);
125 FREE(&key);
126 }
127}
128
134static struct SmimeKey *smime_copy_key(struct SmimeKey *key)
135{
136 if (!key)
137 return NULL;
138
139 struct SmimeKey *copy = NULL;
140
141 copy = mutt_mem_calloc(1, sizeof(struct SmimeKey));
142 copy->email = mutt_str_dup(key->email);
143 copy->hash = mutt_str_dup(key->hash);
144 copy->label = mutt_str_dup(key->label);
145 copy->issuer = mutt_str_dup(key->issuer);
146 copy->trust = key->trust;
147 copy->flags = key->flags;
148
149 return copy;
150}
151
152/*
153 * Queries and passphrase handling.
154 */
155
160{
161 memset(SmimePass, 0, sizeof(SmimePass));
162 SmimeExpTime = 0;
163}
164
169{
170 const time_t now = mutt_date_epoch();
171 if (now < SmimeExpTime)
172 {
173 /* Use cached copy. */
174 return true;
175 }
176
178
179 struct Buffer *buf = mutt_buffer_pool_get();
180 const int rc = mutt_buffer_get_field(_("Enter S/MIME passphrase:"), buf,
182 false, NULL, NULL, NULL);
185
186 if (rc == 0)
187 {
188 const short c_smime_timeout = cs_subset_number(NeoMutt->sub, "smime_timeout");
189 SmimeExpTime = mutt_date_add_timeout(now, c_smime_timeout);
190 return true;
191 }
192 else
193 {
194 SmimeExpTime = 0;
195 }
196
197 return false;
198}
199
200/*
201 * The OpenSSL interface
202 */
203
218static const char *smime_command_format_str(char *buf, size_t buflen, size_t col,
219 int cols, char op, const char *src,
220 const char *prec, const char *if_str,
221 const char *else_str, intptr_t data,
222 MuttFormatFlags flags)
223{
224 char fmt[128] = { 0 };
225 struct SmimeCommandContext *cctx = (struct SmimeCommandContext *) data;
226 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
227
228 switch (op)
229 {
230 case 'C':
231 {
232 const char *const c_smime_ca_location = cs_subset_path(NeoMutt->sub, "smime_ca_location");
233 if (!optional)
234 {
235 struct Buffer *path = mutt_buffer_pool_get();
236 struct Buffer *buf1 = mutt_buffer_pool_get();
237 struct Buffer *buf2 = mutt_buffer_pool_get();
238 struct stat st = { 0 };
239
240 mutt_buffer_strcpy(path, c_smime_ca_location);
243
244 if ((stat(mutt_buffer_string(path), &st) != 0) || !S_ISDIR(st.st_mode))
245 mutt_buffer_printf(buf2, "-CAfile %s", mutt_buffer_string(buf1));
246 else
247 mutt_buffer_printf(buf2, "-CApath %s", mutt_buffer_string(buf1));
248
249 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
250 snprintf(buf, buflen, fmt, mutt_buffer_string(buf2));
251
255 }
256 else if (!c_smime_ca_location)
257 optional = false;
258 break;
259 }
260
261 case 'c':
262 { /* certificate (list) */
263 if (!optional)
264 {
265 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
266 snprintf(buf, buflen, fmt, NONULL(cctx->certificates));
267 }
268 else if (!cctx->certificates)
269 optional = false;
270 break;
271 }
272
273 case 'i':
274 { /* intermediate certificates */
275 if (!optional)
276 {
277 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
278 snprintf(buf, buflen, fmt, NONULL(cctx->intermediates));
279 }
280 else if (!cctx->intermediates)
281 optional = false;
282 break;
283 }
284
285 case 's':
286 { /* detached signature */
287 if (!optional)
288 {
289 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
290 snprintf(buf, buflen, fmt, NONULL(cctx->sig_fname));
291 }
292 else if (!cctx->sig_fname)
293 optional = false;
294 break;
295 }
296
297 case 'k':
298 { /* private key */
299 if (!optional)
300 {
301 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
302 snprintf(buf, buflen, fmt, NONULL(cctx->key));
303 }
304 else if (!cctx->key)
305 optional = false;
306 break;
307 }
308
309 case 'a':
310 { /* algorithm for encryption */
311 if (!optional)
312 {
313 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
314 snprintf(buf, buflen, fmt, NONULL(cctx->cryptalg));
315 }
316 else if (!cctx->key)
317 optional = false;
318 break;
319 }
320
321 case 'f':
322 { /* file to process */
323 if (!optional)
324 {
325 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
326 snprintf(buf, buflen, fmt, NONULL(cctx->fname));
327 }
328 else if (!cctx->fname)
329 optional = false;
330 break;
331 }
332
333 case 'd':
334 { /* algorithm for the signature message digest */
335 if (!optional)
336 {
337 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
338 snprintf(buf, buflen, fmt, NONULL(cctx->digestalg));
339 }
340 else if (!cctx->key)
341 optional = false;
342 break;
343 }
344
345 default:
346 *buf = '\0';
347 break;
348 }
349
350 if (optional)
351 {
352 mutt_expando_format(buf, buflen, col, cols, if_str,
354 }
355 else if (flags & MUTT_FORMAT_OPTIONAL)
356 {
357 mutt_expando_format(buf, buflen, col, cols, else_str,
359 }
360
361 /* We return the format string, unchanged */
362 return src;
363}
364
374static void smime_command(char *buf, size_t buflen,
375 struct SmimeCommandContext *cctx, const char *fmt)
376{
377 mutt_expando_format(buf, buflen, 0, buflen, NONULL(fmt), smime_command_format_str,
378 (intptr_t) cctx, MUTT_FORMAT_NO_FLAGS);
379 mutt_debug(LL_DEBUG2, "%s\n", buf);
380}
381
404static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err,
405 int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd,
406 const char *fname, const char *sig_fname, const char *cryptalg,
407 const char *digestalg, const char *key, const char *certificates,
408 const char *intermediates, const char *format)
409{
410 struct SmimeCommandContext cctx = { 0 };
411 char cmd[STR_COMMAND] = { 0 };
412
413 if (!format || (*format == '\0'))
414 return (pid_t) -1;
415
416 cctx.fname = fname;
417 cctx.sig_fname = sig_fname;
418 cctx.key = key;
419 cctx.cryptalg = cryptalg;
420 cctx.digestalg = digestalg;
423
424 smime_command(cmd, sizeof(cmd), &cctx, format);
425
426 return filter_create_fd(cmd, fp_smime_in, fp_smime_out, fp_smime_err,
427 fp_smime_infd, fp_smime_outfd, fp_smime_errfd);
428}
429
436static struct SmimeKey *smime_parse_key(char *buf)
437{
438 char *pend = NULL, *p = NULL;
439 int field = 0;
440
441 struct SmimeKey *key = mutt_mem_calloc(1, sizeof(struct SmimeKey));
442
443 for (p = buf; p; p = pend)
444 {
445 /* Some users manually maintain their .index file, and use a tab
446 * as a delimiter, which the old parsing code (using fscanf)
447 * happened to allow. smime_keys uses a space, so search for both. */
448 if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
449 *pend++ = 0;
450
451 /* For backward compatibility, don't count consecutive delimiters
452 * as an empty field. */
453 if (*p == '\0')
454 continue;
455
456 field++;
457
458 switch (field)
459 {
460 case 1: /* mailbox */
461 key->email = mutt_str_dup(p);
462 break;
463 case 2: /* hash */
464 key->hash = mutt_str_dup(p);
465 break;
466 case 3: /* label */
467 key->label = mutt_str_dup(p);
468 break;
469 case 4: /* issuer */
470 key->issuer = mutt_str_dup(p);
471 break;
472 case 5: /* trust */
473 key->trust = *p;
474 break;
475 case 6: /* purpose */
476 while (*p)
477 {
478 switch (*p++)
479 {
480 case 'e':
482 break;
483
484 case 's':
485 key->flags |= KEYFLAG_CANSIGN;
486 break;
487 }
488 }
489 break;
490 }
491 }
492
493 /* Old index files could be missing issuer, trust, and purpose,
494 * but anything less than that is an error. */
495 if (field < 3)
496 {
497 smime_key_free(&key);
498 return NULL;
499 }
500
501 if (field < 4)
502 key->issuer = mutt_str_dup("?");
503
504 if (field < 5)
505 key->trust = 't';
506
507 if (field < 6)
509
510 return key;
511}
512
519static struct SmimeKey *smime_get_candidates(const char *search, bool only_public_key)
520{
521 char buf[1024] = { 0 };
522 struct SmimeKey *key = NULL, *results = NULL;
523 struct SmimeKey **results_end = &results;
524
525 struct Buffer *index_file = mutt_buffer_pool_get();
526 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
527 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
528 mutt_buffer_printf(index_file, "%s/.index",
529 only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
530
531 FILE *fp = mutt_file_fopen(mutt_buffer_string(index_file), "r");
532 if (!fp)
533 {
534 mutt_perror(mutt_buffer_string(index_file));
535 mutt_buffer_pool_release(&index_file);
536 return NULL;
537 }
538 mutt_buffer_pool_release(&index_file);
539
540 while (fgets(buf, sizeof(buf), fp))
541 {
542 if (((*search == '\0')) || mutt_istr_find(buf, search))
543 {
544 key = smime_parse_key(buf);
545 if (key)
546 {
547 *results_end = key;
548 results_end = &key->next;
549 }
550 }
551 }
552
553 mutt_file_fclose(&fp);
554
555 return results;
556}
557
567static struct SmimeKey *smime_get_key_by_hash(const char *hash, bool only_public_key)
568{
569 struct SmimeKey *match = NULL;
570 struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
571 for (struct SmimeKey *result = results; result; result = result->next)
572 {
573 if (mutt_istr_equal(hash, result->hash))
574 {
575 match = smime_copy_key(result);
576 break;
577 }
578 }
579
580 smime_key_free(&results);
581
582 return match;
583}
584
593static struct SmimeKey *smime_get_key_by_addr(char *mailbox, KeyFlags abilities,
594 bool only_public_key, bool oppenc_mode)
595{
596 if (!mailbox)
597 return NULL;
598
599 struct SmimeKey *results = NULL, *result = NULL;
600 struct SmimeKey *matches = NULL;
601 struct SmimeKey **matches_end = &matches;
602 struct SmimeKey *match = NULL;
603 struct SmimeKey *trusted_match = NULL;
604 struct SmimeKey *valid_match = NULL;
605 struct SmimeKey *return_key = NULL;
606 bool multi_trusted_matches = false;
607
608 results = smime_get_candidates(mailbox, only_public_key);
609 for (result = results; result; result = result->next)
610 {
611 if (abilities && !(result->flags & abilities))
612 {
613 continue;
614 }
615
616 if (mutt_istr_equal(mailbox, result->email))
617 {
618 match = smime_copy_key(result);
619 *matches_end = match;
620 matches_end = &match->next;
621
622 if (match->trust == 't')
623 {
624 if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
625 {
626 multi_trusted_matches = true;
627 }
628 trusted_match = match;
629 }
630 else if ((match->trust == 'u') || (match->trust == 'v'))
631 {
632 valid_match = match;
633 }
634 }
635 }
636
637 smime_key_free(&results);
638
639 if (matches)
640 {
641 if (oppenc_mode)
642 {
643 const bool c_crypt_opportunistic_encrypt_strong_keys =
644 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
645 if (trusted_match)
646 return_key = smime_copy_key(trusted_match);
647 else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
648 return_key = smime_copy_key(valid_match);
649 else
650 return_key = NULL;
651 }
652 else if (trusted_match && !multi_trusted_matches)
653 {
654 return_key = smime_copy_key(trusted_match);
655 }
656 else
657 {
658 return_key = smime_copy_key(dlg_select_smime_key(matches, mailbox));
659 }
660
661 smime_key_free(&matches);
662 }
663
664 return return_key;
665}
666
674static struct SmimeKey *smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
675{
676 if (!str)
677 return NULL;
678
679 struct SmimeKey *results = NULL, *result = NULL;
680 struct SmimeKey *matches = NULL;
681 struct SmimeKey **matches_end = &matches;
682 struct SmimeKey *match = NULL;
683 struct SmimeKey *return_key = NULL;
684
685 results = smime_get_candidates(str, only_public_key);
686 for (result = results; result; result = result->next)
687 {
688 if (abilities && !(result->flags & abilities))
689 {
690 continue;
691 }
692
693 if (mutt_istr_equal(str, result->hash) ||
694 mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
695 {
696 match = smime_copy_key(result);
697 *matches_end = match;
698 matches_end = &match->next;
699 }
700 }
701
702 smime_key_free(&results);
703
704 if (matches)
705 {
706 return_key = smime_copy_key(dlg_select_smime_key(matches, str));
707 smime_key_free(&matches);
708 }
709
710 return return_key;
711}
712
720static struct SmimeKey *smime_ask_for_key(char *prompt, KeyFlags abilities, bool only_public_key)
721{
722 struct SmimeKey *key = NULL;
723 struct Buffer *resp = mutt_buffer_pool_get();
724
725 if (!prompt)
726 prompt = _("Enter keyID: ");
727
729
730 while (true)
731 {
732 mutt_buffer_reset(resp);
733 if (mutt_buffer_get_field(prompt, resp, MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0)
734 {
735 goto done;
736 }
737
738 key = smime_get_key_by_str(mutt_buffer_string(resp), abilities, only_public_key);
739 if (key)
740 goto done;
741
742 mutt_error(_("No matching keys found for \"%s\""), mutt_buffer_string(resp));
743 }
744
745done:
747 return key;
748}
749
757static void getkeys(char *mailbox)
758{
759 const char *k = NULL;
760
761 struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
762
763 if (!key)
764 {
765 char buf[256] = { 0 };
766 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), mailbox);
767 key = smime_ask_for_key(buf, KEYFLAG_CANENCRYPT, false);
768 }
769
770 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
771 size_t smime_keys_len = mutt_str_len(c_smime_keys);
772
773 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
774 k = key ? key->hash : NONULL(c_smime_default_key);
775
776 /* if the key is different from last time */
777 if ((mutt_buffer_len(&SmimeKeyToUse) <= smime_keys_len) ||
778 !mutt_istr_equal(k, SmimeKeyToUse.data + smime_keys_len + 1))
779 {
781 mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), k);
782 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
783 mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), k);
784 }
785
786 smime_key_free(&key);
787}
788
793{
794 const bool c_smime_decrypt_use_default_key = cs_subset_bool(NeoMutt->sub, "smime_decrypt_use_default_key");
795 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
796 if (c_smime_decrypt_use_default_key && c_smime_default_key)
797 {
798 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
799 mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), c_smime_default_key);
800 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
801 mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates),
802 c_smime_default_key);
803 return;
804 }
805
806 struct Address *a = NULL;
807 TAILQ_FOREACH(a, &env->to, entries)
808 {
809 if (mutt_addr_is_user(a))
810 {
811 getkeys(a->mailbox);
812 return;
813 }
814 }
815
816 TAILQ_FOREACH(a, &env->cc, entries)
817 {
818 if (mutt_addr_is_user(a))
819 {
820 getkeys(a->mailbox);
821 return;
822 }
823 }
824
825 struct Address *f = mutt_default_from(NeoMutt->sub);
826 getkeys(f->mailbox);
827 mutt_addr_free(&f);
828}
829
833char *smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
834{
835 struct SmimeKey *key = NULL;
836 char *keyid = NULL, *keylist = NULL;
837 size_t keylist_size = 0;
838 size_t keylist_used = 0;
839
840 struct Address *a = NULL;
841 TAILQ_FOREACH(a, al, entries)
842 {
843 key = smime_get_key_by_addr(a->mailbox, KEYFLAG_CANENCRYPT, true, oppenc_mode);
844 if (!key && !oppenc_mode)
845 {
846 char buf[1024] = { 0 };
847 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), a->mailbox);
848 key = smime_ask_for_key(buf, KEYFLAG_CANENCRYPT, true);
849 }
850 if (!key)
851 {
852 if (!oppenc_mode)
853 mutt_message(_("No (valid) certificate found for %s"), a->mailbox);
854 FREE(&keylist);
855 return NULL;
856 }
857
858 keyid = key->hash;
859 keylist_size += mutt_str_len(keyid) + 2;
860 mutt_mem_realloc(&keylist, keylist_size);
861 sprintf(keylist + keylist_used, "%s%s", keylist_used ? " " : "", keyid);
862 keylist_used = mutt_str_len(keylist);
863
864 smime_key_free(&key);
865 }
866 return keylist;
867}
868
880static int smime_handle_cert_email(char *certificate, char *mailbox, bool copy,
881 char ***buffer, int *num)
882{
883 char email[256] = { 0 };
884 int rc = -1, count = 0;
885 pid_t pid;
886
887 FILE *fp_err = mutt_file_mkstemp();
888 if (!fp_err)
889 {
890 mutt_perror(_("Can't create temporary file"));
891 return 1;
892 }
893
894 FILE *fp_out = mutt_file_mkstemp();
895 if (!fp_out)
896 {
897 mutt_file_fclose(&fp_err);
898 mutt_perror(_("Can't create temporary file"));
899 return 1;
900 }
901
902 const char *const c_smime_get_cert_email_command = cs_subset_string(NeoMutt->sub, "smime_get_cert_email_command");
903 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
904 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
905 if (pid == -1)
906 {
907 mutt_message(_("Error: unable to create OpenSSL subprocess"));
908 mutt_file_fclose(&fp_err);
909 mutt_file_fclose(&fp_out);
910 return 1;
911 }
912
913 filter_wait(pid);
914
915 fflush(fp_out);
916 rewind(fp_out);
917 fflush(fp_err);
918 rewind(fp_err);
919
920 while ((fgets(email, sizeof(email), fp_out)))
921 {
922 size_t len = mutt_str_len(email);
923 if (len && (email[len - 1] == '\n'))
924 email[len - 1] = '\0';
925 if (mutt_istr_startswith(email, mailbox))
926 rc = 1;
927
928 rc = (rc < 0) ? 0 : rc;
929 count++;
930 }
931
932 if (rc == -1)
933 {
934 mutt_endwin();
935 mutt_file_copy_stream(fp_err, stdout);
936 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
937 rc = 1;
938 }
939 else if (rc == 0)
940 rc = 1;
941 else
942 rc = 0;
943
944 if (copy && buffer && num)
945 {
946 (*num) = count;
947 *buffer = mutt_mem_calloc(count, sizeof(char *));
948 count = 0;
949
950 rewind(fp_out);
951 while ((fgets(email, sizeof(email), fp_out)))
952 {
953 size_t len = mutt_str_len(email);
954 if (len && (email[len - 1] == '\n'))
955 email[len - 1] = '\0';
956 (*buffer)[count] = mutt_mem_calloc(mutt_str_len(email) + 1, sizeof(char));
957 strncpy((*buffer)[count], email, mutt_str_len(email));
958 count++;
959 }
960 }
961 else if (copy)
962 rc = 2;
963
964 mutt_file_fclose(&fp_out);
965 mutt_file_fclose(&fp_err);
966
967 return rc;
968}
969
975static char *smime_extract_certificate(const char *infile)
976{
977 FILE *fp_err = NULL;
978 FILE *fp_out = NULL;
979 FILE *fp_cert = NULL;
980 char *retval = NULL;
981 pid_t pid;
982 int empty;
983
984 struct Buffer *pk7out = mutt_buffer_pool_get();
985 struct Buffer *certfile = mutt_buffer_pool_get();
986
987 fp_err = mutt_file_mkstemp();
988 if (!fp_err)
989 {
990 mutt_perror(_("Can't create temporary file"));
991 goto cleanup;
992 }
993
994 mutt_buffer_mktemp(pk7out);
995 fp_out = mutt_file_fopen(mutt_buffer_string(pk7out), "w+");
996 if (!fp_out)
997 {
999 goto cleanup;
1000 }
1001
1002 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
1003 * extract the full set of certificates directly. */
1004 const char *const c_smime_pk7out_command = cs_subset_string(NeoMutt->sub, "smime_pk7out_command");
1005 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
1006 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_pk7out_command);
1007 if (pid == -1)
1008 {
1009 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1010 goto cleanup;
1011 }
1012
1013 filter_wait(pid);
1014
1015 fflush(fp_out);
1016 rewind(fp_out);
1017 fflush(fp_err);
1018 rewind(fp_err);
1019 empty = (fgetc(fp_out) == EOF);
1020 if (empty)
1021 {
1023 mutt_file_copy_stream(fp_err, stdout);
1024 goto cleanup;
1025 }
1026 mutt_file_fclose(&fp_out);
1027
1028 mutt_buffer_mktemp(certfile);
1029 fp_cert = mutt_file_fopen(mutt_buffer_string(certfile), "w+");
1030 if (!fp_cert)
1031 {
1034 goto cleanup;
1035 }
1036
1037 // Step 2: Extract the certificates from a PKCS#7 structure.
1038 const char *const c_smime_get_cert_command = cs_subset_string(NeoMutt->sub, "smime_get_cert_command");
1039 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
1040 mutt_buffer_string(pk7out), NULL, NULL, NULL, NULL, NULL,
1041 NULL, c_smime_get_cert_command);
1042 if (pid == -1)
1043 {
1044 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1046 goto cleanup;
1047 }
1048
1049 filter_wait(pid);
1050
1052
1053 fflush(fp_cert);
1054 rewind(fp_cert);
1055 fflush(fp_err);
1056 rewind(fp_err);
1057 empty = (fgetc(fp_cert) == EOF);
1058 if (empty)
1059 {
1060 mutt_file_copy_stream(fp_err, stdout);
1061 goto cleanup;
1062 }
1063
1064 mutt_file_fclose(&fp_cert);
1065
1066 retval = mutt_buffer_strdup(certfile);
1067
1068cleanup:
1069 mutt_file_fclose(&fp_err);
1070 if (fp_out)
1071 {
1072 mutt_file_fclose(&fp_out);
1074 }
1075 if (fp_cert)
1076 {
1077 mutt_file_fclose(&fp_cert);
1079 }
1080 mutt_buffer_pool_release(&pk7out);
1081 mutt_buffer_pool_release(&certfile);
1082 return retval;
1083}
1084
1090static char *smime_extract_signer_certificate(const char *infile)
1091{
1092 char *cert = NULL;
1093 struct Buffer *certfile = NULL;
1094 pid_t pid;
1095 int empty;
1096
1097 FILE *fp_err = mutt_file_mkstemp();
1098 if (!fp_err)
1099 {
1100 mutt_perror(_("Can't create temporary file"));
1101 return NULL;
1102 }
1103
1104 certfile = mutt_buffer_pool_get();
1105 mutt_buffer_mktemp(certfile);
1106 FILE *fp_out = mutt_file_fopen(mutt_buffer_string(certfile), "w+");
1107 if (!fp_out)
1108 {
1109 mutt_file_fclose(&fp_err);
1111 goto cleanup;
1112 }
1113
1114 /* Extract signer's certificate
1115 */
1116 const char *const c_smime_get_signer_cert_command = cs_subset_string(NeoMutt->sub, "smime_get_signer_cert_command");
1117 pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL,
1118 NULL, NULL, NULL, mutt_buffer_string(certfile), NULL,
1119 c_smime_get_signer_cert_command);
1120 if (pid == -1)
1121 {
1122 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1123 goto cleanup;
1124 }
1125
1126 filter_wait(pid);
1127
1128 fflush(fp_out);
1129 rewind(fp_out);
1130 fflush(fp_err);
1131 rewind(fp_err);
1132 empty = (fgetc(fp_out) == EOF);
1133 if (empty)
1134 {
1135 mutt_endwin();
1136 mutt_file_copy_stream(fp_err, stdout);
1138 goto cleanup;
1139 }
1140
1141 mutt_file_fclose(&fp_out);
1142 cert = mutt_buffer_strdup(certfile);
1143
1144cleanup:
1145 mutt_file_fclose(&fp_err);
1146 if (fp_out)
1147 {
1148 mutt_file_fclose(&fp_out);
1150 }
1151 mutt_buffer_pool_release(&certfile);
1152 return cert;
1153}
1154
1158void smime_class_invoke_import(const char *infile, const char *mailbox)
1159{
1160 char *certfile = NULL;
1161 struct Buffer *buf = NULL;
1162
1163 FILE *fp_err = mutt_file_mkstemp();
1164 if (!fp_err)
1165 {
1166 mutt_perror(_("Can't create temporary file"));
1167 goto done;
1168 }
1169
1170 FILE *fp_out = mutt_file_mkstemp();
1171 if (!fp_out)
1172 {
1173 mutt_perror(_("Can't create temporary file"));
1174 goto done;
1175 }
1176
1177 buf = mutt_buffer_pool_get();
1178 const bool c_smime_ask_cert_label = cs_subset_bool(NeoMutt->sub, "smime_ask_cert_label");
1179 if (c_smime_ask_cert_label)
1180 {
1181 if ((mutt_buffer_get_field(_("Label for certificate: "), buf,
1182 MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0) ||
1184 {
1185 goto done;
1186 }
1187 }
1188
1189 mutt_endwin();
1190 certfile = smime_extract_certificate(infile);
1191 if (certfile)
1192 {
1193 mutt_endwin();
1194
1195 const char *const c_smime_import_cert_command = cs_subset_string(NeoMutt->sub, "smime_import_cert_command");
1196 FILE *fp_smime_in = NULL;
1197 pid_t pid = smime_invoke(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1198 fileno(fp_err), certfile, NULL, NULL, NULL, NULL,
1199 NULL, NULL, c_smime_import_cert_command);
1200 if (pid == -1)
1201 {
1202 mutt_message(_("Error: unable to create OpenSSL subprocess"));
1203 goto done;
1204 }
1205 fputs(mutt_buffer_string(buf), fp_smime_in);
1206 fputc('\n', fp_smime_in);
1207 mutt_file_fclose(&fp_smime_in);
1208
1209 filter_wait(pid);
1210
1211 mutt_file_unlink(certfile);
1212 FREE(&certfile);
1213 }
1214
1215 fflush(fp_out);
1216 rewind(fp_out);
1217 fflush(fp_err);
1218 rewind(fp_err);
1219
1220 mutt_file_copy_stream(fp_out, stdout);
1221 mutt_file_copy_stream(fp_err, stdout);
1222
1223done:
1224 mutt_file_fclose(&fp_out);
1225 mutt_file_fclose(&fp_err);
1227}
1228
1232int smime_class_verify_sender(struct Email *e, struct Message *msg)
1233{
1234 char *mbox = NULL, *certfile = NULL;
1235 int rc = 1;
1236
1237 struct Buffer *tempfname = mutt_buffer_pool_get();
1238 mutt_buffer_mktemp(tempfname);
1239 FILE *fp_out = mutt_file_fopen(mutt_buffer_string(tempfname), "w");
1240 if (!fp_out)
1241 {
1242 mutt_perror(mutt_buffer_string(tempfname));
1243 goto cleanup;
1244 }
1245
1246 const bool encrypt = e->security & SEC_ENCRYPT;
1247 mutt_copy_message(fp_out, e, msg,
1249 encrypt ? (CH_MIME | CH_WEED | CH_NONEWLINE) : CH_NO_FLAGS, 0);
1250
1251 fflush(fp_out);
1252 mutt_file_fclose(&fp_out);
1253
1254 if (!TAILQ_EMPTY(&e->env->from))
1255 {
1257 mbox = TAILQ_FIRST(&e->env->from)->mailbox;
1258 }
1259 else if (!TAILQ_EMPTY(&e->env->sender))
1260 {
1262 mbox = TAILQ_FIRST(&e->env->sender)->mailbox;
1263 }
1264
1265 if (mbox)
1266 {
1268 if (certfile)
1269 {
1271 if (smime_handle_cert_email(certfile, mbox, false, NULL, NULL))
1272 {
1273 if (isendwin())
1275 }
1276 else
1277 rc = 0;
1278 mutt_file_unlink(certfile);
1279 FREE(&certfile);
1280 }
1281 else
1282 mutt_any_key_to_continue(_("no certfile"));
1283 }
1284 else
1285 mutt_any_key_to_continue(_("no mbox"));
1286
1288
1289cleanup:
1290 mutt_buffer_pool_release(&tempfname);
1291 return rc;
1292}
1293
1310static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1311 FILE **fp_smime_err, int fp_smime_infd,
1312 int fp_smime_outfd, int fp_smime_errfd,
1313 const char *fname, const char *uids)
1314{
1315 const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1316 const char *const c_smime_encrypt_command = cs_subset_string(NeoMutt->sub, "smime_encrypt_command");
1317 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1318 fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1319 NULL, NULL, uids, NULL, c_smime_encrypt_command);
1320}
1321
1337static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out,
1338 FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1339 int fp_smime_errfd, const char *fname)
1340{
1341 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1342 const char *const c_smime_sign_command = cs_subset_string(NeoMutt->sub, "smime_sign_command");
1343 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1344 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL,
1345 c_smime_sign_digest_alg, mutt_buffer_string(&SmimeKeyToUse),
1347 mutt_buffer_string(&SmimeIntermediateToUse), c_smime_sign_command);
1348}
1349
1353struct Body *smime_class_build_smime_entity(struct Body *a, char *certlist)
1354{
1355 char buf[1024], certfile[PATH_MAX];
1356 char *cert_end = NULL;
1357 FILE *fp_smime_in = NULL, *fp_smime_err = NULL, *fp_out = NULL, *fp_tmp = NULL;
1358 struct Body *t = NULL;
1359 int err = 0, empty, off;
1360 pid_t pid;
1361
1362 struct Buffer *tempfile = mutt_buffer_pool_get();
1363 struct Buffer *smime_infile = mutt_buffer_pool_get();
1364
1365 mutt_buffer_mktemp(tempfile);
1366 fp_out = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1367 if (!fp_out)
1368 {
1370 goto cleanup;
1371 }
1372
1373 fp_smime_err = mutt_file_mkstemp();
1374 if (!fp_smime_err)
1375 {
1376 mutt_perror(_("Can't create temporary file"));
1377 goto cleanup;
1378 }
1379
1380 mutt_buffer_mktemp(smime_infile);
1381 fp_tmp = mutt_file_fopen(mutt_buffer_string(smime_infile), "w+");
1382 if (!fp_tmp)
1383 {
1384 mutt_perror(mutt_buffer_string(smime_infile));
1385 goto cleanup;
1386 }
1387
1388 *certfile = '\0';
1389 for (char *cert_start = certlist; cert_start; cert_start = cert_end)
1390 {
1391 cert_end = strchr(cert_start, ' ');
1392 if (cert_end)
1393 *cert_end = '\0';
1394 if (*cert_start)
1395 {
1396 off = mutt_str_len(certfile);
1397 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1398 snprintf(certfile + off, sizeof(certfile) - off, "%s%s/%s",
1399 (off != 0) ? " " : "", NONULL(c_smime_certificates), cert_start);
1400 }
1401 if (cert_end)
1402 *cert_end++ = ' ';
1403 }
1404
1405 /* write a MIME entity */
1406 mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
1407 fputc('\n', fp_tmp);
1408 mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
1409 mutt_file_fclose(&fp_tmp);
1410
1411 pid = smime_invoke_encrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1412 fileno(fp_smime_err),
1413 mutt_buffer_string(smime_infile), certfile);
1414 if (pid == -1)
1415 {
1416 mutt_file_unlink(mutt_buffer_string(smime_infile));
1417 goto cleanup;
1418 }
1419
1420 mutt_file_fclose(&fp_smime_in);
1421
1422 filter_wait(pid);
1423 mutt_file_unlink(mutt_buffer_string(smime_infile));
1424
1425 fflush(fp_out);
1426 rewind(fp_out);
1427 empty = (fgetc(fp_out) == EOF);
1428 mutt_file_fclose(&fp_out);
1429
1430 fflush(fp_smime_err);
1431 rewind(fp_smime_err);
1432 while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1433 {
1434 err = 1;
1435 fputs(buf, stdout);
1436 }
1437 mutt_file_fclose(&fp_smime_err);
1438
1439 /* pause if there is any error output from SMIME */
1440 if (err)
1442
1443 if (empty)
1444 {
1445 /* fatal error while trying to encrypt message */
1446 if (err == 0)
1447 mutt_any_key_to_continue(_("No output from OpenSSL..."));
1449 goto cleanup;
1450 }
1451
1452 t = mutt_body_new();
1454 t->subtype = mutt_str_dup("pkcs7-mime");
1455 mutt_param_set(&t->parameter, "name", "smime.p7m");
1456 mutt_param_set(&t->parameter, "smime-type", "enveloped-data");
1457 t->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1458 t->use_disp = true;
1460 t->d_filename = mutt_str_dup("smime.p7m");
1461 t->filename = mutt_buffer_strdup(tempfile);
1462 t->unlink = true; /* delete after sending the message */
1463 t->parts = NULL;
1464 t->next = NULL;
1465
1466cleanup:
1467 if (fp_out)
1468 {
1469 mutt_file_fclose(&fp_out);
1471 }
1472 mutt_file_fclose(&fp_smime_err);
1473 if (fp_tmp)
1474 {
1475 mutt_file_fclose(&fp_tmp);
1476 mutt_file_unlink(mutt_buffer_string(smime_infile));
1477 }
1478 mutt_buffer_pool_release(&tempfile);
1479 mutt_buffer_pool_release(&smime_infile);
1480
1481 return t;
1482}
1483
1496static char *openssl_md_to_smime_micalg(const char *md)
1497{
1498 if (!md)
1499 return 0;
1500
1501 char *micalg = NULL;
1502 if (mutt_istr_startswith(md, "sha"))
1503 {
1504 const size_t l = strlen(md) + 2;
1505 micalg = mutt_mem_malloc(l);
1506 snprintf(micalg, l, "sha-%s", md + 3);
1507 }
1508 else
1509 {
1510 micalg = mutt_str_dup(md);
1511 }
1512
1513 return micalg;
1514}
1515
1519struct Body *smime_class_sign_message(struct Body *a, const struct AddressList *from)
1520{
1521 struct Body *t = NULL;
1522 struct Body *retval = NULL;
1523 char buf[1024] = { 0 };
1524 struct Buffer *filetosign = NULL, *signedfile = NULL;
1525 FILE *fp_smime_in = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL, *fp_sign = NULL;
1526 int err = 0;
1527 int empty = 0;
1528 pid_t pid;
1529 const char *intermediates = NULL;
1530
1531 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
1532 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1533 const char *signas = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1534 if (!signas || (*signas == '\0'))
1535 {
1536 mutt_error(_("Can't sign: No key specified. Use Sign As."));
1537 return NULL;
1538 }
1539
1540 crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1541
1542 filetosign = mutt_buffer_pool_get();
1543 signedfile = mutt_buffer_pool_get();
1544
1545 mutt_buffer_mktemp(filetosign);
1546 fp_sign = mutt_file_fopen(mutt_buffer_string(filetosign), "w+");
1547 if (!fp_sign)
1548 {
1549 mutt_perror(mutt_buffer_string(filetosign));
1550 goto cleanup;
1551 }
1552
1553 mutt_buffer_mktemp(signedfile);
1554 fp_smime_out = mutt_file_fopen(mutt_buffer_string(signedfile), "w+");
1555 if (!fp_smime_out)
1556 {
1557 mutt_perror(mutt_buffer_string(signedfile));
1558 goto cleanup;
1559 }
1560
1561 mutt_write_mime_header(a, fp_sign, NeoMutt->sub);
1562 fputc('\n', fp_sign);
1563 mutt_write_mime_body(a, fp_sign, NeoMutt->sub);
1564 mutt_file_fclose(&fp_sign);
1565
1566 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
1567 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1568 mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), signas);
1569 mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), signas);
1570
1571 struct SmimeKey *signas_key = smime_get_key_by_hash(signas, 1);
1572 if (!signas_key || mutt_str_equal("?", signas_key->issuer))
1573 intermediates = signas; /* so openssl won't complain in any case */
1574 else
1575 intermediates = signas_key->issuer;
1576
1578 NONULL(c_smime_certificates), intermediates);
1579
1580 smime_key_free(&signas_key);
1581
1582 pid = smime_invoke_sign(&fp_smime_in, NULL, &fp_smime_err, -1,
1583 fileno(fp_smime_out), -1, mutt_buffer_string(filetosign));
1584 if (pid == -1)
1585 {
1586 mutt_perror(_("Can't open OpenSSL subprocess"));
1588 goto cleanup;
1589 }
1590 fputs(SmimePass, fp_smime_in);
1591 fputc('\n', fp_smime_in);
1592 mutt_file_fclose(&fp_smime_in);
1593
1594 filter_wait(pid);
1595
1596 /* check for errors from OpenSSL */
1597 err = 0;
1598 fflush(fp_smime_err);
1599 rewind(fp_smime_err);
1600 while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1601 {
1602 err = 1;
1603 fputs(buf, stdout);
1604 }
1605 mutt_file_fclose(&fp_smime_err);
1606
1607 fflush(fp_smime_out);
1608 rewind(fp_smime_out);
1609 empty = (fgetc(fp_smime_out) == EOF);
1610 mutt_file_fclose(&fp_smime_out);
1611
1613
1614 if (err)
1616
1617 if (empty)
1618 {
1619 mutt_any_key_to_continue(_("No output from OpenSSL..."));
1621 goto cleanup; /* fatal error while signing */
1622 }
1623
1624 t = mutt_body_new();
1625 t->type = TYPE_MULTIPART;
1626 t->subtype = mutt_str_dup("signed");
1627 t->encoding = ENC_7BIT;
1628 t->use_disp = false;
1630
1632
1633 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1634 char *micalg = openssl_md_to_smime_micalg(c_smime_sign_digest_alg);
1635 mutt_param_set(&t->parameter, "micalg", micalg);
1636 FREE(&micalg);
1637
1638 mutt_param_set(&t->parameter, "protocol", "application/pkcs7-signature");
1639
1640 t->parts = a;
1641 retval = t;
1642
1643 t->parts->next = mutt_body_new();
1644 t = t->parts->next;
1646 t->subtype = mutt_str_dup("pkcs7-signature");
1647 t->filename = mutt_buffer_strdup(signedfile);
1648 t->d_filename = mutt_str_dup("smime.p7s");
1649 t->use_disp = true;
1651 t->encoding = ENC_BASE64;
1652 t->unlink = true; /* ok to remove this file after sending. */
1653
1654cleanup:
1655 if (fp_sign)
1656 {
1657 mutt_file_fclose(&fp_sign);
1659 }
1660 if (fp_smime_out)
1661 {
1662 mutt_file_fclose(&fp_smime_out);
1664 }
1665 mutt_buffer_pool_release(&filetosign);
1666 mutt_buffer_pool_release(&signedfile);
1667 return retval;
1668}
1669
1687static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out,
1688 FILE **fp_smime_err, int fp_smime_infd,
1689 int fp_smime_outfd, int fp_smime_errfd,
1690 const char *fname, const char *sig_fname, int opaque)
1691{
1692 const char *const c_smime_verify_opaque_command = cs_subset_string(NeoMutt->sub, "smime_verify_opaque_command");
1693 const char *const c_smime_verify_command = cs_subset_string(NeoMutt->sub, "smime_verify_command");
1694 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1695 fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1696 (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1697}
1698
1714static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1715 FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1716 int fp_smime_errfd, const char *fname)
1717{
1718 const char *const c_smime_decrypt_command = cs_subset_string(NeoMutt->sub, "smime_decrypt_command");
1719 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1720 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1722 mutt_buffer_string(&SmimeCertToUse), NULL, c_smime_decrypt_command);
1723}
1724
1728int smime_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
1729{
1730 FILE *fp = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL;
1731 pid_t pid;
1732 int badsig = -1;
1733
1734 LOFF_T tmpoffset = 0;
1735 size_t tmplength = 0;
1736 int orig_type = sigbdy->type;
1737
1738 struct Buffer *signedfile = mutt_buffer_pool_get();
1739
1740 mutt_buffer_printf(signedfile, "%s.sig", tempfile);
1741
1742 /* decode to a tempfile, saving the original destination */
1743 fp = s->fp_out;
1744 s->fp_out = mutt_file_fopen(mutt_buffer_string(signedfile), "w");
1745 if (!s->fp_out)
1746 {
1747 mutt_perror(mutt_buffer_string(signedfile));
1748 goto cleanup;
1749 }
1750 /* decoding the attachment changes the size and offset, so save a copy
1751 * of the "real" values now, and restore them after processing */
1752 tmplength = sigbdy->length;
1753 tmpoffset = sigbdy->offset;
1754
1755 /* if we are decoding binary bodies, we don't want to prefix each
1756 * line with the prefix or else the data will get corrupted. */
1757 char *save_prefix = s->prefix;
1758 s->prefix = NULL;
1759
1760 mutt_decode_attachment(sigbdy, s);
1761
1762 sigbdy->length = ftello(s->fp_out);
1763 sigbdy->offset = 0;
1765
1766 /* restore final destination and substitute the tempfile for input */
1767 s->fp_out = fp;
1768 fp = s->fp_in;
1769 s->fp_in = fopen(mutt_buffer_string(signedfile), "r");
1770
1771 /* restore the prefix */
1772 s->prefix = save_prefix;
1773
1774 sigbdy->type = orig_type;
1775
1776 fp_smime_err = mutt_file_mkstemp();
1777 if (!fp_smime_err)
1778 {
1779 mutt_perror(_("Can't create temporary file"));
1780 goto cleanup;
1781 }
1782
1783 crypt_current_time(s, "OpenSSL");
1784
1785 pid = smime_invoke_verify(NULL, &fp_smime_out, NULL, -1, -1, fileno(fp_smime_err),
1786 tempfile, mutt_buffer_string(signedfile), 0);
1787 if (pid != -1)
1788 {
1789 fflush(fp_smime_out);
1790 mutt_file_fclose(&fp_smime_out);
1791
1792 if (filter_wait(pid))
1793 badsig = -1;
1794 else
1795 {
1796 char *line = NULL;
1797 size_t linelen;
1798
1799 fflush(fp_smime_err);
1800 rewind(fp_smime_err);
1801
1802 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
1803 if (linelen && mutt_istr_equal(line, "verification successful"))
1804 badsig = 0;
1805
1806 FREE(&line);
1807 }
1808 }
1809
1810 fflush(fp_smime_err);
1811 rewind(fp_smime_err);
1812 mutt_file_copy_stream(fp_smime_err, s->fp_out);
1813 mutt_file_fclose(&fp_smime_err);
1814
1815 state_attach_puts(s, _("[-- End of OpenSSL output --]\n\n"));
1816
1818
1819 sigbdy->length = tmplength;
1820 sigbdy->offset = tmpoffset;
1821
1822 /* restore the original source stream */
1824 s->fp_in = fp;
1825
1826cleanup:
1827 mutt_buffer_pool_release(&signedfile);
1828 return badsig;
1829}
1830
1840static struct Body *smime_handle_entity(struct Body *m, struct State *s, FILE *fp_out_file)
1841{
1842 struct Buffer tmpfname = mutt_buffer_make(0);
1843 FILE *fp_smime_out = NULL, *fp_smime_in = NULL, *fp_smime_err = NULL;
1844 FILE *fp_tmp = NULL, *fp_out = NULL;
1845 struct Body *p = NULL;
1846 pid_t pid = -1;
1848
1849 if (!(type & APPLICATION_SMIME))
1850 return NULL;
1851
1852 /* Because of the mutt_body_handler() we avoid the buffer pool. */
1853 fp_smime_out = mutt_file_mkstemp();
1854 if (!fp_smime_out)
1855 {
1856 mutt_perror(_("Can't create temporary file"));
1857 goto cleanup;
1858 }
1859
1860 fp_smime_err = mutt_file_mkstemp();
1861 if (!fp_smime_err)
1862 {
1863 mutt_perror(_("Can't create temporary file"));
1864 goto cleanup;
1865 }
1866
1867 mutt_buffer_mktemp(&tmpfname);
1868 fp_tmp = mutt_file_fopen(mutt_buffer_string(&tmpfname), "w+");
1869 if (!fp_tmp)
1870 {
1871 mutt_perror(mutt_buffer_string(&tmpfname));
1872 goto cleanup;
1873 }
1874
1875 if (!mutt_file_seek(s->fp_in, m->offset, SEEK_SET))
1876 {
1877 goto cleanup;
1878 }
1879
1880 mutt_file_copy_bytes(s->fp_in, fp_tmp, m->length);
1881
1882 fflush(fp_tmp);
1883 mutt_file_fclose(&fp_tmp);
1884
1885 if ((type & SEC_ENCRYPT) &&
1886 ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1,
1887 fileno(fp_smime_out), fileno(fp_smime_err),
1888 mutt_buffer_string(&tmpfname))) == -1))
1889 {
1891 if (s->flags & MUTT_DISPLAY)
1892 {
1893 state_attach_puts(s, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1894 }
1895 goto cleanup;
1896 }
1897 else if ((type & SEC_SIGNOPAQUE) &&
1898 ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1899 fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1900 mutt_buffer_string(&tmpfname), SEC_SIGNOPAQUE)) == -1))
1901 {
1903 if (s->flags & MUTT_DISPLAY)
1904 {
1905 state_attach_puts(s, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1906 }
1907 goto cleanup;
1908 }
1909
1910 if (type & SEC_ENCRYPT)
1911 {
1914 fputs(SmimePass, fp_smime_in);
1915 fputc('\n', fp_smime_in);
1916 }
1917
1918 mutt_file_fclose(&fp_smime_in);
1919
1920 filter_wait(pid);
1922
1923 if (s->flags & MUTT_DISPLAY)
1924 {
1925 fflush(fp_smime_err);
1926 rewind(fp_smime_err);
1927
1928 const int c = fgetc(fp_smime_err);
1929 if (c != EOF)
1930 {
1931 ungetc(c, fp_smime_err);
1932
1933 crypt_current_time(s, "OpenSSL");
1934 mutt_file_copy_stream(fp_smime_err, s->fp_out);
1935 state_attach_puts(s, _("[-- End of OpenSSL output --]\n\n"));
1936 }
1937
1938 if (type & SEC_ENCRYPT)
1939 {
1940 state_attach_puts(s, _("[-- The following data is S/MIME encrypted --]\n"));
1941 }
1942 else
1943 state_attach_puts(s, _("[-- The following data is S/MIME signed --]\n"));
1944 }
1945
1946 fflush(fp_smime_out);
1947 rewind(fp_smime_out);
1948
1949 if (type & SEC_ENCRYPT)
1950 {
1951 /* void the passphrase, even if that wasn't the problem */
1952 if (fgetc(fp_smime_out) == EOF)
1953 {
1954 mutt_error(_("Decryption failed"));
1956 }
1957 rewind(fp_smime_out);
1958 }
1959
1960 if (fp_out_file)
1961 fp_out = fp_out_file;
1962 else
1963 {
1964 fp_out = mutt_file_mkstemp();
1965 if (!fp_out)
1966 {
1967 mutt_perror(_("Can't create temporary file"));
1968 goto cleanup;
1969 }
1970 }
1971 char buf[8192] = { 0 };
1972 while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1973 {
1974 const size_t len = mutt_str_len(buf);
1975 if ((len > 1) && (buf[len - 2] == '\r'))
1976 {
1977 buf[len - 2] = '\n';
1978 buf[len - 1] = '\0';
1979 }
1980 fputs(buf, fp_out);
1981 }
1982 fflush(fp_out);
1983 rewind(fp_out);
1984
1985 const long size = mutt_file_get_size_fp(fp_out);
1986 if (size == 0)
1987 {
1988 goto cleanup;
1989 }
1990 p = mutt_read_mime_header(fp_out, 0);
1991 if (p)
1992 {
1993 p->length = size - p->offset;
1994
1995 mutt_parse_part(fp_out, p);
1996
1997 if (s->flags & MUTT_DISPLAY)
1999
2000 /* Store any protected headers in the parent so they can be
2001 * accessed for index updates after the handler recursion is done.
2002 * This is done before the handler to prevent a nested encrypted
2003 * handler from freeing the headers. */
2005 m->mime_headers = p->mime_headers;
2006 p->mime_headers = NULL;
2007
2008 if (s->fp_out)
2009 {
2010 rewind(fp_out);
2011 FILE *fp_tmp_buffer = s->fp_in;
2012 s->fp_in = fp_out;
2013 mutt_body_handler(p, s);
2014 s->fp_in = fp_tmp_buffer;
2015 }
2016
2017 /* Embedded multipart signed protected headers override the
2018 * encrypted headers. We need to do this after the handler so
2019 * they can be printed in the pager. */
2020 if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
2021 p->parts->mime_headers)
2022 {
2025 p->parts->mime_headers = NULL;
2026 }
2027 }
2028 mutt_file_fclose(&fp_smime_out);
2029
2030 if (!fp_out_file)
2031 {
2032 mutt_file_fclose(&fp_out);
2034 }
2035 fp_out = NULL;
2036
2037 if (s->flags & MUTT_DISPLAY)
2038 {
2039 if (type & SEC_ENCRYPT)
2040 state_attach_puts(s, _("\n[-- End of S/MIME encrypted data. --]\n"));
2041 else
2042 state_attach_puts(s, _("\n[-- End of S/MIME signed data. --]\n"));
2043 }
2044
2045 if (type & SEC_SIGNOPAQUE)
2046 {
2047 char *line = NULL;
2048 size_t linelen;
2049
2050 rewind(fp_smime_err);
2051
2052 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
2053 if (linelen && mutt_istr_equal(line, "verification successful"))
2054 m->goodsig = true;
2055 FREE(&line);
2056 }
2057 else if (p)
2058 {
2059 m->goodsig = p->goodsig;
2060 m->badsig = p->badsig;
2061 }
2062
2063cleanup:
2064 mutt_file_fclose(&fp_smime_out);
2065 mutt_file_fclose(&fp_smime_err);
2066 mutt_file_fclose(&fp_tmp);
2067 mutt_file_fclose(&fp_out);
2068 mutt_buffer_dealloc(&tmpfname);
2069 return p;
2070}
2071
2075int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
2076{
2077 struct State s = { 0 };
2078 LOFF_T tmpoffset = b->offset;
2079 size_t tmplength = b->length;
2080 int rc = -1;
2081
2083 return -1;
2084
2085 if (b->parts)
2086 return -1;
2087
2088 s.fp_in = fp_in;
2089 if (!mutt_file_seek(s.fp_in, b->offset, SEEK_SET))
2090 {
2091 return -1;
2092 }
2093
2094 FILE *fp_tmp = mutt_file_mkstemp();
2095 if (!fp_tmp)
2096 {
2097 mutt_perror(_("Can't create temporary file"));
2098 return -1;
2099 }
2100
2101 s.fp_out = fp_tmp;
2103 fflush(fp_tmp);
2104 b->length = ftello(s.fp_out);
2105 b->offset = 0;
2106 rewind(fp_tmp);
2107 s.fp_in = fp_tmp;
2108 s.fp_out = 0;
2109
2111 if (!*fp_out)
2112 {
2113 mutt_perror(_("Can't create temporary file"));
2114 goto bail;
2115 }
2116
2117 *cur = smime_handle_entity(b, &s, *fp_out);
2118 if (!*cur)
2119 goto bail;
2120
2121 (*cur)->goodsig = b->goodsig;
2122 (*cur)->badsig = b->badsig;
2123 rc = 0;
2124
2125bail:
2126 b->length = tmplength;
2127 b->offset = tmpoffset;
2128 mutt_file_fclose(&fp_tmp);
2129 if (*fp_out)
2130 rewind(*fp_out);
2131
2132 return rc;
2133}
2134
2139{
2140 int rc = -1;
2141
2142 /* clear out any mime headers before the handler, so they can't be spoofed. */
2144
2145 struct Body *tattach = smime_handle_entity(m, s, NULL);
2146 if (tattach)
2147 {
2148 rc = 0;
2149 mutt_body_free(&tattach);
2150 }
2151 return rc;
2152}
2153
2158{
2159 struct SmimeKey *key = NULL;
2160 const char *prompt = NULL;
2161 const char *letters = NULL;
2162 const char *choices = NULL;
2163 int choice;
2164
2166 return e->security;
2167
2169
2170 /* Opportunistic encrypt is controlling encryption.
2171 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
2172 * letter choices for those. */
2173 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
2174 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
2175 {
2176 /* L10N: S/MIME options (opportunistic encryption is on) */
2177 prompt = _("S/MIME (s)ign, encrypt (w)ith, sign (a)s, (c)lear, or (o)ppenc mode off?");
2178 /* L10N: S/MIME options (opportunistic encryption is on) */
2179 letters = _("swaco");
2180 choices = "SwaCo";
2181 }
2182 /* Opportunistic encryption option is set, but is toggled off
2183 * for this message. */
2184 else if (c_crypt_opportunistic_encrypt)
2185 {
2186 /* L10N: S/MIME options (opportunistic encryption is off) */
2187 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode?");
2188 /* L10N: S/MIME options (opportunistic encryption is off) */
2189 letters = _("eswabco");
2190 choices = "eswabcO";
2191 }
2192 /* Opportunistic encryption is unset */
2193 else
2194 {
2195 /* L10N: S/MIME options */
2196 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear?");
2197 /* L10N: S/MIME options */
2198 letters = _("eswabc");
2199 choices = "eswabc";
2200 }
2201
2202 choice = mutt_multi_choice(prompt, letters);
2203 if (choice > 0)
2204 {
2205 switch (choices[choice - 1])
2206 {
2207 case 'a': /* sign (a)s */
2208 key = smime_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, false);
2209 if (key)
2210 {
2211 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", key->hash, NULL);
2212 smime_key_free(&key);
2213
2214 e->security |= SEC_SIGN;
2215
2216 /* probably need a different passphrase */
2218 }
2219
2220 break;
2221
2222 case 'b': /* (b)oth */
2223 e->security |= (SEC_ENCRYPT | SEC_SIGN);
2224 break;
2225
2226 case 'c': /* (c)lear */
2227 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2228 break;
2229
2230 case 'C':
2231 e->security &= ~SEC_SIGN;
2232 break;
2233
2234 case 'e': /* (e)ncrypt */
2235 e->security |= SEC_ENCRYPT;
2236 e->security &= ~SEC_SIGN;
2237 break;
2238
2239 case 'O': /* oppenc mode on */
2242 break;
2243
2244 case 'o': /* oppenc mode off */
2245 e->security &= ~SEC_OPPENCRYPT;
2246 break;
2247
2248 case 'S': /* (s)ign in oppenc mode */
2249 e->security |= SEC_SIGN;
2250 break;
2251
2252 case 's': /* (s)ign */
2253 e->security &= ~SEC_ENCRYPT;
2254 e->security |= SEC_SIGN;
2255 break;
2256
2257 case 'w': /* encrypt (w)ith */
2258 {
2259 e->security |= SEC_ENCRYPT;
2260 do
2261 {
2262 struct Buffer errmsg = mutt_buffer_make(0);
2263 int rc = CSR_SUCCESS;
2264 switch (mutt_multi_choice(_("Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?"),
2265 // L10N: Options for: Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?
2266 _("123c")))
2267 {
2268 case 1:
2269 switch (choice = mutt_multi_choice(_("(1) DES, (2) Triple-DES?"),
2270 // L10N: Options for: (1) DES, (2) Triple-DES
2271 _("12")))
2272 {
2273 case 1:
2274 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2275 "des", &errmsg);
2276 break;
2277 case 2:
2278 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2279 "des3", &errmsg);
2280 break;
2281 }
2282 break;
2283
2284 case 2:
2285 switch (choice = mutt_multi_choice(_("(1) RC2-40, (2) RC2-64, (3) RC2-128?"),
2286 // L10N: Options for: (1) RC2-40, (2) RC2-64, (3) RC2-128
2287 _("123")))
2288 {
2289 case 1:
2290 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2291 "rc2-40", &errmsg);
2292 break;
2293 case 2:
2294 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2295 "rc2-64", &errmsg);
2296 break;
2297 case 3:
2298 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2299 "rc2-128", &errmsg);
2300 break;
2301 }
2302 break;
2303
2304 case 3:
2305 switch (choice = mutt_multi_choice(_("(1) AES128, (2) AES192, (3) AES256?"),
2306 // L10N: Options for: (1) AES128, (2) AES192, (3) AES256
2307 _("123")))
2308 {
2309 case 1:
2310 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2311 "aes128", &errmsg);
2312 break;
2313 case 2:
2314 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2315 "aes192", &errmsg);
2316 break;
2317 case 3:
2318 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2319 "aes256", &errmsg);
2320 break;
2321 }
2322 break;
2323
2324 case 4:
2325 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2326 NULL, &errmsg);
2327 /* (c)lear */
2328 /* fallthrough */
2329 case -1: /* Ctrl-G or Enter */
2330 choice = 0;
2331 break;
2332 }
2333
2334 if ((CSR_RESULT(rc) != CSR_SUCCESS) && !mutt_buffer_is_empty(&errmsg))
2335 mutt_error("%s", mutt_buffer_string(&errmsg));
2336
2337 mutt_buffer_dealloc(&errmsg);
2338 } while (choice == -1);
2339 break;
2340 }
2341 }
2342 }
2343
2344 return e->security;
2345}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:574
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
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.c:864
Duplicate the structure of an entire email.
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
Convenience wrapper for the core headers.
void crypt_current_time(struct State *s, const char *app_name)
Print the current time.
Definition: crypt.c:70
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1023
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:402
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:599
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:793
Signing/encryption multiplexor.
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:413
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:387
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:354
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
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:637
struct SmimeKey * dlg_select_smime_key(struct SmimeKey *keys, const char *query)
Get the user to select a key.
Definition: dlg_smime.c:194
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Structs that make up an email.
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:259
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:736
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
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:229
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1585
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:907
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:706
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:193
#define mutt_file_mkstemp()
Definition: file.h:122
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
Flags to control mutt_expando_format()
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
int smime_class_application_handler(struct Body *m, struct State *s)
Implements CryptModuleSpecs::application_handler() -.
Definition: smime.c:2138
int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Implements CryptModuleSpecs::decrypt_mime() -.
Definition: smime.c:2075
char * smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
Implements CryptModuleSpecs::find_keys() -.
Definition: smime.c:833
SecurityFlags smime_class_send_menu(struct Email *e)
Implements CryptModuleSpecs::send_menu() -.
Definition: smime.c:2157
struct Body * smime_class_sign_message(struct Body *a, const struct AddressList *from)
Implements CryptModuleSpecs::sign_message() -.
Definition: smime.c:1519
struct Body * smime_class_build_smime_entity(struct Body *a, char *certlist)
Implements CryptModuleSpecs::smime_build_smime_entity() -.
Definition: smime.c:1353
void smime_class_getkeys(struct Envelope *env)
Implements CryptModuleSpecs::smime_getkeys() -.
Definition: smime.c:792
void smime_class_invoke_import(const char *infile, const char *mailbox)
Implements CryptModuleSpecs::smime_invoke_import() -.
Definition: smime.c:1158
int smime_class_verify_sender(struct Email *e, struct Message *msg)
Implements CryptModuleSpecs::smime_verify_sender() -.
Definition: smime.c:1232
bool smime_class_valid_passphrase(void)
Implements CryptModuleSpecs::valid_passphrase() -.
Definition: smime.c:168
int smime_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
Implements CryptModuleSpecs::verify_one() -.
Definition: smime.c:1728
void smime_class_void_passphrase(void)
Implements CryptModuleSpecs::void_passphrase() -.
Definition: smime.c:159
static const char * smime_command_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format an SMIME command - Implements format_t -.
Definition: smime.c:218
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:777
int mutt_protected_headers_handler(struct Body *b, struct State *s)
Process a protected header - Implements handler_t -.
Definition: crypt.c:1093
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1866
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1596
Decide how to display email content.
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:760
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:43
static int search(struct Menu *menu, int op)
Search a menu.
Definition: functions.c:57
@ 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
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:100
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:592
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
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:652
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
Many unsorted constants and some structs.
#define MUTT_COMP_PASS
Password mode (no echo)
Definition: mutt.h:63
#define MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition: mutt.h:64
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define PATH_MAX
Definition: mutt.h:40
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
Some miscellaneous functions.
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:125
#define SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition: lib.h:83
#define SMIME_SIGN
Definition: lib.h:103
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:128
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:127
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1736
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1317
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Ask the user a question.
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_EMPTY(head)
Definition: queue.h:721
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1459
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
GUI display the mailboxes in a side panel.
static struct Buffer SmimeIntermediateToUse
Definition: smime.c:83
static struct SmimeKey * smime_get_key_by_hash(const char *hash, bool only_public_key)
Find a key by its hash.
Definition: smime.c:567
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:1337
char SmimePass[256]
Definition: smime.c:78
time_t SmimeExpTime
Definition: smime.c:79
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition: smime.c:134
static void smime_command(char *buf, size_t buflen, struct SmimeCommandContext *cctx, const char *fmt)
Format an SMIME command string.
Definition: smime.c:374
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:674
void smime_init(void)
Initialise smime globals.
Definition: smime.c:88
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:1687
void smime_cleanup(void)
Clean up smime globals.
Definition: smime.c:98
static int smime_handle_cert_email(char *certificate, char *mailbox, bool copy, char ***buffer, int *num)
Process an email containing certificates.
Definition: smime.c:880
static char * smime_extract_signer_certificate(const char *infile)
Extract the signer's certificate.
Definition: smime.c:1090
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition: smime.c:436
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:1714
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition: smime.c:519
static struct Buffer SmimeKeyToUse
Definition: smime.c:81
static char * smime_extract_certificate(const char *infile)
Extract an SMIME certificate from a file.
Definition: smime.c:975
static struct Body * smime_handle_entity(struct Body *m, struct State *s, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition: smime.c:1840
static struct Buffer SmimeCertToUse
Definition: smime.c:82
static struct SmimeKey * smime_ask_for_key(char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition: smime.c:720
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:1310
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition: smime.c:109
static char * openssl_md_to_smime_micalg(const char *md)
Change the algorithm names.
Definition: smime.c:1496
static void getkeys(char *mailbox)
Get the keys for a mailbox.
Definition: smime.c:757
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 char *format)
Run an SMIME command.
Definition: smime.c:404
static struct SmimeKey * smime_get_key_by_addr(char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition: smime.c:593
SMIME helper routines.
Key value store.
#define NONULL(x)
Definition: string2.h:37
#define STR_COMMAND
Enough space for a long command line.
Definition: string2.h:35
An email address.
Definition: address.h:36
char * 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:72
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:67
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:75
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
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:71
char * subtype
content-type subtype
Definition: body.h:60
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:58
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
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
A local copy of an email.
Definition: mxapi.h:43
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Data for a SIME command.
Definition: smime.c:68
const char * sig_fname
s
Definition: smime.c:73
const char * intermediates
i
Definition: smime.c:75
const char * digestalg
d
Definition: smime.c:71
const char * cryptalg
a
Definition: smime.c:70
const char * key
k
Definition: smime.c:69
const char * fname
f
Definition: smime.c:72
const char * certificates
c
Definition: smime.c:74
An SIME key.
Definition: smime.h:44
KeyFlags flags
Definition: smime.h:50
char * hash
Definition: smime.h:46
struct SmimeKey * next
Definition: smime.h:51
char * issuer
Definition: smime.h:48
char * email
Definition: smime.h:45
char * label
Definition: smime.h:47
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition: smime.h:49
Keep track when processing files.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
FILE * fp_out
File to write to.
Definition: state.h:48
char * prefix
String to add to the beginning of each output line.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:47
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:408