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