mutt stable branch with some hacks
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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.

+325 -165
+63 -28
crypt-gpgme.c
··· 1799 1799 char tempfile[_POSIX_PATH_MAX]; 1800 1800 STATE s; 1801 1801 BODY *first_part = b; 1802 - int is_signed; 1802 + int is_signed = 0; 1803 + int need_decode = 0; 1804 + int saved_type; 1805 + LOFF_T saved_offset; 1806 + size_t saved_length; 1807 + FILE *decoded_fp = NULL; 1808 + int rv = 0; 1803 1809 1804 1810 first_part->goodsig = 0; 1805 1811 first_part->warnsig = 0; 1806 1812 1807 - if(!mutt_is_multipart_encrypted(b)) 1813 + if (mutt_is_valid_multipart_pgp_encrypted (b)) 1814 + b = b->parts->next; 1815 + else if (mutt_is_malformed_multipart_pgp_encrypted (b)) 1816 + { 1817 + b = b->parts->next->next; 1818 + need_decode = 1; 1819 + } 1820 + else 1808 1821 return -1; 1809 - 1810 - if(!b->parts || !b->parts->next) 1811 - return -1; 1812 - 1813 - b = b->parts->next; 1814 1822 1815 1823 memset (&s, 0, sizeof (s)); 1816 1824 s.fpin = fpin; 1825 + 1826 + if (need_decode) 1827 + { 1828 + saved_type = b->type; 1829 + saved_offset = b->offset; 1830 + saved_length = b->length; 1831 + 1832 + mutt_mktemp (tempfile, sizeof (tempfile)); 1833 + if ((decoded_fp = safe_fopen (tempfile, "w+")) == NULL) 1834 + { 1835 + mutt_perror (tempfile); 1836 + return (-1); 1837 + } 1838 + unlink (tempfile); 1839 + 1840 + fseeko (s.fpin, b->offset, 0); 1841 + s.fpout = decoded_fp; 1842 + 1843 + mutt_decode_attachment (b, &s); 1844 + 1845 + fflush (decoded_fp); 1846 + b->length = ftello (decoded_fp); 1847 + b->offset = 0; 1848 + rewind (decoded_fp); 1849 + s.fpin = decoded_fp; 1850 + s.fpout = 0; 1851 + } 1852 + 1817 1853 mutt_mktemp (tempfile, sizeof (tempfile)); 1818 1854 if (!(*fpout = safe_fopen (tempfile, "w+"))) 1819 1855 { 1820 1856 mutt_perror (tempfile); 1821 - return -1; 1857 + rv = -1; 1858 + goto bail; 1822 1859 } 1823 1860 unlink (tempfile); 1824 1861 1825 - *cur = decrypt_part (b, &s, *fpout, 0, &is_signed); 1862 + if ((*cur = decrypt_part (b, &s, *fpout, 0, &is_signed)) == NULL) 1863 + rv = -1; 1826 1864 rewind (*fpout); 1827 1865 if (is_signed > 0) 1828 1866 first_part->goodsig = 1; 1829 - 1830 - return *cur? 0:-1; 1867 + 1868 + bail: 1869 + if (need_decode) 1870 + { 1871 + b->type = saved_type; 1872 + b->length = saved_length; 1873 + b->offset = saved_offset; 1874 + safe_fclose (&decoded_fp); 1875 + } 1876 + 1877 + return rv; 1831 1878 } 1832 1879 1833 1880 ··· 2519 2566 * Implementation of `encrypted_handler'. 2520 2567 */ 2521 2568 2522 - /* MIME handler for pgp/mime encrypted messages. */ 2569 + /* MIME handler for pgp/mime encrypted messages. 2570 + * This handler is passed the application/octet-stream directly. 2571 + * The caller must propagate a->goodsig to its parent. 2572 + */ 2523 2573 int pgp_gpgme_encrypted_handler (BODY *a, STATE *s) 2524 2574 { 2525 2575 char tempfile[_POSIX_PATH_MAX]; 2526 2576 FILE *fpout; 2527 2577 BODY *tattach; 2528 - BODY *orig_body = a; 2529 2578 int is_signed; 2530 2579 int rc = 0; 2531 2580 2532 2581 dprint (2, (debugfile, "Entering pgp_encrypted handler\n")); 2533 - a = a->parts; 2534 - if (!a || a->type != TYPEAPPLICATION || !a->subtype 2535 - || ascii_strcasecmp ("pgp-encrypted", a->subtype) 2536 - || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype 2537 - || ascii_strcasecmp ("octet-stream", a->next->subtype) ) 2538 - { 2539 - if (s->flags & M_DISPLAY) 2540 - state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"), 2541 - s); 2542 - return -1; 2543 - } 2544 - 2545 - /* Move forward to the application/pgp-encrypted body. */ 2546 - a = a->next; 2547 2582 2548 2583 mutt_mktemp (tempfile, sizeof (tempfile)); 2549 2584 if (!(fpout = safe_fopen (tempfile, "w+"))) ··· 2578 2613 * status. 2579 2614 */ 2580 2615 if (mutt_is_multipart_signed (tattach) && !tattach->next) 2581 - orig_body->goodsig |= tattach->goodsig; 2616 + a->goodsig |= tattach->goodsig; 2582 2617 2583 2618 if (s->flags & M_DISPLAY) 2584 2619 {
+63 -1
crypt.c
··· 314 314 ascii_strcasecmp (p, "application/pgp-encrypted")) 315 315 return 0; 316 316 317 - return PGPENCRYPT; 317 + return PGPENCRYPT; 318 318 } 319 319 320 320 return 0; 321 + } 322 + 323 + 324 + int mutt_is_valid_multipart_pgp_encrypted (BODY *b) 325 + { 326 + if (! mutt_is_multipart_encrypted (b)) 327 + return 0; 328 + 329 + b = b->parts; 330 + if (!b || b->type != TYPEAPPLICATION || 331 + !b->subtype || ascii_strcasecmp (b->subtype, "pgp-encrypted")) 332 + return 0; 333 + 334 + b = b->next; 335 + if (!b || b->type != TYPEAPPLICATION || 336 + !b->subtype || ascii_strcasecmp (b->subtype, "octet-stream")) 337 + return 0; 338 + 339 + return PGPENCRYPT; 340 + } 341 + 342 + 343 + /* 344 + * This checks for the malformed layout caused by MS Exchange in 345 + * some cases: 346 + * <multipart/mixed> 347 + * <text/plain> 348 + * <application/pgp-encrypted> [BASE64-encoded] 349 + * <application/octet-stream> [BASE64-encoded] 350 + * See ticket #3742 351 + */ 352 + int mutt_is_malformed_multipart_pgp_encrypted (BODY *b) 353 + { 354 + if (!(WithCrypto & APPLICATION_PGP)) 355 + return 0; 356 + 357 + if (!b || b->type != TYPEMULTIPART || 358 + !b->subtype || ascii_strcasecmp (b->subtype, "mixed")) 359 + return 0; 360 + 361 + b = b->parts; 362 + if (!b || b->type != TYPETEXT || 363 + !b->subtype || ascii_strcasecmp (b->subtype, "plain") || 364 + b->length != 0) 365 + return 0; 366 + 367 + b = b->next; 368 + if (!b || b->type != TYPEAPPLICATION || 369 + !b->subtype || ascii_strcasecmp (b->subtype, "pgp-encrypted")) 370 + return 0; 371 + 372 + b = b->next; 373 + if (!b || b->type != TYPEAPPLICATION || 374 + !b->subtype || ascii_strcasecmp (b->subtype, "octet-stream")) 375 + return 0; 376 + 377 + b = b->next; 378 + if (b) 379 + return 0; 380 + 381 + return PGPENCRYPT; 321 382 } 322 383 323 384 ··· 469 530 { 470 531 t |= mutt_is_multipart_encrypted(m); 471 532 t |= mutt_is_multipart_signed (m); 533 + t |= mutt_is_malformed_multipart_pgp_encrypted (m); 472 534 473 535 if (t && m->goodsig) 474 536 t |= GOODSIGN;
+129 -101
handler.c
··· 1590 1590 return 0; 1591 1591 } 1592 1592 1593 - int mutt_body_handler (BODY *b, STATE *s) 1593 + static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int plaintext) 1594 1594 { 1595 - int decode = 0; 1596 - int plaintext = 0; 1595 + int origType; 1596 + char *savePrefix = NULL; 1597 1597 FILE *fp = NULL; 1598 1598 char tempfile[_POSIX_PATH_MAX]; 1599 - handler_t handler = NULL; 1599 + size_t tmplength = 0; 1600 1600 LOFF_T tmpoffset = 0; 1601 - size_t tmplength = 0; 1601 + int decode = 0; 1602 + int rc = 0; 1603 + 1604 + fseeko (s->fpin, b->offset, 0); 1605 + 1606 + /* see if we need to decode this part before processing it */ 1607 + if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE || 1608 + b->encoding == ENCUUENCODED || plaintext || 1609 + mutt_is_text_part (b)) /* text subtypes may 1610 + * require character 1611 + * set conversion even 1612 + * with 8bit encoding. 1613 + */ 1614 + { 1615 + origType = b->type; 1616 + 1617 + if (!plaintext) 1618 + { 1619 + /* decode to a tempfile, saving the original destination */ 1620 + fp = s->fpout; 1621 + mutt_mktemp (tempfile, sizeof (tempfile)); 1622 + if ((s->fpout = safe_fopen (tempfile, "w")) == NULL) 1623 + { 1624 + mutt_error _("Unable to open temporary file!"); 1625 + dprint (1, (debugfile, "Can't open %s.\n", tempfile)); 1626 + return -1; 1627 + } 1628 + /* decoding the attachment changes the size and offset, so save a copy 1629 + * of the "real" values now, and restore them after processing 1630 + */ 1631 + tmplength = b->length; 1632 + tmpoffset = b->offset; 1633 + 1634 + /* if we are decoding binary bodies, we don't want to prefix each 1635 + * line with the prefix or else the data will get corrupted. 1636 + */ 1637 + savePrefix = s->prefix; 1638 + s->prefix = NULL; 1639 + 1640 + decode = 1; 1641 + } 1642 + else 1643 + b->type = TYPETEXT; 1644 + 1645 + mutt_decode_attachment (b, s); 1646 + 1647 + if (decode) 1648 + { 1649 + b->length = ftello (s->fpout); 1650 + b->offset = 0; 1651 + safe_fclose (&s->fpout); 1652 + 1653 + /* restore final destination and substitute the tempfile for input */ 1654 + s->fpout = fp; 1655 + fp = s->fpin; 1656 + s->fpin = fopen (tempfile, "r"); 1657 + unlink (tempfile); 1658 + 1659 + /* restore the prefix */ 1660 + s->prefix = savePrefix; 1661 + } 1662 + 1663 + b->type = origType; 1664 + } 1665 + 1666 + /* process the (decoded) body part */ 1667 + if (handler) 1668 + { 1669 + rc = handler (b, s); 1670 + 1671 + if (rc) 1672 + { 1673 + dprint (1, (debugfile, "Failed on attachment of type %s/%s.\n", TYPE(b), NONULL (b->subtype))); 1674 + } 1675 + 1676 + if (decode) 1677 + { 1678 + b->length = tmplength; 1679 + b->offset = tmpoffset; 1680 + 1681 + /* restore the original source stream */ 1682 + safe_fclose (&s->fpin); 1683 + s->fpin = fp; 1684 + } 1685 + } 1686 + s->flags |= M_FIRSTDONE; 1687 + 1688 + return rc; 1689 + } 1690 + 1691 + static int valid_pgp_encrypted_handler (BODY *b, STATE *s) 1692 + { 1693 + int rc; 1694 + BODY *octetstream; 1695 + 1696 + octetstream = b->parts->next; 1697 + rc = crypt_pgp_encrypted_handler (octetstream, s); 1698 + b->goodsig |= octetstream->goodsig; 1699 + 1700 + return rc; 1701 + } 1702 + 1703 + static int malformed_pgp_encrypted_handler (BODY *b, STATE *s) 1704 + { 1705 + int rc; 1706 + BODY *octetstream; 1707 + 1708 + octetstream = b->parts->next->next; 1709 + /* exchange encodes the octet-stream, so re-run it through the decoder */ 1710 + rc = run_decode_and_handler (octetstream, s, crypt_pgp_encrypted_handler, 0); 1711 + b->goodsig |= octetstream->goodsig; 1712 + 1713 + return rc; 1714 + } 1715 + 1716 + int mutt_body_handler (BODY *b, STATE *s) 1717 + { 1718 + int plaintext = 0; 1719 + handler_t handler = NULL; 1602 1720 int rc = 0; 1603 1721 1604 1722 int oflags = s->flags; ··· 1653 1771 else if (s->flags & M_VERIFY) 1654 1772 handler = mutt_signed_handler; 1655 1773 } 1656 - else if ((WithCrypto & APPLICATION_PGP) 1657 - && ascii_strcasecmp ("encrypted", b->subtype) == 0) 1658 - { 1659 - p = mutt_get_parameter ("protocol", b->parameter); 1660 - 1661 - if (!p) 1662 - mutt_error _("Error: multipart/encrypted has no protocol parameter!"); 1663 - else if (ascii_strcasecmp ("application/pgp-encrypted", p) == 0) 1664 - handler = crypt_pgp_encrypted_handler; 1665 - } 1774 + else if (mutt_is_valid_multipart_pgp_encrypted (b)) 1775 + handler = valid_pgp_encrypted_handler; 1776 + else if (mutt_is_malformed_multipart_pgp_encrypted (b)) 1777 + handler = malformed_pgp_encrypted_handler; 1666 1778 1667 1779 if (!handler) 1668 1780 handler = multipart_handler; 1669 - 1781 + 1670 1782 if (b->encoding != ENC7BIT && b->encoding != ENC8BIT 1671 1783 && b->encoding != ENCBINARY) 1672 1784 { ··· 1695 1807 option(OPTVIEWATTACH))) && 1696 1808 (plaintext || handler)) 1697 1809 { 1698 - fseeko (s->fpin, b->offset, 0); 1699 - 1700 - /* see if we need to decode this part before processing it */ 1701 - if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE || 1702 - b->encoding == ENCUUENCODED || plaintext || 1703 - mutt_is_text_part (b)) /* text subtypes may 1704 - * require character 1705 - * set conversion even 1706 - * with 8bit encoding. 1707 - */ 1708 - { 1709 - int origType = b->type; 1710 - char *savePrefix = NULL; 1711 - 1712 - if (!plaintext) 1713 - { 1714 - /* decode to a tempfile, saving the original destination */ 1715 - fp = s->fpout; 1716 - mutt_mktemp (tempfile, sizeof (tempfile)); 1717 - if ((s->fpout = safe_fopen (tempfile, "w")) == NULL) 1718 - { 1719 - mutt_error _("Unable to open temporary file!"); 1720 - dprint (1, (debugfile, "Can't open %s.\n", tempfile)); 1721 - goto bail; 1722 - } 1723 - /* decoding the attachment changes the size and offset, so save a copy 1724 - * of the "real" values now, and restore them after processing 1725 - */ 1726 - tmplength = b->length; 1727 - tmpoffset = b->offset; 1728 - 1729 - /* if we are decoding binary bodies, we don't want to prefix each 1730 - * line with the prefix or else the data will get corrupted. 1731 - */ 1732 - savePrefix = s->prefix; 1733 - s->prefix = NULL; 1734 - 1735 - decode = 1; 1736 - } 1737 - else 1738 - b->type = TYPETEXT; 1739 - 1740 - mutt_decode_attachment (b, s); 1741 - 1742 - if (decode) 1743 - { 1744 - b->length = ftello (s->fpout); 1745 - b->offset = 0; 1746 - safe_fclose (&s->fpout); 1747 - 1748 - /* restore final destination and substitute the tempfile for input */ 1749 - s->fpout = fp; 1750 - fp = s->fpin; 1751 - s->fpin = fopen (tempfile, "r"); 1752 - unlink (tempfile); 1753 - 1754 - /* restore the prefix */ 1755 - s->prefix = savePrefix; 1756 - } 1757 - 1758 - b->type = origType; 1759 - } 1760 - 1761 - /* process the (decoded) body part */ 1762 - if (handler) 1763 - { 1764 - rc = handler (b, s); 1765 - 1766 - if (rc) 1767 - { 1768 - dprint (1, (debugfile, "Failed on attachment of type %s/%s.\n", TYPE(b), NONULL (b->subtype))); 1769 - } 1770 - 1771 - if (decode) 1772 - { 1773 - b->length = tmplength; 1774 - b->offset = tmpoffset; 1775 - 1776 - /* restore the original source stream */ 1777 - safe_fclose (&s->fpin); 1778 - s->fpin = fp; 1779 - } 1780 - } 1781 - s->flags |= M_FIRSTDONE; 1810 + rc = run_decode_and_handler (b, s, handler, plaintext); 1782 1811 } 1783 1812 /* print hint to use attachment menu for disposition == attachment 1784 1813 if we're not already being called from there */ ··· 1805 1834 fputs (" --]\n", s->fpout); 1806 1835 } 1807 1836 1808 - bail: 1809 1837 s->flags = oflags | (s->flags & M_FIRSTDONE); 1810 1838 if (rc) 1811 1839 {
+4
mutt_crypt.h
··· 112 112 113 113 int mutt_is_multipart_encrypted (BODY *); 114 114 115 + int mutt_is_valid_multipart_pgp_encrypted (BODY *b); 116 + 117 + int mutt_is_malformed_multipart_pgp_encrypted (BODY *b); 118 + 115 119 int mutt_is_multipart_signed (BODY *); 116 120 117 121 int mutt_is_application_pgp (BODY *);
+64 -34
pgp.c
··· 954 954 char tempfile[_POSIX_PATH_MAX]; 955 955 STATE s; 956 956 BODY *p = b; 957 - 958 - if(!mutt_is_multipart_encrypted(b)) 957 + int need_decode = 0; 958 + int saved_type; 959 + LOFF_T saved_offset; 960 + size_t saved_length; 961 + FILE *decoded_fp = NULL; 962 + int rv = 0; 963 + 964 + if (mutt_is_valid_multipart_pgp_encrypted (b)) 965 + b = b->parts->next; 966 + else if (mutt_is_malformed_multipart_pgp_encrypted (b)) 967 + { 968 + b = b->parts->next->next; 969 + need_decode = 1; 970 + } 971 + else 959 972 return -1; 960 973 961 - if(!b->parts || !b->parts->next) 962 - return -1; 963 - 964 - b = b->parts->next; 965 - 966 974 memset (&s, 0, sizeof (s)); 967 975 s.fpin = fpin; 976 + 977 + if (need_decode) 978 + { 979 + saved_type = b->type; 980 + saved_offset = b->offset; 981 + saved_length = b->length; 982 + 983 + mutt_mktemp (tempfile, sizeof (tempfile)); 984 + if ((decoded_fp = safe_fopen (tempfile, "w+")) == NULL) 985 + { 986 + mutt_perror (tempfile); 987 + return (-1); 988 + } 989 + unlink (tempfile); 990 + 991 + fseeko (s.fpin, b->offset, 0); 992 + s.fpout = decoded_fp; 993 + 994 + mutt_decode_attachment (b, &s); 995 + 996 + fflush (decoded_fp); 997 + b->length = ftello (decoded_fp); 998 + b->offset = 0; 999 + rewind (decoded_fp); 1000 + s.fpin = decoded_fp; 1001 + s.fpout = 0; 1002 + } 1003 + 968 1004 mutt_mktemp (tempfile, sizeof (tempfile)); 969 1005 if ((*fpout = safe_fopen (tempfile, "w+")) == NULL) 970 1006 { 971 1007 mutt_perror (tempfile); 972 - return (-1); 1008 + rv = -1; 1009 + goto bail; 973 1010 } 974 1011 unlink (tempfile); 975 1012 976 - *cur = pgp_decrypt_part (b, &s, *fpout, p); 1013 + if ((*cur = pgp_decrypt_part (b, &s, *fpout, p)) == NULL) 1014 + rv = -1; 1015 + rewind (*fpout); 1016 + 1017 + bail: 1018 + if (need_decode) 1019 + { 1020 + b->type = saved_type; 1021 + b->length = saved_length; 1022 + b->offset = saved_offset; 1023 + safe_fclose (&decoded_fp); 1024 + } 977 1025 978 - rewind (*fpout); 979 - 980 - if (!*cur) 981 - return -1; 982 - 983 - return (0); 1026 + return rv; 984 1027 } 985 1028 1029 + /* 1030 + * This handler is passed the application/octet-stream directly. 1031 + * The caller must propagate a->goodsig to its parent. 1032 + */ 986 1033 int pgp_encrypted_handler (BODY *a, STATE *s) 987 1034 { 988 1035 char tempfile[_POSIX_PATH_MAX]; 989 1036 FILE *fpout, *fpin; 990 1037 BODY *tattach; 991 - BODY *p = a; 992 1038 int rc = 0; 993 - 994 - a = a->parts; 995 - if (!a || a->type != TYPEAPPLICATION || !a->subtype || 996 - ascii_strcasecmp ("pgp-encrypted", a->subtype) != 0 || 997 - !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype || 998 - ascii_strcasecmp ("octet-stream", a->next->subtype) != 0) 999 - { 1000 - if (s->flags & M_DISPLAY) 1001 - state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"), s); 1002 - return -1; 1003 - } 1004 - 1005 - /* 1006 - * Move forward to the application/pgp-encrypted body. 1007 - */ 1008 - a = a->next; 1009 1039 1010 1040 mutt_mktemp (tempfile, sizeof (tempfile)); 1011 1041 if ((fpout = safe_fopen (tempfile, "w+")) == NULL) ··· 1017 1047 1018 1048 if (s->flags & M_DISPLAY) crypt_current_time (s, "PGP"); 1019 1049 1020 - if ((tattach = pgp_decrypt_part (a, s, fpout, p)) != NULL) 1050 + if ((tattach = pgp_decrypt_part (a, s, fpout, a)) != NULL) 1021 1051 { 1022 1052 if (s->flags & M_DISPLAY) 1023 1053 state_attach_puts (_("[-- The following data is PGP/MIME encrypted --]\n\n"), s); ··· 1035 1065 */ 1036 1066 1037 1067 if (mutt_is_multipart_signed (tattach) && !tattach->next) 1038 - p->goodsig |= tattach->goodsig; 1068 + a->goodsig |= tattach->goodsig; 1039 1069 1040 1070 if (s->flags & M_DISPLAY) 1041 1071 {
+2 -1
recvattach.c
··· 996 996 } 997 997 if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP)) 998 998 { 999 - if (mutt_is_multipart_encrypted(hdr->content)) 999 + if (mutt_is_multipart_encrypted(hdr->content) || 1000 + mutt_is_malformed_multipart_pgp_encrypted(hdr->content)) 1000 1001 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur); 1001 1002 else 1002 1003 need_secured = 0;