#include <lib-lib/lib-lib.h>
-#ifdef CRYPT_BACKEND_GPGME
-
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#ifdef HAVE_LANGINFO_D_T_FMT
-# include <langinfo.h>
-#endif
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif
-
#include <gpgme.h>
#include <lib-mime/mime.h>
-
#include <lib-ui/curses.h>
#include <lib-ui/enter.h>
#include <lib-ui/menu.h>
+#include "crypt.h"
+
#include "lib.h"
#include "alias.h"
-#include <lib-crypt/crypt.h>
#include "handler.h"
#include "copy.h"
#include "pager.h"
#include "recvattach.h"
#include "sort.h"
-#include "crypt-gpgme.h"
-
-/*
- * Helper macros.
- */
-#define digitp(p) (*(p) >= '0' && *(p) <= '9')
-#define hexdigitp(a) (digitp (a) \
- || (*(a) >= 'A' && *(a) <= 'F') \
- || (*(a) >= 'a' && *(a) <= 'f'))
-#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
- *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
-#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
/* Values used for comparing addresses. */
#define CRYPT_KV_VALID 1
static struct crypt_cache *id_defaults = NULL;
static gpgme_key_t signature_key = NULL;
+/* Show a message that a backend will be invoked. */
+void crypt_invoke_message (int type)
+{
+ if (type & APPLICATION_PGP) {
+ mutt_message _("Invoking PGP...");
+ }
+ else if (type & APPLICATION_SMIME) {
+ mutt_message _("Invoking S/MIME...");
+ }
+}
+
/*
* General helper functions.
*/
char *tstr;
tstr = p_dupstr(buf, len);
- mutt_convert_string (&tstr, "utf-8", Charset, M_ICONV_HOOK_FROM);
+ mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
fputs (tstr, fp);
p_delete(&tstr);
}
int err = 0;
gpgme_data_t data;
- fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fptmp) {
mutt_perror (_("Can't create temporary file"));
return NULL;
FILE *fp;
ssize_t nread = 0;
- fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fp) {
mutt_perror (_("Can't create temporary file"));
return NULL;
}
+/* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
+static gpgme_error_t
+gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
+ int secret)
+{
+ gpgme_ctx_t listctx;
+ gpgme_error_t err;
+
+ if (!ctx || !r_key || !fpr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (strlen (fpr) < 8) /* We have at least a key ID. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* FIXME: We use our own context because we have to avoid the user's
+ I/O callback handlers. */
+ err = gpgme_new (&listctx);
+ if (err)
+ return err;
+ gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
+ err = gpgme_op_keylist_start (listctx, fpr, secret);
+ if (!err)
+ err = gpgme_op_keylist_next (listctx, r_key);
+ gpgme_release (listctx);
+ return err;
+}
+
/* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
The keys must be space delimited. */
static gpgme_key_t *create_recipient_set (const char *keylist,
key. */
buf[i - 1] = 0;
- err = gpgme_get_key (context, buf, &key, 0);
+ err = gpgme_get_key2 (context, buf, &key, 0);
if (!err)
key->uids->validity = GPGME_VALIDITY_FULL;
buf[i - 1] = '!';
}
else
- err = gpgme_get_key (context, buf, &key, 0);
+ err = gpgme_get_key2 (context, buf, &key, 0);
if (!err) {
p_realloc(&rset, rset_n + 1);
state_attach_puts (p, s);
}
-/*
- * Implementation of `sign_message'.
- */
+/* Implementation of `sign_message'. */
/* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
USE_SMIME is passed as true. Returns the new body or NULL on
}
-BODY *pgp_gpgme_sign_message (BODY * a)
+BODY *crypt_pgp_sign_message (BODY * a)
{
return sign_message (a, 0);
}
-BODY *smime_gpgme_sign_message (BODY * a)
+BODY *crypt_smime_sign_message (BODY * a)
{
return sign_message (a, 1);
}
/* Encrypt the mail body A to all keys given as space separated keyids
or fingerprints in KEYLIST and return the encrypted body. */
-BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
+BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
{
char *outfile = NULL;
BODY *t;
/* Encrypt the mail body A to all keys given as space separated
fingerprints in KEYLIST and return the S/MIME encrypted body. */
-BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
+BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
{
char *outfile = NULL;
BODY *t;
}
-/*
- * Implementation of `verify_one'.
- */
+/* Implementation of `verify_one'. */
/* Display the common attributes of the signature summary SUM.
Return 1 if there is is a severe warning.
/* Show information about one signature. This fucntion is called with
the context CTX of a sucessful verification operation and the
enumerator IDX which should start at 0 and incremete for each
- call/signature.
+ call/signature.
Return values are: 0 for normal procession, 1 for a bad signature,
2 for a signature with a warning or -1 for no more signature. */
if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
anybad = 1;
- err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */
+ err = gpgme_get_key2 (ctx, fpr, &key, 0); /* secret key? */
if (!err) {
uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
if (!signature_key)
return badsig ? 1 : anywarn ? 2 : 0;
}
-int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
+int crypt_pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
{
return verify_one (sigbdy, s, tempfile, 0);
}
-int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
+int crypt_smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
{
return verify_one (sigbdy, s, tempfile, 1);
}
/* Decrypt a PGP/MIME message in FPIN and B and return a new body and
the stream in CUR and FPOUT. Returns 0 on success. */
-int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
+int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
{
char tempfile[_POSIX_PATH_MAX];
STATE s;
p_clear(&s, 1);
s.fpin = fpin;
- *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!*fpout) {
mutt_perror (_("Can't create temporary file"));
return -1;
/* Decrypt a S/MIME message in FPIN and B and return a new body and
the stream in CUR and FPOUT. Returns 0 on success. */
-int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
+int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
BODY ** cur)
{
char tempfile[_POSIX_PATH_MAX];
p_clear(&s, 1);
s.fpin = fpin;
fseeko (s.fpin, b->offset, 0);
- tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!tmpfp) {
mutt_perror (_("Can't create temporary file"));
return -1;
p_clear(&s, 1);
s.fpin = tmpfp;
s.fpout = 0;
- *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!*fpout) {
mutt_perror (_("Can't create temporary file"));
return -1;
p_clear(&s, 1);
s.fpin = *fpout;
fseeko (s.fpin, bb->offset, 0);
- tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!tmpfp) {
mutt_perror (_("Can't create temporary file"));
return -1;
p_clear(&s, 1);
s.fpin = tmpfp;
s.fpout = 0;
- *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!*fpout) {
mutt_perror (_("Can't create temporary file"));
return -1;
}
-/*
+/*
* Implementation of `pgp_check_traditional'.
*/
char tempfile[_POSIX_PATH_MAX];
char buf[HUGE_STRING];
FILE *tfp;
+ int tempfd;
short sgn = 0;
short enc = 0;
if (tagged_only && !b->tagged)
return 0;
- mutt_mktemp (tempfile);
- if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
+ tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+ if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
unlink (tempfile);
return 0;
}
- if ((tfp = fopen (tempfile, "r")) == NULL) {
+ if ((tfp = fopen(tempfile, "r")) == NULL) {
unlink (tempfile);
return 0;
}
return 1;
}
-int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
+int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
{
int rv = 0;
int r;
for (; b; b = b->next) {
if (is_multipart (b))
- rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
+ rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
else if (b->type == TYPETEXT) {
if ((r = mutt_is_application_pgp (b)))
rv = (rv || r);
}
-/*
- * Implementation of `application_handler'.
- */
+/* Implementation of `application_handler'. */
-/*
+/*
Copy a clearsigned message, and strip the signature and PGP's
dash-escaping.
-
+
XXX - charset handling: We assume that it is safe to do
character set decoding first, dash decoding second here, while
we do it the other way around in the main handler.
-
+
(Note that we aren't worse than Outlook & Cie in this, and also
note that we can successfully handle anything produced by any
existing versions of mutt.) */
unlink (fname);
p_delete(&fname);
- fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
+ fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
for (complete = 1, armor_header = 1;
fgetconvs (buf, sizeof (buf), fc) != NULL;
/* Support for classic_application/pgp */
-int pgp_gpgme_application_handler (BODY * m, STATE * s)
+int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
{
int needpass = -1, pgp_keyblock = 0;
int clearsign = 0;
/*
* Now, copy cleartext to the screen. NOTE - we expect that PGP
- * outputs utf-8 cleartext. This may not always be true, but it
+ * outputs utf-8 cleartext. This may not always be true, but it
* seems to be a reasonable guess.
*/
int c;
rewind (pgpout);
- fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
+ fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
while ((c = fgetconv (fc)) != EOF) {
state_putc (c, s);
if (c == '\n' && s->prefix)
return (err);
}
-/*
- * Implementation of `encrypted_handler'.
- */
+/* Implementation of `encrypted_handler'. */
/* MIME handler for pgp/mime encrypted messages. */
-int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
+int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
{
char tempfile[_POSIX_PATH_MAX];
FILE *fpout;
/* Move forward to the application/pgp-encrypted body. */
a = a->next;
- fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fpout) {
if (s->flags & M_DISPLAY)
state_attach_puts (_("[-- Error: could not create temporary file! "
s->fpin = savefp;
}
- /*
+ /*
* if a multipart/signed is the _only_ sub-part of a
* multipart/encrypted, cache signature verification
* status.
}
/* Support for application/smime */
-int smime_gpgme_application_handler (BODY * a, STATE * s)
+int crypt_smime_application_smime_handler (BODY * a, STATE * s)
{
char tempfile[_POSIX_PATH_MAX];
FILE *fpout;
int rc = 0;
a->warnsig = 0;
- fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fpout) {
if (s->flags & M_DISPLAY)
state_attach_puts (_("[-- Error: could not create temporary file! "
s->fpin = savefp;
}
- /*
+ /*
* if a multipart/signed is the _only_ sub-part of a
* multipart/encrypted, cache signature verification
* status.
/*
* Format an entry on the CRYPT key selection menu.
- *
+ *
* %n number
* %k key id %K key id of the principal key
* %u user id
if (*string == '#') { /* hexstring */
string++;
- for (s = string; hexdigitp (s); s++)
+ for (s = string; hexval(*s) >= 0; s++)
s++;
n = s - string;
if (!n || (n & 1))
p = p_new(unsigned char, n + 1);
array->value = (char *) p;
for (s1 = string; n; s1 += 2, n--)
- *p++ = xtoi_2 (s1);
+ *p++ = (hexval(*s1) << 8) | hexval(*s1);
*p = 0;
}
else { /* regular v3 quoted string */
|| *s == '<' || *s == '>' || *s == '#' || *s == ';'
|| *s == '\\' || *s == '\"' || *s == ' ')
n++;
- else if (hexdigitp (s) && hexdigitp (s + 1)) {
+ else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
s++;
n++;
}
for (s = string; n; s++, n--) {
if (*s == '\\') {
s++;
- if (hexdigitp (s)) {
- *p++ = xtoi_2 (s);
+ if (hexval(*s) >= 0) {
+ *p++ = (hexval(*s) << 8) | hexval(*s + 1);
s++;
}
else
gpgme_key_t k = NULL;
int maxdepth = 100;
- fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(Tempdir), NULL);
+ fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
if (!fp) {
mutt_perror (_("Can't create temporary file"));
return;
mutt_do_pager (cmd, tempfile, 0, NULL);
}
-/*
- * Implementation of `findkeys'.
- */
-
+/* Implementation of `findkeys'. */
/* Convert string_list_t into a pattern string suitable to be passed to GPGME.
We need to convert spaces in an item into a '+' and '%' into
if (key_check_cap (key, KEY_CAP_CAN_SIGN))
flags |= KEYFLAG_CANSIGN;
-#if 0 /* DISABLED code */
- if (!flags) {
- /* Bug in gpg. Capabilities are not listed for secret
- keys. Try to deduce them from the algorithm. */
-
- switch (key->subkeys[0].pubkey_algo) {
- case GPGME_PK_RSA:
- flags |= KEYFLAG_CANENCRYPT;
- flags |= KEYFLAG_CANSIGN;
- break;
- case GPGME_PK_ELG_E:
- flags |= KEYFLAG_CANENCRYPT;
- break;
- case GPGME_PK_DSA:
- flags |= KEYFLAG_CANSIGN;
- break;
- }
- }
-#endif /* DISABLED code */
-
for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
k = p_new(crypt_key_t, 1);
k->kobj = key;
if (matches) {
if (the_valid_key && !multi && !weak
&& !(invalid && option (OPTPGPSHOWUNUSABLE))) {
- /*
+ /*
* There was precisely one strong match on a valid ID, there
* were no valid keys with weak matches, and we aren't
* interested in seeing invalid keys.
- *
+ *
* Proceed without asking the user.
*/
k = crypt_copy_key (the_valid_key);
}
else {
- /*
+ /*
* Else: Ask the user.
*/
k = crypt_select_key (matches, a, NULL, app, forced_valid);
return (keylist);
}
-char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
+char *crypt_pgp_findkeys (address_t * to, address_t * cc, address_t * bcc)
{
return find_keys (to, cc, bcc, APPLICATION_PGP);
}
-char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
+char *crypt_smime_findkeys (address_t * to, address_t * cc, address_t * bcc)
{
return find_keys (to, cc, bcc, APPLICATION_SMIME);
}
-/*
- * Implementation of `init'.
- */
-
-/* Initialization. */
-static void init_gpgme (void)
-{
- /* Make sure that gpg-agent is running. */
- if (!getenv ("GPG_AGENT_INFO")) {
- mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
- if (mutt_any_key_to_continue (NULL) == -1)
- mutt_exit (1);
- }
-}
-
-void pgp_gpgme_init (void)
-{
- init_gpgme ();
-}
-
-void smime_gpgme_init (void)
-{
-}
-
static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
{
crypt_key_t *p;
return (msg->security);
}
-int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
+int crypt_pgp_send_menu(HEADER * msg, int *redraw)
{
- return gpgme_send_menu (msg, redraw, 0);
+ return gpgme_send_menu(msg, redraw, 0);
}
-int smime_gpgme_send_menu (HEADER * msg, int *redraw)
+int crypt_smime_send_menu(HEADER * msg, int *redraw)
{
return gpgme_send_menu (msg, redraw, 1);
}
-static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
+int crypt_smime_verify_sender (HEADER * h)
{
address_t *sender = NULL;
unsigned int ret = 1;
return ret;
}
-int smime_gpgme_verify_sender (HEADER * h)
+void crypt_invoke_import(FILE *stream, int smime)
+{
+ gpgme_ctx_t ctx = create_gpgme_context(smime);
+ gpgme_data_t data;
+ gpgme_error_t err;
+
+ err = gpgme_data_new_from_stream(&data, stream);
+ if (err) {
+ mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
+ gpgme_release(ctx);
+ return;
+ }
+
+ err = gpgme_op_import(ctx, data);
+ if (err) {
+ mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
+ gpgme_data_release(data);
+ gpgme_release(ctx);
+ return;
+ }
+
+ gpgme_data_release(data);
+ gpgme_release(ctx);
+ return;
+}
+
+static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
+{
+ STATE s;
+ FILE *tmpfp = tmpfile();
+
+ if (tmpfp == NULL) {
+ mutt_perror (_("Can't create temporary file"));
+ return;
+ }
+
+ p_clear(&s, 1);
+ s.fpin = fp;
+ s.fpout = tmpfp;
+ mutt_body_handler(top, &s);
+
+ rewind(tmpfp);
+ crypt_invoke_import(tmpfp, 0);
+ m_fclose(&tmpfp);
+}
+
+void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
+{
+ mutt_endwin (NULL);
+ set_option (OPTDONTHANDLEPGPKEYS);
+
+ for (; top; top = top->next) {
+ if (!tag || top->tagged)
+ pgp_extract_keys_from_attachment (fp, top);
+
+ if (!tag)
+ break;
+ }
+
+ unset_option (OPTDONTHANDLEPGPKEYS);
+}
+
+
+/* TODO */
+
+/* fixme: needs documentation. */
+void crypt_pgp_invoke_getkeys (address_t * addr)
+{
+}
+
+/* Generate a PGP public key attachment. */
+BODY *crypt_pgp_make_key_attachment (char *tempf)
+{
+ return NULL;
+}
+
+/* S/MIME */
+
+/* fixme: Needs documentation. */
+void crypt_smime_getkeys (ENVELOPE * env)
{
- return verify_sender (h, GPGME_PROTOCOL_CMS);
}
-#endif