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