fix bug 2961, 'Partial retrieval not available with PGP/Inline encrypted messages'
authorPaul <paul@claws-mail.org>
Thu, 11 Jul 2013 14:17:48 +0000 (15:17 +0100)
committerPaul <paul@claws-mail.org>
Thu, 11 Jul 2013 14:20:16 +0000 (15:20 +0100)
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
src/plugins/pgpcore/pgp_utils.c [new file with mode: 0644]
src/plugins/pgpcore/pgp_utils.h [new file with mode: 0644]
src/plugins/pgpinline/pgpinline.c
src/plugins/pgpmime/pgpmime.c

index 4d0a0a3f6511fe9b3663b9e2e972b28c0d3b9d6a..236584e31fb6f1d8366c15bbed93667c81f51964 100644 (file)
@@ -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 (file)
index 0000000..7174ec4
--- /dev/null
@@ -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 <colin@colino.net> 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 <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifdef USE_GPGME
+
+#include <glib.h>
+
+#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 (file)
index 0000000..a7795f7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2013 Colin Leroy <colin@colino.net> 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 <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#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__ */
index a1ab2768b54bb708595c6c7cfd7ca19acb942173..cbd3bb02dcb7149487b97e1254f456eb1f94fe33 100644 (file)
@@ -38,6 +38,7 @@
 #include <plugins/pgpcore/sgpgme.h>
 #include <plugins/pgpcore/prefs_gpg.h>
 #include <plugins/pgpcore/passphrase.h>
+#include <plugins/pgpcore/pgp_utils.h>
 #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)) {
index 1998eab7052f9d8fcbdd44f9f08817bdfb4655eb..a54e527ba46546460dd0c67f13999f9de4d93c91 100644 (file)
@@ -40,6 +40,7 @@
 #include <plugins/pgpcore/sgpgme.h>
 #include <plugins/pgpcore/prefs_gpg.h>
 #include <plugins/pgpcore/passphrase.h>
+#include <plugins/pgpcore/pgp_utils.h>
 
 #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;
 }