-/*
- * Copyright notice from original mutt:
- * Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org>
- * Copyright (C) 2002 Mike Schiraldi <raldi@research.netsol.com>
- * Copyright (C) 2004 g10 Code GmbH
- *
- * This file is part of mutt-ng, see http://www.muttng.org/.
- * It's licensed under the GNU General Public License,
- * please see the file GPL in the top level source directory.
- */
-
-#include <lib-lib/lib-lib.h>
-
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif
-
-#include <lib-mime/mime.h>
-#include <lib-sys/unix.h>
-
-#include <lib-ui/curses.h>
-#include <lib-ui/enter.h>
-#include <lib-ui/menu.h>
-
-#include "alias.h"
-#include "handler.h"
-#include "copy.h"
-#include "alias.h"
-
-#include "crypt.h"
-#include "smime.h"
-
-struct smime_command_context {
- const char *key; /* %k */
- const char *cryptalg; /* %a */
- const char *fname; /* %f */
- const char *sig_fname; /* %s */
- const char *certificates; /* %c */
- const char *intermediates; /* %i */
-};
-
-
-typedef struct {
- unsigned int hash;
- char suffix;
- char email[256];
- char nick[256];
- char trust; /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */
- short public; /* 1=public 0=private */
-} smime_id;
-
-
-char SmimePass[STRING];
-time_t SmimeExptime = 0; /* when does the cached passphrase expire? */
-
-
-static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };
-static char SmimeCertToUse[_POSIX_PATH_MAX];
-static char SmimeIntermediateToUse[_POSIX_PATH_MAX];
-
-
-/*
- * Create a format string to be used with scanf.
- * To use it, write, for instance, MUTT_FORMAT(HUGE_STRING).
- *
- * See K&R 2nd ed, p. 231 for an explanation.
- */
-#define _MUTT_FORMAT_2(a,b) "%" a b
-#define _MUTT_FORMAT_1(a, b) _MUTT_FORMAT_2(#a, b)
-#define MUTT_FORMAT(a) _MUTT_FORMAT_1(a, "s")
-
-
-/*
- * Queries and passphrase handling.
- */
-
-
-/* these are copies from pgp.c */
-
-
-void smime_void_passphrase (void)
-{
- p_clear(SmimePass, countof(SmimePass));
- SmimeExptime = 0;
-}
-
-int smime_valid_passphrase (void)
-{
- time_t now = time (NULL);
-
- if (now < SmimeExptime)
- /* Use cached copy. */
- return 1;
-
- smime_void_passphrase ();
-
- if (mutt_get_field_unbuffered (_("Enter S/MIME passphrase:"), SmimePass,
- sizeof (SmimePass), M_PASS) == 0) {
- SmimeExptime = time (NULL) + SmimeTimeout;
- return (1);
- }
- else
- SmimeExptime = 0;
-
- return 0;
-}
-
-
-/*
- * The OpenSSL interface
- */
-
-/* This is almost identical to ppgp's invoking interface. */
-
-static const char *
-_mutt_fmt_smime_command (char *dest, ssize_t destlen,
- char op, const char *src, const char *prefix,
- const char *ifstr, const char *elstr,
- anytype data, format_flag flags)
-{
- char fmt[16];
- struct smime_command_context *cctx = data.ptr;
- int optional = (flags & M_FORMAT_OPTIONAL);
-
- switch (op) {
- case 'C':
- {
- if (!optional) {
- char path[_POSIX_PATH_MAX];
- char buf1[LONG_STRING], buf2[LONG_STRING];
- struct stat sb;
-
- m_strcpy(path, sizeof(path), NONULL(SmimeCALocation));
- mutt_expand_path (path, sizeof (path));
- mutt_quote_filename (buf1, sizeof (buf1), path);
-
- if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode))
- snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1);
- else
- snprintf (buf2, sizeof (buf2), "-CApath %s", buf1);
-
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, buf2);
- }
- else if (!SmimeCALocation)
- optional = 0;
- break;
- }
-
- case 'c':
- { /* certificate (list) */
- if (!optional) {
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, NONULL (cctx->certificates));
- }
- else if (!cctx->certificates)
- optional = 0;
- break;
- }
-
- case 'i':
- { /* intermediate certificates */
- if (!optional) {
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, NONULL (cctx->intermediates));
- }
- else if (!cctx->intermediates)
- optional = 0;
- break;
- }
-
- case 's':
- { /* detached signature */
- if (!optional) {
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
- }
- else if (!cctx->sig_fname)
- optional = 0;
- break;
- }
-
- case 'k':
- { /* private key */
- if (!optional) {
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, NONULL (cctx->key));
- }
- else if (!cctx->key)
- optional = 0;
- break;
- }
-
- case 'a':
- { /* algorithm for encryption */
- if (!optional) {
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg));
- }
- else if (!cctx->key)
- optional = 0;
- break;
- }
-
- case 'f':
- { /* file to process */
- if (!optional) {
- snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
- snprintf (dest, destlen, fmt, NONULL (cctx->fname));
- }
- else if (!cctx->fname)
- optional = 0;
- break;
- }
-
- default:
- *dest = '\0';
- break;
- }
-
- if (flags & M_FORMAT_OPTIONAL)
- m_strformat(dest, destlen, 0, optional ? ifstr : elstr,
- _mutt_fmt_smime_command, data, 0);
-
- return src;
-}
-
-
-
-static void mutt_smime_command (char *d, ssize_t dlen,
- struct smime_command_context *cctx,
- const char *fmt)
-{
- m_strformat(d, dlen, 0, fmt, _mutt_fmt_smime_command, cctx, 0);
-}
-
-static pid_t smime_invoke (FILE ** smimein, FILE ** smimeout,
- FILE ** smimeerr, int smimeinfd, int smimeoutfd,
- int smimeerrfd, const char *fname,
- const char *sig_fname, const char *cryptalg,
- const char *key, const char *certificates,
- const char *intermediates, const char *format)
-{
- struct smime_command_context cctx;
- char cmd[HUGE_STRING];
-
- p_clear(&cctx, 1);
-
- if (!format || !*format)
- return (pid_t) - 1;
-
- cctx.fname = fname;
- cctx.sig_fname = sig_fname;
- cctx.key = key;
- cctx.cryptalg = cryptalg;
- cctx.certificates = certificates;
- cctx.intermediates = intermediates;
-
- mutt_smime_command (cmd, sizeof (cmd), &cctx, format);
-
- return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr,
- smimeinfd, smimeoutfd, smimeerrfd);
-}
-
-
-
-
-
-
-/*
- * Key and certificate handling.
- */
-
-
-
-/*
- Search the certificate index for given mailbox.
- return certificate file name.
-*/
-
-static void smime_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
-{
- smime_id *Table = (smime_id *) menu->data;
- smime_id this = Table[num];
- const char *truststate;
-
- switch (this.trust) {
- case 't':
- truststate = N_("Trusted ");
- break;
- case 'v':
- truststate = N_("Verified ");
- break;
- case 'u':
- truststate = N_("Unverified");
- break;
- case 'e':
- truststate = N_("Expired ");
- break;
- case 'r':
- truststate = N_("Revoked ");
- break;
- case 'i':
- truststate = N_("Invalid ");
- break;
- default:
- truststate = N_("Unknown ");
- }
- if (this.public)
- snprintf (s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix,
- truststate, this.email, this.nick);
- else
- snprintf (s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix,
- this.email, this.nick);
-}
-
-
-
-
-
-char *smime_ask_for_key (char *prompt, char *mailbox __attribute__((unused)),
- short public)
-{
- char *fname;
- smime_id *Table;
- long cert_num; /* Will contain the number of certificates.
- * To be able to get it, the .index file will be read twice... */
- char index_file[_POSIX_PATH_MAX];
- FILE *idx;
- char buf[LONG_STRING];
- char fields[5][STRING];
- int numFields, hash_suffix, done, cur; /* The current entry */
- MUTTMENU *menu;
- unsigned int hash;
- char helpstr[HUGE_STRING * 3];
- char qry[256];
- char title[256];
-
- if (!prompt)
- prompt = _("Enter keyID: ");
- snprintf (index_file, sizeof (index_file), "%s/.index",
- public ? NONULL (SmimeCertificates) : NONULL (SmimeKeys));
-
- idx = fopen (index_file, "r");
- if (idx == NULL) {
- mutt_perror (index_file);
- return NULL;
- }
- /* Count Lines */
- cert_num = 0;
- while (!feof (idx)) {
- if (fgets (buf, sizeof (buf), idx))
- cert_num++;
- }
- m_fclose(&idx);
-
- for (;;) {
- *qry = 0;
- if (mutt_get_field (prompt, qry, sizeof (qry), 0))
- return NULL;
- snprintf (title, sizeof (title),
- _("S/MIME certificates matching \"%s\"."), qry);
-
-
- idx = fopen (index_file, "r");
- if (idx == NULL) {
- mutt_perror (index_file);
- return NULL;
- }
- /* Read Entries */
- cur = 0;
- Table = p_new(smime_id, cert_num);
- while (!feof (idx)) {
- numFields =
- fscanf (idx, MUTT_FORMAT (STRING) " %x.%i " MUTT_FORMAT (STRING),
- fields[0], &hash, &hash_suffix, fields[2]);
- if (public)
- fscanf (idx, MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) "\n",
- fields[3], fields[4]);
-
- /* 0=email 1=name 2=nick 3=intermediate 4=trust */
- if (numFields < 2)
- continue;
-
- /* Check if query matches this certificate */
- if (!m_stristr(fields[0], qry) && !m_stristr(fields[2], qry))
- continue;
-
- Table[cur].hash = hash;
- Table[cur].suffix = hash_suffix;
- m_strcpy(Table[cur].email, sizeof(Table[cur].email), fields[0]);
- m_strcpy(Table[cur].nick, sizeof(Table[cur].nick), fields[2]);
- Table[cur].trust = *fields[4];
- Table[cur].public = public;
-
- cur++;
- }
- m_fclose(&idx);
-
- /* Make Helpstring */
- helpstr[0] = 0;
- mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT);
- m_strcat(helpstr, sizeof(helpstr), buf);
- mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME,
- OP_GENERIC_SELECT_ENTRY);
- m_strcat(helpstr, sizeof(helpstr), buf);
- mutt_make_help (buf, sizeof (buf), _("Help"), MENU_SMIME, OP_HELP);
- m_strcat(helpstr, sizeof(helpstr), buf);
-
- /* Create the menu */
- menu = mutt_new_menu ();
- menu->max = cur;
- menu->make_entry = smime_entry;
- menu->menu = MENU_SMIME;
- menu->help = helpstr;
- menu->data = Table;
- menu->title = title;
- /* sorting keys might be done later - TODO */
-
- mutt_clear_error ();
-
- done = 0;
- hash = 0;
- while (!done) {
- switch (mutt_menuLoop (menu)) {
- case OP_GENERIC_SELECT_ENTRY:
- cur = menu->current;
- hash = 1;
- done = 1;
- break;
- case OP_EXIT:
- hash = 0;
- done = 1;
- break;
- }
- }
- if (hash) {
- fname = p_new(char, 13); /* Hash + '.' + Suffix + \0 */
- sprintf (fname, "%.8x.%i", Table[cur].hash, Table[cur].suffix);
- }
- else
- fname = NULL;
-
- mutt_menuDestroy (&menu);
- p_delete(&Table);
- set_option (OPTNEEDREDRAW);
-
- if (fname)
- return fname;
- }
-}
-
-
-
-char *smime_get_field_from_db (char *mailbox, char *query, short public,
- short may_ask)
-{
- int addr_len, query_len, found = 0, ask = 0, choice = 0;
- char cert_path[_POSIX_PATH_MAX];
- char buf[LONG_STRING], prompt[STRING];
- char fields[5][STRING];
- char key[STRING];
- int numFields;
- struct stat info;
- char key_trust_level = 0;
- FILE *fp;
-
- if (!mailbox && !query)
- return (NULL);
-
- addr_len = mailbox ? m_strlen(mailbox) : 0;
- query_len = query ? m_strlen(query) : 0;
-
- *key = '\0';
-
- /* index-file format:
- mailbox certfile label issuer_certfile trust_flags\n
-
- certfile is a hash value generated by openssl.
- Note that this was done according to the OpenSSL
- specs on their CA-directory.
-
- */
- snprintf (cert_path, sizeof (cert_path), "%s/.index",
- (public ? NONULL (SmimeCertificates) : NONULL (SmimeKeys)));
-
- if (!stat (cert_path, &info)) {
- if ((fp = safe_fopen (cert_path, "r")) == NULL) {
- mutt_perror (cert_path);
- return (NULL);
- }
-
- while (fgets (buf, sizeof (buf) - 1, fp) != NULL)
- if (mailbox && !(m_strncasecmp(mailbox, buf, addr_len))) {
- numFields = sscanf (buf,
- MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
- MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
- MUTT_FORMAT (STRING) "\n",
- fields[0], fields[1],
- fields[2], fields[3], fields[4]);
- if (numFields < 2)
- continue;
- if (mailbox && public &&
- (!fields[4] ||
- *fields[4] == 'i' || *fields[4] == 'e' || *fields[4] == 'r'))
- continue;
-
- if (found) {
- if (public && *fields[4] == 'u')
- snprintf (prompt, sizeof (prompt),
- _
- ("ID %s is unverified. Do you want to use it for %s ?"),
- fields[1], mailbox);
- else if (public && *fields[4] == 'v')
- snprintf (prompt, sizeof (prompt),
- _("Use (untrusted!) ID %s for %s ?"),
- fields[1], mailbox);
- else
- snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"),
- fields[1], mailbox);
- if (may_ask == 0)
- choice = M_YES;
- if (may_ask && (choice = mutt_yesorno (prompt, M_NO)) == -1) {
- found = 0;
- ask = 0;
- *key = '\0';
- break;
- }
- else if (choice == M_NO) {
- ask = 1;
- continue;
- }
- else if (choice == M_YES) {
- m_strcpy(key, sizeof(key), fields[1]);
- ask = 0;
- break;
- }
- }
- else {
- if (public)
- key_trust_level = *fields[4];
- m_strcpy(key, sizeof(key), fields[1]);
- }
- found = 1;
- }
- else if (query) {
- numFields = sscanf (buf,
- MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
- MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
- MUTT_FORMAT (STRING) "\n",
- fields[0], fields[1],
- fields[2], fields[3], fields[4]);
-
- /* query = label: return certificate. */
- if (numFields >= 3 &&
- !(m_strncasecmp(query, fields[2], query_len))) {
- ask = 0;
- m_strcpy(key, sizeof(key), fields[1]);
- }
- /* query = certificate: return intermediate certificate. */
- else if (numFields >= 4 &&
- !(m_strncasecmp(query, fields[1], query_len))) {
- ask = 0;
- m_strcpy(key, sizeof(key), fields[3]);
- }
- }
-
- m_fclose(&fp);
-
- if (ask) {
- if (public && *fields[4] == 'u')
- snprintf (prompt, sizeof (prompt),
- _("ID %s is unverified. Do you want to use it for %s ?"),
- fields[1], mailbox);
- else if (public && *fields[4] == 'v')
- snprintf (prompt, sizeof (prompt),
- _("Use (untrusted!) ID %s for %s ?"), fields[1], mailbox);
- else
- snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"), key,
- mailbox);
- choice = mutt_yesorno (prompt, M_NO);
- if (choice == -1 || choice == M_NO)
- *key = '\0';
- }
- else if (key_trust_level && may_ask) {
- if (key_trust_level == 'u') {
- snprintf (prompt, sizeof (prompt),
- _("ID %s is unverified. Do you want to use it for %s ?"),
- key, mailbox);
- choice = mutt_yesorno (prompt, M_NO);
- if (choice != M_YES)
- *key = '\0';
- }
- else if (key_trust_level == 'v') {
- mutt_error (_
- ("Warning: You have not yet decided to trust ID %s. (any key to continue)"),
- key);
- mutt_sleep (5);
- }
- }
-
- }
-
- /* Note: m_strdup("") returns NULL. */
- return m_strdup(key);
-}
-
-/*
- This sets the '*ToUse' variables for an upcoming decryption, where
- the reuquired key is different from SmimeDefaultKey.
-*/
-static void _smime_getkeys (char *mailbox)
-{
- char *k = NULL;
- char buf[STRING];
-
- k = smime_get_field_from_db (mailbox, NULL, 0, 1);
-
- if (!k) {
- snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), mailbox);
- k = smime_ask_for_key (buf, mailbox, 0);
- }
-
- if (k) {
- /* the key used last time. */
- if (*SmimeKeyToUse &&
- !m_strcasecmp(k, SmimeKeyToUse + m_strlen(SmimeKeys) + 1)) {
- p_delete(&k);
- return;
- }
- else
- smime_void_passphrase ();
-
- snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
- NONULL (SmimeKeys), k);
-
- snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
- NONULL (SmimeCertificates), k);
-
- if (m_strcasecmp(k, SmimeDefaultKey))
- smime_void_passphrase ();
-
- p_delete(&k);
- return;
- }
-
- if (*SmimeKeyToUse) {
- if (!m_strcasecmp(SmimeDefaultKey,
- SmimeKeyToUse + m_strlen(SmimeKeys) + 1))
- return;
-
- smime_void_passphrase ();
- }
-
- snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
- NONULL (SmimeKeys), NONULL (SmimeDefaultKey));
-
- snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
- NONULL (SmimeCertificates), NONULL (SmimeDefaultKey));
-}
-
-void smime_getkeys (ENVELOPE * env)
-{
- address_t *t;
- int found = 0;
-
- if (option (OPTSDEFAULTDECRYPTKEY) && SmimeDefaultKey && *SmimeDefaultKey) {
- snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
- NONULL (SmimeKeys), SmimeDefaultKey);
-
- snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
- NONULL (SmimeCertificates), SmimeDefaultKey);
-
- return;
- }
-
- for (t = env->to; !found && t; t = t->next)
- if (mutt_addr_is_user (t)) {
- found = 1;
- _smime_getkeys (t->mailbox);
- }
- for (t = env->cc; !found && t; t = t->next)
- if (mutt_addr_is_user (t)) {
- found = 1;
- _smime_getkeys (t->mailbox);
- }
- if (!found && (t = mutt_default_from ())) {
- _smime_getkeys (t->mailbox);
- address_list_wipe(&t);
- }
-}
-
-/* This routine attempts to find the keyids of the recipients of a message.
- * It returns NULL if any of the keys can not be found.
- */
-
-char *smime_findKeys (address_t * to, address_t * cc, address_t * bcc)
-{
- char *keyID, *keylist = NULL;
- ssize_t keylist_size = 0;
- ssize_t keylist_used = 0;
- address_t *tmp = NULL, *addr = NULL;
- address_t **last = &tmp;
- address_t *p, *q;
- int i;
-
- for (i = 0; i < 3; i++) {
- switch (i) {
- case 0:
- p = to;
- break;
- case 1:
- p = cc;
- break;
- case 2:
- p = bcc;
- break;
- default:
- abort ();
- }
-
- *last = address_list_dup (p);
- while (*last)
- last = &((*last)->next);
- }
-
- rfc822_qualify(tmp, mutt_fqdn(1));
-
- address_list_uniq(tmp);
-
- for (p = tmp; p; p = p->next) {
- char buf[LONG_STRING];
-
- q = p;
-
- if ((keyID = smime_get_field_from_db (q->mailbox, NULL, 1, 1)) == NULL) {
- snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
- keyID = smime_ask_for_key (buf, q->mailbox, 1);
- }
- if (!keyID) {
- mutt_message (_("No (valid) certificate found for %s."), q->mailbox);
- p_delete(&keylist);
- address_list_wipe(&tmp);
- address_list_wipe(&addr);
- return NULL;
- }
-
- keylist_size += m_strlen(keyID) + 2;
- p_realloc(&keylist, keylist_size);
- sprintf (keylist + keylist_used, "%s\n", keyID);
- keylist_used = m_strlen(keylist);
-
- address_list_wipe(&addr);
-
- }
- address_list_wipe(&tmp);
- return (keylist);
-}
-
-
-
-
-
-
-static int smime_handle_cert_email (char *certificate, char *mailbox,
- int copy, char ***buffer, int *num)
-{
- FILE *fpout = NULL, *fperr = NULL;
- char tmpfname[_POSIX_PATH_MAX];
- char email[STRING];
- int ret = -1, count = 0;
- pid_t thepid;
-
- fperr = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fperr) {
- mutt_perror (tmpfname);
- return 1;
- }
- mutt_unlink (tmpfname);
-
- fpout = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- m_fclose(&fperr);
- mutt_perror (tmpfname);
- return 1;
- }
- mutt_unlink (tmpfname);
-
- if ((thepid = smime_invoke (NULL, NULL, NULL,
- -1, fileno (fpout), fileno (fperr),
- certificate, NULL, NULL, NULL, NULL, NULL,
- SmimeGetCertEmailCommand)) == -1) {
- mutt_message (_("Error: unable to create OpenSSL subprocess!"));
- m_fclose(&fperr);
- m_fclose(&fpout);
- return 1;
- }
-
- mutt_wait_filter (thepid);
-
- fflush (fpout);
- rewind (fpout);
- rewind (fperr);
- fflush (fperr);
-
-
- while ((fgets (email, sizeof (email), fpout))) {
- *(email + m_strlen(email) - 1) = '\0';
- if (m_strncasecmp(email, mailbox, m_strlen(mailbox)) == 0)
- ret = 1;
-
- ret = ret < 0 ? 0 : ret;
- count++;
- }
-
- if (ret == -1) {
- mutt_endwin (NULL);
- mutt_copy_stream (fperr, stdout);
- mutt_any_key_to_continue (_
- ("Error: unable to create OpenSSL subprocess!"));
- ret = 1;
- }
- else if (!ret)
- ret = 1;
- else
- ret = 0;
-
- if (copy && buffer && num) {
- (*num) = count;
- *buffer = p_new(char *, count);
- count = 0;
-
- rewind (fpout);
- while ((fgets (email, sizeof (email), fpout))) {
- *(email + m_strlen(email) - 1) = '\0';
- (*buffer)[count] = p_dupstr(email, m_strlen(email));
- count++;
- }
- }
- else if (copy)
- ret = 2;
-
- m_fclose(&fpout);
- m_fclose(&fperr);
-
- return ret;
-}
-
-
-
-static char *smime_extract_certificate (char *infile)
-{
- FILE *fpout = NULL, *fperr = NULL;
- char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
- char tmpfname[_POSIX_PATH_MAX];
- pid_t thepid;
- int empty;
-
-
- fperr = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fperr) {
- mutt_perror (tmpfname);
- return NULL;
- }
- mutt_unlink (tmpfname);
-
- fpout = m_tempfile (pk7out, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- m_fclose(&fperr);
- mutt_perror (pk7out);
- return NULL;
- }
-
- /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
- extract the full set of certificates directly.
- */
- if ((thepid = smime_invoke (NULL, NULL, NULL,
- -1, fileno (fpout), fileno (fperr),
- infile, NULL, NULL, NULL, NULL, NULL,
- SmimePk7outCommand)) == -1) {
- mutt_any_key_to_continue (_
- ("Error: unable to create OpenSSL subprocess!"));
- m_fclose(&fperr);
- m_fclose(&fpout);
- mutt_unlink (pk7out);
- return NULL;
- }
-
- mutt_wait_filter (thepid);
-
-
- fflush (fpout);
- rewind (fpout);
- rewind (fperr);
- fflush (fperr);
-
- empty = (fgetc (fpout) == EOF);
-
- m_fclose(&fpout);
-
- if (empty) {
- mutt_perror (pk7out);
- mutt_copy_stream (fperr, stdout);
- m_fclose(&fperr);
- mutt_unlink (pk7out);
- return NULL;
- }
-
- fpout = m_tempfile (certfile, sizeof(certfile), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- m_fclose(&fperr);
- mutt_unlink (pk7out);
- mutt_perror (certfile);
- return NULL;
- }
-
- /* Step 2: Extract the certificates from a PKCS#7 structure.
- */
- if ((thepid = smime_invoke (NULL, NULL, NULL,
- -1, fileno (fpout), fileno (fperr),
- pk7out, NULL, NULL, NULL, NULL, NULL,
- SmimeGetCertCommand)) == -1) {
- mutt_any_key_to_continue (_
- ("Error: unable to create OpenSSL subprocess!"));
- m_fclose(&fperr);
- m_fclose(&fpout);
- mutt_unlink (pk7out);
- mutt_unlink (certfile);
- return NULL;
- }
-
- mutt_wait_filter (thepid);
-
- mutt_unlink (pk7out);
-
- fflush (fpout);
- rewind (fpout);
- rewind (fperr);
- fflush (fperr);
- empty = (fgetc (fpout) == EOF);
- if (empty) {
- mutt_copy_stream (fperr, stdout);
- m_fclose(&fpout);
- m_fclose(&fperr);
- mutt_unlink (certfile);
- return NULL;
- }
-
- m_fclose(&fpout);
- m_fclose(&fperr);
-
- return m_strdup(certfile);
-}
-
-static char *smime_extract_signer_certificate (char *infile)
-{
- FILE *fpout = NULL, *fperr = NULL;
- char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
- char tmpfname[_POSIX_PATH_MAX];
- pid_t thepid;
- int empty;
-
- fperr = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fperr) {
- mutt_perror (tmpfname);
- return NULL;
- }
- mutt_unlink (tmpfname);
-
- m_tempfile (certfile, sizeof(certfile), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- m_fclose(&fperr);
- mutt_perror (certfile);
- return NULL;
- }
-
- /* Extract signer's certificate
- */
- if ((thepid = smime_invoke (NULL, NULL, NULL,
- -1, -1, fileno (fperr),
- infile, NULL, NULL, NULL, certfile, NULL,
- SmimeGetSignerCertCommand)) == -1) {
- mutt_any_key_to_continue (_
- ("Error: unable to create OpenSSL subprocess!"));
- m_fclose(&fperr);
- m_fclose(&fpout);
- mutt_unlink (pk7out);
- mutt_unlink (certfile);
- return NULL;
- }
-
- mutt_wait_filter (thepid);
-
- fflush (fpout);
- rewind (fpout);
- rewind (fperr);
- fflush (fperr);
- empty = (fgetc (fpout) == EOF);
- m_fclose(&fpout);
-
- if (empty) {
- mutt_endwin (NULL);
- mutt_copy_stream (fperr, stdout);
- mutt_any_key_to_continue (NULL);
- m_fclose(&fperr);
- mutt_unlink (certfile);
- return NULL;
- }
-
- m_fclose(&fperr);
-
- return m_strdup(certfile);
-}
-
-/* Add a certificate and update index file (externally). */
-
-void smime_invoke_import (char *infile, char *mailbox __attribute__ ((unused)))
-{
- char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
- FILE *smimein = NULL, *fpout = NULL, *fperr = NULL;
- pid_t thepid = -1;
-
- fperr = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fperr) {
- mutt_perror (tmpfname);
- return;
- }
- mutt_unlink (tmpfname);
-
- fpout = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- m_fclose(&fperr);
- mutt_perror (tmpfname);
- return;
- }
- mutt_unlink (tmpfname);
-
- buf[0] = '\0';
- if (option (OPTASKCERTLABEL))
- mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
-
- mutt_endwin (NULL);
- if ((certfile = smime_extract_certificate (infile))) {
- mutt_endwin (NULL);
-
- if ((thepid = smime_invoke (&smimein, NULL, NULL,
- -1, fileno (fpout), fileno (fperr),
- certfile, NULL, NULL, NULL, NULL, NULL,
- SmimeImportCertCommand)) == -1) {
- mutt_message (_("Error: unable to create OpenSSL subprocess!"));
- return;
- }
- fputs (buf, smimein);
- fputc ('\n', smimein);
- m_fclose(&smimein);
-
- mutt_wait_filter (thepid);
-
- mutt_unlink (certfile);
- p_delete(&certfile);
- }
-
- fflush (fpout);
- rewind (fpout);
- fflush (fperr);
- rewind (fperr);
-
- mutt_copy_stream (fpout, stdout);
- mutt_copy_stream (fperr, stdout);
-
- m_fclose(&fpout);
- m_fclose(&fperr);
-}
-
-int smime_verify_sender (HEADER * h)
-{
- char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
- FILE *fpout;
- int retval = 1;
-
- fpout = m_tempfile (tempfname, sizeof(tempfname), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- mutt_perror (_("Can't create temporary file"));
- return 1;
- }
-
- if (h->security & ENCRYPT)
- mutt_copy_message (fpout, Context, h,
- M_CM_DECODE_CRYPT & M_CM_DECODE_SMIME,
- CH_MIME | CH_WEED | CH_NONEWLINE);
- else
- mutt_copy_message (fpout, Context, h, 0, 0);
-
- fflush (fpout);
- m_fclose(&fpout);
-
- if (h->env->from) {
- h->env->from = mutt_expand_aliases (h->env->from);
- mbox = h->env->from->mailbox;
- }
- else if (h->env->sender) {
- h->env->sender = mutt_expand_aliases (h->env->sender);
- mbox = h->env->sender->mailbox;
- }
-
- if (mbox) {
- if ((certfile = smime_extract_signer_certificate (tempfname))) {
- mutt_unlink (tempfname);
- if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL)) {
- if (isendwin ())
- mutt_any_key_to_continue (NULL);
- }
- else
- retval = 0;
- mutt_unlink (certfile);
- p_delete(&certfile);
- }
- else
- mutt_any_key_to_continue (_("no certfile"));
- }
- else
- mutt_any_key_to_continue (_("no mbox"));
-
- mutt_unlink (tempfname);
- return retval;
-}
-
-
-
-
-
-
-
-
-
-/*
- * Creating S/MIME - bodies.
- */
-
-
-
-
-static
-pid_t smime_invoke_encrypt (FILE ** smimein, FILE ** smimeout,
- FILE ** smimeerr, int smimeinfd, int smimeoutfd,
- int smimeerrfd, const char *fname,
- const char *uids)
-{
- return smime_invoke (smimein, smimeout, smimeerr,
- smimeinfd, smimeoutfd, smimeerrfd,
- fname, NULL, SmimeCryptAlg, NULL, uids, NULL,
- SmimeEncryptCommand);
-}
-
-
-static
-pid_t smime_invoke_sign (FILE ** smimein, FILE ** smimeout, FILE ** smimeerr,
- int smimeinfd, int smimeoutfd, int smimeerrfd,
- const char *fname)
-{
- return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
- smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
- SmimeCertToUse, SmimeIntermediateToUse,
- SmimeSignCommand);
-}
-
-
-
-
-BODY *smime_build_smime_entity (BODY * a, char *certlist)
-{
- char buf[LONG_STRING], certfile[LONG_STRING];
- char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
- char smimeinfile[_POSIX_PATH_MAX];
- char *cert_start = certlist, *cert_end = certlist;
- FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
- BODY *t;
- int err = 0, empty;
- pid_t thepid;
-
- fpout = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- mutt_perror (_("Can't create temporary file"));
- return NULL;
- }
-
- smimeerr = m_tempfile (smimeerrfile, sizeof(smimeerrfile), NONULL(MCore.tmpdir), NULL);
- if (!smimeerr) {
- mutt_perror (smimeerrfile);
- m_fclose(&fpout);
- mutt_unlink (tempfile);
- return NULL;
- }
- mutt_unlink (smimeerrfile);
-
- fptmp = m_tempfile (smimeinfile, sizeof(smimeinfile), NONULL(MCore.tmpdir), NULL);
- if (!fptmp) {
- mutt_perror (smimeinfile);
- mutt_unlink (tempfile);
- m_fclose(&fpout);
- m_fclose(&smimeerr);
- return NULL;
- }
-
- *certfile = '\0';
- while (1) {
- int off = m_strlen(certfile);
-
- while (*++cert_end && *cert_end != '\n');
- if (!*cert_end)
- break;
- *cert_end = '\0';
- snprintf (certfile + off, sizeof (certfile) - off, " %s/%s",
- NONULL (SmimeCertificates), cert_start);
- *cert_end = '\n';
- cert_start = cert_end;
- cert_start++;
- }
-
- /* write a MIME entity */
- mutt_write_mime_header (a, fptmp);
- fputc ('\n', fptmp);
- mutt_write_mime_body (a, fptmp);
- m_fclose(&fptmp);
-
- if ((thepid =
- smime_invoke_encrypt (&smimein, NULL, NULL, -1,
- fileno (fpout), fileno (smimeerr),
- smimeinfile, certfile)) == -1) {
- m_fclose(&smimeerr);
- mutt_unlink (smimeinfile);
- mutt_unlink (certfile);
- return (NULL);
- }
-
- m_fclose(&smimein);
-
- mutt_wait_filter (thepid);
- mutt_unlink (smimeinfile);
- mutt_unlink (certfile);
-
- fflush (fpout);
- rewind (fpout);
- empty = (fgetc (fpout) == EOF);
- m_fclose(&fpout);
-
- fflush (smimeerr);
- rewind (smimeerr);
- while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL) {
- err = 1;
- fputs (buf, stdout);
- }
- m_fclose(&smimeerr);
-
- /* pause if there is any error output from SMIME */
- if (err)
- mutt_any_key_to_continue (NULL);
-
- if (empty) {
- /* fatal error while trying to encrypt message */
- if (!err)
- mutt_any_key_to_continue _("No output from OpenSSL..");
-
- mutt_unlink (tempfile);
- return (NULL);
- }
-
- t = body_new();
- t->type = TYPEAPPLICATION;
- t->subtype = m_strdup("x-pkcs7-mime");
- parameter_setval(&t->parameter, "name", "smime.p7m");
- parameter_setval(&t->parameter, "smime-type", "enveloped-data");
- t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
- t->use_disp = 1;
- t->disposition = DISPATTACH;
- t->d_filename = m_strdup("smime.p7m");
- t->filename = m_strdup(tempfile);
- t->unlink = 1; /*delete after sending the message */
- t->parts = 0;
- t->next = 0;
-
- return (t);
-}
-
-
-
-
-BODY *smime_sign_message (BODY * a)
-{
- BODY *t;
- char buffer[LONG_STRING];
- char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
- FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
- int err = 0;
- int empty = 0;
- pid_t thepid;
- char *intermediates = smime_get_field_from_db (NULL, SmimeDefaultKey, 1, 1);
-
- if (!intermediates) {
- mutt_message (_("Warning: Intermediate certificate not found."));
- intermediates = SmimeDefaultKey; /* so openssl won't complain in any case */
- }
-
- convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
-
- sfp = m_tempfile (filetosign, sizeof(filetosign), NONULL(MCore.tmpdir), NULL);
- if (!sfp) {
- mutt_perror (filetosign);
- return NULL;
- }
-
- smimeout = m_tempfile (signedfile, sizeof(signedfile), NONULL(MCore.tmpdir), NULL);
- if (!smimeout) {
- mutt_perror (signedfile);
- m_fclose(&sfp);
- mutt_unlink (filetosign);
- return NULL;
- }
-
- mutt_write_mime_header (a, sfp);
- fputc ('\n', sfp);
- mutt_write_mime_body (a, sfp);
- m_fclose(&sfp);
-
-
-
- snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
- NONULL (SmimeKeys), SmimeDefaultKey);
-
- snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
- NONULL (SmimeCertificates), SmimeDefaultKey);
-
- snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
- NONULL (SmimeCertificates), intermediates);
-
-
-
- if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
- -1, fileno (smimeout), -1,
- filetosign)) == -1) {
- mutt_perror (_("Can't open OpenSSL subprocess!"));
-
- m_fclose(&smimeout);
- mutt_unlink (signedfile);
- mutt_unlink (filetosign);
- return NULL;
- }
- fputs (SmimePass, smimein);
- fputc ('\n', smimein);
- m_fclose(&smimein);
-
-
- mutt_wait_filter (thepid);
-
- /* check for errors from OpenSSL */
- err = 0;
- fflush (smimeerr);
- rewind (smimeerr);
- while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL) {
- err = 1;
- fputs (buffer, stdout);
- }
- m_fclose(&smimeerr);
-
-
- fflush (smimeout);
- rewind (smimeout);
- empty = (fgetc (smimeout) == EOF);
- m_fclose(&smimeout);
-
- mutt_unlink (filetosign);
-
-
- if (err)
- mutt_any_key_to_continue (NULL);
-
- if (empty) {
- mutt_any_key_to_continue _("No output from OpenSSL...");
-
- mutt_unlink (signedfile);
- return (NULL); /* fatal error while signing */
- }
-
- t = body_new();
- t->type = TYPEMULTIPART;
- t->subtype = m_strdup("signed");
- t->encoding = ENC7BIT;
- t->use_disp = 0;
- t->disposition = DISPINLINE;
-
- parameter_set_boundary(&t->parameter);
- /* check if this can be extracted from private key somehow.... */
- parameter_setval(&t->parameter, "micalg", "sha1");
- parameter_setval(&t->parameter, "protocol",
- "application/x-pkcs7-signature");
-
- t->parts = a;
- a = t;
-
- t->parts->next = body_new();
- t = t->parts->next;
- t->type = TYPEAPPLICATION;
- t->subtype = m_strdup("x-pkcs7-signature");
- t->filename = m_strdup(signedfile);
- t->d_filename = m_strdup("smime.p7s");
- t->use_disp = 1;
- t->disposition = DISPATTACH;
- t->encoding = ENCBASE64;
- t->unlink = 1; /* ok to remove this file after sending. */
-
- return (a);
-
-}
-
-
-/*
- * Handling S/MIME - bodies.
- */
-
-
-static
-pid_t smime_invoke_verify (FILE ** smimein, FILE ** smimeout,
- FILE ** smimeerr, int smimeinfd, int smimeoutfd,
- int smimeerrfd, const char *fname,
- const char *sig_fname, int opaque)
-{
- return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
- smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL,
- (opaque ? SmimeVerifyOpaqueCommand :
- SmimeVerifyCommand));
-}
-
-
-static
-pid_t smime_invoke_decrypt (FILE ** smimein, FILE ** smimeout,
- FILE ** smimeerr, int smimeinfd, int smimeoutfd,
- int smimeerrfd, const char *fname)
-{
- return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
- smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
- SmimeCertToUse, NULL, SmimeDecryptCommand);
-}
-
-
-
-int smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
-{
- char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
- FILE *fp = NULL, *smimeout = NULL, *smimeerr = NULL;
- pid_t thepid;
- int badsig = -1;
-
- long tmpoffset = 0;
- ssize_t tmplength = 0;
- int origType = sigbdy->type;
- char *savePrefix = NULL;
-
-
- snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
-
- /* decode to a tempfile, saving the original destination */
- fp = s->fpout;
- if ((s->fpout = safe_fopen (signedfile, "w")) == NULL) {
- mutt_perror (signedfile);
- return -1;
- }
- /* decoding the attachment changes the size and offset, so save a copy
- * of the "real" values now, and restore them after processing
- */
- tmplength = sigbdy->length;
- tmpoffset = sigbdy->offset;
-
- /* if we are decoding binary bodies, we don't want to prefix each
- * line with the prefix or else the data will get corrupted.
- */
- savePrefix = s->prefix;
- s->prefix = NULL;
-
- mutt_decode_attachment (sigbdy, s);
-
- sigbdy->length = ftello (s->fpout);
- sigbdy->offset = 0;
- m_fclose(&s->fpout);
-
- /* restore final destination and substitute the tempfile for input */
- s->fpout = fp;
- fp = s->fpin;
- s->fpin = fopen (signedfile, "r");
-
- /* restore the prefix */
- s->prefix = savePrefix;
-
- sigbdy->type = origType;
-
- smimeerr = m_tempfile(smimeerrfile, sizeof(smimeerrfile), NONULL(MCore.tmpdir), NULL);
- if (!smimeerr) {
- mutt_perror (smimeerrfile);
- mutt_unlink (signedfile);
- return -1;
- }
-
- crypt_current_time (s, "OpenSSL");
-
- if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
- -1, -1, fileno (smimeerr),
- tempfile, signedfile, 0)) != -1) {
- m_fclose(&smimeout);
-
- if (mutt_wait_filter (thepid))
- badsig = -1;
- else {
- char *line = NULL;
- int lineno = 0;
- ssize_t linelen;
-
- fflush (smimeerr);
- rewind (smimeerr);
-
- line = mutt_read_line (line, &linelen, smimeerr, &lineno);
- if (linelen && !m_strcasecmp(line, "verification successful"))
- badsig = 0;
-
- p_delete(&line);
- }
- }
-
- fflush (smimeerr);
- rewind (smimeerr);
- mutt_copy_stream (smimeerr, s->fpout);
- m_fclose(&smimeerr);
-
- state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
-
- mutt_unlink (signedfile);
- mutt_unlink (smimeerrfile);
-
- sigbdy->length = tmplength;
- sigbdy->offset = tmpoffset;
-
- /* restore the original source stream */
- m_fclose(&s->fpin);
- s->fpin = fp;
-
-
- return badsig;
-}
-
-
-
-
-
-/*
- This handles application/pkcs7-mime which can either be a signed
- or an encrypted message.
-*/
-
-static BODY *smime_handle_entity (BODY * m, STATE * s, FILE * outFile)
-{
- int len = 0;
- int c;
- long last_pos;
- char buf[HUGE_STRING];
- char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
- char tmpfname[_POSIX_PATH_MAX];
- char tmptmpfname[_POSIX_PATH_MAX];
- FILE *smimeout = NULL, *smimein = NULL, *smimeerr = NULL;
- FILE *tmpfp = NULL, *tmpfp_buffer = NULL, *fpout = NULL;
- struct stat info;
- BODY *p = NULL;
- pid_t thepid = -1;
- unsigned int type = mutt_is_application_smime (m);
-
- if (!(type & APPLICATION_SMIME))
- return NULL;
-
- smimeout = m_tempfile (outfile, sizeof(outfile), NONULL(MCore.tmpdir), NULL);
- if (!smimeout) {
- mutt_perror (outfile);
- return NULL;
- }
-
- smimeerr = m_tempfile(errfile, sizeof(errfile), NONULL(MCore.tmpdir), NULL);
- if (!smimeerr) {
- mutt_perror (errfile);
- m_fclose(&smimeout);
- return NULL;
- }
- mutt_unlink (errfile);
-
- tmpfp = m_tempfile (tmpfname, sizeof(tmpfname), NONULL(MCore.tmpdir), NULL);
- if (!tmpfp) {
- mutt_perror (tmpfname);
- m_fclose(&smimeout);
- m_fclose(&smimeerr);
- return NULL;
- }
-
- fseeko (s->fpin, m->offset, 0);
- last_pos = m->offset;
-
- mutt_copy_bytes (s->fpin, tmpfp, m->length);
- m_fclose(&tmpfp);
-
- if ((type & ENCRYPT) &&
- (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
- fileno (smimeout), fileno (smimeerr),
- tmpfname)) == -1) {
- m_fclose(&smimeout);
- mutt_unlink (tmpfname);
- if (s->flags & M_DISPLAY)
- state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
- return NULL;
- }
- else if ((type & SIGNOPAQUE) &&
- (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
- fileno (smimeout),
- fileno (smimeerr), NULL, tmpfname,
- SIGNOPAQUE)) == -1) {
- m_fclose(&smimeout);
- mutt_unlink (tmpfname);
- if (s->flags & M_DISPLAY)
- state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
- return NULL;
- }
-
-
- if (type & ENCRYPT) {
- if (!smime_valid_passphrase ())
- smime_void_passphrase ();
- fputs (SmimePass, smimein);
- fputc ('\n', smimein);
- }
-
- m_fclose(&smimein);
-
- mutt_wait_filter (thepid);
- mutt_unlink (tmpfname);
-
-
- if (s->flags & M_DISPLAY) {
- rewind (smimeerr);
-
- if ((c = fgetc (smimeerr)) != EOF) {
- ungetc (c, smimeerr);
-
- crypt_current_time (s, "OpenSSL");
- mutt_copy_stream (smimeerr, s->fpout);
- state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
- }
-
- if (type & ENCRYPT)
- state_attach_puts (_("[-- The following data is S/MIME"
- " encrypted --]\n"), s);
- else
- state_attach_puts (_("[-- The following data is S/MIME signed --]\n"),
- s);
- }
-
- if (smimeout) {
- fflush (smimeout);
- rewind (smimeout);
-
- if (outFile)
- fpout = outFile;
- else {
- fpout = m_tempfile (tmptmpfname, sizeof(tmptmpfname), NONULL(MCore.tmpdir), NULL);
- if (!fpout) {
- mutt_perror (tmptmpfname);
- m_fclose(&smimeout);
- return NULL;
- }
- }
- while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL) {
- len = m_strlen(buf);
- if (len > 1 && buf[len - 2] == '\r') {
- buf[len - 2] = '\n';
- buf[len - 1] = '\0';
- }
- fputs (buf, fpout);
- }
- fflush (fpout);
- rewind (fpout);
-
-
- if ((p = mutt_read_mime_header (fpout, 0)) != NULL) {
- fstat (fileno (fpout), &info);
- p->length = info.st_size - p->offset;
-
- mutt_parse_part (fpout, p);
- if (s->fpout) {
- rewind (fpout);
- tmpfp_buffer = s->fpin;
- s->fpin = fpout;
- mutt_body_handler (p, s);
- s->fpin = tmpfp_buffer;
- }
-
- }
- m_fclose(&smimeout);
- mutt_unlink (outfile);
-
- if (!outFile) {
- m_fclose(&fpout);
- mutt_unlink (tmptmpfname);
- }
- fpout = NULL;
- }
-
- if (s->flags & M_DISPLAY) {
- if (type & ENCRYPT)
- state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
- else
- state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
- }
-
- if (type & SIGNOPAQUE) {
- char *line = NULL;
- int lineno = 0;
- ssize_t linelen;
-
- rewind (smimeerr);
-
- line = mutt_read_line (line, &linelen, smimeerr, &lineno);
- if (linelen && !m_strcasecmp(line, "verification successful"))
- m->goodsig = 1;
- p_delete(&line);
- }
- else {
- m->goodsig = p->goodsig;
- m->badsig = p->badsig;
- }
- m_fclose(&smimeerr);
-
- return (p);
-}
-
-
-
-
-
-int smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
-{
-
-
- char tempfile[_POSIX_PATH_MAX];
- STATE s;
- long tmpoffset = b->offset;
- ssize_t tmplength = b->length;
- int origType = b->type;
- FILE *tmpfp = NULL;
- int rv = 0;
-
- if (!mutt_is_application_smime (b))
- return -1;
-
- if (b->parts)
- return -1;
-
- p_clear(&s, 1);
- s.fpin = fpin;
- fseeko (s.fpin, b->offset, 0);
-
- tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
- if (!tmpfp) {
- mutt_perror (_("Can't create temporary file"));
- return (-1);
- }
-
- mutt_unlink (tempfile);
- s.fpout = tmpfp;
- mutt_decode_attachment (b, &s);
- fflush (tmpfp);
- b->length = ftello (s.fpout);
- b->offset = 0;
- rewind (tmpfp);
- s.fpin = tmpfp;
- s.fpout = 0;
-
- *fpout = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
- if (!*fpout) {
- mutt_perror (_("Can't create temporary file"));
- rv = -1;
- goto bail;
- }
- mutt_unlink (tempfile);
-
- if (!(*cur = smime_handle_entity (b, &s, *fpout))) {
- rv = -1;
- goto bail;
- }
-
- (*cur)->goodsig = b->goodsig;
- (*cur)->badsig = b->badsig;
-
-bail:
- b->type = origType;
- b->length = tmplength;
- b->offset = tmpoffset;
-
- m_fclose(&tmpfp);
- if (*fpout)
- rewind (*fpout);
- return (rv);
-}
-
-
-int smime_application_smime_handler (BODY * m, STATE * s)
-{
- return smime_handle_entity (m, s, NULL) ? 0 : -1;
-}
-
-int smime_send_menu (HEADER * msg, int *redraw)
-{
- char *p;
-
- switch (mutt_multi_choice
- (_("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? "),
- _("eswabfc"))) {
- case 1: /* (e)ncrypt */
- msg->security |= ENCRYPT;
- msg->security &= ~SIGN;
- break;
-
- case 3: /* encrypt (w)ith */
- {
- int choice = 0;
- msg->security |= ENCRYPT;
-
- do {
- /* I use "dra" because "123" is recognized anyway */
- switch (mutt_multi_choice (_("Choose algorithm family:"
- " 1: DES, 2: RC2, 3: AES,"
- " or (c)lear? "), _("drac"))) {
- case 1:
- switch (choice = mutt_multi_choice (_("1: DES, 2: Triple-DES "),
- _("dt"))) {
- case 1:
- m_strreplace(&SmimeCryptAlg, "des");
- break;
- case 2:
- m_strreplace(&SmimeCryptAlg, "des3");
- break;
- }
- break;
-
- case 2:
- switch (choice = mutt_multi_choice (_("1: RC2-40, 2: RC2-64, 3: RC2-128 "),
- _("468"))) {
- case 1:
- m_strreplace(&SmimeCryptAlg, "rc2-40");
- break;
- case 2:
- m_strreplace(&SmimeCryptAlg, "rc2-64");
- break;
- case 3:
- m_strreplace(&SmimeCryptAlg, "rc2-128");
- break;
- }
- break;
-
- case 3:
- switch (choice = mutt_multi_choice (_("1: AES128, 2: AES192, 3: AES256 "),
- _("895"))) {
- case 1:
- m_strreplace(&SmimeCryptAlg, "aes128");
- break;
- case 2:
- m_strreplace(&SmimeCryptAlg, "aes192");
- break;
- case 3:
- m_strreplace(&SmimeCryptAlg, "aes256");
- break;
- }
- break;
-
- case 4: /* (c)lear */
- p_delete(&SmimeCryptAlg);
- /* fallback */
- case -1: /* Ctrl-G or Enter */
- choice = 0;
- break;
- }
- } while (choice == -1);
- }
- break;
-
- case 2: /* (s)ign */
-
- if (!SmimeDefaultKey)
- mutt_message (_("Can't sign: No key specified. Use Sign As."));
-
- else {
- msg->security |= SIGN;
- msg->security &= ~ENCRYPT;
- }
- break;
-
- case 4: /* sign (a)s */
-
- if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) {
- m_strreplace(&SmimeDefaultKey, p);
-
- msg->security |= SIGN;
-
- /* probably need a different passphrase */
- crypt_smime_void_passphrase ();
- }
-
- *redraw = REDRAW_FULL;
- break;
-
- case 5: /* (b)oth */
- msg->security |= (ENCRYPT | SIGN);
- break;
-
- case 6: /* (f)orget it */
- case 7: /* (c)lear */
- msg->security = 0;
- break;
- }
-
- if (msg->security && msg->security != APPLICATION_SMIME)
- msg->security |= APPLICATION_SMIME;
- else
- msg->security = 0;
-
- return (msg->security);
-}