5d773cd100b0d1c68e838f323728c19880ff3271
[apps/madmutt.git] / lib-crypt / smime.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org>
4  * Copyright (C) 2002 Mike Schiraldi <raldi@research.netsol.com>
5  * Copyright (C) 2004 g10 Code GmbH
6  *
7  * This file is part of mutt-ng, see http://www.muttng.org/.
8  * It's licensed under the GNU General Public License,
9  * please see the file GPL in the top level source directory.
10  */
11
12 #if HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15
16 #include <sys/wait.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 #include <ctype.h>
23
24 #ifdef HAVE_LOCALE_H
25 #  include <locale.h>
26 #endif
27 #ifdef HAVE_SYS_TIME_H
28 #  include <sys/time.h>
29 #endif
30 #ifdef HAVE_SYS_RESOURCE_H
31 #  include <sys/resource.h>
32 #endif
33
34 #include <lib-lib/mem.h>
35 #include <lib-lib/str.h>
36 #include <lib-lib/macros.h>
37 #include <lib-lib/file.h>
38 #include <lib-lib/debug.h>
39
40 #include <lib-mime/mime.h>
41
42 #include <lib-ui/curses.h>
43 #include <lib-ui/enter.h>
44 #include <lib-ui/menu.h>
45
46 #include "mutt.h"
47 #include "alias.h"
48 #include "handler.h"
49 #include "copy.h"
50 #include "alias.h"
51 #include "crypt.h"
52
53 struct smime_command_context {
54   const char *key;              /* %k */
55   const char *cryptalg;         /* %a */
56   const char *fname;            /* %f */
57   const char *sig_fname;        /* %s */
58   const char *certificates;     /* %c */
59   const char *intermediates;    /* %i */
60 };
61
62
63 typedef struct {
64   unsigned int hash;
65   char suffix;
66   char email[256];
67   char nick[256];
68   char trust;                   /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */
69   short public;                 /* 1=public 0=private */
70 } smime_id;
71
72
73 char SmimePass[STRING];
74 time_t SmimeExptime = 0;        /* when does the cached passphrase expire? */
75
76
77 static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };
78 static char SmimeCertToUse[_POSIX_PATH_MAX];
79 static char SmimeIntermediateToUse[_POSIX_PATH_MAX];
80
81
82 /*
83  * Create a format string to be used with scanf.
84  * To use it, write, for instance, MUTT_FORMAT(HUGE_STRING).
85  * 
86  * See K&R 2nd ed, p. 231 for an explanation.
87  */
88 #define _MUTT_FORMAT_2(a,b)     "%" a  b
89 #define _MUTT_FORMAT_1(a, b)    _MUTT_FORMAT_2(#a, b)
90 #define MUTT_FORMAT(a)          _MUTT_FORMAT_1(a, "s")
91
92
93 /*
94  *     Queries and passphrase handling.
95  */
96
97
98 /* these are copies from pgp.c */
99
100
101 void smime_void_passphrase (void)
102 {
103   p_clear(SmimePass, countof(SmimePass));
104   SmimeExptime = 0;
105 }
106
107 int smime_valid_passphrase (void)
108 {
109   time_t now = time (NULL);
110
111   if (now < SmimeExptime)
112     /* Use cached copy.  */
113     return 1;
114
115   smime_void_passphrase ();
116
117   if (mutt_get_field_unbuffered (_("Enter S/MIME passphrase:"), SmimePass,
118                                  sizeof (SmimePass), M_PASS) == 0) {
119     SmimeExptime = time (NULL) + SmimeTimeout;
120     return (1);
121   }
122   else
123     SmimeExptime = 0;
124
125   return 0;
126 }
127
128
129 /*
130  *     The OpenSSL interface
131  */
132
133 /* This is almost identical to ppgp's invoking interface. */
134
135 static const char *
136 _mutt_fmt_smime_command (char *dest, ssize_t destlen, char op,
137                          const char *src, const char *prefix,
138                          const char *ifstring, const char *elsestring,
139                          unsigned long data, format_flag flags)
140 {
141   char fmt[16];
142   struct smime_command_context *cctx = (struct smime_command_context *) data;
143   int optional = (flags & M_FORMAT_OPTIONAL);
144
145   switch (op) {
146   case 'C':
147     {
148       if (!optional) {
149         char path[_POSIX_PATH_MAX];
150         char buf1[LONG_STRING], buf2[LONG_STRING];
151         struct stat sb;
152
153         m_strcpy(path, sizeof(path), NONULL(SmimeCALocation));
154         mutt_expand_path (path, sizeof (path));
155         mutt_quote_filename (buf1, sizeof (buf1), path);
156
157         if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode))
158           snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1);
159         else
160           snprintf (buf2, sizeof (buf2), "-CApath %s", buf1);
161
162         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
163         snprintf (dest, destlen, fmt, buf2);
164       }
165       else if (!SmimeCALocation)
166         optional = 0;
167       break;
168     }
169
170   case 'c':
171     {                           /* certificate (list) */
172       if (!optional) {
173         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
174         snprintf (dest, destlen, fmt, NONULL (cctx->certificates));
175       }
176       else if (!cctx->certificates)
177         optional = 0;
178       break;
179     }
180
181   case 'i':
182     {                           /* intermediate certificates  */
183       if (!optional) {
184         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
185         snprintf (dest, destlen, fmt, NONULL (cctx->intermediates));
186       }
187       else if (!cctx->intermediates)
188         optional = 0;
189       break;
190     }
191
192   case 's':
193     {                           /* detached signature */
194       if (!optional) {
195         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
196         snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
197       }
198       else if (!cctx->sig_fname)
199         optional = 0;
200       break;
201     }
202
203   case 'k':
204     {                           /* private key */
205       if (!optional) {
206         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
207         snprintf (dest, destlen, fmt, NONULL (cctx->key));
208       }
209       else if (!cctx->key)
210         optional = 0;
211       break;
212     }
213
214   case 'a':
215     {                           /* algorithm for encryption */
216       if (!optional) {
217         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
218         snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg));
219       }
220       else if (!cctx->key)
221         optional = 0;
222       break;
223     }
224
225   case 'f':
226     {                           /* file to process */
227       if (!optional) {
228         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
229         snprintf (dest, destlen, fmt, NONULL (cctx->fname));
230       }
231       else if (!cctx->fname)
232         optional = 0;
233       break;
234     }
235
236   default:
237     *dest = '\0';
238     break;
239   }
240
241   if (optional)
242     mutt_FormatString (dest, destlen, ifstring, _mutt_fmt_smime_command,
243                        data, 0);
244   else if (flags & M_FORMAT_OPTIONAL)
245     mutt_FormatString (dest, destlen, elsestring, _mutt_fmt_smime_command,
246                        data, 0);
247
248   return (src);
249 }
250
251
252
253 static void mutt_smime_command (char *d, ssize_t dlen,
254                                 struct smime_command_context *cctx,
255                                 const char *fmt)
256 {
257   mutt_FormatString (d, dlen, NONULL (fmt), _mutt_fmt_smime_command,
258                      (unsigned long) cctx, 0);
259   debug_print (2, ("%s\n", d));
260 }
261
262 static pid_t smime_invoke (FILE ** smimein, FILE ** smimeout,
263                            FILE ** smimeerr, int smimeinfd, int smimeoutfd,
264                            int smimeerrfd, const char *fname,
265                            const char *sig_fname, const char *cryptalg,
266                            const char *key, const char *certificates,
267                            const char *intermediates, const char *format)
268 {
269   struct smime_command_context cctx;
270   char cmd[HUGE_STRING];
271
272   p_clear(&cctx, 1);
273
274   if (!format || !*format)
275     return (pid_t) - 1;
276
277   cctx.fname = fname;
278   cctx.sig_fname = sig_fname;
279   cctx.key = key;
280   cctx.cryptalg = cryptalg;
281   cctx.certificates = certificates;
282   cctx.intermediates = intermediates;
283
284   mutt_smime_command (cmd, sizeof (cmd), &cctx, format);
285
286   return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr,
287                                 smimeinfd, smimeoutfd, smimeerrfd);
288 }
289
290
291
292
293
294
295 /*
296  *    Key and certificate handling.
297  */
298
299
300
301 /* 
302    Search the certificate index for given mailbox.
303    return certificate file name.
304 */
305
306 static void smime_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
307 {
308   smime_id *Table = (smime_id *) menu->data;
309   smime_id this = Table[num];
310   const char *truststate;
311
312   switch (this.trust) {
313   case 't':
314     truststate = N_("Trusted   ");
315     break;
316   case 'v':
317     truststate = N_("Verified  ");
318     break;
319   case 'u':
320     truststate = N_("Unverified");
321     break;
322   case 'e':
323     truststate = N_("Expired   ");
324     break;
325   case 'r':
326     truststate = N_("Revoked   ");
327     break;
328   case 'i':
329     truststate = N_("Invalid   ");
330     break;
331   default:
332     truststate = N_("Unknown   ");
333   }
334   if (this.public)
335     snprintf (s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix,
336               truststate, this.email, this.nick);
337   else
338     snprintf (s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix,
339               this.email, this.nick);
340 }
341
342
343
344
345
346 char *smime_ask_for_key (char *prompt, char *mailbox __attribute__((unused)),
347                          short public)
348 {
349   char *fname;
350   smime_id *Table;
351   long cert_num;                /* Will contain the number of certificates.
352                                  * To be able to get it, the .index file will be read twice... */
353   char index_file[_POSIX_PATH_MAX];
354   FILE *idx;
355   char buf[LONG_STRING];
356   char fields[5][STRING];
357   int numFields, hash_suffix, done, cur;        /* The current entry */
358   MUTTMENU *menu;
359   unsigned int hash;
360   char helpstr[HUGE_STRING * 3];
361   char qry[256];
362   char title[256];
363
364   if (!prompt)
365     prompt = _("Enter keyID: ");
366   snprintf (index_file, sizeof (index_file), "%s/.index",
367             public ? NONULL (SmimeCertificates) : NONULL (SmimeKeys));
368
369   idx = fopen (index_file, "r");
370   if (idx == NULL) {
371     mutt_perror (index_file);
372     return NULL;
373   }
374   /* Count Lines */
375   cert_num = 0;
376   while (!feof (idx)) {
377     if (fgets (buf, sizeof (buf), idx))
378       cert_num++;
379   }
380   fclose (idx);
381
382   for (;;) {
383     *qry = 0;
384     if (mutt_get_field (prompt, qry, sizeof (qry), 0))
385       return NULL;
386     snprintf (title, sizeof (title),
387               _("S/MIME certificates matching \"%s\"."), qry);
388
389
390     idx = fopen (index_file, "r");
391     if (idx == NULL) {
392       mutt_perror (index_file);
393       return NULL;
394     }
395     /* Read Entries */
396     cur = 0;
397     Table = p_new(smime_id, cert_num);
398     while (!feof (idx)) {
399       numFields =
400         fscanf (idx, MUTT_FORMAT (STRING) " %x.%i " MUTT_FORMAT (STRING),
401                 fields[0], &hash, &hash_suffix, fields[2]);
402       if (public)
403         fscanf (idx, MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) "\n",
404                 fields[3], fields[4]);
405
406       /* 0=email 1=name 2=nick 3=intermediate 4=trust */
407       if (numFields < 2)
408         continue;
409
410       /* Check if query matches this certificate */
411       if (!m_stristr(fields[0], qry) && !m_stristr(fields[2], qry))
412         continue;
413
414       Table[cur].hash = hash;
415       Table[cur].suffix = hash_suffix;
416       m_strcpy(Table[cur].email, sizeof(Table[cur].email), fields[0]);
417       m_strcpy(Table[cur].nick,  sizeof(Table[cur].nick),  fields[2]);
418       Table[cur].trust = *fields[4];
419       Table[cur].public = public;
420
421       cur++;
422     }
423     fclose (idx);
424
425     /* Make Helpstring */
426     helpstr[0] = 0;
427     mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_SMIME, OP_EXIT);
428     strcat (helpstr, buf);      /* __STRCAT_CHECKED__ */
429     mutt_make_help (buf, sizeof (buf), _("Select  "), MENU_SMIME,
430                     OP_GENERIC_SELECT_ENTRY);
431     strcat (helpstr, buf);      /* __STRCAT_CHECKED__ */
432     mutt_make_help (buf, sizeof (buf), _("Help"), MENU_SMIME, OP_HELP);
433     strcat (helpstr, buf);      /* __STRCAT_CHECKED__ */
434
435     /* Create the menu */
436     menu = mutt_new_menu ();
437     menu->max = cur;
438     menu->make_entry = smime_entry;
439     menu->menu = MENU_SMIME;
440     menu->help = helpstr;
441     menu->data = Table;
442     menu->title = title;
443     /* sorting keys might be done later - TODO */
444
445     mutt_clear_error ();
446
447     done = 0;
448     hash = 0;
449     while (!done) {
450       switch (mutt_menuLoop (menu)) {
451       case OP_GENERIC_SELECT_ENTRY:
452         cur = menu->current;
453         hash = 1;
454         done = 1;
455         break;
456       case OP_EXIT:
457         hash = 0;
458         done = 1;
459         break;
460       }
461     }
462     if (hash) {
463       fname = p_new(char, 13); /* Hash + '.' + Suffix + \0 */
464       sprintf (fname, "%.8x.%i", Table[cur].hash, Table[cur].suffix);
465     }
466     else
467       fname = NULL;
468
469     mutt_menuDestroy (&menu);
470     p_delete(&Table);
471     set_option (OPTNEEDREDRAW);
472
473     if (fname)
474       return fname;
475   }
476 }
477
478
479
480 char *smime_get_field_from_db (char *mailbox, char *query, short public,
481                                short may_ask)
482 {
483   int addr_len, query_len, found = 0, ask = 0, choice = 0;
484   char cert_path[_POSIX_PATH_MAX];
485   char buf[LONG_STRING], prompt[STRING];
486   char fields[5][STRING];
487   char key[STRING];
488   int numFields;
489   struct stat info;
490   char key_trust_level = 0;
491   FILE *fp;
492
493   if (!mailbox && !query)
494     return (NULL);
495
496   addr_len = mailbox ? m_strlen(mailbox) : 0;
497   query_len = query ? m_strlen(query) : 0;
498
499   *key = '\0';
500
501   /* index-file format:
502      mailbox certfile label issuer_certfile trust_flags\n
503
504      certfile is a hash value generated by openssl.
505      Note that this was done according to the OpenSSL
506      specs on their CA-directory.
507
508    */
509   snprintf (cert_path, sizeof (cert_path), "%s/.index",
510             (public ? NONULL (SmimeCertificates) : NONULL (SmimeKeys)));
511
512   if (!stat (cert_path, &info)) {
513     if ((fp = safe_fopen (cert_path, "r")) == NULL) {
514       mutt_perror (cert_path);
515       return (NULL);
516     }
517
518     while (fgets (buf, sizeof (buf) - 1, fp) != NULL)
519       if (mailbox && !(m_strncasecmp(mailbox, buf, addr_len))) {
520         numFields = sscanf (buf,
521                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
522                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
523                             MUTT_FORMAT (STRING) "\n",
524                             fields[0], fields[1],
525                             fields[2], fields[3], fields[4]);
526         if (numFields < 2)
527           continue;
528         if (mailbox && public &&
529             (!fields[4] ||
530              *fields[4] == 'i' || *fields[4] == 'e' || *fields[4] == 'r'))
531           continue;
532
533         if (found) {
534           if (public && *fields[4] == 'u')
535             snprintf (prompt, sizeof (prompt),
536                       _
537                       ("ID %s is unverified. Do you want to use it for %s ?"),
538                       fields[1], mailbox);
539           else if (public && *fields[4] == 'v')
540             snprintf (prompt, sizeof (prompt),
541                       _("Use (untrusted!) ID %s for %s ?"),
542                       fields[1], mailbox);
543           else
544             snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"),
545                       fields[1], mailbox);
546           if (may_ask == 0)
547             choice = M_YES;
548           if (may_ask && (choice = mutt_yesorno (prompt, M_NO)) == -1) {
549             found = 0;
550             ask = 0;
551             *key = '\0';
552             break;
553           }
554           else if (choice == M_NO) {
555             ask = 1;
556             continue;
557           }
558           else if (choice == M_YES) {
559             m_strcpy(key, sizeof(key), fields[1]);
560             ask = 0;
561             break;
562           }
563         }
564         else {
565           if (public)
566             key_trust_level = *fields[4];
567           m_strcpy(key, sizeof(key), fields[1]);
568         }
569         found = 1;
570       }
571       else if (query) {
572         numFields = sscanf (buf,
573                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
574                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
575                             MUTT_FORMAT (STRING) "\n",
576                             fields[0], fields[1],
577                             fields[2], fields[3], fields[4]);
578
579         /* query = label: return certificate. */
580         if (numFields >= 3 &&
581             !(m_strncasecmp(query, fields[2], query_len))) {
582           ask = 0;
583           m_strcpy(key, sizeof(key), fields[1]);
584         }
585         /* query = certificate: return intermediate certificate. */
586         else if (numFields >= 4 &&
587                  !(m_strncasecmp(query, fields[1], query_len))) {
588           ask = 0;
589           m_strcpy(key, sizeof(key), fields[3]);
590         }
591       }
592
593     safe_fclose (&fp);
594
595     if (ask) {
596       if (public && *fields[4] == 'u')
597         snprintf (prompt, sizeof (prompt),
598                   _("ID %s is unverified. Do you want to use it for %s ?"),
599                   fields[1], mailbox);
600       else if (public && *fields[4] == 'v')
601         snprintf (prompt, sizeof (prompt),
602                   _("Use (untrusted!) ID %s for %s ?"), fields[1], mailbox);
603       else
604         snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"), key,
605                   mailbox);
606       choice = mutt_yesorno (prompt, M_NO);
607       if (choice == -1 || choice == M_NO)
608         *key = '\0';
609     }
610     else if (key_trust_level && may_ask) {
611       if (key_trust_level == 'u') {
612         snprintf (prompt, sizeof (prompt),
613                   _("ID %s is unverified. Do you want to use it for %s ?"),
614                   key, mailbox);
615         choice = mutt_yesorno (prompt, M_NO);
616         if (choice != M_YES)
617           *key = '\0';
618       }
619       else if (key_trust_level == 'v') {
620         mutt_error (_
621                     ("Warning: You have not yet decided to trust ID %s. (any key to continue)"),
622                     key);
623         mutt_sleep (5);
624       }
625     }
626
627   }
628
629   /* Note: m_strdup("") returns NULL. */
630   return m_strdup(key);
631 }
632
633
634
635
636 /* 
637    This sets the '*ToUse' variables for an upcoming decryption, where
638    the reuquired key is different from SmimeDefaultKey.
639 */
640
641 void _smime_getkeys (char *mailbox)
642 {
643   char *k = NULL;
644   char buf[STRING];
645
646   k = smime_get_field_from_db (mailbox, NULL, 0, 1);
647
648   if (!k) {
649     snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), mailbox);
650     k = smime_ask_for_key (buf, mailbox, 0);
651   }
652
653   if (k) {
654     /* the key used last time. */
655     if (*SmimeKeyToUse &&
656         !m_strcasecmp(k, SmimeKeyToUse + m_strlen(SmimeKeys) + 1)) {
657       p_delete(&k);
658       return;
659     }
660     else
661       smime_void_passphrase ();
662
663     snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
664               NONULL (SmimeKeys), k);
665
666     snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
667               NONULL (SmimeCertificates), k);
668
669     if (m_strcasecmp(k, SmimeDefaultKey))
670       smime_void_passphrase ();
671
672     p_delete(&k);
673     return;
674   }
675
676   if (*SmimeKeyToUse) {
677     if (!m_strcasecmp(SmimeDefaultKey,
678                           SmimeKeyToUse + m_strlen(SmimeKeys) + 1))
679       return;
680
681     smime_void_passphrase ();
682   }
683
684   snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
685             NONULL (SmimeKeys), NONULL (SmimeDefaultKey));
686
687   snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
688             NONULL (SmimeCertificates), NONULL (SmimeDefaultKey));
689 }
690
691 void smime_getkeys (ENVELOPE * env)
692 {
693   address_t *t;
694   int found = 0;
695
696   if (option (OPTSDEFAULTDECRYPTKEY) && SmimeDefaultKey && *SmimeDefaultKey) {
697     snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
698               NONULL (SmimeKeys), SmimeDefaultKey);
699
700     snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
701               NONULL (SmimeCertificates), SmimeDefaultKey);
702
703     return;
704   }
705
706   for (t = env->to; !found && t; t = t->next)
707     if (mutt_addr_is_user (t)) {
708       found = 1;
709       _smime_getkeys (t->mailbox);
710     }
711   for (t = env->cc; !found && t; t = t->next)
712     if (mutt_addr_is_user (t)) {
713       found = 1;
714       _smime_getkeys (t->mailbox);
715     }
716   if (!found && (t = mutt_default_from ())) {
717     _smime_getkeys (t->mailbox);
718     address_list_wipe(&t);
719   }
720 }
721
722 /* This routine attempts to find the keyids of the recipients of a message.
723  * It returns NULL if any of the keys can not be found.
724  */
725
726 char *smime_findKeys (address_t * to, address_t * cc, address_t * bcc)
727 {
728   char *keyID, *keylist = NULL;
729   ssize_t keylist_size = 0;
730   ssize_t keylist_used = 0;
731   address_t *tmp = NULL, *addr = NULL;
732   address_t **last = &tmp;
733   address_t *p, *q;
734   int i;
735
736   const char *fqdn = mutt_fqdn (1);
737
738   for (i = 0; i < 3; i++) {
739     switch (i) {
740     case 0:
741       p = to;
742       break;
743     case 1:
744       p = cc;
745       break;
746     case 2:
747       p = bcc;
748       break;
749     default:
750       abort ();
751     }
752
753     *last = address_list_dup (p);
754     while (*last)
755       last = &((*last)->next);
756   }
757
758   if (fqdn)
759     rfc822_qualify (tmp, fqdn);
760
761   tmp = mutt_remove_duplicates (tmp);
762
763   for (p = tmp; p; p = p->next) {
764     char buf[LONG_STRING];
765
766     q = p;
767
768     if ((keyID = smime_get_field_from_db (q->mailbox, NULL, 1, 1)) == NULL) {
769       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
770       keyID = smime_ask_for_key (buf, q->mailbox, 1);
771     }
772     if (!keyID) {
773       mutt_message (_("No (valid) certificate found for %s."), q->mailbox);
774       p_delete(&keylist);
775       address_list_wipe(&tmp);
776       address_list_wipe(&addr);
777       return NULL;
778     }
779
780     keylist_size += m_strlen(keyID) + 2;
781     p_realloc(&keylist, keylist_size);
782     sprintf (keylist + keylist_used, "%s\n", keyID);    /* __SPRINTF_CHECKED__ */
783     keylist_used = m_strlen(keylist);
784
785     address_list_wipe(&addr);
786
787   }
788   address_list_wipe(&tmp);
789   return (keylist);
790 }
791
792
793
794
795
796
797 static int smime_handle_cert_email (char *certificate, char *mailbox,
798                                     int copy, char ***buffer, int *num)
799 {
800   FILE *fpout = NULL, *fperr = NULL;
801   char tmpfname[_POSIX_PATH_MAX];
802   char email[STRING];
803   int ret = -1, count = 0;
804   pid_t thepid;
805
806   mutt_mktemp (tmpfname);
807   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
808     mutt_perror (tmpfname);
809     return 1;
810   }
811   mutt_unlink (tmpfname);
812
813   mutt_mktemp (tmpfname);
814   if ((fpout = safe_fopen (tmpfname, "w+")) == NULL) {
815     fclose (fperr);
816     mutt_perror (tmpfname);
817     return 1;
818   }
819   mutt_unlink (tmpfname);
820
821   if ((thepid = smime_invoke (NULL, NULL, NULL,
822                               -1, fileno (fpout), fileno (fperr),
823                               certificate, NULL, NULL, NULL, NULL, NULL,
824                               SmimeGetCertEmailCommand)) == -1) {
825     mutt_message (_("Error: unable to create OpenSSL subprocess!"));
826     fclose (fperr);
827     fclose (fpout);
828     return 1;
829   }
830
831   mutt_wait_filter (thepid);
832
833   fflush (fpout);
834   rewind (fpout);
835   rewind (fperr);
836   fflush (fperr);
837
838
839   while ((fgets (email, sizeof (email), fpout))) {
840     *(email + m_strlen(email) - 1) = '\0';
841     if (m_strncasecmp(email, mailbox, m_strlen(mailbox)) == 0)
842       ret = 1;
843
844     ret = ret < 0 ? 0 : ret;
845     count++;
846   }
847
848   if (ret == -1) {
849     mutt_endwin (NULL);
850     mutt_copy_stream (fperr, stdout);
851     mutt_any_key_to_continue (_
852                               ("Error: unable to create OpenSSL subprocess!"));
853     ret = 1;
854   }
855   else if (!ret)
856     ret = 1;
857   else
858     ret = 0;
859
860   if (copy && buffer && num) {
861     (*num) = count;
862     *buffer = p_new(char *, count);
863     count = 0;
864
865     rewind (fpout);
866     while ((fgets (email, sizeof (email), fpout))) {
867       *(email + m_strlen(email) - 1) = '\0';
868       (*buffer)[count] = p_dupstr(email, m_strlen(email));
869       count++;
870     }
871   }
872   else if (copy)
873     ret = 2;
874
875   fclose (fpout);
876   fclose (fperr);
877
878   return ret;
879 }
880
881
882
883 static char *smime_extract_certificate (char *infile)
884 {
885   FILE *fpout = NULL, *fperr = NULL;
886   char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
887   char tmpfname[_POSIX_PATH_MAX];
888   pid_t thepid;
889   int empty;
890
891
892   mutt_mktemp (tmpfname);
893   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
894     mutt_perror (tmpfname);
895     return NULL;
896   }
897   mutt_unlink (tmpfname);
898
899   mutt_mktemp (pk7out);
900   if ((fpout = safe_fopen (pk7out, "w+")) == NULL) {
901     fclose (fperr);
902     mutt_perror (pk7out);
903     return NULL;
904   }
905
906   /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
907      extract the full set of certificates directly.
908    */
909   if ((thepid = smime_invoke (NULL, NULL, NULL,
910                               -1, fileno (fpout), fileno (fperr),
911                               infile, NULL, NULL, NULL, NULL, NULL,
912                               SmimePk7outCommand)) == -1) {
913     mutt_any_key_to_continue (_
914                               ("Error: unable to create OpenSSL subprocess!"));
915     fclose (fperr);
916     fclose (fpout);
917     mutt_unlink (pk7out);
918     return NULL;
919   }
920
921   mutt_wait_filter (thepid);
922
923
924   fflush (fpout);
925   rewind (fpout);
926   rewind (fperr);
927   fflush (fperr);
928   empty = (fgetc (fpout) == EOF);
929   if (empty) {
930     mutt_perror (pk7out);
931     mutt_copy_stream (fperr, stdout);
932     fclose (fpout);
933     fclose (fperr);
934     mutt_unlink (pk7out);
935     return NULL;
936
937   }
938
939
940   fclose (fpout);
941   mutt_mktemp (certfile);
942   if ((fpout = safe_fopen (certfile, "w+")) == NULL) {
943     fclose (fperr);
944     mutt_unlink (pk7out);
945     mutt_perror (certfile);
946     return NULL;
947   }
948
949   /* Step 2: Extract the certificates from a PKCS#7 structure.
950    */
951   if ((thepid = smime_invoke (NULL, NULL, NULL,
952                               -1, fileno (fpout), fileno (fperr),
953                               pk7out, NULL, NULL, NULL, NULL, NULL,
954                               SmimeGetCertCommand)) == -1) {
955     mutt_any_key_to_continue (_
956                               ("Error: unable to create OpenSSL subprocess!"));
957     fclose (fperr);
958     fclose (fpout);
959     mutt_unlink (pk7out);
960     mutt_unlink (certfile);
961     return NULL;
962   }
963
964   mutt_wait_filter (thepid);
965
966   mutt_unlink (pk7out);
967
968   fflush (fpout);
969   rewind (fpout);
970   rewind (fperr);
971   fflush (fperr);
972   empty = (fgetc (fpout) == EOF);
973   if (empty) {
974     mutt_copy_stream (fperr, stdout);
975     fclose (fpout);
976     fclose (fperr);
977     mutt_unlink (certfile);
978     return NULL;
979   }
980
981   fclose (fpout);
982   fclose (fperr);
983
984   return m_strdup(certfile);
985 }
986
987 static char *smime_extract_signer_certificate (char *infile)
988 {
989   FILE *fpout = NULL, *fperr = NULL;
990   char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
991   char tmpfname[_POSIX_PATH_MAX];
992   pid_t thepid;
993   int empty;
994
995
996   mutt_mktemp (tmpfname);
997   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
998     mutt_perror (tmpfname);
999     return NULL;
1000   }
1001   mutt_unlink (tmpfname);
1002
1003
1004   mutt_mktemp (certfile);
1005   if ((fpout = safe_fopen (certfile, "w+")) == NULL) {
1006     fclose (fperr);
1007     mutt_perror (certfile);
1008     return NULL;
1009   }
1010
1011   /* Extract signer's certificate
1012    */
1013   if ((thepid = smime_invoke (NULL, NULL, NULL,
1014                               -1, -1, fileno (fperr),
1015                               infile, NULL, NULL, NULL, certfile, NULL,
1016                               SmimeGetSignerCertCommand)) == -1) {
1017     mutt_any_key_to_continue (_
1018                               ("Error: unable to create OpenSSL subprocess!"));
1019     fclose (fperr);
1020     fclose (fpout);
1021     mutt_unlink (pk7out);
1022     mutt_unlink (certfile);
1023     return NULL;
1024   }
1025
1026   mutt_wait_filter (thepid);
1027
1028   fflush (fpout);
1029   rewind (fpout);
1030   rewind (fperr);
1031   fflush (fperr);
1032   empty = (fgetc (fpout) == EOF);
1033   if (empty) {
1034     mutt_endwin (NULL);
1035     mutt_copy_stream (fperr, stdout);
1036     mutt_any_key_to_continue (NULL);
1037     fclose (fpout);
1038     fclose (fperr);
1039     mutt_unlink (certfile);
1040     return NULL;
1041   }
1042
1043   fclose (fpout);
1044   fclose (fperr);
1045
1046   return m_strdup(certfile);
1047 }
1048
1049
1050
1051
1052 /* Add a certificate and update index file (externally). */
1053
1054 void smime_invoke_import (char *infile, char *mailbox __attribute__ ((unused)))
1055 {
1056   char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
1057   FILE *smimein = NULL, *fpout = NULL, *fperr = NULL;
1058   pid_t thepid = -1;
1059
1060   mutt_mktemp (tmpfname);
1061   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
1062     mutt_perror (tmpfname);
1063     return;
1064   }
1065   mutt_unlink (tmpfname);
1066
1067   mutt_mktemp (tmpfname);
1068   if ((fpout = safe_fopen (tmpfname, "w+")) == NULL) {
1069     fclose (fperr);
1070     mutt_perror (tmpfname);
1071     return;
1072   }
1073   mutt_unlink (tmpfname);
1074
1075
1076   buf[0] = '\0';
1077   if (option (OPTASKCERTLABEL))
1078     mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
1079
1080   mutt_endwin (NULL);
1081   if ((certfile = smime_extract_certificate (infile))) {
1082     mutt_endwin (NULL);
1083
1084     if ((thepid = smime_invoke (&smimein, NULL, NULL,
1085                                 -1, fileno (fpout), fileno (fperr),
1086                                 certfile, NULL, NULL, NULL, NULL, NULL,
1087                                 SmimeImportCertCommand)) == -1) {
1088       mutt_message (_("Error: unable to create OpenSSL subprocess!"));
1089       return;
1090     }
1091     fputs (buf, smimein);
1092     fputc ('\n', smimein);
1093     fclose (smimein);
1094
1095     mutt_wait_filter (thepid);
1096
1097     mutt_unlink (certfile);
1098     p_delete(&certfile);
1099   }
1100
1101   fflush (fpout);
1102   rewind (fpout);
1103   fflush (fperr);
1104   rewind (fperr);
1105
1106   mutt_copy_stream (fpout, stdout);
1107   mutt_copy_stream (fperr, stdout);
1108
1109   fclose (fpout);
1110   fclose (fperr);
1111
1112 }
1113
1114
1115
1116 int smime_verify_sender (HEADER * h)
1117 {
1118   char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
1119   FILE *fpout;
1120   int retval = 1;
1121
1122   mutt_mktemp (tempfname);
1123   if (!(fpout = safe_fopen (tempfname, "w"))) {
1124     mutt_perror (tempfname);
1125     return 1;
1126   }
1127
1128   if (h->security & ENCRYPT)
1129     mutt_copy_message (fpout, Context, h,
1130                        M_CM_DECODE_CRYPT & M_CM_DECODE_SMIME,
1131                        CH_MIME | CH_WEED | CH_NONEWLINE);
1132   else
1133     mutt_copy_message (fpout, Context, h, 0, 0);
1134
1135   fflush (fpout);
1136   fclose (fpout);
1137
1138   if (h->env->from) {
1139     h->env->from = mutt_expand_aliases (h->env->from);
1140     mbox = h->env->from->mailbox;
1141   }
1142   else if (h->env->sender) {
1143     h->env->sender = mutt_expand_aliases (h->env->sender);
1144     mbox = h->env->sender->mailbox;
1145   }
1146
1147   if (mbox) {
1148     if ((certfile = smime_extract_signer_certificate (tempfname))) {
1149       mutt_unlink (tempfname);
1150       if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL)) {
1151         if (isendwin ())
1152           mutt_any_key_to_continue (NULL);
1153       }
1154       else
1155         retval = 0;
1156       mutt_unlink (certfile);
1157       p_delete(&certfile);
1158     }
1159     else
1160       mutt_any_key_to_continue (_("no certfile"));
1161   }
1162   else
1163     mutt_any_key_to_continue (_("no mbox"));
1164
1165   mutt_unlink (tempfname);
1166   return retval;
1167 }
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177 /*
1178  *    Creating S/MIME - bodies.
1179  */
1180
1181
1182
1183
1184 static
1185 pid_t smime_invoke_encrypt (FILE ** smimein, FILE ** smimeout,
1186                             FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1187                             int smimeerrfd, const char *fname,
1188                             const char *uids)
1189 {
1190   return smime_invoke (smimein, smimeout, smimeerr,
1191                        smimeinfd, smimeoutfd, smimeerrfd,
1192                        fname, NULL, SmimeCryptAlg, NULL, uids, NULL,
1193                        SmimeEncryptCommand);
1194 }
1195
1196
1197 static
1198 pid_t smime_invoke_sign (FILE ** smimein, FILE ** smimeout, FILE ** smimeerr,
1199                          int smimeinfd, int smimeoutfd, int smimeerrfd,
1200                          const char *fname)
1201 {
1202   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1203                        smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1204                        SmimeCertToUse, SmimeIntermediateToUse,
1205                        SmimeSignCommand);
1206 }
1207
1208
1209
1210
1211 BODY *smime_build_smime_entity (BODY * a, char *certlist)
1212 {
1213   char buf[LONG_STRING], certfile[LONG_STRING];
1214   char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1215   char smimeinfile[_POSIX_PATH_MAX];
1216   char *cert_start = certlist, *cert_end = certlist;
1217   FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
1218   BODY *t;
1219   int err = 0, empty;
1220   pid_t thepid;
1221
1222   mutt_mktemp (tempfile);
1223   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
1224     mutt_perror (tempfile);
1225     return (NULL);
1226   }
1227
1228   mutt_mktemp (smimeerrfile);
1229   if ((smimeerr = safe_fopen (smimeerrfile, "w+")) == NULL) {
1230     mutt_perror (smimeerrfile);
1231     fclose (fpout);
1232     mutt_unlink (tempfile);
1233     return NULL;
1234   }
1235   mutt_unlink (smimeerrfile);
1236
1237   mutt_mktemp (smimeinfile);
1238   if ((fptmp = safe_fopen (smimeinfile, "w+")) == NULL) {
1239     mutt_perror (smimeinfile);
1240     mutt_unlink (tempfile);
1241     fclose (fpout);
1242     fclose (smimeerr);
1243     return NULL;
1244   }
1245
1246   *certfile = '\0';
1247   while (1) {
1248     int off = m_strlen(certfile);
1249
1250     while (*++cert_end && *cert_end != '\n');
1251     if (!*cert_end)
1252       break;
1253     *cert_end = '\0';
1254     snprintf (certfile + off, sizeof (certfile) - off, " %s/%s",
1255               NONULL (SmimeCertificates), cert_start);
1256     *cert_end = '\n';
1257     cert_start = cert_end;
1258     cert_start++;
1259   }
1260
1261   /* write a MIME entity */
1262   mutt_write_mime_header (a, fptmp);
1263   fputc ('\n', fptmp);
1264   mutt_write_mime_body (a, fptmp);
1265   fclose (fptmp);
1266
1267   if ((thepid =
1268        smime_invoke_encrypt (&smimein, NULL, NULL, -1,
1269                              fileno (fpout), fileno (smimeerr),
1270                              smimeinfile, certfile)) == -1) {
1271     fclose (smimeerr);
1272     mutt_unlink (smimeinfile);
1273     mutt_unlink (certfile);
1274     return (NULL);
1275   }
1276
1277   fclose (smimein);
1278
1279   mutt_wait_filter (thepid);
1280   mutt_unlink (smimeinfile);
1281   mutt_unlink (certfile);
1282
1283   fflush (fpout);
1284   rewind (fpout);
1285   empty = (fgetc (fpout) == EOF);
1286   fclose (fpout);
1287
1288   fflush (smimeerr);
1289   rewind (smimeerr);
1290   while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL) {
1291     err = 1;
1292     fputs (buf, stdout);
1293   }
1294   fclose (smimeerr);
1295
1296   /* pause if there is any error output from SMIME */
1297   if (err)
1298     mutt_any_key_to_continue (NULL);
1299
1300   if (empty) {
1301     /* fatal error while trying to encrypt message */
1302     if (!err)
1303       mutt_any_key_to_continue _("No output from OpenSSL..");
1304
1305     mutt_unlink (tempfile);
1306     return (NULL);
1307   }
1308
1309   t = mutt_new_body ();
1310   t->type = TYPEAPPLICATION;
1311   t->subtype = m_strdup("x-pkcs7-mime");
1312   mutt_set_parameter ("name", "smime.p7m", &t->parameter);
1313   mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
1314   t->encoding = ENCBASE64;      /* The output of OpenSSL SHOULD be binary */
1315   t->use_disp = 1;
1316   t->disposition = DISPATTACH;
1317   t->d_filename = m_strdup("smime.p7m");
1318   t->filename = m_strdup(tempfile);
1319   t->unlink = 1;                /*delete after sending the message */
1320   t->parts = 0;
1321   t->next = 0;
1322
1323   return (t);
1324 }
1325
1326
1327
1328
1329 BODY *smime_sign_message (BODY * a)
1330 {
1331   BODY *t;
1332   char buffer[LONG_STRING];
1333   char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
1334   FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
1335   int err = 0;
1336   int empty = 0;
1337   pid_t thepid;
1338   char *intermediates = smime_get_field_from_db (NULL, SmimeDefaultKey, 1, 1);
1339
1340   if (!intermediates) {
1341     mutt_message (_("Warning: Intermediate certificate not found."));
1342     intermediates = SmimeDefaultKey;    /* so openssl won't complain in any case */
1343   }
1344
1345   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
1346
1347   mutt_mktemp (filetosign);
1348   if ((sfp = safe_fopen (filetosign, "w+")) == NULL) {
1349     mutt_perror (filetosign);
1350     return NULL;
1351   }
1352
1353   mutt_mktemp (signedfile);
1354   if ((smimeout = safe_fopen (signedfile, "w+")) == NULL) {
1355     mutt_perror (signedfile);
1356     fclose (sfp);
1357     mutt_unlink (filetosign);
1358     return NULL;
1359   }
1360
1361   mutt_write_mime_header (a, sfp);
1362   fputc ('\n', sfp);
1363   mutt_write_mime_body (a, sfp);
1364   fclose (sfp);
1365
1366
1367
1368   snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
1369             NONULL (SmimeKeys), SmimeDefaultKey);
1370
1371   snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
1372             NONULL (SmimeCertificates), SmimeDefaultKey);
1373
1374   snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
1375             NONULL (SmimeCertificates), intermediates);
1376
1377
1378
1379   if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
1380                                    -1, fileno (smimeout), -1,
1381                                    filetosign)) == -1) {
1382     mutt_perror (_("Can't open OpenSSL subprocess!"));
1383
1384     fclose (smimeout);
1385     mutt_unlink (signedfile);
1386     mutt_unlink (filetosign);
1387     return NULL;
1388   }
1389   fputs (SmimePass, smimein);
1390   fputc ('\n', smimein);
1391   fclose (smimein);
1392
1393
1394   mutt_wait_filter (thepid);
1395
1396   /* check for errors from OpenSSL */
1397   err = 0;
1398   fflush (smimeerr);
1399   rewind (smimeerr);
1400   while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL) {
1401     err = 1;
1402     fputs (buffer, stdout);
1403   }
1404   fclose (smimeerr);
1405
1406
1407   fflush (smimeout);
1408   rewind (smimeout);
1409   empty = (fgetc (smimeout) == EOF);
1410   fclose (smimeout);
1411
1412   mutt_unlink (filetosign);
1413
1414
1415   if (err)
1416     mutt_any_key_to_continue (NULL);
1417
1418   if (empty) {
1419     mutt_any_key_to_continue _("No output from OpenSSL...");
1420
1421     mutt_unlink (signedfile);
1422     return (NULL);              /* fatal error while signing */
1423   }
1424
1425   t = mutt_new_body ();
1426   t->type = TYPEMULTIPART;
1427   t->subtype = m_strdup("signed");
1428   t->encoding = ENC7BIT;
1429   t->use_disp = 0;
1430   t->disposition = DISPINLINE;
1431
1432   mutt_generate_boundary (&t->parameter);
1433   /* check if this can be extracted from private key somehow.... */
1434   mutt_set_parameter ("micalg", "sha1", &t->parameter);
1435   mutt_set_parameter ("protocol", "application/x-pkcs7-signature",
1436                       &t->parameter);
1437
1438   t->parts = a;
1439   a = t;
1440
1441   t->parts->next = mutt_new_body ();
1442   t = t->parts->next;
1443   t->type = TYPEAPPLICATION;
1444   t->subtype = m_strdup("x-pkcs7-signature");
1445   t->filename = m_strdup(signedfile);
1446   t->d_filename = m_strdup("smime.p7s");
1447   t->use_disp = 1;
1448   t->disposition = DISPATTACH;
1449   t->encoding = ENCBASE64;
1450   t->unlink = 1;                /* ok to remove this file after sending. */
1451
1452   return (a);
1453
1454 }
1455
1456
1457
1458
1459
1460
1461 /*
1462  *    Handling S/MIME - bodies.
1463  */
1464
1465
1466
1467
1468
1469
1470 static
1471 pid_t smime_invoke_verify (FILE ** smimein, FILE ** smimeout,
1472                            FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1473                            int smimeerrfd, const char *fname,
1474                            const char *sig_fname, int opaque)
1475 {
1476   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1477                        smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL,
1478                        (opaque ? SmimeVerifyOpaqueCommand :
1479                         SmimeVerifyCommand));
1480 }
1481
1482
1483 static
1484 pid_t smime_invoke_decrypt (FILE ** smimein, FILE ** smimeout,
1485                             FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1486                             int smimeerrfd, const char *fname)
1487 {
1488   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1489                        smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1490                        SmimeCertToUse, NULL, SmimeDecryptCommand);
1491 }
1492
1493
1494
1495 int smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1496 {
1497   char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1498   FILE *fp = NULL, *smimeout = NULL, *smimeerr = NULL;
1499   pid_t thepid;
1500   int badsig = -1;
1501
1502   long tmpoffset = 0;
1503   ssize_t tmplength = 0;
1504   int origType = sigbdy->type;
1505   char *savePrefix = NULL;
1506
1507
1508   snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
1509
1510   /* decode to a tempfile, saving the original destination */
1511   fp = s->fpout;
1512   if ((s->fpout = safe_fopen (signedfile, "w")) == NULL) {
1513     mutt_perror (signedfile);
1514     return -1;
1515   }
1516   /* decoding the attachment changes the size and offset, so save a copy
1517    * of the "real" values now, and restore them after processing
1518    */
1519   tmplength = sigbdy->length;
1520   tmpoffset = sigbdy->offset;
1521
1522   /* if we are decoding binary bodies, we don't want to prefix each
1523    * line with the prefix or else the data will get corrupted.
1524    */
1525   savePrefix = s->prefix;
1526   s->prefix = NULL;
1527
1528   mutt_decode_attachment (sigbdy, s);
1529
1530   sigbdy->length = ftello (s->fpout);
1531   sigbdy->offset = 0;
1532   fclose (s->fpout);
1533
1534   /* restore final destination and substitute the tempfile for input */
1535   s->fpout = fp;
1536   fp = s->fpin;
1537   s->fpin = fopen (signedfile, "r");
1538
1539   /* restore the prefix */
1540   s->prefix = savePrefix;
1541
1542   sigbdy->type = origType;
1543
1544
1545   mutt_mktemp (smimeerrfile);
1546   if (!(smimeerr = safe_fopen (smimeerrfile, "w+"))) {
1547     mutt_perror (smimeerrfile);
1548     mutt_unlink (signedfile);
1549     return -1;
1550   }
1551
1552   crypt_current_time (s, "OpenSSL");
1553
1554   if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
1555                                      -1, -1, fileno (smimeerr),
1556                                      tempfile, signedfile, 0)) != -1) {
1557     fflush (smimeout);
1558     fclose (smimeout);
1559
1560     if (mutt_wait_filter (thepid))
1561       badsig = -1;
1562     else {
1563       char *line = NULL;
1564       int lineno = 0;
1565       ssize_t linelen;
1566
1567       fflush (smimeerr);
1568       rewind (smimeerr);
1569
1570       line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1571       if (linelen && !m_strcasecmp(line, "verification successful"))
1572         badsig = 0;
1573
1574       p_delete(&line);
1575     }
1576   }
1577
1578   fflush (smimeerr);
1579   rewind (smimeerr);
1580   mutt_copy_stream (smimeerr, s->fpout);
1581   fclose (smimeerr);
1582
1583   state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1584
1585   mutt_unlink (signedfile);
1586   mutt_unlink (smimeerrfile);
1587
1588   sigbdy->length = tmplength;
1589   sigbdy->offset = tmpoffset;
1590
1591   /* restore the original source stream */
1592   fclose (s->fpin);
1593   s->fpin = fp;
1594
1595
1596   return badsig;
1597 }
1598
1599
1600
1601
1602
1603 /*
1604   This handles application/pkcs7-mime which can either be a signed
1605   or an encrypted message.
1606 */
1607
1608 static BODY *smime_handle_entity (BODY * m, STATE * s, FILE * outFile)
1609 {
1610   int len = 0;
1611   int c;
1612   long last_pos;
1613   char buf[HUGE_STRING];
1614   char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
1615   char tmpfname[_POSIX_PATH_MAX];
1616   char tmptmpfname[_POSIX_PATH_MAX];
1617   FILE *smimeout = NULL, *smimein = NULL, *smimeerr = NULL;
1618   FILE *tmpfp = NULL, *tmpfp_buffer = NULL, *fpout = NULL;
1619   struct stat info;
1620   BODY *p = NULL;
1621   pid_t thepid = -1;
1622   unsigned int type = mutt_is_application_smime (m);
1623
1624   if (!(type & APPLICATION_SMIME))
1625     return NULL;
1626
1627   mutt_mktemp (outfile);
1628   if ((smimeout = safe_fopen (outfile, "w+")) == NULL) {
1629     mutt_perror (outfile);
1630     return NULL;
1631   }
1632
1633   mutt_mktemp (errfile);
1634   if ((smimeerr = safe_fopen (errfile, "w+")) == NULL) {
1635     mutt_perror (errfile);
1636     fclose (smimeout);
1637     smimeout = NULL;
1638     return NULL;
1639   }
1640   mutt_unlink (errfile);
1641
1642
1643   mutt_mktemp (tmpfname);
1644   if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL) {
1645     mutt_perror (tmpfname);
1646     fclose (smimeout);
1647     smimeout = NULL;
1648     fclose (smimeerr);
1649     smimeerr = NULL;
1650     return NULL;
1651   }
1652
1653   fseeko (s->fpin, m->offset, 0);
1654   last_pos = m->offset;
1655
1656   mutt_copy_bytes (s->fpin, tmpfp, m->length);
1657
1658   fflush (tmpfp);
1659   fclose (tmpfp);
1660
1661   if ((type & ENCRYPT) &&
1662       (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
1663                                       fileno (smimeout), fileno (smimeerr),
1664                                       tmpfname)) == -1) {
1665     fclose (smimeout);
1666     smimeout = NULL;
1667     mutt_unlink (tmpfname);
1668     if (s->flags & M_DISPLAY)
1669       state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1670     return NULL;
1671   }
1672   else if ((type & SIGNOPAQUE) &&
1673            (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
1674                                           fileno (smimeout),
1675                                           fileno (smimeerr), NULL, tmpfname,
1676                                           SIGNOPAQUE)) == -1) {
1677     fclose (smimeout);
1678     smimeout = NULL;
1679     mutt_unlink (tmpfname);
1680     if (s->flags & M_DISPLAY)
1681       state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1682     return NULL;
1683   }
1684
1685
1686   if (type & ENCRYPT) {
1687     if (!smime_valid_passphrase ())
1688       smime_void_passphrase ();
1689     fputs (SmimePass, smimein);
1690     fputc ('\n', smimein);
1691   }
1692
1693   fclose (smimein);
1694
1695   mutt_wait_filter (thepid);
1696   mutt_unlink (tmpfname);
1697
1698
1699   if (s->flags & M_DISPLAY) {
1700     rewind (smimeerr);
1701
1702     if ((c = fgetc (smimeerr)) != EOF) {
1703       ungetc (c, smimeerr);
1704
1705       crypt_current_time (s, "OpenSSL");
1706       mutt_copy_stream (smimeerr, s->fpout);
1707       state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1708     }
1709
1710     if (type & ENCRYPT)
1711       state_attach_puts (_("[-- The following data is S/MIME"
1712                            " encrypted --]\n"), s);
1713     else
1714       state_attach_puts (_("[-- The following data is S/MIME signed --]\n"),
1715                          s);
1716   }
1717
1718   if (smimeout) {
1719     fflush (smimeout);
1720     rewind (smimeout);
1721
1722     if (outFile)
1723       fpout = outFile;
1724     else {
1725       mutt_mktemp (tmptmpfname);
1726       if ((fpout = safe_fopen (tmptmpfname, "w+")) == NULL) {
1727         mutt_perror (tmptmpfname);
1728         fclose (smimeout);
1729         smimeout = NULL;
1730         return NULL;
1731       }
1732     }
1733     while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL) {
1734       len = m_strlen(buf);
1735       if (len > 1 && buf[len - 2] == '\r') {
1736         buf[len - 2] = '\n';
1737         buf[len - 1] = '\0';
1738       }
1739       fputs (buf, fpout);
1740     }
1741     fflush (fpout);
1742     rewind (fpout);
1743
1744
1745     if ((p = mutt_read_mime_header (fpout, 0)) != NULL) {
1746       fstat (fileno (fpout), &info);
1747       p->length = info.st_size - p->offset;
1748
1749       mutt_parse_part (fpout, p);
1750       if (s->fpout) {
1751         rewind (fpout);
1752         tmpfp_buffer = s->fpin;
1753         s->fpin = fpout;
1754         mutt_body_handler (p, s);
1755         s->fpin = tmpfp_buffer;
1756       }
1757
1758     }
1759     fclose (smimeout);
1760     smimeout = NULL;
1761     mutt_unlink (outfile);
1762
1763     if (!outFile) {
1764       fclose (fpout);
1765       mutt_unlink (tmptmpfname);
1766     }
1767     fpout = NULL;
1768   }
1769
1770   if (s->flags & M_DISPLAY) {
1771     if (type & ENCRYPT)
1772       state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
1773     else
1774       state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
1775   }
1776
1777   if (type & SIGNOPAQUE) {
1778     char *line = NULL;
1779     int lineno = 0;
1780     ssize_t linelen;
1781
1782     rewind (smimeerr);
1783
1784     line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1785     if (linelen && !m_strcasecmp(line, "verification successful"))
1786       m->goodsig = 1;
1787     p_delete(&line);
1788   }
1789   else {
1790     m->goodsig = p->goodsig;
1791     m->badsig = p->badsig;
1792   }
1793   fclose (smimeerr);
1794
1795   return (p);
1796 }
1797
1798
1799
1800
1801
1802 int smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1803 {
1804
1805
1806   char tempfile[_POSIX_PATH_MAX];
1807   STATE s;
1808   long tmpoffset = b->offset;
1809   ssize_t tmplength = b->length;
1810   int origType = b->type;
1811   FILE *tmpfp = NULL;
1812   int rv = 0;
1813
1814   if (!mutt_is_application_smime (b))
1815     return -1;
1816
1817   if (b->parts)
1818     return -1;
1819
1820   p_clear(&s, 1);
1821   s.fpin = fpin;
1822   fseeko (s.fpin, b->offset, 0);
1823
1824   mutt_mktemp (tempfile);
1825   if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL) {
1826     mutt_perror (tempfile);
1827     return (-1);
1828   }
1829
1830   mutt_unlink (tempfile);
1831   s.fpout = tmpfp;
1832   mutt_decode_attachment (b, &s);
1833   fflush (tmpfp);
1834   b->length = ftello (s.fpout);
1835   b->offset = 0;
1836   rewind (tmpfp);
1837   s.fpin = tmpfp;
1838   s.fpout = 0;
1839
1840   mutt_mktemp (tempfile);
1841   if ((*fpout = safe_fopen (tempfile, "w+")) == NULL) {
1842     mutt_perror (tempfile);
1843     rv = -1;
1844     goto bail;
1845   }
1846   mutt_unlink (tempfile);
1847
1848   if (!(*cur = smime_handle_entity (b, &s, *fpout))) {
1849     rv = -1;
1850     goto bail;
1851   }
1852
1853   (*cur)->goodsig = b->goodsig;
1854   (*cur)->badsig  = b->badsig;
1855
1856 bail:
1857   b->type = origType;
1858   b->length = tmplength;
1859   b->offset = tmpoffset;
1860
1861   safe_fclose (&tmpfp);
1862   if (*fpout)
1863     rewind (*fpout);
1864   return (rv);
1865 }
1866
1867
1868 int smime_application_smime_handler (BODY * m, STATE * s)
1869 {
1870   return smime_handle_entity (m, s, NULL) ? 0 : -1;
1871 }
1872
1873 int smime_send_menu (HEADER * msg, int *redraw)
1874 {
1875   char *p;
1876
1877   switch (mutt_multi_choice
1878           (_("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? "),
1879            _("eswabfc"))) {
1880   case 1:                      /* (e)ncrypt */
1881     msg->security |= ENCRYPT;
1882     msg->security &= ~SIGN;
1883     break;
1884
1885   case 3:                      /* encrypt (w)ith */
1886     {
1887       int choice = 0;
1888       msg->security |= ENCRYPT;
1889
1890       do {
1891         /* I use "dra" because "123" is recognized anyway */
1892         switch (mutt_multi_choice (_("Choose algorithm family:"
1893                                      " 1: DES, 2: RC2, 3: AES,"
1894                                      " or (c)lear? "), _("drac"))) {
1895           case 1:
1896             switch (choice = mutt_multi_choice (_("1: DES, 2: Triple-DES "),
1897                                                 _("dt"))) {
1898               case 1:
1899                 m_strreplace(&SmimeCryptAlg, "des");
1900                 break;
1901               case 2:
1902                 m_strreplace(&SmimeCryptAlg, "des3");
1903                 break;
1904             }
1905             break;
1906
1907           case 2:
1908             switch (choice = mutt_multi_choice (_("1: RC2-40, 2: RC2-64, 3: RC2-128 "),
1909                                                 _("468"))) {
1910               case 1:
1911                 m_strreplace(&SmimeCryptAlg, "rc2-40");
1912                 break;
1913               case 2:
1914                 m_strreplace(&SmimeCryptAlg, "rc2-64");
1915                 break;
1916               case 3:
1917                 m_strreplace(&SmimeCryptAlg, "rc2-128");
1918                 break;
1919             }
1920             break;
1921
1922           case 3:
1923             switch (choice = mutt_multi_choice (_("1: AES128, 2: AES192, 3: AES256 "),
1924                                                 _("895"))) {
1925               case 1:
1926                 m_strreplace(&SmimeCryptAlg, "aes128");
1927                 break;
1928               case 2:
1929                 m_strreplace(&SmimeCryptAlg, "aes192");
1930                 break;
1931               case 3:
1932                 m_strreplace(&SmimeCryptAlg, "aes256");
1933                 break;
1934             }
1935             break;
1936
1937           case 4: /* (c)lear */
1938             p_delete(&SmimeCryptAlg);
1939             /* fallback */
1940           case -1: /* Ctrl-G or Enter */
1941             choice = 0;
1942             break;
1943         }
1944       } while (choice == -1);
1945     }
1946     break;
1947
1948   case 2:                      /* (s)ign */
1949
1950     if (!SmimeDefaultKey)
1951       mutt_message (_("Can't sign: No key specified. Use Sign As."));
1952
1953     else {
1954       msg->security |= SIGN;
1955       msg->security &= ~ENCRYPT;
1956     }
1957     break;
1958
1959   case 4:                      /* sign (a)s */
1960
1961     if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) {
1962       m_strreplace(&SmimeDefaultKey, p);
1963
1964       msg->security |= SIGN;
1965
1966       /* probably need a different passphrase */
1967       crypt_smime_void_passphrase ();
1968     }
1969 #if 0
1970     else
1971       msg->security &= ~SIGN;
1972 #endif
1973
1974     *redraw = REDRAW_FULL;
1975     break;
1976
1977   case 5:                      /* (b)oth */
1978     msg->security |= (ENCRYPT | SIGN);
1979     break;
1980
1981   case 6:                      /* (f)orget it */
1982   case 7:                      /* (c)lear */
1983     msg->security = 0;
1984     break;
1985   }
1986
1987   if (msg->security && msg->security != APPLICATION_SMIME)
1988     msg->security |= APPLICATION_SMIME;
1989   else
1990     msg->security = 0;
1991
1992   return (msg->security);
1993 }