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