X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fplugins%2Fpgpmime%2Fpgpmime.c;h=b9a3d7dfef5ebda13768ee662e833214da36d350;hp=3f4a29f7d602e8caedaa54258ee4bb2584d2650c;hb=81b0679965b506fce98bedb70f74f8df70e81312;hpb=8942ef06ae3f81021ddba843fa4afab14b870f31 diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c index 3f4a29f7d..b9a3d7dfe 100644 --- a/src/plugins/pgpmime/pgpmime.c +++ b/src/plugins/pgpmime/pgpmime.c @@ -1,10 +1,10 @@ /* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2006 Hiroyuki Yamamoto & the Sylpheed-Claws team + * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2014 the Claws Mail team * * 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 Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -13,12 +13,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . + * */ #ifdef HAVE_CONFIG_H # include "config.h" +#include "claws-features.h" #endif #ifdef USE_GPGME @@ -39,6 +40,7 @@ #include #include #include +#include #include "prefs_common.h" @@ -61,13 +63,17 @@ static gint pgpmime_check_signature(MimeInfo *mimeinfo); static PrivacyDataPGP *pgpmime_new_privacydata() { PrivacyDataPGP *data; + gpgme_error_t err; data = g_new0(PrivacyDataPGP, 1); data->data.system = &pgpmime_system; data->done_sigtest = FALSE; data->is_signed = FALSE; data->sigstatus = NULL; - gpgme_new(&data->ctx); + if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) { + g_warning(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + return NULL; + } return data; } @@ -86,7 +92,7 @@ static gboolean pgpmime_is_signed(MimeInfo *mimeinfo) const gchar *protocol; PrivacyDataPGP *data = NULL; - g_return_val_if_fail(mimeinfo != NULL, FALSE); + cm_return_val_if_fail(mimeinfo != NULL, FALSE); if (mimeinfo->privacy != NULL) { data = (PrivacyDataPGP *) mimeinfo->privacy; if (data->done_sigtest) @@ -122,9 +128,10 @@ static gboolean pgpmime_is_signed(MimeInfo *mimeinfo) data = pgpmime_new_privacydata(); mimeinfo->privacy = (PrivacyData *) data; } - - data->done_sigtest = TRUE; - data->is_signed = TRUE; + if (data != NULL) { + data->done_sigtest = TRUE; + data->is_signed = TRUE; + } return TRUE; } @@ -169,10 +176,15 @@ static gint pgpmime_check_signature(MimeInfo *mimeinfo) gchar *textstr; gpgme_data_t sigdata = NULL, textdata = NULL; gpgme_error_t err; - g_return_val_if_fail(mimeinfo != NULL, -1); - g_return_val_if_fail(mimeinfo->privacy != NULL, -1); + cm_return_val_if_fail(mimeinfo != NULL, -1); + cm_return_val_if_fail(mimeinfo->privacy != NULL, -1); data = (PrivacyDataPGP *) mimeinfo->privacy; - gpgme_new(&data->ctx); + if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) { + debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + return 0; + } + debug_print("Checking PGP/MIME signature\n"); @@ -185,16 +197,17 @@ static gint pgpmime_check_signature(MimeInfo *mimeinfo) parent = procmime_mimeinfo_parent(mimeinfo); fp = g_fopen(parent->data.filename, "rb"); - g_return_val_if_fail(fp != NULL, SIGNATURE_INVALID); + cm_return_val_if_fail(fp != NULL, SIGNATURE_INVALID); boundary = g_hash_table_lookup(parent->typeparameters, "boundary"); if (!boundary) { privacy_set_error(_("Signature boundary not found.")); + fclose(fp); return 0; } textstr = get_canonical_content(fp, boundary); - err = gpgme_data_new_from_mem(&textdata, textstr, strlen(textstr), 0); + err = gpgme_data_new_from_mem(&textdata, textstr, (size_t)strlen(textstr), 0); if (err) { debug_print ("gpgme_data_new_from_mem failed: %s\n", gpgme_strerror (err)); @@ -227,12 +240,8 @@ static SignatureStatus pgpmime_get_sig_status(MimeInfo *mimeinfo) { PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy; - g_return_val_if_fail(data != NULL, SIGNATURE_INVALID); + cm_return_val_if_fail(data != NULL, SIGNATURE_INVALID); - if (data->sigstatus == NULL && - prefs_gpg_get_config()->auto_check_signatures) - pgpmime_check_signature(mimeinfo); - return sgpgme_sigstat_gpgme_to_privacy(data->ctx, data->sigstatus); } @@ -240,25 +249,17 @@ static gchar *pgpmime_get_sig_info_short(MimeInfo *mimeinfo) { PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy; - g_return_val_if_fail(data != NULL, g_strdup("Error")); + cm_return_val_if_fail(data != NULL, g_strdup("Error")); - if (data->sigstatus == NULL && - prefs_gpg_get_config()->auto_check_signatures) - pgpmime_check_signature(mimeinfo); - return sgpgme_sigstat_info_short(data->ctx, data->sigstatus); } static gchar *pgpmime_get_sig_info_full(MimeInfo *mimeinfo) { PrivacyDataPGP *data = (PrivacyDataPGP *) mimeinfo->privacy; - - g_return_val_if_fail(data != NULL, g_strdup("Error")); - if (data->sigstatus == NULL && - prefs_gpg_get_config()->auto_check_signatures) - pgpmime_check_signature(mimeinfo); - + cm_return_val_if_fail(data != NULL, g_strdup("Error")); + return sgpgme_sigstat_info_full(data->ctx, data->sigstatus); } @@ -266,7 +267,10 @@ static gboolean pgpmime_is_encrypted(MimeInfo *mimeinfo) { MimeInfo *tmpinfo; const gchar *tmpstr; - + const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----"; + const gchar *end_indicator = "-----END PGP MESSAGE-----"; + gchar *textdata; + if (mimeinfo->type != MIMETYPE_MULTIPART) return FALSE; if (g_ascii_strcasecmp(mimeinfo->subtype, "encrypted")) @@ -289,6 +293,21 @@ static gboolean pgpmime_is_encrypted(MimeInfo *mimeinfo) if (g_ascii_strcasecmp(tmpinfo->subtype, "octet-stream")) return FALSE; + textdata = get_part_as_string(tmpinfo); + if (!textdata) + return FALSE; + + if (!pgp_locate_armor_header(textdata, begin_indicator)) { + g_free(textdata); + return FALSE; + } + if (!pgp_locate_armor_header(textdata, end_indicator)) { + g_free(textdata); + return FALSE; + } + + g_free(textdata); + return TRUE; } @@ -307,11 +326,12 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo) gpgme_error_t err; if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { - privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); return NULL; } - g_return_val_if_fail(pgpmime_is_encrypted(mimeinfo), NULL); + cm_return_val_if_fail(pgpmime_is_encrypted(mimeinfo), NULL); encinfo = (MimeInfo *) g_node_nth_child(mimeinfo->node, 1)->data; @@ -338,12 +358,42 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo) return NULL; } - fprintf(dstfp, "MIME-Version: 1.0\n"); + if (fprintf(dstfp, "MIME-Version: 1.0\n") < 0) { + FILE_OP_ERROR(fname, "fprintf"); + fclose(dstfp); + privacy_set_error(_("Couldn't write to decrypted file %s"), fname); + g_free(fname); + gpgme_data_release(plain); + gpgme_release(ctx); + debug_print("can't open!\n"); + return NULL; + } + + chars = sgpgme_data_release_and_get_mem(plain, &len); + if (len > 0) { + if (fwrite(chars, 1, len, dstfp) < len) { + FILE_OP_ERROR(fname, "fwrite"); + g_free(chars); + fclose(dstfp); + privacy_set_error(_("Couldn't write to decrypted file %s"), fname); + g_free(fname); + gpgme_data_release(plain); + gpgme_release(ctx); + debug_print("can't open!\n"); + return NULL; + } + } + g_free(chars); - chars = gpgme_data_release_and_get_mem(plain, &len); - if (len > 0) - fwrite(chars, len, 1, dstfp); - fclose(dstfp); + if (fclose(dstfp) == EOF) { + FILE_OP_ERROR(fname, "fclose"); + privacy_set_error(_("Couldn't close decrypted file %s"), fname); + g_free(fname); + gpgme_data_release(plain); + gpgme_release(ctx); + debug_print("can't open!\n"); + return NULL; + } parseinfo = procmime_scan_file(fname); g_free(fname); @@ -372,22 +422,24 @@ static MimeInfo *pgpmime_decrypt(MimeInfo *mimeinfo) data = pgpmime_new_privacydata(); decinfo->privacy = (PrivacyData *) data; } - data->done_sigtest = TRUE; - data->is_signed = TRUE; - data->sigstatus = sigstat; - if (data->ctx) - gpgme_release(data->ctx); - data->ctx = ctx; + if (data != NULL) { + data->done_sigtest = TRUE; + data->is_signed = TRUE; + data->sigstatus = sigstat; + if (data->ctx) + gpgme_release(data->ctx); + data->ctx = ctx; + } } else gpgme_release(ctx); return decinfo; } -gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account) +gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *from_addr) { MimeInfo *msgcontent, *sigmultipart, *newinfo; - gchar *textstr, *micalg; + gchar *textstr, *micalg = NULL; FILE *fp; gchar *boundary = NULL; gchar *sigcontent; @@ -451,19 +503,24 @@ gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account) fclose(fp); - gpgme_data_new_from_mem(&gpgtext, textstr, strlen(textstr), 0); + gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0); gpgme_data_new(&gpgsig); - gpgme_new(&ctx); + if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { + debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + return FALSE; + } gpgme_set_textmode(ctx, 1); gpgme_set_armor(ctx, 1); gpgme_signers_clear (ctx); - if (!sgpgme_setup_signers(ctx, account)) { + if (!sgpgme_setup_signers(ctx, account, from_addr)) { gpgme_release(ctx); return FALSE; } - if (getenv("GPG_AGENT_INFO")) { + prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent); + if (getenv("GPG_AGENT_INFO") && prefs_gpg_get_config()->use_gpg_agent) { debug_print("GPG_AGENT_INFO environment defined, running without passphrase callback\n"); } else { info.c = ctx; @@ -487,8 +544,8 @@ gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account) if (result && result->signatures) { gpgme_new_signature_t sig = result->signatures; if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) { - micalg = g_strdup_printf("PGP-%s", gpgme_hash_algo_name( - result->signatures->hash_algo)); + micalg = g_strdup_printf("pgp-%s", g_ascii_strdown(gpgme_hash_algo_name( + result->signatures->hash_algo),-1)); } else { micalg = g_strdup(gpgme_hash_algo_name( result->signatures->hash_algo)); @@ -516,14 +573,15 @@ gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account) return FALSE; } - gpgme_release(ctx); - sigcontent = gpgme_data_release_and_get_mem(gpgsig, &len); + sigcontent = sgpgme_data_release_and_get_mem(gpgsig, &len); gpgme_data_release(gpgtext); g_free(textstr); if (sigcontent == NULL || len <= 0) { - g_warning("gpgme_data_release_and_get_mem failed"); + g_warning("sgpgme_data_release_and_get_mem failed"); privacy_set_error(_("Data signing failed, no contents.")); + g_free(micalg); + g_free(sigcontent); return FALSE; } @@ -534,18 +592,15 @@ gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account) newinfo = procmime_mimeinfo_new(); newinfo->type = MIMETYPE_APPLICATION; newinfo->subtype = g_strdup("pgp-signature"); - g_hash_table_insert(newinfo->typeparameters, g_strdup("name"), - g_strdup("signature.asc")); + newinfo->description = g_strdup(_("OpenPGP digital signature")); newinfo->content = MIMECONTENT_MEM; - newinfo->disposition = DISPOSITIONTYPE_ATTACHMENT; - g_hash_table_insert(newinfo->dispositionparameters, g_strdup("filename"), - g_strdup("signature.asc")); newinfo->data.mem = g_malloc(len + 1); g_memmove(newinfo->data.mem, sigcontent, len); newinfo->data.mem[len] = '\0'; g_node_append(sigmultipart->node, newinfo->node); g_free(sigcontent); + gpgme_release(ctx); return TRUE; } @@ -554,6 +609,23 @@ gchar *pgpmime_get_encrypt_data(GSList *recp_names) return sgpgme_get_encrypt_data(recp_names, GPGME_PROTOCOL_OpenPGP); } +static const gchar *pgpmime_get_encrypt_warning(void) +{ + if (prefs_gpg_should_skip_encryption_warning(pgpmime_system.id)) + return NULL; + else + return _("Please note that email headers, like Subject, " + "are not encrypted by the PGP/Mime system."); +} + +static void pgpmime_inhibit_encrypt_warning(gboolean inhibit) +{ + if (inhibit) + prefs_gpg_add_skip_encryption_warning(pgpmime_system.id); + else + prefs_gpg_remove_skip_encryption_warning(pgpmime_system.id); +} + gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) { MimeInfo *msgcontent, *encmultipart, *newinfo; @@ -574,7 +646,12 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) kset = g_malloc(sizeof(gpgme_key_t)*(i+1)); memset(kset, 0, sizeof(gpgme_key_t)*(i+1)); - gpgme_new(&ctx); + if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { + debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); + g_free(kset); + return FALSE; + } i = 0; while (fprs[i] && strlen(fprs[i])) { gpgme_key_t key; @@ -582,6 +659,7 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) if (err) { debug_print("can't add key '%s'[%d] (%s)\n", fprs[i],i, gpgme_strerror(err)); privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs[i], gpgme_strerror(err)); + g_free(kset); return FALSE; } debug_print("found %s at %d\n", fprs[i], i); @@ -610,6 +688,7 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) fp = my_tmpfile(); if (fp == NULL) { privacy_set_error(_("Couldn't create temporary file, %s"), strerror(errno)); + g_free(kset); return FALSE; } procmime_write_mimeinfo(encmultipart, fp); @@ -621,21 +700,23 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) fclose(fp); /* encrypt data */ - gpgme_data_new_from_mem(&gpgtext, textstr, strlen(textstr), 0); + gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0); gpgme_data_new(&gpgenc); gpgme_set_armor(ctx, 1); - gpgme_data_rewind(gpgtext); + cm_gpgme_data_rewind(gpgtext); err = gpgme_op_encrypt(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, gpgtext, gpgenc); - gpgme_release(ctx); - enccontent = gpgme_data_release_and_get_mem(gpgenc, &len); + enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len); gpgme_data_release(gpgtext); g_free(textstr); + g_free(kset); if (enccontent == NULL || len <= 0) { - g_warning("gpgme_data_release_and_get_mem failed"); + g_warning("sgpgme_data_release_and_get_mem failed"); privacy_set_error(_("Encryption failed, %s"), gpgme_strerror(err)); + gpgme_release(ctx); + g_free(enccontent); return FALSE; } @@ -661,6 +742,7 @@ gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) g_node_append(encmultipart->node, newinfo->node); g_free(enccontent); + gpgme_release(ctx); return TRUE; } @@ -686,6 +768,9 @@ static PrivacySystem pgpmime_system = { TRUE, pgpmime_get_encrypt_data, pgpmime_encrypt, + pgpmime_get_encrypt_warning, + pgpmime_inhibit_encrypt_warning, + prefs_gpg_auto_check_signatures, }; void pgpmime_init()