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