Merge branch 'pr-1111'

Fix a bunch of conflicts, tests.
This commit is contained in:
djcb
2018-08-18 10:29:40 +03:00
9 changed files with 147 additions and 323 deletions

View File

@ -1,5 +1,5 @@
/*
** Copyright (C) 2012-2016 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** Copyright (C) 2012-2018 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
@ -31,150 +31,6 @@
#include <gmime/gmime.h>
#include <gmime/gmime-multipart-signed.h>
#define CALLBACK_DATA "callback-data"
struct _CallbackData {
MuMsgPartPasswordFunc pw_func;
gpointer user_data;
};
typedef struct _CallbackData CallbackData;
static gboolean
password_requester (GMimeCryptoContext *ctx, const char *user_id,
const char* prompt_ctx, gboolean reprompt,
GMimeStream *response, GError **err)
{
CallbackData *cbdata;
gchar *password;
ssize_t written;
cbdata = g_object_get_data (G_OBJECT(ctx), CALLBACK_DATA);
if (!cbdata || !cbdata->pw_func)
return FALSE;
password = cbdata->pw_func (user_id, prompt_ctx, reprompt,
cbdata->user_data);
if (!password) {
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
"failed to get password");
return FALSE;
}
written = g_mime_stream_write_string (response, password);
if (written != -1)
written = g_mime_stream_write_string (response, "\n");
if (written == -1)
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
"writing password to mime stream failed");
/* it seems that GMime tries to flush the fd; however, this
* does not work for pipes/sockets, causing getting a password
* to fail.
*
* I have reported this, and it has been fixed now:
*
* http://git.gnome.org/browse/gmime/commit/
* ?id=bda4834d3d9a1fbefb6d97edfef2bc1da9357f58
*
* however, it may take a while before everybody has this
* version of GMime (ie. version > 2.6.10)
*
*/
memset (password, 0, strlen(password));
g_free (password);
return written != -1 ? TRUE : FALSE;
}
static char*
dummy_password_func (const char *user_id, const char *prompt_ctx,
gboolean reprompt, gpointer user_data)
{
g_print ("password requested for %s (%s) %s\n",
user_id, prompt_ctx, reprompt ? "again" : "");
return NULL;
}
static char*
get_gpg (GError **err)
{
char *path;
const char *envpath;
if ((envpath = g_getenv ("MU_GPG_PATH"))) {
if (access (envpath, X_OK) != 0) {
mu_util_g_set_error (
err, MU_ERROR,
"'%s': not a valid gpg path: %s",
envpath, strerror (errno));
return NULL;
}
return g_strdup (envpath);
}
if (!(path = g_find_program_in_path ("gpg2")) &&
!(path = g_find_program_in_path ("gpg"))) {
mu_util_g_set_error (err, MU_ERROR, "gpg/gpg2 not found");
return NULL;
} else
return path;
}
static GMimeCryptoContext*
get_gpg_crypto_context (MuMsgOptions opts, GError **err)
{
GMimeCryptoContext *cctx;
char *gpg;
cctx = NULL;
if (!(gpg = get_gpg (err)))
return NULL;
cctx = g_mime_gpg_context_new (
(GMimePasswordRequestFunc)password_requester, gpg);
g_free (gpg);
if (!cctx) {
mu_util_g_set_error (err, MU_ERROR,
"failed to get GPG crypto context");
return NULL;
}
/* always try to use the agent */
g_mime_gpg_context_set_use_agent (GMIME_GPG_CONTEXT(cctx), TRUE);
g_mime_gpg_context_set_auto_key_retrieve
(GMIME_GPG_CONTEXT(cctx),
opts & MU_MSG_OPTION_AUTO_RETRIEVE ? TRUE:FALSE);
return cctx;
}
static GMimeCryptoContext*
get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func,
gpointer user_data, GError **err)
{
CallbackData *cbdata;
GMimeCryptoContext *cctx;
cctx = get_gpg_crypto_context (opts, err);
if (!cctx)
return NULL;
/* use gobject to pass data to the callback func */
cbdata = g_new0 (CallbackData, 1);
cbdata->pw_func = password_func ? password_func : dummy_password_func;
cbdata->user_data = user_data;
g_object_set_data_full (G_OBJECT(cctx), CALLBACK_DATA,
cbdata, (GDestroyNotify)g_free);
return cctx;
}
static const char*
get_pubkey_algo_name (GMimePubKeyAlgo algo)
@ -235,14 +91,14 @@ get_digestkey_algo_name (GMimeDigestAlgo algo)
/* get data from the 'certificate' */
static char*
get_cert_details (GMimeCertificate *cert)
get_cert_data (GMimeCertificate *cert)
{
const char /**email,*/ *name, *digest_algo, *pubkey_algo,
*keyid, *trust;
/* email = g_mime_certificate_get_email (cert); */
name = g_mime_certificate_get_name (cert);
keyid = g_mime_certificate_get_key_id (cert);
name = g_mime_certificate_get_name (cert);
keyid = g_mime_certificate_get_key_id (cert);
digest_algo = get_digestkey_algo_name
(g_mime_certificate_get_digest_algo (cert));
@ -250,12 +106,12 @@ get_cert_details (GMimeCertificate *cert)
(g_mime_certificate_get_pubkey_algo (cert));
switch (g_mime_certificate_get_trust (cert)) {
case GMIME_CERTIFICATE_TRUST_NONE: trust = "none"; break;
case GMIME_CERTIFICATE_TRUST_NEVER: trust = "never"; break;
case GMIME_CERTIFICATE_TRUST_UNDEFINED: trust = "undefined"; break;
case GMIME_CERTIFICATE_TRUST_MARGINAL: trust = "marginal"; break;
case GMIME_CERTIFICATE_TRUST_FULLY: trust = "full"; break;
case GMIME_CERTIFICATE_TRUST_ULTIMATE: trust = "ultimate"; break;
case GMIME_TRUST_UNKNOWN: trust = "unknown"; break;
case GMIME_TRUST_UNDEFINED: trust = "undefined"; break;
case GMIME_TRUST_NEVER: trust = "never"; break;
case GMIME_TRUST_MARGINAL: trust = "marginal"; break;
case GMIME_TRUST_FULL: trust = "full"; break;
case GMIME_TRUST_ULTIMATE: trust = "ultimate"; break;
default:
g_return_val_if_reached (NULL);
}
@ -269,29 +125,24 @@ get_cert_details (GMimeCertificate *cert)
}
/* get a human-readable report about the signature */
static char*
get_verdict_report (GMimeSignature *msig)
{
time_t t;
const char *created, *expires, *verdict;
char *certdata, *report;
time_t t;
const char *status, *created, *expires;
gchar *certdata, *report;
GMimeSignatureStatus sigstat;
switch (g_mime_signature_get_status (msig)) {
case GMIME_SIGNATURE_STATUS_GOOD:
verdict = "good";
break;
case GMIME_SIGNATURE_STATUS_ERROR:
verdict = "error";
break;
case GMIME_SIGNATURE_STATUS_BAD:
verdict = "bad";
break;
default:
sigstat = g_mime_signature_get_status (msig);
if (sigstat & GMIME_SIGNATURE_STATUS_ERROR_MASK)
status = "error";
else if (sigstat & GMIME_SIGNATURE_STATUS_RED)
status = "bad";
else if (sigstat & GMIME_SIGNATURE_STATUS_GREEN)
status = "good";
else
g_return_val_if_reached (NULL);
return NULL;
}
t = g_mime_signature_get_created (msig);
created = (t == 0 || t == (time_t)-1) ? "?" : mu_date_str_s ("%x", t);
@ -299,15 +150,15 @@ get_verdict_report (GMimeSignature *msig)
t = g_mime_signature_get_expires (msig);
expires = (t == 0 || t == (time_t)-1) ? "?" : mu_date_str_s ("%x", t);
certdata = get_cert_details (g_mime_signature_get_certificate (msig));
report = g_strdup_printf ("%s\ncreated:%s, expires:%s, %s",
verdict, created, expires,
certdata = get_cert_data (g_mime_signature_get_certificate (msig));
report = g_strdup_printf ("%s; created:%s, expires:%s, %s",
status, created, expires,
certdata ? certdata : "?");
g_free (certdata);
return report;
}
static char*
get_signers (GHashTable *signerhash)
{
@ -353,17 +204,13 @@ get_status_report (GMimeSignatureList *sigs)
msig = g_mime_signature_list_get_signature (sigs, i);
sigstat = g_mime_signature_get_status (msig);
switch (sigstat) {
case GMIME_SIGNATURE_STATUS_GOOD:
break;
case GMIME_SIGNATURE_STATUS_ERROR:
/* downgrade our expectations */
if ((sigstat & GMIME_SIGNATURE_STATUS_ERROR_MASK) &&
status != MU_MSG_PART_SIG_STATUS_ERROR)
status = MU_MSG_PART_SIG_STATUS_ERROR;
break;
case GMIME_SIGNATURE_STATUS_BAD:
else if ((sigstat & GMIME_SIGNATURE_STATUS_RED) &&
status == MU_MSG_PART_SIG_STATUS_GOOD)
status = MU_MSG_PART_SIG_STATUS_BAD;
break;
default: g_return_val_if_reached (NULL);
}
rep = get_verdict_report (msig);
report = g_strdup_printf ("%s%s%d: %s",
@ -419,20 +266,11 @@ mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, MuMsgOptions opts,
{
/* the signature status */
MuMsgPartSigStatusReport *report;
GMimeCryptoContext *ctx;
GMimeSignatureList *sigs;
g_return_if_fail (GMIME_IS_MULTIPART_SIGNED(sig));
ctx = get_crypto_context (opts, NULL, NULL, err);
if (!ctx) {
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
"failed to get crypto context");
return;
}
sigs = g_mime_multipart_signed_verify (sig, ctx, err);
g_object_unref (ctx);
sigs = g_mime_multipart_signed_verify (sig, GMIME_VERIFY_NONE, err);
if (!sigs) {
if (err && !*err)
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
@ -482,29 +320,13 @@ mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts,
GError **err)
{
GMimeObject *dec;
GMimeCryptoContext *ctx;
GMimeDecryptResult *res;
g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED(enc), NULL);
ctx = get_crypto_context (opts, func, user_data, err);
if (!ctx) {
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
"failed to get crypto context");
return NULL;
}
/* at the time of writing, there is a small leak in
* g_mime_multipart_encrypted_decrypt; I've notified its
* author and it has been fixed 2012-09-12:
* http://git.gnome.org/browse/gmime/commit/
* ?id=1bacd43b50d91bd03a4ae1dc9f46f5783dee61b1
* (or GMime > 2.6.10)
* */
res = NULL;
dec = g_mime_multipart_encrypted_decrypt (enc, ctx, &res, err);
g_object_unref (ctx);
dec = g_mime_multipart_encrypted_decrypt (enc, GMIME_DECRYPT_NONE, NULL,
&res, err);
check_decrypt_result(enc, res, err);
if (!dec) {