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