summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>2017-02-14 19:38:41 +0100
committerPhil Pennock <pdp@exim.org>2017-02-14 18:24:27 -0500
commit5db00eeac41e74cb9749b6344258b38b1da8c700 (patch)
treebf8296e5570b1bf7c1df6037ad3605107e85a541
parentd1673981c8c80b5aaa0cd4031d37663a2b2fa889 (diff)
downloadexim4-5db00eeac41e74cb9749b6344258b38b1da8c700.tar.gz
Fix missing line termination on the last received BDAT chunk (Bug 1974)
(cherry picked from commit d953610fa77ec9a08fad9c1a183181079a79674e) Signed-off-by: Phil Pennock <pdp@exim.org>
-rw-r--r--doc/doc-txt/ChangeLog4
-rw-r--r--src/src/receive.c30
2 files changed, 33 insertions, 1 deletions
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 39e17b350..23f05ebe9 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -102,6 +102,10 @@ JH/17 Fix inbound CHUNKING when DKIM disabled at runtime.
HS/01 Fix portability problems introduced by PP/08 for platforms where
realloc(NULL) is not equivalent to malloc() [SunOS et al].
+HS/02 Bug 1974: Fix missing line terminator on the last received BDAT
+ chunk. This allows us to accept broken chunked messages. We need a more
+ general solution here.
+
Exim version 4.88
-----------------
diff --git a/src/src/receive.c b/src/src/receive.c
index b152ceefb..5125a4f47 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -916,14 +916,41 @@ read_message_bdat_smtp(FILE *fout)
{
int linelength = 0, ch;
enum CH_STATE ch_state = LF_SEEN;
+BOOL fix_nl = FALSE;
for(;;)
{
switch ((ch = (bdat_getc)(GETC_BUFFER_UNLIMITED)))
{
case EOF: return END_EOF;
- case EOD: return END_DOT; /* normal exit */
case ERR: return END_PROTOCOL;
+ case EOD:
+ /* Nothing to get from the sender anymore. We check the last
+ character written to the spool.
+
+ RFC 3030 states, that BDAT chunks are normal text, terminated by CRLF.
+ If we would be strict, we would refuse such broken messages.
+ But we are liberal, so we fix it. It would be easy just to append
+ the "\n" to the spool.
+
+ But there are some more things (line counting, message size calculation and such),
+ that would need to be duplicated here. So we simply do some ungetc
+ trickery.
+ */
+ fseek(fout, -1, SEEK_CUR);
+ if (fgetc(fout) == '\n') return END_DOT;
+
+ if (linelength == -1) /* \r already seen (see below) */
+ {
+ DEBUG(D_receive) debug_printf("Add missing LF\n");
+ bdat_ungetc('\n');
+ continue;
+ }
+ DEBUG(D_receive) debug_printf("Add missing CRLF\n");
+ bdat_ungetc('\r'); /* not even \r was seen */
+ fix_nl = TRUE;
+
+ continue;
case '\0': body_zerocount++; break;
}
switch (ch_state)
@@ -944,6 +971,7 @@ for(;;)
else if (ch == '\r')
{
ch_state = CR_SEEN;
+ if (fix_nl) bdat_ungetc('\n');
continue; /* don't write CR */
}
break;