drop mem_alloc and mem_free, use my own hand crafted optmized macros that
[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 = mem_calloc (cert_num, sizeof (smime_id));
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 = mem_calloc (sizeof (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] = mem_calloc (1, str_len (email) + 1);
866       strncpy ((*buffer)[count], email, str_len (email));
867       count++;
868     }
869   }
870   else if (copy)
871     ret = 2;
872
873   fclose (fpout);
874   fclose (fperr);
875
876   return ret;
877 }
878
879
880
881 static char *smime_extract_certificate (char *infile)
882 {
883   FILE *fpout = NULL, *fperr = NULL;
884   char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
885   char tmpfname[_POSIX_PATH_MAX];
886   pid_t thepid;
887   int empty;
888
889
890   mutt_mktemp (tmpfname);
891   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
892     mutt_perror (tmpfname);
893     return NULL;
894   }
895   mutt_unlink (tmpfname);
896
897   mutt_mktemp (pk7out);
898   if ((fpout = safe_fopen (pk7out, "w+")) == NULL) {
899     fclose (fperr);
900     mutt_perror (pk7out);
901     return NULL;
902   }
903
904   /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
905      extract the full set of certificates directly.
906    */
907   if ((thepid = smime_invoke (NULL, NULL, NULL,
908                               -1, fileno (fpout), fileno (fperr),
909                               infile, NULL, NULL, NULL, NULL, NULL,
910                               SmimePk7outCommand)) == -1) {
911     mutt_any_key_to_continue (_
912                               ("Error: unable to create OpenSSL subprocess!"));
913     fclose (fperr);
914     fclose (fpout);
915     mutt_unlink (pk7out);
916     return NULL;
917   }
918
919   mutt_wait_filter (thepid);
920
921
922   fflush (fpout);
923   rewind (fpout);
924   rewind (fperr);
925   fflush (fperr);
926   empty = (fgetc (fpout) == EOF);
927   if (empty) {
928     mutt_perror (pk7out);
929     mutt_copy_stream (fperr, stdout);
930     fclose (fpout);
931     fclose (fperr);
932     mutt_unlink (pk7out);
933     return NULL;
934
935   }
936
937
938   fclose (fpout);
939   mutt_mktemp (certfile);
940   if ((fpout = safe_fopen (certfile, "w+")) == NULL) {
941     fclose (fperr);
942     mutt_unlink (pk7out);
943     mutt_perror (certfile);
944     return NULL;
945   }
946
947   /* Step 2: Extract the certificates from a PKCS#7 structure.
948    */
949   if ((thepid = smime_invoke (NULL, NULL, NULL,
950                               -1, fileno (fpout), fileno (fperr),
951                               pk7out, NULL, NULL, NULL, NULL, NULL,
952                               SmimeGetCertCommand)) == -1) {
953     mutt_any_key_to_continue (_
954                               ("Error: unable to create OpenSSL subprocess!"));
955     fclose (fperr);
956     fclose (fpout);
957     mutt_unlink (pk7out);
958     mutt_unlink (certfile);
959     return NULL;
960   }
961
962   mutt_wait_filter (thepid);
963
964   mutt_unlink (pk7out);
965
966   fflush (fpout);
967   rewind (fpout);
968   rewind (fperr);
969   fflush (fperr);
970   empty = (fgetc (fpout) == EOF);
971   if (empty) {
972     mutt_copy_stream (fperr, stdout);
973     fclose (fpout);
974     fclose (fperr);
975     mutt_unlink (certfile);
976     return NULL;
977   }
978
979   fclose (fpout);
980   fclose (fperr);
981
982   return str_dup (certfile);
983 }
984
985 static char *smime_extract_signer_certificate (char *infile)
986 {
987   FILE *fpout = NULL, *fperr = NULL;
988   char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
989   char tmpfname[_POSIX_PATH_MAX];
990   pid_t thepid;
991   int empty;
992
993
994   mutt_mktemp (tmpfname);
995   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
996     mutt_perror (tmpfname);
997     return NULL;
998   }
999   mutt_unlink (tmpfname);
1000
1001
1002   mutt_mktemp (certfile);
1003   if ((fpout = safe_fopen (certfile, "w+")) == NULL) {
1004     fclose (fperr);
1005     mutt_perror (certfile);
1006     return NULL;
1007   }
1008
1009   /* Extract signer's certificate
1010    */
1011   if ((thepid = smime_invoke (NULL, NULL, NULL,
1012                               -1, -1, fileno (fperr),
1013                               infile, NULL, NULL, NULL, certfile, NULL,
1014                               SmimeGetSignerCertCommand)) == -1) {
1015     mutt_any_key_to_continue (_
1016                               ("Error: unable to create OpenSSL subprocess!"));
1017     fclose (fperr);
1018     fclose (fpout);
1019     mutt_unlink (pk7out);
1020     mutt_unlink (certfile);
1021     return NULL;
1022   }
1023
1024   mutt_wait_filter (thepid);
1025
1026   fflush (fpout);
1027   rewind (fpout);
1028   rewind (fperr);
1029   fflush (fperr);
1030   empty = (fgetc (fpout) == EOF);
1031   if (empty) {
1032     mutt_endwin (NULL);
1033     mutt_copy_stream (fperr, stdout);
1034     mutt_any_key_to_continue (NULL);
1035     fclose (fpout);
1036     fclose (fperr);
1037     mutt_unlink (certfile);
1038     return NULL;
1039   }
1040
1041   fclose (fpout);
1042   fclose (fperr);
1043
1044   return str_dup (certfile);
1045 }
1046
1047
1048
1049
1050 /* Add a certificate and update index file (externally). */
1051
1052 void smime_invoke_import (char *infile, char *mailbox)
1053 {
1054   char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
1055   FILE *smimein = NULL, *fpout = NULL, *fperr = NULL;
1056   pid_t thepid = -1;
1057
1058   mutt_mktemp (tmpfname);
1059   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
1060     mutt_perror (tmpfname);
1061     return;
1062   }
1063   mutt_unlink (tmpfname);
1064
1065   mutt_mktemp (tmpfname);
1066   if ((fpout = safe_fopen (tmpfname, "w+")) == NULL) {
1067     fclose (fperr);
1068     mutt_perror (tmpfname);
1069     return;
1070   }
1071   mutt_unlink (tmpfname);
1072
1073
1074   buf[0] = '\0';
1075   if (option (OPTASKCERTLABEL))
1076     mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
1077
1078   mutt_endwin (NULL);
1079   if ((certfile = smime_extract_certificate (infile))) {
1080     mutt_endwin (NULL);
1081
1082     if ((thepid = smime_invoke (&smimein, NULL, NULL,
1083                                 -1, fileno (fpout), fileno (fperr),
1084                                 certfile, NULL, NULL, NULL, NULL, NULL,
1085                                 SmimeImportCertCommand)) == -1) {
1086       mutt_message (_("Error: unable to create OpenSSL subprocess!"));
1087       return;
1088     }
1089     fputs (buf, smimein);
1090     fputc ('\n', smimein);
1091     fclose (smimein);
1092
1093     mutt_wait_filter (thepid);
1094
1095     mutt_unlink (certfile);
1096     p_delete(&certfile);
1097   }
1098
1099   fflush (fpout);
1100   rewind (fpout);
1101   fflush (fperr);
1102   rewind (fperr);
1103
1104   mutt_copy_stream (fpout, stdout);
1105   mutt_copy_stream (fperr, stdout);
1106
1107   fclose (fpout);
1108   fclose (fperr);
1109
1110 }
1111
1112
1113
1114 int smime_verify_sender (HEADER * h)
1115 {
1116   char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
1117   FILE *fpout;
1118   int retval = 1;
1119
1120   mutt_mktemp (tempfname);
1121   if (!(fpout = safe_fopen (tempfname, "w"))) {
1122     mutt_perror (tempfname);
1123     return 1;
1124   }
1125
1126   if (h->security & ENCRYPT)
1127     mutt_copy_message (fpout, Context, h,
1128                        M_CM_DECODE_CRYPT & M_CM_DECODE_SMIME,
1129                        CH_MIME | CH_WEED | CH_NONEWLINE);
1130   else
1131     mutt_copy_message (fpout, Context, h, 0, 0);
1132
1133   fflush (fpout);
1134   fclose (fpout);
1135
1136   if (h->env->from) {
1137     h->env->from = mutt_expand_aliases (h->env->from);
1138     mbox = h->env->from->mailbox;
1139   }
1140   else if (h->env->sender) {
1141     h->env->sender = mutt_expand_aliases (h->env->sender);
1142     mbox = h->env->sender->mailbox;
1143   }
1144
1145   if (mbox) {
1146     if ((certfile = smime_extract_signer_certificate (tempfname))) {
1147       mutt_unlink (tempfname);
1148       if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL)) {
1149         if (isendwin ())
1150           mutt_any_key_to_continue (NULL);
1151       }
1152       else
1153         retval = 0;
1154       mutt_unlink (certfile);
1155       p_delete(&certfile);
1156     }
1157     else
1158       mutt_any_key_to_continue (_("no certfile"));
1159   }
1160   else
1161     mutt_any_key_to_continue (_("no mbox"));
1162
1163   mutt_unlink (tempfname);
1164   return retval;
1165 }
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175 /*
1176  *    Creating S/MIME - bodies.
1177  */
1178
1179
1180
1181
1182 static
1183 pid_t smime_invoke_encrypt (FILE ** smimein, FILE ** smimeout,
1184                             FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1185                             int smimeerrfd, const char *fname,
1186                             const char *uids)
1187 {
1188   return smime_invoke (smimein, smimeout, smimeerr,
1189                        smimeinfd, smimeoutfd, smimeerrfd,
1190                        fname, NULL, SmimeCryptAlg, NULL, uids, NULL,
1191                        SmimeEncryptCommand);
1192 }
1193
1194
1195 static
1196 pid_t smime_invoke_sign (FILE ** smimein, FILE ** smimeout, FILE ** smimeerr,
1197                          int smimeinfd, int smimeoutfd, int smimeerrfd,
1198                          const char *fname)
1199 {
1200   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1201                        smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1202                        SmimeCertToUse, SmimeIntermediateToUse,
1203                        SmimeSignCommand);
1204 }
1205
1206
1207
1208
1209 BODY *smime_build_smime_entity (BODY * a, char *certlist)
1210 {
1211   char buf[LONG_STRING], certfile[LONG_STRING];
1212   char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1213   char smimeinfile[_POSIX_PATH_MAX];
1214   char *cert_start = certlist, *cert_end = certlist;
1215   FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
1216   BODY *t;
1217   int err = 0, empty;
1218   pid_t thepid;
1219
1220   mutt_mktemp (tempfile);
1221   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
1222     mutt_perror (tempfile);
1223     return (NULL);
1224   }
1225
1226   mutt_mktemp (smimeerrfile);
1227   if ((smimeerr = safe_fopen (smimeerrfile, "w+")) == NULL) {
1228     mutt_perror (smimeerrfile);
1229     fclose (fpout);
1230     mutt_unlink (tempfile);
1231     return NULL;
1232   }
1233   mutt_unlink (smimeerrfile);
1234
1235   mutt_mktemp (smimeinfile);
1236   if ((fptmp = safe_fopen (smimeinfile, "w+")) == NULL) {
1237     mutt_perror (smimeinfile);
1238     mutt_unlink (tempfile);
1239     fclose (fpout);
1240     fclose (smimeerr);
1241     return NULL;
1242   }
1243
1244   *certfile = '\0';
1245   while (1) {
1246     int off = str_len (certfile);
1247
1248     while (*++cert_end && *cert_end != '\n');
1249     if (!*cert_end)
1250       break;
1251     *cert_end = '\0';
1252     snprintf (certfile + off, sizeof (certfile) - off, " %s/%s",
1253               NONULL (SmimeCertificates), cert_start);
1254     *cert_end = '\n';
1255     cert_start = cert_end;
1256     cert_start++;
1257   }
1258
1259   /* write a MIME entity */
1260   mutt_write_mime_header (a, fptmp);
1261   fputc ('\n', fptmp);
1262   mutt_write_mime_body (a, fptmp);
1263   fclose (fptmp);
1264
1265   if ((thepid =
1266        smime_invoke_encrypt (&smimein, NULL, NULL, -1,
1267                              fileno (fpout), fileno (smimeerr),
1268                              smimeinfile, certfile)) == -1) {
1269     fclose (smimeerr);
1270     mutt_unlink (smimeinfile);
1271     mutt_unlink (certfile);
1272     return (NULL);
1273   }
1274
1275   fclose (smimein);
1276
1277   mutt_wait_filter (thepid);
1278   mutt_unlink (smimeinfile);
1279   mutt_unlink (certfile);
1280
1281   fflush (fpout);
1282   rewind (fpout);
1283   empty = (fgetc (fpout) == EOF);
1284   fclose (fpout);
1285
1286   fflush (smimeerr);
1287   rewind (smimeerr);
1288   while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL) {
1289     err = 1;
1290     fputs (buf, stdout);
1291   }
1292   fclose (smimeerr);
1293
1294   /* pause if there is any error output from SMIME */
1295   if (err)
1296     mutt_any_key_to_continue (NULL);
1297
1298   if (empty) {
1299     /* fatal error while trying to encrypt message */
1300     if (!err)
1301       mutt_any_key_to_continue _("No output from OpenSSL..");
1302
1303     mutt_unlink (tempfile);
1304     return (NULL);
1305   }
1306
1307   t = mutt_new_body ();
1308   t->type = TYPEAPPLICATION;
1309   t->subtype = str_dup ("x-pkcs7-mime");
1310   mutt_set_parameter ("name", "smime.p7m", &t->parameter);
1311   mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
1312   t->encoding = ENCBASE64;      /* The output of OpenSSL SHOULD be binary */
1313   t->use_disp = 1;
1314   t->disposition = DISPATTACH;
1315   t->d_filename = str_dup ("smime.p7m");
1316   t->filename = str_dup (tempfile);
1317   t->unlink = 1;                /*delete after sending the message */
1318   t->parts = 0;
1319   t->next = 0;
1320
1321   return (t);
1322 }
1323
1324
1325
1326
1327 BODY *smime_sign_message (BODY * a)
1328 {
1329   BODY *t;
1330   char buffer[LONG_STRING];
1331   char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
1332   FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
1333   int err = 0;
1334   int empty = 0;
1335   pid_t thepid;
1336   char *intermediates = smime_get_field_from_db (NULL, SmimeDefaultKey, 1, 1);
1337
1338   if (!intermediates) {
1339     mutt_message (_("Warning: Intermediate certificate not found."));
1340     intermediates = SmimeDefaultKey;    /* so openssl won't complain in any case */
1341   }
1342
1343   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
1344
1345   mutt_mktemp (filetosign);
1346   if ((sfp = safe_fopen (filetosign, "w+")) == NULL) {
1347     mutt_perror (filetosign);
1348     return NULL;
1349   }
1350
1351   mutt_mktemp (signedfile);
1352   if ((smimeout = safe_fopen (signedfile, "w+")) == NULL) {
1353     mutt_perror (signedfile);
1354     fclose (sfp);
1355     mutt_unlink (filetosign);
1356     return NULL;
1357   }
1358
1359   mutt_write_mime_header (a, sfp);
1360   fputc ('\n', sfp);
1361   mutt_write_mime_body (a, sfp);
1362   fclose (sfp);
1363
1364
1365
1366   snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
1367             NONULL (SmimeKeys), SmimeDefaultKey);
1368
1369   snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
1370             NONULL (SmimeCertificates), SmimeDefaultKey);
1371
1372   snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
1373             NONULL (SmimeCertificates), intermediates);
1374
1375
1376
1377   if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
1378                                    -1, fileno (smimeout), -1,
1379                                    filetosign)) == -1) {
1380     mutt_perror (_("Can't open OpenSSL subprocess!"));
1381
1382     fclose (smimeout);
1383     mutt_unlink (signedfile);
1384     mutt_unlink (filetosign);
1385     return NULL;
1386   }
1387   fputs (SmimePass, smimein);
1388   fputc ('\n', smimein);
1389   fclose (smimein);
1390
1391
1392   mutt_wait_filter (thepid);
1393
1394   /* check for errors from OpenSSL */
1395   err = 0;
1396   fflush (smimeerr);
1397   rewind (smimeerr);
1398   while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL) {
1399     err = 1;
1400     fputs (buffer, stdout);
1401   }
1402   fclose (smimeerr);
1403
1404
1405   fflush (smimeout);
1406   rewind (smimeout);
1407   empty = (fgetc (smimeout) == EOF);
1408   fclose (smimeout);
1409
1410   mutt_unlink (filetosign);
1411
1412
1413   if (err)
1414     mutt_any_key_to_continue (NULL);
1415
1416   if (empty) {
1417     mutt_any_key_to_continue _("No output from OpenSSL...");
1418
1419     mutt_unlink (signedfile);
1420     return (NULL);              /* fatal error while signing */
1421   }
1422
1423   t = mutt_new_body ();
1424   t->type = TYPEMULTIPART;
1425   t->subtype = str_dup ("signed");
1426   t->encoding = ENC7BIT;
1427   t->use_disp = 0;
1428   t->disposition = DISPINLINE;
1429
1430   mutt_generate_boundary (&t->parameter);
1431   /* check if this can be extracted from private key somehow.... */
1432   mutt_set_parameter ("micalg", "sha1", &t->parameter);
1433   mutt_set_parameter ("protocol", "application/x-pkcs7-signature",
1434                       &t->parameter);
1435
1436   t->parts = a;
1437   a = t;
1438
1439   t->parts->next = mutt_new_body ();
1440   t = t->parts->next;
1441   t->type = TYPEAPPLICATION;
1442   t->subtype = str_dup ("x-pkcs7-signature");
1443   t->filename = str_dup (signedfile);
1444   t->d_filename = str_dup ("smime.p7s");
1445   t->use_disp = 1;
1446   t->disposition = DISPATTACH;
1447   t->encoding = ENCBASE64;
1448   t->unlink = 1;                /* ok to remove this file after sending. */
1449
1450   return (a);
1451
1452 }
1453
1454
1455
1456
1457
1458
1459 /*
1460  *    Handling S/MIME - bodies.
1461  */
1462
1463
1464
1465
1466
1467
1468 static
1469 pid_t smime_invoke_verify (FILE ** smimein, FILE ** smimeout,
1470                            FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1471                            int smimeerrfd, const char *fname,
1472                            const char *sig_fname, int opaque)
1473 {
1474   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1475                        smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL,
1476                        (opaque ? SmimeVerifyOpaqueCommand :
1477                         SmimeVerifyCommand));
1478 }
1479
1480
1481 static
1482 pid_t smime_invoke_decrypt (FILE ** smimein, FILE ** smimeout,
1483                             FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1484                             int smimeerrfd, const char *fname)
1485 {
1486   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1487                        smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1488                        SmimeCertToUse, NULL, SmimeDecryptCommand);
1489 }
1490
1491
1492
1493 int smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1494 {
1495   char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1496   FILE *fp = NULL, *smimeout = NULL, *smimeerr = NULL;
1497   pid_t thepid;
1498   int badsig = -1;
1499
1500   long tmpoffset = 0;
1501   size_t tmplength = 0;
1502   int origType = sigbdy->type;
1503   char *savePrefix = NULL;
1504
1505
1506   snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
1507
1508   /* decode to a tempfile, saving the original destination */
1509   fp = s->fpout;
1510   if ((s->fpout = safe_fopen (signedfile, "w")) == NULL) {
1511     mutt_perror (signedfile);
1512     return -1;
1513   }
1514   /* decoding the attachment changes the size and offset, so save a copy
1515    * of the "real" values now, and restore them after processing
1516    */
1517   tmplength = sigbdy->length;
1518   tmpoffset = sigbdy->offset;
1519
1520   /* if we are decoding binary bodies, we don't want to prefix each
1521    * line with the prefix or else the data will get corrupted.
1522    */
1523   savePrefix = s->prefix;
1524   s->prefix = NULL;
1525
1526   mutt_decode_attachment (sigbdy, s);
1527
1528   sigbdy->length = ftello (s->fpout);
1529   sigbdy->offset = 0;
1530   fclose (s->fpout);
1531
1532   /* restore final destination and substitute the tempfile for input */
1533   s->fpout = fp;
1534   fp = s->fpin;
1535   s->fpin = fopen (signedfile, "r");
1536
1537   /* restore the prefix */
1538   s->prefix = savePrefix;
1539
1540   sigbdy->type = origType;
1541
1542
1543   mutt_mktemp (smimeerrfile);
1544   if (!(smimeerr = safe_fopen (smimeerrfile, "w+"))) {
1545     mutt_perror (smimeerrfile);
1546     mutt_unlink (signedfile);
1547     return -1;
1548   }
1549
1550   crypt_current_time (s, "OpenSSL");
1551
1552   if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
1553                                      -1, -1, fileno (smimeerr),
1554                                      tempfile, signedfile, 0)) != -1) {
1555     fflush (smimeout);
1556     fclose (smimeout);
1557
1558     if (mutt_wait_filter (thepid))
1559       badsig = -1;
1560     else {
1561       char *line = NULL;
1562       int lineno = 0;
1563       size_t linelen;
1564
1565       fflush (smimeerr);
1566       rewind (smimeerr);
1567
1568       line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1569       if (linelen && !str_casecmp (line, "verification successful"))
1570         badsig = 0;
1571
1572       p_delete(&line);
1573     }
1574   }
1575
1576   fflush (smimeerr);
1577   rewind (smimeerr);
1578   mutt_copy_stream (smimeerr, s->fpout);
1579   fclose (smimeerr);
1580
1581   state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1582
1583   mutt_unlink (signedfile);
1584   mutt_unlink (smimeerrfile);
1585
1586   sigbdy->length = tmplength;
1587   sigbdy->offset = tmpoffset;
1588
1589   /* restore the original source stream */
1590   fclose (s->fpin);
1591   s->fpin = fp;
1592
1593
1594   return badsig;
1595 }
1596
1597
1598
1599
1600
1601 /*
1602   This handles application/pkcs7-mime which can either be a signed
1603   or an encrypted message.
1604 */
1605
1606 static BODY *smime_handle_entity (BODY * m, STATE * s, FILE * outFile)
1607 {
1608   int len = 0;
1609   int c;
1610   long last_pos;
1611   char buf[HUGE_STRING];
1612   char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
1613   char tmpfname[_POSIX_PATH_MAX];
1614   char tmptmpfname[_POSIX_PATH_MAX];
1615   FILE *smimeout = NULL, *smimein = NULL, *smimeerr = NULL;
1616   FILE *tmpfp = NULL, *tmpfp_buffer = NULL, *fpout = NULL;
1617   struct stat info;
1618   BODY *p = NULL;
1619   pid_t thepid = -1;
1620   unsigned int type = mutt_is_application_smime (m);
1621
1622   if (!(type & APPLICATION_SMIME))
1623     return NULL;
1624
1625   mutt_mktemp (outfile);
1626   if ((smimeout = safe_fopen (outfile, "w+")) == NULL) {
1627     mutt_perror (outfile);
1628     return NULL;
1629   }
1630
1631   mutt_mktemp (errfile);
1632   if ((smimeerr = safe_fopen (errfile, "w+")) == NULL) {
1633     mutt_perror (errfile);
1634     fclose (smimeout);
1635     smimeout = NULL;
1636     return NULL;
1637   }
1638   mutt_unlink (errfile);
1639
1640
1641   mutt_mktemp (tmpfname);
1642   if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL) {
1643     mutt_perror (tmpfname);
1644     fclose (smimeout);
1645     smimeout = NULL;
1646     fclose (smimeerr);
1647     smimeerr = NULL;
1648     return NULL;
1649   }
1650
1651   fseeko (s->fpin, m->offset, 0);
1652   last_pos = m->offset;
1653
1654   mutt_copy_bytes (s->fpin, tmpfp, m->length);
1655
1656   fflush (tmpfp);
1657   fclose (tmpfp);
1658
1659   if ((type & ENCRYPT) &&
1660       (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
1661                                       fileno (smimeout), fileno (smimeerr),
1662                                       tmpfname)) == -1) {
1663     fclose (smimeout);
1664     smimeout = NULL;
1665     mutt_unlink (tmpfname);
1666     if (s->flags & M_DISPLAY)
1667       state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1668     return NULL;
1669   }
1670   else if ((type & SIGNOPAQUE) &&
1671            (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
1672                                           fileno (smimeout),
1673                                           fileno (smimeerr), NULL, tmpfname,
1674                                           SIGNOPAQUE)) == -1) {
1675     fclose (smimeout);
1676     smimeout = NULL;
1677     mutt_unlink (tmpfname);
1678     if (s->flags & M_DISPLAY)
1679       state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1680     return NULL;
1681   }
1682
1683
1684   if (type & ENCRYPT) {
1685     if (!smime_valid_passphrase ())
1686       smime_void_passphrase ();
1687     fputs (SmimePass, smimein);
1688     fputc ('\n', smimein);
1689   }
1690
1691   fclose (smimein);
1692
1693   mutt_wait_filter (thepid);
1694   mutt_unlink (tmpfname);
1695
1696
1697   if (s->flags & M_DISPLAY) {
1698     rewind (smimeerr);
1699
1700     if ((c = fgetc (smimeerr)) != EOF) {
1701       ungetc (c, smimeerr);
1702
1703       crypt_current_time (s, "OpenSSL");
1704       mutt_copy_stream (smimeerr, s->fpout);
1705       state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1706     }
1707
1708     if (type & ENCRYPT)
1709       state_attach_puts (_("[-- The following data is S/MIME"
1710                            " encrypted --]\n"), s);
1711     else
1712       state_attach_puts (_("[-- The following data is S/MIME signed --]\n"),
1713                          s);
1714   }
1715
1716   if (smimeout) {
1717     fflush (smimeout);
1718     rewind (smimeout);
1719
1720     if (outFile)
1721       fpout = outFile;
1722     else {
1723       mutt_mktemp (tmptmpfname);
1724       if ((fpout = safe_fopen (tmptmpfname, "w+")) == NULL) {
1725         mutt_perror (tmptmpfname);
1726         fclose (smimeout);
1727         smimeout = NULL;
1728         return NULL;
1729       }
1730     }
1731     while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL) {
1732       len = str_len (buf);
1733       if (len > 1 && buf[len - 2] == '\r') {
1734         buf[len - 2] = '\n';
1735         buf[len - 1] = '\0';
1736       }
1737       fputs (buf, fpout);
1738     }
1739     fflush (fpout);
1740     rewind (fpout);
1741
1742
1743     if ((p = mutt_read_mime_header (fpout, 0)) != NULL) {
1744       fstat (fileno (fpout), &info);
1745       p->length = info.st_size - p->offset;
1746
1747       mutt_parse_part (fpout, p);
1748       if (s->fpout) {
1749         rewind (fpout);
1750         tmpfp_buffer = s->fpin;
1751         s->fpin = fpout;
1752         mutt_body_handler (p, s);
1753         s->fpin = tmpfp_buffer;
1754       }
1755
1756     }
1757     fclose (smimeout);
1758     smimeout = NULL;
1759     mutt_unlink (outfile);
1760
1761     if (!outFile) {
1762       fclose (fpout);
1763       mutt_unlink (tmptmpfname);
1764     }
1765     fpout = NULL;
1766   }
1767
1768   if (s->flags & M_DISPLAY) {
1769     if (type & ENCRYPT)
1770       state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
1771     else
1772       state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
1773   }
1774
1775   if (type & SIGNOPAQUE) {
1776     char *line = NULL;
1777     int lineno = 0;
1778     size_t linelen;
1779
1780     rewind (smimeerr);
1781
1782     line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1783     if (linelen && !str_casecmp (line, "verification successful"))
1784       m->goodsig = 1;
1785     p_delete(&line);
1786   }
1787   else {
1788     m->goodsig = p->goodsig;
1789     m->badsig = p->badsig;
1790   }
1791   fclose (smimeerr);
1792
1793   return (p);
1794 }
1795
1796
1797
1798
1799
1800 int smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1801 {
1802
1803
1804   char tempfile[_POSIX_PATH_MAX];
1805   STATE s;
1806   long tmpoffset = b->offset;
1807   size_t tmplength = b->length;
1808   int origType = b->type;
1809   FILE *tmpfp = NULL;
1810   int rv = 0;
1811
1812   if (!mutt_is_application_smime (b))
1813     return -1;
1814
1815   if (b->parts)
1816     return -1;
1817
1818   memset (&s, 0, sizeof (s));
1819   s.fpin = fpin;
1820   fseeko (s.fpin, b->offset, 0);
1821
1822   mutt_mktemp (tempfile);
1823   if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL) {
1824     mutt_perror (tempfile);
1825     return (-1);
1826   }
1827
1828   mutt_unlink (tempfile);
1829   s.fpout = tmpfp;
1830   mutt_decode_attachment (b, &s);
1831   fflush (tmpfp);
1832   b->length = ftello (s.fpout);
1833   b->offset = 0;
1834   rewind (tmpfp);
1835   s.fpin = tmpfp;
1836   s.fpout = 0;
1837
1838   mutt_mktemp (tempfile);
1839   if ((*fpout = safe_fopen (tempfile, "w+")) == NULL) {
1840     mutt_perror (tempfile);
1841     rv = -1;
1842     goto bail;
1843   }
1844   mutt_unlink (tempfile);
1845
1846   if (!(*cur = smime_handle_entity (b, &s, *fpout))) {
1847     rv = -1;
1848     goto bail;
1849   }
1850
1851   (*cur)->goodsig = b->goodsig;
1852   (*cur)->badsig  = b->badsig;
1853
1854 bail:
1855   b->type = origType;
1856   b->length = tmplength;
1857   b->offset = tmpoffset;
1858
1859   safe_fclose (&tmpfp);
1860   if (*fpout)
1861     rewind (*fpout);
1862   return (rv);
1863 }
1864
1865
1866 int smime_application_smime_handler (BODY * m, STATE * s)
1867 {
1868   return smime_handle_entity (m, s, NULL) ? 0 : -1;
1869 }
1870
1871 int smime_send_menu (HEADER * msg, int *redraw)
1872 {
1873   char *p;
1874
1875   if (!(WithCrypto & APPLICATION_SMIME))
1876     return msg->security;
1877
1878   switch (mutt_multi_choice
1879           (_
1880            ("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? "),
1881            _("eswabfc"))) {
1882   case 1:                      /* (e)ncrypt */
1883     msg->security |= ENCRYPT;
1884     msg->security &= ~SIGN;
1885     break;
1886
1887   case 3:                      /* encrypt (w)ith */
1888     {
1889       int choice = 0;
1890       msg->security |= ENCRYPT;
1891
1892       do {
1893         /* I use "dra" because "123" is recognized anyway */
1894         switch (mutt_multi_choice (_("Choose algorithm family:"
1895                                      " 1: DES, 2: RC2, 3: AES,"
1896                                      " or (c)lear? "), _("drac"))) {
1897           case 1:
1898             switch (choice = mutt_multi_choice (_("1: DES, 2: Triple-DES "),
1899                                                 _("dt"))) {
1900               case 1:
1901                 str_replace (&SmimeCryptAlg, "des");
1902                 break;
1903               case 2:
1904                 str_replace (&SmimeCryptAlg, "des3");
1905                 break;
1906             }
1907             break;
1908
1909           case 2:
1910             switch (choice = mutt_multi_choice (_("1: RC2-40, 2: RC2-64, 3: RC2-128 "),
1911                                                 _("468"))) {
1912               case 1:
1913                 str_replace (&SmimeCryptAlg, "rc2-40");
1914                 break;
1915               case 2:
1916                 str_replace (&SmimeCryptAlg, "rc2-64");
1917                 break;
1918               case 3:
1919                 str_replace (&SmimeCryptAlg, "rc2-128");
1920                 break;
1921             }
1922             break;
1923
1924           case 3:
1925             switch (choice = mutt_multi_choice (_("1: AES128, 2: AES192, 3: AES256 "),
1926                                                 _("895"))) {
1927               case 1:
1928                 str_replace (&SmimeCryptAlg, "aes128");
1929                 break;
1930               case 2:
1931                 str_replace (&SmimeCryptAlg, "aes192");
1932                 break;
1933               case 3:
1934                 str_replace (&SmimeCryptAlg, "aes256");
1935                 break;
1936             }
1937             break;
1938
1939           case 4: /* (c)lear */
1940             p_delete(&SmimeCryptAlg);
1941             /* fallback */
1942           case -1: /* Ctrl-G or Enter */
1943             choice = 0;
1944             break;
1945         }
1946       } while (choice == -1);
1947     }
1948     break;
1949
1950   case 2:                      /* (s)ign */
1951
1952     if (!SmimeDefaultKey)
1953       mutt_message (_("Can't sign: No key specified. Use Sign As."));
1954
1955     else {
1956       msg->security |= SIGN;
1957       msg->security &= ~ENCRYPT;
1958     }
1959     break;
1960
1961   case 4:                      /* sign (a)s */
1962
1963     if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) {
1964       str_replace (&SmimeDefaultKey, p);
1965
1966       msg->security |= SIGN;
1967
1968       /* probably need a different passphrase */
1969       crypt_smime_void_passphrase ();
1970     }
1971 #if 0
1972     else
1973       msg->security &= ~SIGN;
1974 #endif
1975
1976     *redraw = REDRAW_FULL;
1977     break;
1978
1979   case 5:                      /* (b)oth */
1980     msg->security |= (ENCRYPT | SIGN);
1981     break;
1982
1983   case 6:                      /* (f)orget it */
1984   case 7:                      /* (c)lear */
1985     msg->security = 0;
1986     break;
1987   }
1988
1989   if (msg->security && msg->security != APPLICATION_SMIME)
1990     msg->security |= APPLICATION_SMIME;
1991   else
1992     msg->security = 0;
1993
1994   return (msg->security);
1995 }
1996
1997
1998 #endif /* CRYPT_BACKEND_CLASSIC_SMIME */