summaryrefslogtreecommitdiffstats
path: root/handler.c
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2015-07-26 14:48:53 -0700
committerKevin McCarthy <kevin@8t8.us>2015-07-26 14:48:53 -0700
commit5360d1d5111a2aca89918335f930af39380059a9 (patch)
tree2249ed73b6f64f66fc2aaaafdd33881edc00b7a4 /handler.c
parent9ffe468aefd72fbc2e44131b00cf4e83621708ca (diff)
Handle malformed ms-exchange pgp-encrypted block. (closes #3742)
In certain circumstances, Exchange corrupts a multipart/encrypted block into: <multipart/mixed> <text/plain> <application/pgp-encrypted> [BASE64-encoded] <application/octet-stream> [BASE64-encoded] This patch pulls the full detection of valid/invalid multiparts into mutt_body_handler(). It extracts a run_decode_and_handler() function, which is reused by new intermediate handlers to decode the application/octet-stream part before passing it directly to crypt_pgp_encrypted_handler. These intermediate handlers then check and set any GOODSIG flags back into the parent part. This change may result in less error messages for invalid multipart/encrypted parts. Instead, mutt will default to the multipart_handler if it isn't fully "correct". Viewing attachments uses crypt_pgp_decrypt_mime() which bypasses the handler mechanism. Add decoding to the decrypt_mime() functions for pgp and gpgme. Thanks to Vincent Brillault for his analysis and initial patch.
Diffstat (limited to 'handler.c')
-rw-r--r--handler.c230
1 files changed, 129 insertions, 101 deletions
diff --git a/handler.c b/handler.c
index 0d71296c..1a062bea 100644
--- a/handler.c
+++ b/handler.c
@@ -1590,15 +1590,133 @@ static int text_plain_handler (BODY *b, STATE *s)
return 0;
}
-int mutt_body_handler (BODY *b, STATE *s)
+static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int plaintext)
{
- int decode = 0;
- int plaintext = 0;
+ int origType;
+ char *savePrefix = NULL;
FILE *fp = NULL;
char tempfile[_POSIX_PATH_MAX];
- handler_t handler = NULL;
- LOFF_T tmpoffset = 0;
size_t tmplength = 0;
+ LOFF_T tmpoffset = 0;
+ int decode = 0;
+ int rc = 0;
+
+ fseeko (s->fpin, b->offset, 0);
+
+ /* see if we need to decode this part before processing it */
+ if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE ||
+ b->encoding == ENCUUENCODED || plaintext ||
+ mutt_is_text_part (b)) /* text subtypes may
+ * require character
+ * set conversion even
+ * with 8bit encoding.
+ */
+ {
+ origType = b->type;
+
+ if (!plaintext)
+ {
+ /* decode to a tempfile, saving the original destination */
+ fp = s->fpout;
+ mutt_mktemp (tempfile, sizeof (tempfile));
+ if ((s->fpout = safe_fopen (tempfile, "w")) == NULL)
+ {
+ mutt_error _("Unable to open temporary file!");
+ dprint (1, (debugfile, "Can't open %s.\n", tempfile));
+ return -1;
+ }
+ /* decoding the attachment changes the size and offset, so save a copy
+ * of the "real" values now, and restore them after processing
+ */
+ tmplength = b->length;
+ tmpoffset = b->offset;
+
+ /* if we are decoding binary bodies, we don't want to prefix each
+ * line with the prefix or else the data will get corrupted.
+ */
+ savePrefix = s->prefix;
+ s->prefix = NULL;
+
+ decode = 1;
+ }
+ else
+ b->type = TYPETEXT;
+
+ mutt_decode_attachment (b, s);
+
+ if (decode)
+ {
+ b->length = ftello (s->fpout);
+ b->offset = 0;
+ safe_fclose (&s->fpout);
+
+ /* restore final destination and substitute the tempfile for input */
+ s->fpout = fp;
+ fp = s->fpin;
+ s->fpin = fopen (tempfile, "r");
+ unlink (tempfile);
+
+ /* restore the prefix */
+ s->prefix = savePrefix;
+ }
+
+ b->type = origType;
+ }
+
+ /* process the (decoded) body part */
+ if (handler)
+ {
+ rc = handler (b, s);
+
+ if (rc)
+ {
+ dprint (1, (debugfile, "Failed on attachment of type %s/%s.\n", TYPE(b), NONULL (b->subtype)));
+ }
+
+ if (decode)
+ {
+ b->length = tmplength;
+ b->offset = tmpoffset;
+
+ /* restore the original source stream */
+ safe_fclose (&s->fpin);
+ s->fpin = fp;
+ }
+ }
+ s->flags |= M_FIRSTDONE;
+
+ return rc;
+}
+
+static int valid_pgp_encrypted_handler (BODY *b, STATE *s)
+{
+ int rc;
+ BODY *octetstream;
+
+ octetstream = b->parts->next;
+ rc = crypt_pgp_encrypted_handler (octetstream, s);
+ b->goodsig |= octetstream->goodsig;
+
+ return rc;
+}
+
+static int malformed_pgp_encrypted_handler (BODY *b, STATE *s)
+{
+ int rc;
+ BODY *octetstream;
+
+ octetstream = b->parts->next->next;
+ /* exchange encodes the octet-stream, so re-run it through the decoder */
+ rc = run_decode_and_handler (octetstream, s, crypt_pgp_encrypted_handler, 0);
+ b->goodsig |= octetstream->goodsig;
+
+ return rc;
+}
+
+int mutt_body_handler (BODY *b, STATE *s)
+{
+ int plaintext = 0;
+ handler_t handler = NULL;
int rc = 0;
int oflags = s->flags;
@@ -1653,20 +1771,14 @@ int mutt_body_handler (BODY *b, STATE *s)
else if (s->flags & M_VERIFY)
handler = mutt_signed_handler;
}
- else if ((WithCrypto & APPLICATION_PGP)
- && ascii_strcasecmp ("encrypted", b->subtype) == 0)
- {
- p = mutt_get_parameter ("protocol", b->parameter);
-
- if (!p)
- mutt_error _("Error: multipart/encrypted has no protocol parameter!");
- else if (ascii_strcasecmp ("application/pgp-encrypted", p) == 0)
- handler = crypt_pgp_encrypted_handler;
- }
+ else if (mutt_is_valid_multipart_pgp_encrypted (b))
+ handler = valid_pgp_encrypted_handler;
+ else if (mutt_is_malformed_multipart_pgp_encrypted (b))
+ handler = malformed_pgp_encrypted_handler;
if (!handler)
handler = multipart_handler;
-
+
if (b->encoding != ENC7BIT && b->encoding != ENC8BIT
&& b->encoding != ENCBINARY)
{
@@ -1695,90 +1807,7 @@ int mutt_body_handler (BODY *b, STATE *s)
option(OPTVIEWATTACH))) &&
(plaintext || handler))
{
- fseeko (s->fpin, b->offset, 0);
-
- /* see if we need to decode this part before processing it */
- if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE ||
- b->encoding == ENCUUENCODED || plaintext ||
- mutt_is_text_part (b)) /* text subtypes may
- * require character
- * set conversion even
- * with 8bit encoding.
- */
- {
- int origType = b->type;
- char *savePrefix = NULL;
-
- if (!plaintext)
- {
- /* decode to a tempfile, saving the original destination */
- fp = s->fpout;
- mutt_mktemp (tempfile, sizeof (tempfile));
- if ((s->fpout = safe_fopen (tempfile, "w")) == NULL)
- {
- mutt_error _("Unable to open temporary file!");
- dprint (1, (debugfile, "Can't open %s.\n", tempfile));
- goto bail;
- }
- /* decoding the attachment changes the size and offset, so save a copy
- * of the "real" values now, and restore them after processing
- */
- tmplength = b->length;
- tmpoffset = b->offset;
-
- /* if we are decoding binary bodies, we don't want to prefix each
- * line with the prefix or else the data will get corrupted.
- */
- savePrefix = s->prefix;
- s->prefix = NULL;
-
- decode = 1;
- }
- else
- b->type = TYPETEXT;
-
- mutt_decode_attachment (b, s);
-
- if (decode)
- {
- b->length = ftello (s->fpout);
- b->offset = 0;
- safe_fclose (&s->fpout);
-
- /* restore final destination and substitute the tempfile for input */
- s->fpout = fp;
- fp = s->fpin;
- s->fpin = fopen (tempfile, "r");
- unlink (tempfile);
-
- /* restore the prefix */
- s->prefix = savePrefix;
- }
-
- b->type = origType;
- }
-
- /* process the (decoded) body part */
- if (handler)
- {
- rc = handler (b, s);
-
- if (rc)
- {
- dprint (1, (debugfile, "Failed on attachment of type %s/%s.\n", TYPE(b), NONULL (b->subtype)));
- }
-
- if (decode)
- {
- b->length = tmplength;
- b->offset = tmpoffset;
-
- /* restore the original source stream */
- safe_fclose (&s->fpin);
- s->fpin = fp;
- }
- }
- s->flags |= M_FIRSTDONE;
+ rc = run_decode_and_handler (b, s, handler, plaintext);
}
/* print hint to use attachment menu for disposition == attachment
if we're not already being called from there */
@@ -1805,7 +1834,6 @@ int mutt_body_handler (BODY *b, STATE *s)
fputs (" --]\n", s->fpout);
}
- bail:
s->flags = oflags | (s->flags & M_FIRSTDONE);
if (rc)
{