From 1de8172c2e3c8eef2bac4a2cd9ebe727c0773f8a Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 11 Jul 2013 15:17:48 +0100 Subject: [PATCH] fix bug 2961, 'Partial retrieval not available with PGP/Inline encrypted messages' do a more thorough check before deciding to go ahead with a (ultimately failed) decryption attempt: check for the end of the encrypted block, don't just assume, (never assume, it makes an ...), that it must be there if the beginning of the block is found. Move some stuff, which is now used in both -mime and -inline, into a new file, pgpcore/pgp_utils.[ch] --- src/plugins/pgpcore/Makefile.am | 2 + src/plugins/pgpcore/pgp_utils.c | 136 ++++++++++++++++++++++++++++++ src/plugins/pgpcore/pgp_utils.h | 34 ++++++++ src/plugins/pgpinline/pgpinline.c | 123 +++------------------------ src/plugins/pgpmime/pgpmime.c | 21 ++++- 5 files changed, 204 insertions(+), 112 deletions(-) create mode 100644 src/plugins/pgpcore/pgp_utils.c create mode 100644 src/plugins/pgpcore/pgp_utils.h diff --git a/src/plugins/pgpcore/Makefile.am b/src/plugins/pgpcore/Makefile.am index 4d0a0a3f6..236584e31 100644 --- a/src/plugins/pgpcore/Makefile.am +++ b/src/plugins/pgpcore/Makefile.am @@ -53,6 +53,7 @@ pgpcore_la_SOURCES = \ prefs_gpg.c \ select-keys.c \ sgpgme.c \ + pgp_utils.c \ pgp_viewer.c pluginincludedir = $(pkgincludedir)/plugins/pgpcore @@ -61,6 +62,7 @@ plugininclude_HEADERS = \ prefs_gpg.h \ select-keys.h \ sgpgme.h \ + pgp_utils.h \ pgp_viewer.h pgpcore_la_LDFLAGS = \ diff --git a/src/plugins/pgpcore/pgp_utils.c b/src/plugins/pgpcore/pgp_utils.c new file mode 100644 index 000000000..7174ec425 --- /dev/null +++ b/src/plugins/pgpcore/pgp_utils.c @@ -0,0 +1,136 @@ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#include "claws-features.h" +#endif + +/* + * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2013 Colin Leroy and + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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, see . + * + */ + +#ifdef USE_GPGME + +#include + +#include "pgp_utils.h" +#include "codeconv.h" + +gchar *fp_read_noconv(FILE *fp) +{ + GByteArray *array; + guchar buf[BUFSIZ]; + gint n_read; + gchar *result = NULL; + + if (!fp) + return NULL; + array = g_byte_array_new(); + + while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) { + if (n_read < sizeof(buf) && ferror(fp)) + break; + g_byte_array_append(array, buf, n_read); + } + + if (ferror(fp)) { + FILE_OP_ERROR("file stream", "fread"); + g_byte_array_free(array, TRUE); + return NULL; + } + + buf[0] = '\0'; + g_byte_array_append(array, buf, 1); + result = (gchar *)array->data; + g_byte_array_free(array, FALSE); + + return result; +} + +gchar *get_part_as_string(MimeInfo *mimeinfo) +{ + gchar *textdata = NULL; + gchar *filename = NULL; + FILE *fp; + + cm_return_val_if_fail(mimeinfo != NULL, 0); + procmime_decode_content(mimeinfo); + + if (mimeinfo->content == MIMECONTENT_MEM) + textdata = g_strdup(mimeinfo->data.mem); + else { + filename = procmime_get_tmp_file_name(mimeinfo); + if (procmime_get_part(filename, mimeinfo) < 0) { + printf("error dumping file\n"); + return NULL; + } + fp = g_fopen(filename,"rb"); + if (!fp) { + printf("error reading file\n"); + return NULL; + } + textdata = fp_read_noconv(fp); + fclose(fp); + g_unlink(filename); + g_free(filename); + } + + if (!g_utf8_validate(textdata, -1, NULL)) { + gchar *tmp = NULL; + codeconv_set_strict(TRUE); + if (procmime_mimeinfo_get_parameter(mimeinfo, "charset")) { + tmp = conv_codeset_strdup(textdata, + procmime_mimeinfo_get_parameter(mimeinfo, "charset"), + CS_UTF_8); + } + if (!tmp) { + tmp = conv_codeset_strdup(textdata, + conv_get_locale_charset_str_no_utf8(), + CS_UTF_8); + } + codeconv_set_strict(FALSE); + if (!tmp) { + tmp = conv_codeset_strdup(textdata, + conv_get_locale_charset_str_no_utf8(), + CS_UTF_8); + } + if (tmp) { + g_free(textdata); + textdata = tmp; + } + } + + return textdata; +} + +gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header) +{ + gchar *pos; + + pos = strstr(textdata, armor_header); + /* + * It's only a valid armor header if it's at the + * beginning of the buffer or a new line. + */ + if (pos != NULL && (pos == textdata || *(pos-1) == '\n')) + { + return pos; + } + return NULL; +} +#endif /* USE_GPGME */ diff --git a/src/plugins/pgpcore/pgp_utils.h b/src/plugins/pgpcore/pgp_utils.h new file mode 100644 index 000000000..a7795f72b --- /dev/null +++ b/src/plugins/pgpcore/pgp_utils.h @@ -0,0 +1,34 @@ +/* + * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2013 Colin Leroy and + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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, see . + * + */ + +#ifndef __PGP_UTILS_H__ +#define __PGP_UTILS_H__ + +#ifdef HAVE_CONFIG_H +#include "claws-features.h" +#endif + +#include "procmime.h" + +gchar *fp_read_noconv(FILE *fp); +gchar *get_part_as_string(MimeInfo *mimeinfo); +gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header); + +#endif /* __PGP_UTILS_H__ */ diff --git a/src/plugins/pgpinline/pgpinline.c b/src/plugins/pgpinline/pgpinline.c index a1ab2768b..cbd3bb02d 100644 --- a/src/plugins/pgpinline/pgpinline.c +++ b/src/plugins/pgpinline/pgpinline.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "quoted-printable.h" #include "base64.h" #include "codeconv.h" @@ -86,109 +87,6 @@ static void pgpinline_free_privacydata(PrivacyData *_data) g_free(data); } -static gchar *fp_read_noconv(FILE *fp) -{ - GByteArray *array; - guchar buf[BUFSIZ]; - gint n_read; - gchar *result = NULL; - - if (!fp) - return NULL; - array = g_byte_array_new(); - - while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) { - if (n_read < sizeof(buf) && ferror(fp)) - break; - g_byte_array_append(array, buf, n_read); - } - - if (ferror(fp)) { - FILE_OP_ERROR("file stream", "fread"); - g_byte_array_free(array, TRUE); - return NULL; - } - - buf[0] = '\0'; - g_byte_array_append(array, buf, 1); - result = (gchar *)array->data; - g_byte_array_free(array, FALSE); - - return result; -} - -static gchar *get_part_as_string(MimeInfo *mimeinfo) -{ - gchar *textdata = NULL; - gchar *filename = NULL; - FILE *fp; - - cm_return_val_if_fail(mimeinfo != NULL, 0); - procmime_decode_content(mimeinfo); - - if (mimeinfo->content == MIMECONTENT_MEM) - textdata = g_strdup(mimeinfo->data.mem); - else { - filename = procmime_get_tmp_file_name(mimeinfo); - if (procmime_get_part(filename, mimeinfo) < 0) { - printf("error dumping file\n"); - return NULL; - } - fp = g_fopen(filename,"rb"); - if (!fp) { - printf("error reading file\n"); - return NULL; - } - textdata = fp_read_noconv(fp); - fclose(fp); - g_unlink(filename); - g_free(filename); - } - - if (!g_utf8_validate(textdata, -1, NULL)) { - gchar *tmp = NULL; - codeconv_set_strict(TRUE); - if (procmime_mimeinfo_get_parameter(mimeinfo, "charset")) { - tmp = conv_codeset_strdup(textdata, - procmime_mimeinfo_get_parameter(mimeinfo, "charset"), - CS_UTF_8); - } - if (!tmp) { - tmp = conv_codeset_strdup(textdata, - conv_get_locale_charset_str_no_utf8(), - CS_UTF_8); - } - codeconv_set_strict(FALSE); - if (!tmp) { - tmp = conv_codeset_strdup(textdata, - conv_get_locale_charset_str_no_utf8(), - CS_UTF_8); - } - if (tmp) { - g_free(textdata); - textdata = tmp; - } - } - - return textdata; -} - -static gchar *pgpinline_locate_armor_header(gchar *textdata, const gchar *armor_header) -{ - gchar *pos; - - pos = strstr(textdata, armor_header); - /* - * It's only a valid armor header if it's at the - * beginning of the buffer or a new line. - */ - if (pos != NULL && (pos == textdata || *(pos-1) == '\n')) - { - return pos; - } - return NULL; -} - static gboolean pgpinline_is_signed(MimeInfo *mimeinfo) { PrivacyDataPGP *data = NULL; @@ -351,11 +249,10 @@ static gchar *pgpinline_get_sig_info_full(MimeInfo *mimeinfo) return sgpgme_sigstat_info_full(data->ctx, data->sigstatus); } - - static gboolean pgpinline_is_encrypted(MimeInfo *mimeinfo) { - const gchar *enc_indicator = "-----BEGIN PGP MESSAGE-----"; + const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----"; + const gchar *end_indicator = "-----END PGP MESSAGE-----"; gchar *textdata; cm_return_val_if_fail(mimeinfo != NULL, FALSE); @@ -375,12 +272,16 @@ static gboolean pgpinline_is_encrypted(MimeInfo *mimeinfo) g_free(mimeinfo->subtype); mimeinfo->subtype = g_strdup("plain"); } - + textdata = get_part_as_string(mimeinfo); if (!textdata) return FALSE; - - if (!pgpinline_locate_armor_header(textdata, enc_indicator)) { + + 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; } @@ -472,7 +373,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo) } /* Store any part before encrypted text */ - pos = pgpinline_locate_armor_header(textdata, begin_indicator); + pos = pgp_locate_armor_header(textdata, begin_indicator); if (pos != NULL && (pos - textdata) > 0) { if (fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) { FILE_OP_ERROR(fname, "fwrite"); @@ -507,7 +408,7 @@ static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo) goto FILE_ERROR; } if (pos != NULL) { - pos = pgpinline_locate_armor_header(pos, end_indicator); + pos = pgp_locate_armor_header(pos, end_indicator); if (pos != NULL && *pos != '\0') { pos += strlen(end_indicator); if (fwrite(pos, 1, strlen(pos), dstfp) < strlen(pos)) { diff --git a/src/plugins/pgpmime/pgpmime.c b/src/plugins/pgpmime/pgpmime.c index 1998eab70..a54e527ba 100644 --- a/src/plugins/pgpmime/pgpmime.c +++ b/src/plugins/pgpmime/pgpmime.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "prefs_common.h" @@ -277,7 +278,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")) @@ -300,6 +304,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; } -- 2.25.1