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