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