diff options
author | Kevin McCarthy <kevin@8t8.us> | 2015-07-26 14:48:53 -0700 |
---|---|---|
committer | Kevin McCarthy <kevin@8t8.us> | 2015-07-26 14:48:53 -0700 |
commit | 5360d1d5111a2aca89918335f930af39380059a9 (patch) | |
tree | 2249ed73b6f64f66fc2aaaafdd33881edc00b7a4 /handler.c | |
parent | 9ffe468aefd72fbc2e44131b00cf4e83621708ca (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.c | 230 |
1 files changed, 129 insertions, 101 deletions
@@ -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) { |