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