NeoMutt  2020-06-26-89-g172cd3
Teaching an old dog new tricks
DOXYGEN
smime.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <limits.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <time.h>
40 #include "private.h"
41 #include "mutt/lib.h"
42 #include "address/lib.h"
43 #include "config/lib.h"
44 #include "email/lib.h"
45 #include "core/lib.h"
46 #include "alias/lib.h"
47 #include "gui/lib.h"
48 #include "mutt.h"
49 #include "copy.h"
50 #include "crypt.h"
51 #include "cryptglue.h"
52 #include "format_flags.h"
53 #include "handler.h"
54 #include "keymap.h"
55 #include "mutt_globals.h"
56 #include "mutt_logging.h"
57 #include "mutt_menu.h"
58 #include "muttlib.h"
59 #include "opcodes.h"
60 #include "protos.h"
61 #include "state.h"
62 #include "ncrypt/lib.h"
63 #include "send/lib.h"
64 #ifdef CRYPT_BACKEND_CLASSIC_SMIME
65 #include "smime.h"
66 #endif
67 
72 {
73  const char *key;
74  const char *cryptalg;
75  const char *digestalg;
76  const char *fname;
77  const char *sig_fname;
78  const char *certificates;
79  const char *intermediates;
80 };
81 
82 char SmimePass[256];
83 time_t SmimeExpTime = 0; /* when does the cached passphrase expire? */
84 
85 static struct Buffer SmimeKeyToUse = { 0 };
86 static struct Buffer SmimeCertToUse = { 0 };
87 static struct Buffer SmimeIntermediateToUse = { 0 };
88 
92 void smime_init(void)
93 {
94  mutt_buffer_alloc(&SmimeKeyToUse, 256);
95  mutt_buffer_alloc(&SmimeCertToUse, 256);
96  mutt_buffer_alloc(&SmimeIntermediateToUse, 256);
97 }
98 
102 void smime_cleanup(void)
103 {
104  mutt_buffer_dealloc(&SmimeKeyToUse);
105  mutt_buffer_dealloc(&SmimeCertToUse);
106  mutt_buffer_dealloc(&SmimeIntermediateToUse);
107 }
108 
113 static void smime_key_free(struct SmimeKey **keylist)
114 {
115  if (!keylist)
116  return;
117 
118  struct SmimeKey *key = NULL;
119 
120  while (*keylist)
121  {
122  key = *keylist;
123  *keylist = (*keylist)->next;
124 
125  FREE(&key->email);
126  FREE(&key->hash);
127  FREE(&key->label);
128  FREE(&key->issuer);
129  FREE(&key);
130  }
131 }
132 
138 static struct SmimeKey *smime_copy_key(struct SmimeKey *key)
139 {
140  if (!key)
141  return NULL;
142 
143  struct SmimeKey *copy = NULL;
144 
145  copy = mutt_mem_calloc(1, sizeof(struct SmimeKey));
146  copy->email = mutt_str_dup(key->email);
147  copy->hash = mutt_str_dup(key->hash);
148  copy->label = mutt_str_dup(key->label);
149  copy->issuer = mutt_str_dup(key->issuer);
150  copy->trust = key->trust;
151  copy->flags = key->flags;
152 
153  return copy;
154 }
155 
156 /*
157  * Queries and passphrase handling.
158  */
159 
164 {
165  memset(SmimePass, 0, sizeof(SmimePass));
166  SmimeExpTime = 0;
167 }
168 
173 {
174  const time_t now = mutt_date_epoch();
175  if (now < SmimeExpTime)
176  {
177  /* Use cached copy. */
178  return true;
179  }
180 
182 
183  if (mutt_get_password(_("Enter S/MIME passphrase:"), SmimePass, sizeof(SmimePass)) == 0)
184  {
186  return true;
187  }
188  else
189  SmimeExpTime = 0;
190 
191  return false;
192 }
193 
194 /*
195  * The OpenSSL interface
196  */
197 
212 static const char *smime_command_format_str(char *buf, size_t buflen, size_t col,
213  int cols, char op, const char *src,
214  const char *prec, const char *if_str,
215  const char *else_str, intptr_t data,
217 {
218  char fmt[128];
219  struct SmimeCommandContext *cctx = (struct SmimeCommandContext *) data;
220  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
221 
222  switch (op)
223  {
224  case 'C':
225  {
226  if (!optional)
227  {
228  struct Buffer *path = mutt_buffer_pool_get();
229  struct Buffer *buf1 = mutt_buffer_pool_get();
230  struct Buffer *buf2 = mutt_buffer_pool_get();
231  struct stat sb;
232 
235  mutt_buffer_quote_filename(buf1, mutt_b2s(path), true);
236 
237  if ((stat(mutt_b2s(path), &sb) != 0) || !S_ISDIR(sb.st_mode))
238  mutt_buffer_printf(buf2, "-CAfile %s", mutt_b2s(buf1));
239  else
240  mutt_buffer_printf(buf2, "-CApath %s", mutt_b2s(buf1));
241 
242  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
243  snprintf(buf, buflen, fmt, mutt_b2s(buf2));
244 
248  }
249  else if (!C_SmimeCaLocation)
250  optional = false;
251  break;
252  }
253 
254  case 'c':
255  { /* certificate (list) */
256  if (!optional)
257  {
258  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
259  snprintf(buf, buflen, fmt, NONULL(cctx->certificates));
260  }
261  else if (!cctx->certificates)
262  optional = false;
263  break;
264  }
265 
266  case 'i':
267  { /* intermediate certificates */
268  if (!optional)
269  {
270  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
271  snprintf(buf, buflen, fmt, NONULL(cctx->intermediates));
272  }
273  else if (!cctx->intermediates)
274  optional = false;
275  break;
276  }
277 
278  case 's':
279  { /* detached signature */
280  if (!optional)
281  {
282  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
283  snprintf(buf, buflen, fmt, NONULL(cctx->sig_fname));
284  }
285  else if (!cctx->sig_fname)
286  optional = false;
287  break;
288  }
289 
290  case 'k':
291  { /* private key */
292  if (!optional)
293  {
294  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
295  snprintf(buf, buflen, fmt, NONULL(cctx->key));
296  }
297  else if (!cctx->key)
298  optional = false;
299  break;
300  }
301 
302  case 'a':
303  { /* algorithm for encryption */
304  if (!optional)
305  {
306  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
307  snprintf(buf, buflen, fmt, NONULL(cctx->cryptalg));
308  }
309  else if (!cctx->key)
310  optional = false;
311  break;
312  }
313 
314  case 'f':
315  { /* file to process */
316  if (!optional)
317  {
318  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
319  snprintf(buf, buflen, fmt, NONULL(cctx->fname));
320  }
321  else if (!cctx->fname)
322  optional = false;
323  break;
324  }
325 
326  case 'd':
327  { /* algorithm for the signature message digest */
328  if (!optional)
329  {
330  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
331  snprintf(buf, buflen, fmt, NONULL(cctx->digestalg));
332  }
333  else if (!cctx->key)
334  optional = false;
335  break;
336  }
337 
338  default:
339  *buf = '\0';
340  break;
341  }
342 
343  if (optional)
344  {
345  mutt_expando_format(buf, buflen, col, cols, if_str,
347  }
348  else if (flags & MUTT_FORMAT_OPTIONAL)
349  {
350  mutt_expando_format(buf, buflen, col, cols, else_str,
352  }
353 
354  return src;
355 }
356 
364 static void smime_command(char *buf, size_t buflen,
365  struct SmimeCommandContext *cctx, const char *fmt)
366 {
367  mutt_expando_format(buf, buflen, 0, buflen, NONULL(fmt), smime_command_format_str,
368  (intptr_t) cctx, MUTT_FORMAT_NO_FLAGS);
369  mutt_debug(LL_DEBUG2, "%s\n", buf);
370 }
371 
394 static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err,
395  int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd,
396  const char *fname, const char *sig_fname, const char *cryptalg,
397  const char *digestalg, const char *key, const char *certificates,
398  const char *intermediates, const char *format)
399 {
400  struct SmimeCommandContext cctx = { 0 };
401  char cmd[STR_COMMAND];
402 
403  if (!format || (*format == '\0'))
404  return (pid_t) -1;
405 
406  cctx.fname = fname;
407  cctx.sig_fname = sig_fname;
408  cctx.key = key;
409  cctx.cryptalg = cryptalg;
410  cctx.digestalg = digestalg;
411  cctx.certificates = certificates;
413 
414  smime_command(cmd, sizeof(cmd), &cctx, format);
415 
416  return filter_create_fd(cmd, fp_smime_in, fp_smime_out, fp_smime_err,
417  fp_smime_infd, fp_smime_outfd, fp_smime_errfd);
418 }
419 
420 /*
421  * Key and certificate handling.
422  */
423 
431 static char *smime_key_flags(KeyFlags flags)
432 {
433  static char buf[3];
434 
435  if (!(flags & KEYFLAG_CANENCRYPT))
436  buf[0] = '-';
437  else
438  buf[0] = 'e';
439 
440  if (!(flags & KEYFLAG_CANSIGN))
441  buf[1] = '-';
442  else
443  buf[1] = 's';
444 
445  buf[2] = '\0';
446 
447  return buf;
448 }
449 
453 static void smime_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
454 {
455  struct SmimeKey **table = menu->mdata;
456  struct SmimeKey *key = table[line];
457  char *truststate = NULL;
458  switch (key->trust)
459  {
460  case 'e':
461  /* L10N: Describes the trust state of a S/MIME key.
462  This translation must be padded with spaces to the right such that it
463  has the same length as the other translations.
464  The translation strings which need to be padded are:
465  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
466  truststate = _("Expired ");
467  break;
468  case 'i':
469  /* L10N: Describes the trust state of a S/MIME key.
470  This translation must be padded with spaces to the right such that it
471  has the same length as the other translations.
472  The translation strings which need to be padded are:
473  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
474  truststate = _("Invalid ");
475  break;
476  case 'r':
477  /* L10N: Describes the trust state of a S/MIME key.
478  This translation must be padded with spaces to the right such that it
479  has the same length as the other translations.
480  The translation strings which need to be padded are:
481  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
482  truststate = _("Revoked ");
483  break;
484  case 't':
485  /* L10N: Describes the trust state of a S/MIME key.
486  This translation must be padded with spaces to the right such that it
487  has the same length as the other translations.
488  The translation strings which need to be padded are:
489  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
490  truststate = _("Trusted ");
491  break;
492  case 'u':
493  /* L10N: Describes the trust state of a S/MIME key.
494  This translation must be padded with spaces to the right such that it
495  has the same length as the other translations.
496  The translation strings which need to be padded are:
497  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
498  truststate = _("Unverified");
499  break;
500  case 'v':
501  /* L10N: Describes the trust state of a S/MIME key.
502  This translation must be padded with spaces to the right such that it
503  has the same length as the other translations.
504  The translation strings which need to be padded are:
505  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
506  truststate = _("Verified ");
507  break;
508  default:
509  /* L10N: Describes the trust state of a S/MIME key.
510  This translation must be padded with spaces to the right such that it
511  has the same length as the other translations.
512  The translation strings which need to be padded are:
513  Expired, Invalid, Revoked, Trusted, Unverified, Verified, and Unknown. */
514  truststate = _("Unknown ");
515  }
516  snprintf(buf, buflen, " 0x%s %s %s %-35.35s %s", key->hash,
517  smime_key_flags(key->flags), truststate, key->email, key->label);
518 }
519 
526 static struct SmimeKey *smime_select_key(struct SmimeKey *keys, char *query)
527 {
528  struct SmimeKey **table = NULL;
529  int table_size = 0;
530  int table_index = 0;
531  struct SmimeKey *key = NULL;
532  struct SmimeKey *selected_key = NULL;
533  char helpstr[1024];
534  char buf[1024];
535  char title[256];
536  struct Menu *menu = NULL;
537  const char *s = "";
538  bool done = false;
539 
540  for (table_index = 0, key = keys; key; key = key->next)
541  {
542  if (table_index == table_size)
543  {
544  table_size += 5;
545  mutt_mem_realloc(&table, sizeof(struct SmimeKey *) * table_size);
546  }
547 
548  table[table_index++] = key;
549  }
550 
551  snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\""), query);
552 
553  /* Make Helpstring */
554  helpstr[0] = '\0';
555  mutt_make_help(buf, sizeof(buf), _("Exit "), MENU_SMIME, OP_EXIT);
556  strcat(helpstr, buf);
557  mutt_make_help(buf, sizeof(buf), _("Select "), MENU_SMIME, OP_GENERIC_SELECT_ENTRY);
558  strcat(helpstr, buf);
559  mutt_make_help(buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP);
560  strcat(helpstr, buf);
561 
562  struct MuttWindow *dlg =
565 
566  struct MuttWindow *index =
569 
570  struct MuttWindow *ibar =
573 
574  if (C_StatusOnTop)
575  {
576  mutt_window_add_child(dlg, ibar);
577  mutt_window_add_child(dlg, index);
578  }
579  else
580  {
581  mutt_window_add_child(dlg, index);
582  mutt_window_add_child(dlg, ibar);
583  }
584 
585  dialog_push(dlg);
586 
587  /* Create the menu */
588  menu = mutt_menu_new(MENU_SMIME);
589 
590  menu->pagelen = index->state.rows;
591  menu->win_index = index;
592  menu->win_ibar = ibar;
593 
594  menu->max = table_index;
596  menu->help = helpstr;
597  menu->mdata = table;
598  menu->title = title;
600  /* sorting keys might be done later - TODO */
601 
603 
604  done = false;
605  while (!done)
606  {
607  switch (mutt_menu_loop(menu))
608  {
609  case OP_GENERIC_SELECT_ENTRY:
610  if (table[menu->current]->trust != 't')
611  {
612  switch (table[menu->current]->trust)
613  {
614  case 'e':
615  case 'i':
616  case 'r':
617  s = _("ID is expired/disabled/revoked. Do you really want to use "
618  "the key?");
619  break;
620  case 'u':
621  s = _("ID has undefined validity. Do you really want to use the "
622  "key?");
623  break;
624  case 'v':
625  s = _("ID is not trusted. Do you really want to use the key?");
626  break;
627  }
628 
629  snprintf(buf, sizeof(buf), "%s", s);
630 
631  if (mutt_yesorno(buf, MUTT_NO) != MUTT_YES)
632  {
634  break;
635  }
636  }
637 
638  selected_key = table[menu->current];
639  done = true;
640  break;
641  case OP_EXIT:
642  done = true;
643  break;
644  }
645  }
646 
647  mutt_menu_pop_current(menu);
648  mutt_menu_free(&menu);
649  FREE(&table);
650  dialog_pop();
651  mutt_window_free(&dlg);
652 
653  return selected_key;
654 }
655 
662 static struct SmimeKey *smime_parse_key(char *buf)
663 {
664  char *pend = NULL, *p = NULL;
665  int field = 0;
666 
667  struct SmimeKey *key = mutt_mem_calloc(1, sizeof(struct SmimeKey));
668 
669  for (p = buf; p; p = pend)
670  {
671  /* Some users manually maintain their .index file, and use a tab
672  * as a delimiter, which the old parsing code (using fscanf)
673  * happened to allow. smime_keys uses a space, so search for both. */
674  if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
675  *pend++ = 0;
676 
677  /* For backward compatibility, don't count consecutive delimiters
678  * as an empty field. */
679  if (*p == '\0')
680  continue;
681 
682  field++;
683 
684  switch (field)
685  {
686  case 1: /* mailbox */
687  key->email = mutt_str_dup(p);
688  break;
689  case 2: /* hash */
690  key->hash = mutt_str_dup(p);
691  break;
692  case 3: /* label */
693  key->label = mutt_str_dup(p);
694  break;
695  case 4: /* issuer */
696  key->issuer = mutt_str_dup(p);
697  break;
698  case 5: /* trust */
699  key->trust = *p;
700  break;
701  case 6: /* purpose */
702  while (*p)
703  {
704  switch (*p++)
705  {
706  case 'e':
707  key->flags |= KEYFLAG_CANENCRYPT;
708  break;
709 
710  case 's':
711  key->flags |= KEYFLAG_CANSIGN;
712  break;
713  }
714  }
715  break;
716  }
717  }
718 
719  /* Old index files could be missing issuer, trust, and purpose,
720  * but anything less than that is an error. */
721  if (field < 3)
722  {
723  smime_key_free(&key);
724  return NULL;
725  }
726 
727  if (field < 4)
728  key->issuer = mutt_str_dup("?");
729 
730  if (field < 5)
731  key->trust = 't';
732 
733  if (field < 6)
735 
736  return key;
737 }
738 
745 static struct SmimeKey *smime_get_candidates(char *search, bool only_public_key)
746 {
747  char buf[1024];
748  struct SmimeKey *key = NULL, *results = NULL;
749  struct SmimeKey **results_end = &results;
750 
751  struct Buffer *index_file = mutt_buffer_pool_get();
752  mutt_buffer_printf(index_file, "%s/.index",
753  only_public_key ? NONULL(C_SmimeCertificates) : NONULL(C_SmimeKeys));
754 
755  FILE *fp = mutt_file_fopen(mutt_b2s(index_file), "r");
756  if (!fp)
757  {
758  mutt_perror(mutt_b2s(index_file));
759  mutt_buffer_pool_release(&index_file);
760  return NULL;
761  }
762  mutt_buffer_pool_release(&index_file);
763 
764  while (fgets(buf, sizeof(buf), fp))
765  {
766  if (((*search == '\0')) || mutt_istr_find(buf, search))
767  {
768  key = smime_parse_key(buf);
769  if (key)
770  {
771  *results_end = key;
772  results_end = &key->next;
773  }
774  }
775  }
776 
777  mutt_file_fclose(&fp);
778 
779  return results;
780 }
781 
791 static struct SmimeKey *smime_get_key_by_hash(char *hash, bool only_public_key)
792 {
793  struct SmimeKey *match = NULL;
794  struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
795  for (struct SmimeKey *result = results; result; result = result->next)
796  {
797  if (mutt_istr_equal(hash, result->hash))
798  {
799  match = smime_copy_key(result);
800  break;
801  }
802  }
803 
804  smime_key_free(&results);
805 
806  return match;
807 }
808 
817 static struct SmimeKey *smime_get_key_by_addr(char *mailbox, KeyFlags abilities,
818  bool only_public_key, bool oppenc_mode)
819 {
820  if (!mailbox)
821  return NULL;
822 
823  struct SmimeKey *results = NULL, *result = NULL;
824  struct SmimeKey *matches = NULL;
825  struct SmimeKey **matches_end = &matches;
826  struct SmimeKey *match = NULL;
827  struct SmimeKey *trusted_match = NULL;
828  struct SmimeKey *valid_match = NULL;
829  struct SmimeKey *return_key = NULL;
830  bool multi_trusted_matches = false;
831 
832  results = smime_get_candidates(mailbox, only_public_key);
833  for (result = results; result; result = result->next)
834  {
835  if (abilities && !(result->flags & abilities))
836  {
837  continue;
838  }
839 
840  if (mutt_istr_equal(mailbox, result->email))
841  {
842  match = smime_copy_key(result);
843  *matches_end = match;
844  matches_end = &match->next;
845 
846  if (match->trust == 't')
847  {
848  if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
849  {
850  multi_trusted_matches = true;
851  }
852  trusted_match = match;
853  }
854  else if ((match->trust == 'u') || (match->trust == 'v'))
855  {
856  valid_match = match;
857  }
858  }
859  }
860 
861  smime_key_free(&results);
862 
863  if (matches)
864  {
865  if (oppenc_mode)
866  {
867  if (trusted_match)
868  return_key = smime_copy_key(trusted_match);
869  else if (valid_match && !C_CryptOpportunisticEncryptStrongKeys)
870  return_key = smime_copy_key(valid_match);
871  else
872  return_key = NULL;
873  }
874  else if (trusted_match && !multi_trusted_matches)
875  {
876  return_key = smime_copy_key(trusted_match);
877  }
878  else
879  {
880  return_key = smime_copy_key(smime_select_key(matches, mailbox));
881  }
882 
883  smime_key_free(&matches);
884  }
885 
886  return return_key;
887 }
888 
896 static struct SmimeKey *smime_get_key_by_str(char *str, KeyFlags abilities, bool only_public_key)
897 {
898  if (!str)
899  return NULL;
900 
901  struct SmimeKey *results = NULL, *result = NULL;
902  struct SmimeKey *matches = NULL;
903  struct SmimeKey **matches_end = &matches;
904  struct SmimeKey *match = NULL;
905  struct SmimeKey *return_key = NULL;
906 
907  results = smime_get_candidates(str, only_public_key);
908  for (result = results; result; result = result->next)
909  {
910  if (abilities && !(result->flags & abilities))
911  {
912  continue;
913  }
914 
915  if (mutt_istr_equal(str, result->hash) ||
916  mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
917  {
918  match = smime_copy_key(result);
919  *matches_end = match;
920  matches_end = &match->next;
921  }
922  }
923 
924  smime_key_free(&results);
925 
926  if (matches)
927  {
928  return_key = smime_copy_key(smime_select_key(matches, str));
929  smime_key_free(&matches);
930  }
931 
932  return return_key;
933 }
934 
942 static struct SmimeKey *smime_ask_for_key(char *prompt, KeyFlags abilities, bool only_public_key)
943 {
944  struct SmimeKey *key = NULL;
945  char resp[128];
946 
947  if (!prompt)
948  prompt = _("Enter keyID: ");
949 
951 
952  while (true)
953  {
954  resp[0] = '\0';
955  if (mutt_get_field(prompt, resp, sizeof(resp), MUTT_COMP_NO_FLAGS) != 0)
956  return NULL;
957 
958  key = smime_get_key_by_str(resp, abilities, only_public_key);
959  if (key)
960  return key;
961 
962  mutt_error(_("No matching keys found for \"%s\""), resp);
963  }
964 }
965 
973 static void getkeys(char *mailbox)
974 {
975  const char *k = NULL;
976 
977  struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
978 
979  if (!key)
980  {
981  char buf[256];
982  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), mailbox);
983  key = smime_ask_for_key(buf, KEYFLAG_CANENCRYPT, false);
984  }
985 
986  size_t smime_keys_len = mutt_str_len(C_SmimeKeys);
987 
988  k = key ? key->hash : NONULL(C_SmimeDefaultKey);
989 
990  /* if the key is different from last time */
991  if ((mutt_buffer_len(&SmimeKeyToUse) <= smime_keys_len) ||
992  !mutt_istr_equal(k, SmimeKeyToUse.data + smime_keys_len + 1))
993  {
995  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(C_SmimeKeys), k);
996  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(C_SmimeCertificates), k);
997  }
998 
999  smime_key_free(&key);
1000 }
1001 
1006 {
1008  {
1009  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(C_SmimeKeys), C_SmimeDefaultKey);
1010  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(C_SmimeCertificates), C_SmimeDefaultKey);
1011  return;
1012  }
1013 
1014  struct Address *a = NULL;
1015  TAILQ_FOREACH(a, &env->to, entries)
1016  {
1017  if (mutt_addr_is_user(a))
1018  {
1019  getkeys(a->mailbox);
1020  return;
1021  }
1022  }
1023 
1024  TAILQ_FOREACH(a, &env->cc, entries)
1025  {
1026  if (mutt_addr_is_user(a))
1027  {
1028  getkeys(a->mailbox);
1029  return;
1030  }
1031  }
1032 
1033  struct Address *f = mutt_default_from(NeoMutt->sub);
1034  getkeys(f->mailbox);
1035  mutt_addr_free(&f);
1036 }
1037 
1041 char *smime_class_find_keys(struct AddressList *al, bool oppenc_mode)
1042 {
1043  struct SmimeKey *key = NULL;
1044  char *keyid = NULL, *keylist = NULL;
1045  size_t keylist_size = 0;
1046  size_t keylist_used = 0;
1047 
1048  struct Address *a = NULL;
1049  TAILQ_FOREACH(a, al, entries)
1050  {
1051  key = smime_get_key_by_addr(a->mailbox, KEYFLAG_CANENCRYPT, true, oppenc_mode);
1052  if (!key && !oppenc_mode)
1053  {
1054  char buf[1024];
1055  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), a->mailbox);
1056  key = smime_ask_for_key(buf, KEYFLAG_CANENCRYPT, true);
1057  }
1058  if (!key)
1059  {
1060  if (!oppenc_mode)
1061  mutt_message(_("No (valid) certificate found for %s"), a->mailbox);
1062  FREE(&keylist);
1063  return NULL;
1064  }
1065 
1066  keyid = key->hash;
1067  keylist_size += mutt_str_len(keyid) + 2;
1068  mutt_mem_realloc(&keylist, keylist_size);
1069  sprintf(keylist + keylist_used, "%s%s", keylist_used ? " " : "", keyid);
1070  keylist_used = mutt_str_len(keylist);
1071 
1072  smime_key_free(&key);
1073  }
1074  return keylist;
1075 }
1076 
1088 static int smime_handle_cert_email(char *certificate, char *mailbox, bool copy,
1089  char ***buffer, int *num)
1090 {
1091  char email[256];
1092  int rc = -1, count = 0;
1093  pid_t pid;
1094 
1095  FILE *fp_err = mutt_file_mkstemp();
1096  if (!fp_err)
1097  {
1098  mutt_perror(_("Can't create temporary file"));
1099  return 1;
1100  }
1101 
1102  FILE *fp_out = mutt_file_mkstemp();
1103  if (!fp_out)
1104  {
1105  mutt_file_fclose(&fp_err);
1106  mutt_perror(_("Can't create temporary file"));
1107  return 1;
1108  }
1109 
1110  pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
1111  NULL, NULL, NULL, NULL, NULL, NULL, C_SmimeGetCertEmailCommand);
1112  if (pid == -1)
1113  {
1114  mutt_message(_("Error: unable to create OpenSSL subprocess"));
1115  mutt_file_fclose(&fp_err);
1116  mutt_file_fclose(&fp_out);
1117  return 1;
1118  }
1119 
1120  filter_wait(pid);
1121 
1122  fflush(fp_out);
1123  rewind(fp_out);
1124  fflush(fp_err);
1125  rewind(fp_err);
1126 
1127  while ((fgets(email, sizeof(email), fp_out)))
1128  {
1129  size_t len = mutt_str_len(email);
1130  if (len && (email[len - 1] == '\n'))
1131  email[len - 1] = '\0';
1132  if (mutt_istr_startswith(email, mailbox))
1133  rc = 1;
1134 
1135  rc = (rc < 0) ? 0 : rc;
1136  count++;
1137  }
1138 
1139  if (rc == -1)
1140  {
1141  mutt_endwin();
1142  mutt_file_copy_stream(fp_err, stdout);
1143  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1144  rc = 1;
1145  }
1146  else if (rc == 0)
1147  rc = 1;
1148  else
1149  rc = 0;
1150 
1151  if (copy && buffer && num)
1152  {
1153  (*num) = count;
1154  *buffer = mutt_mem_calloc(count, sizeof(char *));
1155  count = 0;
1156 
1157  rewind(fp_out);
1158  while ((fgets(email, sizeof(email), fp_out)))
1159  {
1160  size_t len = mutt_str_len(email);
1161  if (len && (email[len - 1] == '\n'))
1162  email[len - 1] = '\0';
1163  (*buffer)[count] = mutt_mem_calloc(mutt_str_len(email) + 1, sizeof(char));
1164  strncpy((*buffer)[count], email, mutt_str_len(email));
1165  count++;
1166  }
1167  }
1168  else if (copy)
1169  rc = 2;
1170 
1171  mutt_file_fclose(&fp_out);
1172  mutt_file_fclose(&fp_err);
1173 
1174  return rc;
1175 }
1176 
1182 static char *smime_extract_certificate(const char *infile)
1183 {
1184  FILE *fp_err = NULL;
1185  FILE *fp_out = NULL;
1186  FILE *fp_cert = NULL;
1187  char *retval = NULL;
1188  pid_t pid;
1189  int empty;
1190 
1191  struct Buffer *pk7out = mutt_buffer_pool_get();
1192  struct Buffer *certfile = mutt_buffer_pool_get();
1193 
1194  fp_err = mutt_file_mkstemp();
1195  if (!fp_err)
1196  {
1197  mutt_perror(_("Can't create temporary file"));
1198  goto cleanup;
1199  }
1200 
1201  mutt_buffer_mktemp(pk7out);
1202  fp_out = mutt_file_fopen(mutt_b2s(pk7out), "w+");
1203  if (!fp_out)
1204  {
1205  mutt_perror(mutt_b2s(pk7out));
1206  goto cleanup;
1207  }
1208 
1209  /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
1210  * extract the full set of certificates directly. */
1211  pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
1212  NULL, NULL, NULL, NULL, NULL, NULL, C_SmimePk7outCommand);
1213  if (pid == -1)
1214  {
1215  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1216  goto cleanup;
1217  }
1218 
1219  filter_wait(pid);
1220 
1221  fflush(fp_out);
1222  rewind(fp_out);
1223  fflush(fp_err);
1224  rewind(fp_err);
1225  empty = (fgetc(fp_out) == EOF);
1226  if (empty)
1227  {
1228  mutt_perror(mutt_b2s(pk7out));
1229  mutt_file_copy_stream(fp_err, stdout);
1230  goto cleanup;
1231  }
1232  mutt_file_fclose(&fp_out);
1233 
1234  mutt_buffer_mktemp(certfile);
1235  fp_cert = mutt_file_fopen(mutt_b2s(certfile), "w+");
1236  if (!fp_cert)
1237  {
1238  mutt_perror(mutt_b2s(certfile));
1239  mutt_file_unlink(mutt_b2s(pk7out));
1240  goto cleanup;
1241  }
1242 
1243  // Step 2: Extract the certificates from a PKCS#7 structure.
1244  pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
1245  mutt_b2s(pk7out), NULL, NULL, NULL, NULL, NULL, NULL,
1247  if (pid == -1)
1248  {
1249  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1250  mutt_file_unlink(mutt_b2s(pk7out));
1251  goto cleanup;
1252  }
1253 
1254  filter_wait(pid);
1255 
1256  mutt_file_unlink(mutt_b2s(pk7out));
1257 
1258  fflush(fp_cert);
1259  rewind(fp_cert);
1260  fflush(fp_err);
1261  rewind(fp_err);
1262  empty = (fgetc(fp_cert) == EOF);
1263  if (empty)
1264  {
1265  mutt_file_copy_stream(fp_err, stdout);
1266  goto cleanup;
1267  }
1268 
1269  mutt_file_fclose(&fp_cert);
1270 
1271  retval = mutt_buffer_strdup(certfile);
1272 
1273 cleanup:
1274  mutt_file_fclose(&fp_err);
1275  if (fp_out)
1276  {
1277  mutt_file_fclose(&fp_out);
1278  mutt_file_unlink(mutt_b2s(pk7out));
1279  }
1280  if (fp_cert)
1281  {
1282  mutt_file_fclose(&fp_cert);
1283  mutt_file_unlink(mutt_b2s(certfile));
1284  }
1285  mutt_buffer_pool_release(&pk7out);
1286  mutt_buffer_pool_release(&certfile);
1287  return retval;
1288 }
1289 
1295 static char *smime_extract_signer_certificate(const char *infile)
1296 {
1297  char *cert = NULL;
1298  struct Buffer *certfile = NULL;
1299  pid_t pid;
1300  int empty;
1301 
1302  FILE *fp_err = mutt_file_mkstemp();
1303  if (!fp_err)
1304  {
1305  mutt_perror(_("Can't create temporary file"));
1306  return NULL;
1307  }
1308 
1309  certfile = mutt_buffer_pool_get();
1310  mutt_buffer_mktemp(certfile);
1311  FILE *fp_out = mutt_file_fopen(mutt_b2s(certfile), "w+");
1312  if (!fp_out)
1313  {
1314  mutt_file_fclose(&fp_err);
1315  mutt_perror(mutt_b2s(certfile));
1316  goto cleanup;
1317  }
1318 
1319  /* Extract signer's certificate
1320  */
1321  pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL, NULL, NULL,
1322  NULL, mutt_b2s(certfile), NULL, C_SmimeGetSignerCertCommand);
1323  if (pid == -1)
1324  {
1325  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1326  goto cleanup;
1327  }
1328 
1329  filter_wait(pid);
1330 
1331  fflush(fp_out);
1332  rewind(fp_out);
1333  fflush(fp_err);
1334  rewind(fp_err);
1335  empty = (fgetc(fp_out) == EOF);
1336  if (empty)
1337  {
1338  mutt_endwin();
1339  mutt_file_copy_stream(fp_err, stdout);
1341  goto cleanup;
1342  }
1343 
1344  mutt_file_fclose(&fp_out);
1345  cert = mutt_buffer_strdup(certfile);
1346 
1347 cleanup:
1348  mutt_file_fclose(&fp_err);
1349  if (fp_out)
1350  {
1351  mutt_file_fclose(&fp_out);
1352  mutt_file_unlink(mutt_b2s(certfile));
1353  }
1354  mutt_buffer_pool_release(&certfile);
1355  return cert;
1356 }
1357 
1361 void smime_class_invoke_import(const char *infile, const char *mailbox)
1362 {
1363  char *certfile = NULL;
1364  char buf[256];
1365  FILE *fp_smime_in = NULL;
1366 
1367  FILE *fp_err = mutt_file_mkstemp();
1368  if (!fp_err)
1369  {
1370  mutt_perror(_("Can't create temporary file"));
1371  return;
1372  }
1373 
1374  FILE *fp_out = mutt_file_mkstemp();
1375  if (!fp_out)
1376  {
1377  mutt_file_fclose(&fp_err);
1378  mutt_perror(_("Can't create temporary file"));
1379  return;
1380  }
1381 
1382  buf[0] = '\0';
1383  if (C_SmimeAskCertLabel)
1384  {
1385  if ((mutt_get_field(_("Label for certificate: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
1386  (buf[0] == '\0'))
1387  {
1388  mutt_file_fclose(&fp_out);
1389  mutt_file_fclose(&fp_err);
1390  return;
1391  }
1392  }
1393 
1394  mutt_endwin();
1395  certfile = smime_extract_certificate(infile);
1396  if (certfile)
1397  {
1398  mutt_endwin();
1399 
1400  pid_t pid = smime_invoke(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1401  fileno(fp_err), certfile, NULL, NULL, NULL, NULL,
1402  NULL, NULL, C_SmimeImportCertCommand);
1403  if (pid == -1)
1404  {
1405  mutt_message(_("Error: unable to create OpenSSL subprocess"));
1406  return;
1407  }
1408  fputs(buf, fp_smime_in);
1409  fputc('\n', fp_smime_in);
1410  mutt_file_fclose(&fp_smime_in);
1411 
1412  filter_wait(pid);
1413 
1414  mutt_file_unlink(certfile);
1415  FREE(&certfile);
1416  }
1417 
1418  fflush(fp_out);
1419  rewind(fp_out);
1420  fflush(fp_err);
1421  rewind(fp_err);
1422 
1423  mutt_file_copy_stream(fp_out, stdout);
1424  mutt_file_copy_stream(fp_err, stdout);
1425 
1426  mutt_file_fclose(&fp_out);
1427  mutt_file_fclose(&fp_err);
1428 }
1429 
1433 int smime_class_verify_sender(struct Mailbox *m, struct Email *e)
1434 {
1435  char *mbox = NULL, *certfile = NULL;
1436  int rc = 1;
1437 
1438  struct Buffer *tempfname = mutt_buffer_pool_get();
1439  mutt_buffer_mktemp(tempfname);
1440  FILE *fp_out = mutt_file_fopen(mutt_b2s(tempfname), "w");
1441  if (!fp_out)
1442  {
1443  mutt_perror(mutt_b2s(tempfname));
1444  goto cleanup;
1445  }
1446 
1447  if (e->security & SEC_ENCRYPT)
1448  {
1450  CH_MIME | CH_WEED | CH_NONEWLINE, 0);
1451  }
1452  else
1453  mutt_copy_message(fp_out, m, e, MUTT_CM_NO_FLAGS, CH_NO_FLAGS, 0);
1454 
1455  fflush(fp_out);
1456  mutt_file_fclose(&fp_out);
1457 
1458  if (!TAILQ_EMPTY(&e->env->from))
1459  {
1461  mbox = TAILQ_FIRST(&e->env->from)->mailbox;
1462  }
1463  else if (!TAILQ_EMPTY(&e->env->sender))
1464  {
1466  mbox = TAILQ_FIRST(&e->env->sender)->mailbox;
1467  }
1468 
1469  if (mbox)
1470  {
1471  certfile = smime_extract_signer_certificate(mutt_b2s(tempfname));
1472  if (certfile)
1473  {
1474  mutt_file_unlink(mutt_b2s(tempfname));
1475  if (smime_handle_cert_email(certfile, mbox, false, NULL, NULL))
1476  {
1477  if (isendwin())
1479  }
1480  else
1481  rc = 0;
1482  mutt_file_unlink(certfile);
1483  FREE(&certfile);
1484  }
1485  else
1486  mutt_any_key_to_continue(_("no certfile"));
1487  }
1488  else
1489  mutt_any_key_to_continue(_("no mbox"));
1490 
1491  mutt_file_unlink(mutt_b2s(tempfname));
1492 
1493 cleanup:
1494  mutt_buffer_pool_release(&tempfname);
1495  return rc;
1496 }
1497 
1498 /* Creating S/MIME - bodies */
1499 
1516 static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1517  FILE **fp_smime_err, int fp_smime_infd,
1518  int fp_smime_outfd, int fp_smime_errfd,
1519  const char *fname, const char *uids)
1520 {
1521  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1522  fp_smime_outfd, fp_smime_errfd, fname, NULL, C_SmimeEncryptWith,
1523  NULL, NULL, uids, NULL, C_SmimeEncryptCommand);
1524 }
1525 
1541 static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out,
1542  FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1543  int fp_smime_errfd, const char *fname)
1544 {
1545  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1546  fp_smime_errfd, fname, NULL, NULL, C_SmimeSignDigestAlg,
1547  mutt_b2s(&SmimeKeyToUse), mutt_b2s(&SmimeCertToUse),
1548  mutt_b2s(&SmimeIntermediateToUse), C_SmimeSignCommand);
1549 }
1550 
1554 struct Body *smime_class_build_smime_entity(struct Body *a, char *certlist)
1555 {
1556  char buf[1024], certfile[PATH_MAX];
1557  char *cert_end = NULL;
1558  FILE *fp_smime_in = NULL, *fp_smime_err = NULL, *fp_out = NULL, *fp_tmp = NULL;
1559  struct Body *t = NULL;
1560  int err = 0, empty, off;
1561  pid_t pid;
1562 
1563  struct Buffer *tempfile = mutt_buffer_pool_get();
1564  struct Buffer *smime_infile = mutt_buffer_pool_get();
1565 
1566  mutt_buffer_mktemp(tempfile);
1567  fp_out = mutt_file_fopen(mutt_b2s(tempfile), "w+");
1568  if (!fp_out)
1569  {
1570  mutt_perror(mutt_b2s(tempfile));
1571  goto cleanup;
1572  }
1573 
1574  fp_smime_err = mutt_file_mkstemp();
1575  if (!fp_smime_err)
1576  {
1577  mutt_perror(_("Can't create temporary file"));
1578  goto cleanup;
1579  }
1580 
1581  mutt_buffer_mktemp(smime_infile);
1582  fp_tmp = mutt_file_fopen(mutt_b2s(smime_infile), "w+");
1583  if (!fp_tmp)
1584  {
1585  mutt_perror(mutt_b2s(smime_infile));
1586  goto cleanup;
1587  }
1588 
1589  *certfile = '\0';
1590  for (char *cert_start = certlist; cert_start; cert_start = cert_end)
1591  {
1592  cert_end = strchr(cert_start, ' ');
1593  if (cert_end)
1594  *cert_end = '\0';
1595  if (*cert_start)
1596  {
1597  off = mutt_str_len(certfile);
1598  snprintf(certfile + off, sizeof(certfile) - off, "%s%s/%s",
1599  (off != 0) ? " " : "", NONULL(C_SmimeCertificates), cert_start);
1600  }
1601  if (cert_end)
1602  *cert_end++ = ' ';
1603  }
1604 
1605  /* write a MIME entity */
1606  mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
1607  fputc('\n', fp_tmp);
1608  mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
1609  mutt_file_fclose(&fp_tmp);
1610 
1611  pid = smime_invoke_encrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1612  fileno(fp_smime_err), mutt_b2s(smime_infile), certfile);
1613  if (pid == -1)
1614  {
1615  mutt_file_unlink(mutt_b2s(smime_infile));
1616  goto cleanup;
1617  }
1618 
1619  mutt_file_fclose(&fp_smime_in);
1620 
1621  filter_wait(pid);
1622  mutt_file_unlink(mutt_b2s(smime_infile));
1623 
1624  fflush(fp_out);
1625  rewind(fp_out);
1626  empty = (fgetc(fp_out) == EOF);
1627  mutt_file_fclose(&fp_out);
1628 
1629  fflush(fp_smime_err);
1630  rewind(fp_smime_err);
1631  while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1632  {
1633  err = 1;
1634  fputs(buf, stdout);
1635  }
1636  mutt_file_fclose(&fp_smime_err);
1637 
1638  /* pause if there is any error output from SMIME */
1639  if (err)
1641 
1642  if (empty)
1643  {
1644  /* fatal error while trying to encrypt message */
1645  if (err == 0)
1646  mutt_any_key_to_continue(_("No output from OpenSSL..."));
1647  mutt_file_unlink(mutt_b2s(tempfile));
1648  goto cleanup;
1649  }
1650 
1651  t = mutt_body_new();
1652  t->type = TYPE_APPLICATION;
1653  t->subtype = mutt_str_dup("x-pkcs7-mime");
1654  mutt_param_set(&t->parameter, "name", "smime.p7m");
1655  mutt_param_set(&t->parameter, "smime-type", "enveloped-data");
1656  t->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1657  t->use_disp = true;
1658  t->disposition = DISP_ATTACH;
1659  t->d_filename = mutt_str_dup("smime.p7m");
1660  t->filename = mutt_buffer_strdup(tempfile);
1661  t->unlink = true; /* delete after sending the message */
1662  t->parts = NULL;
1663  t->next = NULL;
1664 
1665 cleanup:
1666  if (fp_out)
1667  {
1668  mutt_file_fclose(&fp_out);
1669  mutt_file_unlink(mutt_b2s(tempfile));
1670  }
1671  mutt_file_fclose(&fp_smime_err);
1672  if (fp_tmp)
1673  {
1674  mutt_file_fclose(&fp_tmp);
1675  mutt_file_unlink(mutt_b2s(smime_infile));
1676  }
1677  mutt_buffer_pool_release(&tempfile);
1678  mutt_buffer_pool_release(&smime_infile);
1679 
1680  return t;
1681 }
1682 
1695 static char *openssl_md_to_smime_micalg(char *md)
1696 {
1697  if (!md)
1698  return 0;
1699 
1700  char *micalg = NULL;
1701  if (mutt_istr_startswith(md, "sha"))
1702  {
1703  const size_t l = strlen(md) + 2;
1704  micalg = mutt_mem_malloc(l);
1705  snprintf(micalg, l, "sha-%s", md + 3);
1706  }
1707  else
1708  {
1709  micalg = mutt_str_dup(md);
1710  }
1711 
1712  return micalg;
1713 }
1714 
1718 struct Body *smime_class_sign_message(struct Body *a, const struct AddressList *from)
1719 {
1720  struct Body *t = NULL;
1721  struct Body *retval = NULL;
1722  char buf[1024];
1723  struct Buffer *filetosign = NULL, *signedfile = NULL;
1724  FILE *fp_smime_in = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL, *fp_sign = NULL;
1725  int err = 0;
1726  int empty = 0;
1727  pid_t pid;
1728  char *intermediates = NULL;
1729 
1730  char *signas = C_SmimeSignAs ? C_SmimeSignAs : C_SmimeDefaultKey;
1731  if (!signas || (*signas == '\0'))
1732  {
1733  mutt_error(_("Can't sign: No key specified. Use Sign As."));
1734  return NULL;
1735  }
1736 
1737  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1738 
1739  filetosign = mutt_buffer_pool_get();
1740  signedfile = mutt_buffer_pool_get();
1741 
1742  mutt_buffer_mktemp(filetosign);
1743  fp_sign = mutt_file_fopen(mutt_b2s(filetosign), "w+");
1744  if (!fp_sign)
1745  {
1746  mutt_perror(mutt_b2s(filetosign));
1747  goto cleanup;
1748  }
1749 
1750  mutt_buffer_mktemp(signedfile);
1751  fp_smime_out = mutt_file_fopen(mutt_b2s(signedfile), "w+");
1752  if (!fp_smime_out)
1753  {
1754  mutt_perror(mutt_b2s(signedfile));
1755  goto cleanup;
1756  }
1757 
1758  mutt_write_mime_header(a, fp_sign, NeoMutt->sub);
1759  fputc('\n', fp_sign);
1760  mutt_write_mime_body(a, fp_sign, NeoMutt->sub);
1761  mutt_file_fclose(&fp_sign);
1762 
1763  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(C_SmimeKeys), signas);
1764  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(C_SmimeCertificates), signas);
1765 
1766  struct SmimeKey *signas_key = smime_get_key_by_hash(signas, 1);
1767  if (!signas_key || mutt_str_equal("?", signas_key->issuer))
1768  intermediates = signas; /* so openssl won't complain in any case */
1769  else
1770  intermediates = signas_key->issuer;
1771 
1772  mutt_buffer_printf(&SmimeIntermediateToUse, "%s/%s",
1773  NONULL(C_SmimeCertificates), intermediates);
1774 
1775  smime_key_free(&signas_key);
1776 
1777  pid = smime_invoke_sign(&fp_smime_in, NULL, &fp_smime_err, -1,
1778  fileno(fp_smime_out), -1, mutt_b2s(filetosign));
1779  if (pid == -1)
1780  {
1781  mutt_perror(_("Can't open OpenSSL subprocess"));
1782  mutt_file_unlink(mutt_b2s(filetosign));
1783  goto cleanup;
1784  }
1785  fputs(SmimePass, fp_smime_in);
1786  fputc('\n', fp_smime_in);
1787  mutt_file_fclose(&fp_smime_in);
1788 
1789  filter_wait(pid);
1790 
1791  /* check for errors from OpenSSL */
1792  err = 0;
1793  fflush(fp_smime_err);
1794  rewind(fp_smime_err);
1795  while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1796  {
1797  err = 1;
1798  fputs(buf, stdout);
1799  }
1800  mutt_file_fclose(&fp_smime_err);
1801 
1802  fflush(fp_smime_out);
1803  rewind(fp_smime_out);
1804  empty = (fgetc(fp_smime_out) == EOF);
1805  mutt_file_fclose(&fp_smime_out);
1806 
1807  mutt_file_unlink(mutt_b2s(filetosign));
1808 
1809  if (err)
1811 
1812  if (empty)
1813  {
1814  mutt_any_key_to_continue(_("No output from OpenSSL..."));
1815  mutt_file_unlink(mutt_b2s(signedfile));
1816  goto cleanup; /* fatal error while signing */
1817  }
1818 
1819  t = mutt_body_new();
1820  t->type = TYPE_MULTIPART;
1821  t->subtype = mutt_str_dup("signed");
1822  t->encoding = ENC_7BIT;
1823  t->use_disp = false;
1824  t->disposition = DISP_INLINE;
1825 
1827 
1829  mutt_param_set(&t->parameter, "micalg", micalg);
1830  FREE(&micalg);
1831 
1832  mutt_param_set(&t->parameter, "protocol", "application/x-pkcs7-signature");
1833 
1834  t->parts = a;
1835  retval = t;
1836 
1837  t->parts->next = mutt_body_new();
1838  t = t->parts->next;
1839  t->type = TYPE_APPLICATION;
1840  t->subtype = mutt_str_dup("x-pkcs7-signature");
1841  t->filename = mutt_buffer_strdup(signedfile);
1842  t->d_filename = mutt_str_dup("smime.p7s");
1843  t->use_disp = true;
1844  t->disposition = DISP_ATTACH;
1845  t->encoding = ENC_BASE64;
1846  t->unlink = true; /* ok to remove this file after sending. */
1847 
1848 cleanup:
1849  if (fp_sign)
1850  {
1851  mutt_file_fclose(&fp_sign);
1852  mutt_file_unlink(mutt_b2s(filetosign));
1853  }
1854  if (fp_smime_out)
1855  {
1856  mutt_file_fclose(&fp_smime_out);
1857  mutt_file_unlink(mutt_b2s(signedfile));
1858  }
1859  mutt_buffer_pool_release(&filetosign);
1860  mutt_buffer_pool_release(&signedfile);
1861  return retval;
1862 }
1863 
1864 /* Handling S/MIME - bodies */
1865 
1883 static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out,
1884  FILE **fp_smime_err, int fp_smime_infd,
1885  int fp_smime_outfd, int fp_smime_errfd,
1886  const char *fname, const char *sig_fname, int opaque)
1887 {
1888  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1889  fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1891 }
1892 
1908 static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1909  FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1910  int fp_smime_errfd, const char *fname)
1911 {
1912  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1913  fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1914  mutt_b2s(&SmimeKeyToUse), mutt_b2s(&SmimeCertToUse), NULL,
1916 }
1917 
1921 int smime_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
1922 {
1923  FILE *fp = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL;
1924  pid_t pid;
1925  int badsig = -1;
1926 
1927  LOFF_T tmpoffset = 0;
1928  size_t tmplength = 0;
1929  int orig_type = sigbdy->type;
1930 
1931  struct Buffer *signedfile = mutt_buffer_pool_get();
1932 
1933  mutt_buffer_printf(signedfile, "%s.sig", tempfile);
1934 
1935  /* decode to a tempfile, saving the original destination */
1936  fp = s->fp_out;
1937  s->fp_out = mutt_file_fopen(mutt_b2s(signedfile), "w");
1938  if (!s->fp_out)
1939  {
1940  mutt_perror(mutt_b2s(signedfile));
1941  goto cleanup;
1942  }
1943  /* decoding the attachment changes the size and offset, so save a copy
1944  * of the "real" values now, and restore them after processing */
1945  tmplength = sigbdy->length;
1946  tmpoffset = sigbdy->offset;
1947 
1948  /* if we are decoding binary bodies, we don't want to prefix each
1949  * line with the prefix or else the data will get corrupted. */
1950  char *save_prefix = s->prefix;
1951  s->prefix = NULL;
1952 
1953  mutt_decode_attachment(sigbdy, s);
1954 
1955  sigbdy->length = ftello(s->fp_out);
1956  sigbdy->offset = 0;
1957  mutt_file_fclose(&s->fp_out);
1958 
1959  /* restore final destination and substitute the tempfile for input */
1960  s->fp_out = fp;
1961  fp = s->fp_in;
1962  s->fp_in = fopen(mutt_b2s(signedfile), "r");
1963 
1964  /* restore the prefix */
1965  s->prefix = save_prefix;
1966 
1967  sigbdy->type = orig_type;
1968 
1969  fp_smime_err = mutt_file_mkstemp();
1970  if (!fp_smime_err)
1971  {
1972  mutt_perror(_("Can't create temporary file"));
1973  goto cleanup;
1974  }
1975 
1976  crypt_current_time(s, "OpenSSL");
1977 
1978  pid = smime_invoke_verify(NULL, &fp_smime_out, NULL, -1, -1, fileno(fp_smime_err),
1979  tempfile, mutt_b2s(signedfile), 0);
1980  if (pid != -1)
1981  {
1982  fflush(fp_smime_out);
1983  mutt_file_fclose(&fp_smime_out);
1984 
1985  if (filter_wait(pid))
1986  badsig = -1;
1987  else
1988  {
1989  char *line = NULL;
1990  size_t linelen;
1991 
1992  fflush(fp_smime_err);
1993  rewind(fp_smime_err);
1994 
1995  line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, 0);
1996  if (linelen && mutt_istr_equal(line, "verification successful"))
1997  badsig = 0;
1998 
1999  FREE(&line);
2000  }
2001  }
2002 
2003  fflush(fp_smime_err);
2004  rewind(fp_smime_err);
2005  mutt_file_copy_stream(fp_smime_err, s->fp_out);
2006  mutt_file_fclose(&fp_smime_err);
2007 
2008  state_attach_puts(s, _("[-- End of OpenSSL output --]\n\n"));
2009 
2010  mutt_file_unlink(mutt_b2s(signedfile));
2011 
2012  sigbdy->length = tmplength;
2013  sigbdy->offset = tmpoffset;
2014 
2015  /* restore the original source stream */
2016  mutt_file_fclose(&s->fp_in);
2017  s->fp_in = fp;
2018 
2019 cleanup:
2020  mutt_buffer_pool_release(&signedfile);
2021  return badsig;
2022 }
2023 
2033 static struct Body *smime_handle_entity(struct Body *m, struct State *s, FILE *fp_out_file)
2034 {
2035  struct Buffer tmpfname = mutt_buffer_make(0);
2036  FILE *fp_smime_out = NULL, *fp_smime_in = NULL, *fp_smime_err = NULL;
2037  FILE *fp_tmp = NULL, *fp_out = NULL;
2038  struct stat info;
2039  struct Body *p = NULL;
2040  pid_t pid = -1;
2042 
2043  if (!(type & APPLICATION_SMIME))
2044  return NULL;
2045 
2046  /* Because of the mutt_body_handler() we avoid the buffer pool. */
2047  fp_smime_out = mutt_file_mkstemp();
2048  if (!fp_smime_out)
2049  {
2050  mutt_perror(_("Can't create temporary file"));
2051  goto cleanup;
2052  }
2053 
2054  fp_smime_err = mutt_file_mkstemp();
2055  if (!fp_smime_err)
2056  {
2057  mutt_perror(_("Can't create temporary file"));
2058  goto cleanup;
2059  }
2060 
2061  mutt_buffer_mktemp(&tmpfname);
2062  fp_tmp = mutt_file_fopen(mutt_b2s(&tmpfname), "w+");
2063  if (!fp_tmp)
2064  {
2065  mutt_perror(mutt_b2s(&tmpfname));
2066  goto cleanup;
2067  }
2068 
2069  fseeko(s->fp_in, m->offset, SEEK_SET);
2070 
2071  mutt_file_copy_bytes(s->fp_in, fp_tmp, m->length);
2072 
2073  fflush(fp_tmp);
2074  mutt_file_fclose(&fp_tmp);
2075 
2076  if ((type & SEC_ENCRYPT) &&
2077  ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_smime_out),
2078  fileno(fp_smime_err), mutt_b2s(&tmpfname))) == -1))
2079  {
2080  mutt_file_unlink(mutt_b2s(&tmpfname));
2081  if (s->flags & MUTT_DISPLAY)
2082  {
2084  s, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
2085  }
2086  goto cleanup;
2087  }
2088  else if ((type & SEC_SIGNOPAQUE) &&
2089  ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
2090  fileno(fp_smime_out), fileno(fp_smime_err), NULL,
2091  mutt_b2s(&tmpfname), SEC_SIGNOPAQUE)) == -1))
2092  {
2093  mutt_file_unlink(mutt_b2s(&tmpfname));
2094  if (s->flags & MUTT_DISPLAY)
2095  {
2097  s, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
2098  }
2099  goto cleanup;
2100  }
2101 
2102  if (type & SEC_ENCRYPT)
2103  {
2106  fputs(SmimePass, fp_smime_in);
2107  fputc('\n', fp_smime_in);
2108  }
2109 
2110  mutt_file_fclose(&fp_smime_in);
2111 
2112  filter_wait(pid);
2113  mutt_file_unlink(mutt_b2s(&tmpfname));
2114 
2115  if (s->flags & MUTT_DISPLAY)
2116  {
2117  fflush(fp_smime_err);
2118  rewind(fp_smime_err);
2119 
2120  const int c = fgetc(fp_smime_err);
2121  if (c != EOF)
2122  {
2123  ungetc(c, fp_smime_err);
2124 
2125  crypt_current_time(s, "OpenSSL");
2126  mutt_file_copy_stream(fp_smime_err, s->fp_out);
2127  state_attach_puts(s, _("[-- End of OpenSSL output --]\n\n"));
2128  }
2129 
2130  if (type & SEC_ENCRYPT)
2131  {
2133  _("[-- The following data is S/MIME encrypted --]\n"));
2134  }
2135  else
2136  state_attach_puts(s, _("[-- The following data is S/MIME signed --]\n"));
2137  }
2138 
2139  fflush(fp_smime_out);
2140  rewind(fp_smime_out);
2141 
2142  if (type & SEC_ENCRYPT)
2143  {
2144  /* void the passphrase, even if that wasn't the problem */
2145  if (fgetc(fp_smime_out) == EOF)
2146  {
2147  mutt_error(_("Decryption failed"));
2149  }
2150  rewind(fp_smime_out);
2151  }
2152 
2153  if (fp_out_file)
2154  fp_out = fp_out_file;
2155  else
2156  {
2157  fp_out = mutt_file_mkstemp();
2158  if (!fp_out)
2159  {
2160  mutt_perror(_("Can't create temporary file"));
2161  goto cleanup;
2162  }
2163  }
2164  char buf[8192];
2165  while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
2166  {
2167  const size_t len = mutt_str_len(buf);
2168  if ((len > 1) && (buf[len - 2] == '\r'))
2169  {
2170  buf[len - 2] = '\n';
2171  buf[len - 1] = '\0';
2172  }
2173  fputs(buf, fp_out);
2174  }
2175  fflush(fp_out);
2176  rewind(fp_out);
2177 
2178  p = mutt_read_mime_header(fp_out, 0);
2179  if (p)
2180  {
2181  fstat(fileno(fp_out), &info);
2182  p->length = info.st_size - p->offset;
2183 
2184  mutt_parse_part(fp_out, p);
2185 
2186  if (s->flags & MUTT_DISPLAY)
2188 
2189  /* Store any protected headers in the parent so they can be
2190  * accessed for index updates after the handler recursion is done.
2191  * This is done before the handler to prevent a nested encrypted
2192  * handler from freeing the headers. */
2194  m->mime_headers = p->mime_headers;
2195  p->mime_headers = NULL;
2196 
2197  if (s->fp_out)
2198  {
2199  rewind(fp_out);
2200  FILE *fp_tmp_buffer = s->fp_in;
2201  s->fp_in = fp_out;
2202  mutt_body_handler(p, s);
2203  s->fp_in = fp_tmp_buffer;
2204  }
2205 
2206  /* Embedded multipart signed protected headers override the
2207  * encrypted headers. We need to do this after the handler so
2208  * they can be printed in the pager. */
2209  if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
2210  p->parts->mime_headers)
2211  {
2213  m->mime_headers = p->parts->mime_headers;
2214  p->parts->mime_headers = NULL;
2215  }
2216  }
2217  mutt_file_fclose(&fp_smime_out);
2218 
2219  if (!fp_out_file)
2220  {
2221  mutt_file_fclose(&fp_out);
2222  mutt_file_unlink(mutt_b2s(&tmpfname));
2223  }
2224  fp_out = NULL;
2225 
2226  if (s->flags & MUTT_DISPLAY)
2227  {
2228  if (type & SEC_ENCRYPT)
2229  state_attach_puts(s, _("\n[-- End of S/MIME encrypted data. --]\n"));
2230  else
2231  state_attach_puts(s, _("\n[-- End of S/MIME signed data. --]\n"));
2232  }
2233 
2234  if (type & SEC_SIGNOPAQUE)
2235  {
2236  char *line = NULL;
2237  size_t linelen;
2238 
2239  rewind(fp_smime_err);
2240 
2241  line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, 0);
2242  if (linelen && mutt_istr_equal(line, "verification successful"))
2243  m->goodsig = true;
2244  FREE(&line);
2245  }
2246  else if (p)
2247  {
2248  m->goodsig = p->goodsig;
2249  m->badsig = p->badsig;
2250  }
2251 
2252 cleanup:
2253  mutt_file_fclose(&fp_smime_out);
2254  mutt_file_fclose(&fp_smime_err);
2255  mutt_file_fclose(&fp_tmp);
2256  mutt_file_fclose(&fp_out);
2257  mutt_buffer_dealloc(&tmpfname);
2258  return p;
2259 }
2260 
2264 int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
2265 {
2266  struct State s = { 0 };
2267  LOFF_T tmpoffset = b->offset;
2268  size_t tmplength = b->length;
2269  int orig_type = b->type;
2270  int rc = -1;
2271 
2272  if (!mutt_is_application_smime(b))
2273  return -1;
2274 
2275  if (b->parts)
2276  return -1;
2277 
2278  s.fp_in = fp_in;
2279  fseeko(s.fp_in, b->offset, SEEK_SET);
2280 
2281  FILE *fp_tmp = mutt_file_mkstemp();
2282  if (!fp_tmp)
2283  {
2284  mutt_perror(_("Can't create temporary file"));
2285  return -1;
2286  }
2287 
2288  s.fp_out = fp_tmp;
2289  mutt_decode_attachment(b, &s);
2290  fflush(fp_tmp);
2291  b->length = ftello(s.fp_out);
2292  b->offset = 0;
2293  rewind(fp_tmp);
2294  s.fp_in = fp_tmp;
2295  s.fp_out = 0;
2296 
2297  *fp_out = mutt_file_mkstemp();
2298  if (!*fp_out)
2299  {
2300  mutt_perror(_("Can't create temporary file"));
2301  goto bail;
2302  }
2303 
2304  *cur = smime_handle_entity(b, &s, *fp_out);
2305  if (!*cur)
2306  goto bail;
2307 
2308  (*cur)->goodsig = b->goodsig;
2309  (*cur)->badsig = b->badsig;
2310  rc = 0;
2311 
2312 bail:
2313  b->type = orig_type;
2314  b->length = tmplength;
2315  b->offset = tmpoffset;
2316  mutt_file_fclose(&fp_tmp);
2317  if (*fp_out)
2318  rewind(*fp_out);
2319 
2320  return rc;
2321 }
2322 
2326 int smime_class_application_handler(struct Body *m, struct State *s)
2327 {
2328  int rc = -1;
2329 
2330  /* clear out any mime headers before the handler, so they can't be spoofed. */
2332 
2333  struct Body *tattach = smime_handle_entity(m, s, NULL);
2334  if (tattach)
2335  {
2336  rc = 0;
2337  mutt_body_free(&tattach);
2338  }
2339  return rc;
2340 }
2341 
2346 {
2347  struct SmimeKey *key = NULL;
2348  const char *prompt = NULL;
2349  const char *letters = NULL;
2350  const char *choices = NULL;
2351  int choice;
2352 
2353  if (!(WithCrypto & APPLICATION_SMIME))
2354  return e->security;
2355 
2357 
2358  /* Opportunistic encrypt is controlling encryption.
2359  * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
2360  * letter choices for those. */
2362  {
2363  /* L10N: S/MIME options (opportunistic encryption is on) */
2364  prompt = _("S/MIME (s)ign, encrypt (w)ith, sign (a)s, (c)lear, or (o)ppenc "
2365  "mode off?");
2366  /* L10N: S/MIME options (opportunistic encryption is on) */
2367  letters = _("swaco");
2368  choices = "SwaCo";
2369  }
2370  /* Opportunistic encryption option is set, but is toggled off
2371  * for this message. */
2372  else if (C_CryptOpportunisticEncrypt)
2373  {
2374  /* L10N: S/MIME options (opportunistic encryption is off) */
2375  prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, "
2376  "(c)lear, or (o)ppenc mode?");
2377  /* L10N: S/MIME options (opportunistic encryption is off) */
2378  letters = _("eswabco");
2379  choices = "eswabcO";
2380  }
2381  /* Opportunistic encryption is unset */
2382  else
2383  {
2384  /* L10N: S/MIME options */
2385  prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, "
2386  "or (c)lear?");
2387  /* L10N: S/MIME options */
2388  letters = _("eswabc");
2389  choices = "eswabc";
2390  }
2391 
2392  choice = mutt_multi_choice(prompt, letters);
2393  if (choice > 0)
2394  {
2395  switch (choices[choice - 1])
2396  {
2397  case 'a': /* sign (a)s */
2398  key = smime_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, false);
2399  if (key)
2400  {
2402  smime_key_free(&key);
2403 
2404  e->security |= SEC_SIGN;
2405 
2406  /* probably need a different passphrase */
2408  }
2409 
2410  break;
2411 
2412  case 'b': /* (b)oth */
2413  e->security |= (SEC_ENCRYPT | SEC_SIGN);
2414  break;
2415 
2416  case 'c': /* (c)lear */
2417  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2418  break;
2419 
2420  case 'C':
2421  e->security &= ~SEC_SIGN;
2422  break;
2423 
2424  case 'e': /* (e)ncrypt */
2425  e->security |= SEC_ENCRYPT;
2426  e->security &= ~SEC_SIGN;
2427  break;
2428 
2429  case 'O': /* oppenc mode on */
2430  e->security |= SEC_OPPENCRYPT;
2432  break;
2433 
2434  case 'o': /* oppenc mode off */
2435  e->security &= ~SEC_OPPENCRYPT;
2436  break;
2437 
2438  case 'S': /* (s)ign in oppenc mode */
2439  e->security |= SEC_SIGN;
2440  break;
2441 
2442  case 's': /* (s)ign */
2443  e->security &= ~SEC_ENCRYPT;
2444  e->security |= SEC_SIGN;
2445  break;
2446 
2447  case 'w': /* encrypt (w)ith */
2448  {
2449  e->security |= SEC_ENCRYPT;
2450  do
2451  {
2452  struct Buffer errmsg = mutt_buffer_make(0);
2453  int rc = CSR_SUCCESS;
2454  switch (mutt_multi_choice(_("Choose algorithm family: (1) DES, (2) "
2455  "RC2, (3) AES, or (c)lear?"),
2456  // L10N: Options for: Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?
2457  _("123c")))
2458  {
2459  case 1:
2460  switch (choice = mutt_multi_choice(_("(1) DES, (2) Triple-DES?"),
2461  // L10N: Options for: (1) DES, (2) Triple-DES
2462  _("12")))
2463  {
2464  case 1:
2465  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2466  "des", &errmsg);
2467  break;
2468  case 2:
2469  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2470  "des3", &errmsg);
2471  break;
2472  }
2473  break;
2474 
2475  case 2:
2476  switch (choice = mutt_multi_choice(
2477  _("(1) RC2-40, (2) RC2-64, (3) RC2-128?"),
2478  // L10N: Options for: (1) RC2-40, (2) RC2-64, (3) RC2-128
2479  _("123")))
2480  {
2481  case 1:
2482  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2483  "rc2-40", &errmsg);
2484  break;
2485  case 2:
2486  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2487  "rc2-64", &errmsg);
2488  break;
2489  case 3:
2490  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2491  "rc2-128", &errmsg);
2492  break;
2493  }
2494  break;
2495 
2496  case 3:
2497  switch (choice = mutt_multi_choice(
2498  _("(1) AES128, (2) AES192, (3) AES256?"),
2499  // L10N: Options for: (1) AES128, (2) AES192, (3) AES256
2500  _("123")))
2501  {
2502  case 1:
2503  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2504  "aes128", &errmsg);
2505  break;
2506  case 2:
2507  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2508  "aes192", &errmsg);
2509  break;
2510  case 3:
2511  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2512  "aes256", &errmsg);
2513  break;
2514  }
2515  break;
2516 
2517  case 4:
2518  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2519  NULL, &errmsg);
2520  /* (c)lear */
2521  /* fallthrough */
2522  case -1: /* Ctrl-G or Enter */
2523  choice = 0;
2524  break;
2525  }
2526 
2527  if ((CSR_RESULT(rc) != CSR_SUCCESS) && !mutt_buffer_is_empty(&errmsg))
2528  mutt_error("%s", mutt_b2s(&errmsg));
2529 
2530  mutt_buffer_dealloc(&errmsg);
2531  } while (choice == -1);
2532  break;
2533  }
2534  }
2535  }
2536 
2537  return e->security;
2538 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:47
int mutt_protected_headers_handler(struct Body *a, struct State *s)
Process a protected header - Implements handler_t.
Definition: crypt.c:1085
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:414
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell&#39;s quoting rules.
Definition: file.c:836
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1835
const char * certificates
c
Definition: smime.c:78
char * C_SmimeVerifyOpaqueCommand
Config: (smime) External command to verify a signature.
Definition: config.c:106
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:60
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * C_SmimeEncryptCommand
Config: (smime) External command to encrypt a message.
Definition: config.c:95
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
Manage keymappings.
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
#define SMIME_SIGN
Definition: lib.h:105
#define WithCrypto
Definition: lib.h:118
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
The envelope/body of an email.
Definition: email.h:37
void smime_init(void)
Initialise smime globals.
Definition: smime.c:92
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define mutt_perror(...)
Definition: logging.h:85
GUI selectable list of items.
Definition: mutt_menu.h:80
#define CSR_RESULT(x)
Definition: set.h:52
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
char * C_SmimeDecryptCommand
Config: (smime) External command to decrypt an SMIME message.
Definition: config.c:93
Structs that make up an email.
Convenience wrapper for the send headers.
7-bit text
Definition: mime.h:49
#define mutt_message(...)
Definition: logging.h:83
KeyFlags flags
Definition: smime.h:50
char * C_SmimePk7outCommand
Config: (smime) External command to extract a public certificate.
Definition: config.c:101
Window uses all available vertical space.
Definition: mutt_window.h:35
#define mutt_get_password(msg, buf, buflen)
Definition: curs_lib.h:92
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
Wrapper around crypto functions.
void dialog_pop(void)
Hide a Window from the user.
Definition: mutt_window.c:750
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:799
static int const char * fmt
Definition: acutest.h:488
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: mutt_window.c:720
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
char * C_SmimeGetSignerCertCommand
Config: (smime) External command to extract a certificate from an email.
Definition: config.c:98
String manipulation buffer.
Definition: buffer.h:33
static char * openssl_md_to_smime_micalg(char *md)
Change the algorithm names.
Definition: smime.c:1695
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
static struct Body * smime_handle_entity(struct Body *m, struct State *s, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition: smime.c:2033
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
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:1541
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:821
#define _(a)
Definition: message.h:28
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
int smime_class_verify_sender(struct Mailbox *m, struct Email *e)
Implements CryptModuleSpecs::smime_verify_sender()
Definition: smime.c:1433
struct Body * next
next attachment in the list
Definition: body.h:53
An email address.
Definition: address.h:34
FILE * fp_out
File to write to.
Definition: state.h:47
char * mailbox
Mailbox and host address.
Definition: address.h:37
long C_SmimeTimeout
Config: Time in seconds to cache a passphrase.
Definition: config.c:104
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition: smime.h:49
A division of the screen.
Definition: mutt_window.h:114
An SIME key.
Definition: smime.h:43
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:78
void smime_class_getkeys(struct Envelope *env)
Implements CryptModuleSpecs::smime_getkeys()
Definition: smime.c:1005
int smime_class_application_handler(struct Body *m, struct State *s)
Implements CryptModuleSpecs::application_handler()
Definition: smime.c:2326
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
bool C_CryptOpportunisticEncryptStrongKeys
Config: Enable encryption only when strong a key is available.
Definition: config.c:42
int smime_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
Implements CryptModuleSpecs::verify_one()
Definition: smime.c:1921
Shared constants/structs that are private to libconn.
const char * sig_fname
s
Definition: smime.c:77
Flags to control mutt_expando_format()
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:395
All user-callable functions.
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
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:1908
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:130
static const char * smime_command_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format an SMIME command - Implements format_t.
Definition: smime.c:212
const char * digestalg
d
Definition: smime.c:75
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition: smime.c:138
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
Convenience wrapper for the config headers.
An Index Window containing a selection list.
Definition: mutt_window.h:93
Email Address Handling.
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition: smime.c:113
char * C_SmimeVerifyCommand
Config: (smime) External command to verify a signed message.
Definition: config.c:105
char * C_SmimeKeys
Config: File containing user&#39;s private certificates.
Definition: config.c:100
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:151
Data for a SIME command.
Definition: smime.c:71
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Some miscellaneous functions.
static void getkeys(char *mailbox)
Get the keys for a mailbox.
Definition: smime.c:973
bool smime_class_valid_passphrase(void)
Implements CryptModuleSpecs::valid_passphrase()
Definition: smime.c:172
SMIME encryption menu.
Definition: keymap.h:83
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:772
void smime_class_invoke_import(const char *infile, const char *mailbox)
Implements CryptModuleSpecs::smime_invoke_import()
Definition: smime.c:1361
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:623
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
bool C_CryptOpportunisticEncrypt
Config: Enable encryption when the recipient&#39;s key is available.
Definition: config.c:41
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct MuttWindow * win_ibar
Definition: mutt_menu.h:93
const char * title
Title of this menu.
Definition: mutt_menu.h:82
#define CH_WEED
Weed the headers?
Definition: copy.h:52
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:89
Convenience wrapper for the core headers.
void crypt_current_time(struct State *s, const char *app_name)
Print the current time.
Definition: crypt.c:71
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:85
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:77
char SmimePass[256]
Definition: smime.c:82
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Content is attached.
Definition: mime.h:63
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:755
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:405
const char * fname
f
Definition: smime.c:76
static int smime_handle_cert_email(char *certificate, char *mailbox, bool copy, char ***buffer, int *num)
Process an email containing certificates.
Definition: smime.c:1088
Email Aliases.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
const char * cryptalg
a
Definition: smime.c:74
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:411
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
Window has a fixed size.
Definition: mutt_window.h:44
static struct SmimeKey * smime_ask_for_key(char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition: smime.c:942
const char * help
Quickref for the current menu.
Definition: mutt_menu.h:83
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
bool goodsig
Good cryptographic signature.
Definition: body.h:75
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:93
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:930
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:1883
static int const char char buffer[256]
Definition: acutest.h:489
Prototypes for many functions.
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:1516
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:119
void * mdata
Extra data for the current menu.
Definition: mutt_menu.h:84
char * smime_class_find_keys(struct AddressList *al, bool oppenc_mode)
Implements CryptModuleSpecs::find_keys()
Definition: smime.c:1041
Signing/encryption multiplexor.
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:569
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
char * C_SmimeEncryptWith
Config: Algorithm for encryption.
Definition: config.c:56
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1323
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition: smime.c:662
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:49
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
bool C_SmimeAskCertLabel
Config: Prompt the user for a label for SMIME certificates.
Definition: config.c:90
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
char * C_SmimeCertificates
Config: File containing user&#39;s public certificates.
Definition: config.c:92
char * C_SmimeImportCertCommand
Config: (smime) External command to import a certificate.
Definition: config.c:99
static struct SmimeKey * smime_get_key_by_hash(char *hash, bool only_public_key)
Find a key by its hash.
Definition: smime.c:791
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:127
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
struct Body * smime_class_sign_message(struct Body *a, const struct AddressList *from)
Implements CryptModuleSpecs::sign_message()
Definition: smime.c:1718
char * data
Pointer to data.
Definition: buffer.h:35
static void smime_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the smime key list - Implements Menu::make_entry()
Definition: smime.c:453
char * C_SmimeCaLocation
Config: File containing trusted certificates.
Definition: config.c:91
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void smime_class_void_passphrase(void)
Implements CryptModuleSpecs::void_passphrase()
Definition: smime.c:163
struct SmimeKey * next
Definition: smime.h:51
GUI present the user with a selectable list.
#define mutt_file_mkstemp()
Definition: file.h:106
API for encryption/signing of emails.
static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const char *format)
Run an SMIME command.
Definition: smime.c:394
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:608
const char * key
k
Definition: smime.c:73
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
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:241
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:89
int smime_class_send_menu(struct Email *e)
Implements CryptModuleSpecs::send_menu()
Definition: smime.c:2345
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:129
char * C_SmimeDefaultKey
Config: Default key for SMIME operations.
Definition: config.c:54
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:88
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * C_SmimeSignAs
Config: Use this alternative key for signing messages.
Definition: config.c:55
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
int max
Number of entries in the menu.
Definition: mutt_menu.h:86
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:561
const char * intermediates
i
Definition: smime.c:79
char * C_SmimeGetCertCommand
Config: (smime) External command to extract a certificate from a message.
Definition: config.c:96
#define STR_COMMAND
Enough space for a long command line.
Definition: string2.h:35
#define SEC_SIGN
Email is signed.
Definition: lib.h:81
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:45
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:602
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:70
Keep track when processing files.
char * email
Definition: smime.h:45
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1375
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1019
Smime Dialog, smime_select_key()
Definition: mutt_window.h:88
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:661
char * label
Definition: smime.h:47
void smime_cleanup(void)
Clean up smime globals.
Definition: smime.c:102
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Duplicate the structure of an entire email.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
static struct SmimeKey * smime_get_key_by_str(char *str, KeyFlags abilities, bool only_public_key)
Find an SMIME key by string.
Definition: smime.c:896
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
SMIME helper routines.
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: mutt_globals.h:166
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
time_t SmimeExpTime
Definition: smime.c:83
static char * smime_key_flags(KeyFlags flags)
Turn SMIME key flags into a string.
Definition: smime.c:431
char * C_SmimeSignDigestAlg
Config: Digest algorithm.
Definition: config.c:103
static char * smime_extract_signer_certificate(const char *infile)
Extract the signer&#39;s certificate.
Definition: smime.c:1295
char * C_SmimeGetCertEmailCommand
Config: (smime) External command to get a certificate for an email.
Definition: config.c:97
char * hash
Definition: smime.h:46
#define FREE(x)
Definition: memory.h:40
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:545
static struct SmimeKey * smime_select_key(struct SmimeKey *keys, char *query)
Get the user to select a key.
Definition: smime.c:526
Keep track when processing files.
Definition: state.h:44
char * issuer
Definition: smime.h:48
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1585
char * C_SmimeSignCommand
Config: (smime) External command to sign a message.
Definition: config.c:102
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
void mutt_make_help(char *buf, size_t buflen, const char *txt, enum MenuType menu, int op)
Create one entry for the help bar.
Definition: help.c:87
Hundreds of global variables to back the user variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define TAILQ_EMPTY(head)
Definition: queue.h:714
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:131
int const char int line
Definition: acutest.h:617
int current
Current entry.
Definition: mutt_menu.h:85
struct Body * smime_class_build_smime_entity(struct Body *a, char *certlist)
Implements CryptModuleSpecs::smime_build_smime_entity()
Definition: smime.c:1554
struct MuttWindow * win_index
Definition: mutt_menu.h:92
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
Window wants as much space as possible.
Definition: mutt_window.h:45
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Decide how to display email content.
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
bool C_SmimeDecryptUseDefaultKey
Config: Use the default key for decryption.
Definition: config.c:94
Index Bar containing status info about the Index.
Definition: mutt_window.h:94
static char * smime_extract_certificate(const char *infile)
Extract an SMIME certificate from a file.
Definition: smime.c:1182
void(* make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:117
Type: &#39;application/*&#39;.
Definition: mime.h:33
static struct SmimeKey * smime_get_candidates(char *search, bool only_public_key)
Find keys matching a string.
Definition: smime.c:745
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1262
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
static void smime_command(char *buf, size_t buflen, struct SmimeCommandContext *cctx, const char *fmt)
Format an SMIME command string.
Definition: smime.c:364
The header of an Email.
Definition: envelope.h:54
static struct SmimeKey * smime_get_key_by_addr(char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition: smime.c:817
int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Implements CryptModuleSpecs::decrypt_mime()
Definition: smime.c:2264
#define SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition: lib.h:85
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265