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