NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: bin/47567: Mail(1)/mailx(1)/mail(1) - quoted-printable CTE excesses RFC limit
The following reply was made to PR bin/47567; it has been noted by GNATS.
From: Steffen "Daode" Nurpmeso <sdaoden%gmail.com@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: gnats-admin%netbsd.org@localhost, netbsd-bugs%netbsd.org@localhost
Subject: Re: bin/47567: Mail(1)/mailx(1)/mail(1) - quoted-printable CTE
excesses RFC limit
Date: Thu, 14 Feb 2013 19:15:43 +0100
This is a multi-part message in MIME format.
--=_01360865743=-C2i7u6QpIKuG+1sOp7X1OrfKIFPZ+M=_
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
sdaoden%gmail.com@localhost wrote:
|>Number: 47567
|>Category: bin
|>Synopsis: Mail(1)/mailx(1)/mail(1) - quoted-printable CTE excesses \
| RFC limit
|>Confidential: no
|>Severity: non-critical
|>Priority: low
|>Responsible: bin-bug-people
|>State: open
|>Class: sw-bug
|>Submitter-Id: net
|>Arrival-Date: Thu Feb 14 18:00:00 +0000 2013
|>Originator: Steffen Nurpmeso
|>Release: 6.99.16
|>Organization:
|>Environment:
|NetBSD nhead 6.99.16 NetBSD 6.99.16 (GENERIC) #0: Mon Feb 11 21:12:26 UTC \
|2013
builds%b6.netbsd.org@localhost:/home/builds/ab/HEAD/amd64/201302111840Z-obj/home\
|/builds/ab/HEAD/src/sys/arch/amd64/compile/GENERIC amd64
|
|>Description:
|mail(1) may excess the 76 character line limit as REQUIREd by RFC 2045.
|
|>How-To-Repeat:
|cat <<_EOT | awk 'BEGIN{ORS="\r\n"}{print}' | env mime-encode-message= mail \
|-s test ./test.mbox
|Ich bin eine DOS-Datei mit sehr langen Zeilen und auch sonst sehr doof.
|Ich bin eine DOS-Datei mit sehr langen Zeilen und auch sonst sehr doof..
|Ich bin eine DOS-Datei mit sehr langen Zeilen und auch sonst sehr doof...
|Ich bin eine DOS-Datei mit sehr langen Zeilen und auch sonst sehr doof....
|_EOT
|>Fix:
|I'll reply with a patch that addresses the problem.
|
|It'll also encapsulate all the content-transfer-encoding stuff in \
|mime_codecs.c and replace calls of strtol(3) with a handcrafted version \
|that allows simple error checking by testing the return value.
|
|The latter allowed to easily add special code to handle illegal QP \
|sequences.
The patch:
--steffen
--=_01360865743=-C2i7u6QpIKuG+1sOp7X1OrfKIFPZ+M=_
Content-Type: text/diff; charset=US-ASCII
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="nbsd-mail.diff"
--- mime_codecs.c.orig 2013-02-12 19:25:00.000000000 +0100
+++ mime_codecs.c 2013-02-13 04:08:50.000000000 +0100
@@ -389,10 +389,84 @@ mime_fB64_decode(FILE *fi, FILE *fo, voi
/************************************************************************
* Core quoted-printable routines.
*
- * Note: the header QP routines are slightly different and burried
- * inside mime_header.c
+ * Defined in sec 6.7 of RFC 2045.
*/
=20
+/*
+ * strtol(3), but inline and with easy error indication.
+ */
+static inline int
+_qp_cfromhex(char const *hex)
+{
+ /* Be robust, allow lowercase hexadecimal letters, too */
+ static unsigned char const atoi16[] =3D {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x30-0x37 */
+ 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x38-0x3F */
+ 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, /* 0x40-0x47 */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x48-0x4f */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x50-0x57 */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x58-0x5f */
+ 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF /* 0x60-0x67 */
+ };
+ unsigned char i1, i2;
+ int r;
+
+ if ((i1 =3D (unsigned char)hex[0] - '0') >=3D __arraycount(atoi16) ||
+ (i2 =3D (unsigned char)hex[1] - '0') >=3D __arraycount(atoi16))
+ goto jerr;
+ i1 =3D atoi16[i1];
+ i2 =3D atoi16[i2];
+ if ((i1 | i2) & 0xF0)
+ goto jerr;
+ r =3D i1;
+ r <<=3D 4;
+ r +=3D i2;
+jleave:
+ return r;
+jerr:
+ r =3D -1;
+ goto jleave;
+}
+
+/*
+ * Header specific "quoted-printable" decode!
+ * Differences with body QP decoding (see rfc 2047, sec 4.2):
+ * 1) '=3D' occurs _only_ when followed by two hex digits (FWS is not allo=
wed).
+ * 2) Spaces can be encoded as '_' in headers for readability.
+ */
+static ssize_t
+mime_QPh_decode(char *outbuf, size_t outlen, const char *inbuf, size_t inl=
en)
+{
+ const char *p, *inend;
+ char *outend;
+ char *q;
+
+ outend =3D outbuf + outlen;
+ inend =3D inbuf + inlen;
+ q =3D outbuf;
+ for (p =3D inbuf; p < inend; p++) {
+ if (q >=3D outend)
+ return -1;
+ if (*p =3D=3D '=3D') {
+ p++;
+ if (p + 1 < inend) {
+ int c =3D _qp_cfromhex(p++);
+ if (c < 0)
+ return -1;
+ *q++ =3D (char)c;
+ }
+ else
+ return -1;
+ }
+ else if (*p =3D=3D '_') /* header's may encode ' ' as '_' */
+ *q++ =3D ' ';
+ else
+ *q++ =3D *p;
+ }
+ return q - outbuf;
+}
+
+
static int
mustquote(unsigned char *p, unsigned char *end, size_t l)
{
@@ -479,8 +553,11 @@ fput_quoted_line(FILE *fo, char *line, s
}
else {
if (*p =3D=3D '\n') {
- if (p > beg && p[-1] =3D=3D '\r')
+ if (p > beg && p[-1] =3D=3D '\r') {
+ if (l + 4 > limit)
+ (void)fputs("=3D\n", fo);
(void)fputs("=3D0A=3D", fo);
+ }
l =3D (size_t)-1;
}
else if (l + 2 > limit) {
@@ -541,14 +618,11 @@ mime_fQP_decode(FILE *fi, FILE *fo, void
while (p < end && is_WSP(*p))
p++;
if (*p !=3D '\n' && p + 1 < end) {
- int c;
- char buf[3];
-
- buf[0] =3D *p++;
- buf[1] =3D *p;
- buf[2] =3D '\0';
- c =3D (int)strtol(buf, NULL, 16);
- (void)fputc(c, fo);
+ int c =3D _qp_cfromhex(p++);
+ if (c >=3D 0)
+ (void)fputc(c, fo);
+ else
+ (void)fputs("[?]", fo);
}
}
else
@@ -631,6 +705,24 @@ mime_fio_decoder(const char *ename)
}
=20
/*
+ * Decode a RFC 2047 extended message header *encoded-word*.
+ * *encoding* is the corresponding character of the *encoded-word*.
+ */
+PUBLIC ssize_t
+mime_rfc2047_decode(char encoding, char *outbuf, size_t outlen,
+ const char *inbuf, size_t inlen)
+{
+ ssize_t declen =3D -1;
+
+ if (encoding =3D=3D 'B' || encoding =3D=3D 'b') {
+ if (outlen >=3D 3 * roundup(inlen, 4) / 4)
+ declen =3D mime_b64tobin(outbuf, inbuf, inlen);
+ } else if (encoding =3D=3D 'Q' || encoding =3D=3D 'q')
+ declen =3D mime_QPh_decode(outbuf, outlen, inbuf, inlen);
+ return declen;
+}
+
+/*
* This is for use in complete.c and mime.c to get the list of
* encoding names without exposing the transfer_encoding_tbl[]. The
* first name is returned if called with a pointer to a NULL pointer.
--- mime_codecs.h.orig 2013-02-12 19:25:05.000000000 +0100
+++ mime_codecs.h 2013-02-12 19:58:45.000000000 +0100
@@ -50,6 +50,8 @@ mime_codec_t mime_fio_decoder(const char
=20
void mime_fio_copy(FILE *, FILE *, void *);
=20
+ssize_t mime_rfc2047_decode(char, char *, size_t, const char *, size_t);
+
#include "mime.h"
=20
/* This is also declared in mime.h for export to complete.c. */
--- mime_header.c.orig 2013-02-12 19:25:16.000000000 +0100
+++ mime_header.c 2013-02-12 19:58:26.000000000 +0100
@@ -53,68 +53,6 @@ __RCSID("$NetBSD: mime_header.c,v 1.8 20
#include "mime_header.h"
#include "mime_codecs.h"
=20
-/*
- * Our interface to mime_b64tobin()
- *
- * XXX - This should move to mime_codecs.c.
- */
-static ssize_t
-mime_B64_decode(char *outbuf, size_t outlen, const char *inbuf, size_t inl=
en)
-{
- if (outlen < 3 * roundup(inlen, 4) / 4)
- return -1;
-
- return mime_b64tobin(outbuf, inbuf, inlen);
-}
-
-
-/*
- * Header specific "quoted-printable" decode!
- * Differences with body QP decoding (see rfc 2047, sec 4.2):
- * 1) '=3D' occurs _only_ when followed by two hex digits (FWS is not allo=
wed).
- * 2) Spaces can be encoded as '_' in headers for readability.
- *
- * XXX - This should move to mime_codecs.c.
- */
-static ssize_t
-mime_QPh_decode(char *outbuf, size_t outlen, const char *inbuf, size_t inl=
en)
-{
- const char *p, *inend;
- char *outend;
- char *q;
-
- outend =3D outbuf + outlen;
- inend =3D inbuf + inlen;
- q =3D outbuf;
- for (p =3D inbuf; p < inend; p++) {
- if (q >=3D outend)
- return -1;
- if (*p =3D=3D '=3D') {
- p++;
- if (p + 1 < inend) {
- size_t c;
- char *bufend;
- char buf[3];
-
- buf[0] =3D *p++;
- buf[1] =3D *p;
- buf[2] =3D '\0';
- c =3D strtol(buf, &bufend, 16);
- if (bufend !=3D &buf[2])
- return -1;
- *q++ =3D (char)c;
- }
- else
- return -1;
- }
- else if (*p =3D=3D '_') /* header's may encode ' ' as '_' */
- *q++ =3D ' ';
- else
- *q++ =3D *p;
- }
- return q - outbuf;
-}
-
static const char *
grab_charset(char *from_cs, size_t from_cs_len, const char *p)
{
@@ -190,13 +128,7 @@ decode_word(const char **ibuf, char **ob
dstend =3D to_cs ? decword : *obuf;
dstlen =3D (to_cs ? sizeof(decword) : (size_t)(oend - *obuf)) - 1;
=20
- if (enctype =3D=3D 'B' || enctype =3D=3D 'b')
- declen =3D mime_B64_decode(dstend, dstlen, encword, enclen);
- else if (enctype =3D=3D 'Q' || enctype =3D=3D 'q')
- declen =3D mime_QPh_decode(dstend, dstlen, encword, enclen);
- else
- return -1;
-
+ declen =3D mime_rfc2047_decode(enctype, dstend, dstlen, encword,
enclen);
if (declen =3D=3D -1)
return -1;
=20
--=_01360865743=-C2i7u6QpIKuG+1sOp7X1OrfKIFPZ+M=_--
Home |
Main Index |
Thread Index |
Old Index