nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 83e8e3215d2f664d6bb369562fcabb427fb18b5a
parent 0117ad3ff8a1354e0c6af3ebe2435c9bd5c4483a
Author: Rolf Eike Beer <eike@sf-mail.de>
Date:   Mon, 21 Feb 2005 14:07:21 +0100

qmail-remote: avoid recoding CRLF to CRCRLF

If qmail-remote get's a '\r' (CR, carriage return) in it's input stream (which
means that a mail injected into qmail-queue contained a '\r') it will send this
unmasked to the network. This patch works this way: if there is a single '\r'
somewhere in the input stream it is handled as a line break, so it is send as
CRLF to the network. If there is a CRLF sequence in the input stream (normally
there should only be bare LFs) it will not double the CR (like qmail-remote
normally does) but send this CRLF sequence as is.

Diffstat:
MCHANGES.md | 1+
Mqmail-remote.c | 10++++++++++
Mtests/.gitignore | 2++
Mtests/Makefile | 26++++++++++++++++++++++++--
Atests/unittest_blast.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 188 insertions(+), 2 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md @@ -1,3 +1,4 @@ +- 20200803 avoid sending CRCRLF in qmail-remote if input contains CRLF - 20200614 remove maildirwatch - 20200614 stop rewriting RCPT TO: domains when they are a CNAME (RFC 5321 5.1) - 20200523 doc: give text files .md extensions. diff --git a/qmail-remote.c b/qmail-remote.c @@ -200,6 +200,16 @@ void blast() if (ch == '.') substdio_put(&smtpto,".",1); while (ch != '\n') { + if (ch == '\r') { + r = substdio_get(&ssin, &ch, 1); + if (r == 0) + break; + if (r == -1) temp_read(); + if (ch != '\n') { + substdio_put(&smtpto, "\r\n", 2); + } else + break; + } substdio_put(&smtpto,&ch,1); r = substdio_get(&ssin,&ch,1); if (r == 0) perm_partialline(); diff --git a/tests/.gitignore b/tests/.gitignore @@ -1,2 +1,4 @@ *.o +unittest_blast unittest_stralloc +blast.c diff --git a/tests/Makefile b/tests/Makefile @@ -9,10 +9,10 @@ default: it .PHONY: clean default it test -TESTBINS = unittest_stralloc +TESTBINS = unittest_stralloc unittest_blast clean: - rm -f $(TESTBINS) *.o + rm -f $(TESTBINS) *.o blast.c it: $(TESTBINS) @@ -30,3 +30,25 @@ unittest_stralloc.o: \ ../compile unittest_stralloc.c ../alloc.h ../stralloc.h ../compile unittest_stralloc.c -I.. \ `pkg-config --cflags check` + +blast.c: ../qmail-remote.c + `head -n $$(grep -n '^int main(' ../qmail-remote.c | sed 's/:.*//') ../qmail-remote.c | sed '/^int main(/d' > blast.c` + +blast.o: ../compile blast.c + ../compile blast.c -I.. + +unittest_blast: \ +../load unittest_blast.o blast.o ../control.o ../ip.o ../constmap.o \ +../timeoutread.o ../timeoutwrite.o ../quote.o \ +../stralloc.a ../str.a ../error.a ../substdio.a ../fs.a ../open.a ../str.a \ +../getln.a ../case.a + ../load unittest_blast blast.o ../control.o ../ip.o ../constmap.o \ + ../timeoutread.o ../timeoutwrite.o ../quote.o \ + ../stralloc.a ../str.a ../error.a ../substdio.a ../fs.a ../open.a \ + ../getln.a ../str.a ../case.a \ + `pkg-config --libs check` + +unittest_blast.o: \ +../compile unittest_blast.c ../alloc.h ../stralloc.h + ../compile unittest_blast.c -I.. \ + `pkg-config --cflags check` diff --git a/tests/unittest_blast.c b/tests/unittest_blast.c @@ -0,0 +1,151 @@ +#include <check.h> + +#include "substdio.h" + +/* provided by qmail-remote.c/blast.c */ +extern void blast(); +extern char inbuf[1024]; +extern substdio ssin; +extern char smtptobuf[1024]; +extern substdio smtpto; + +static const char *readexpect; +static const char *writeexpect; +static size_t readoffs; +static size_t writeoffs; + +int readstub(int fd, char *buf, int len) +{ + size_t inlen = strlen(readexpect) - readoffs; + + ck_assert_int_eq(fd, -1); + ck_assert_int_gt(len, 0); + + if (len < inlen) + inlen = len; + + if (inlen > 0) { + memcpy(buf, readexpect + readoffs, inlen); + readoffs += inlen; + } + + return inlen; +} + +int writestub(int fd, const char *buf, int len) +{ + size_t outlen = strlen(writeexpect) - writeoffs; + + ck_assert_int_eq(fd, -1); + ck_assert_int_gt(len, 0); + + if (len < outlen) + outlen = len; + +#if (CHECK_MAJOR_VERSION > 0) || (CHECK_MINOR_VERSION >= 11) + ck_assert_mem_eq(writeexpect + writeoffs, buf, outlen); +#else + ck_assert_int_eq(memcmp(writeexpect + writeoffs, buf, outlen), 0); +#endif + + writeoffs += outlen; + + return outlen; +} + +static void ssin_setup(const char *indata, const char *outdata) +{ + substdio tmpin = SUBSTDIO_FDBUF(readstub,-1,inbuf,sizeof inbuf); + substdio tmpto = SUBSTDIO_FDBUF(writestub,-1,smtptobuf,sizeof smtptobuf); + ssin = tmpin; + smtpto = tmpto; + + readexpect = indata; + readoffs = 0; + writeexpect = outdata; + writeoffs = 0; +} + +START_TEST(test_blast_empty) +{ + const char *dotcrlf = ".\r\n"; + + ssin_setup("", dotcrlf); + + blast(); + + ck_assert_uint_eq(writeoffs, strlen(dotcrlf)); +} +END_TEST + +START_TEST(test_blast_dot) +{ + const char *dotcrlf = "..\r\n.\r\n"; + + ssin_setup(".\n", dotcrlf); + + blast(); + + ck_assert_uint_eq(writeoffs, strlen(dotcrlf)); +} +END_TEST + +START_TEST(test_blast_barecr) +{ + const char *dotcrlf = "cr\r\nlf\r\n.\r\n"; + + ssin_setup("cr\rlf\n", dotcrlf); + + blast(); + + ck_assert_uint_eq(writeoffs, strlen(dotcrlf)); +} +END_TEST + +START_TEST(test_blast_crlf) +{ + const char *dotcrlf = "..\r\n.\r\n"; + + ssin_setup(".\r\n", dotcrlf); + + blast(); + + ck_assert_uint_eq(writeoffs, strlen(dotcrlf)); +} +END_TEST + +TCase +*blast_something(void) +{ + TCase *tc = tcase_create("basic operations"); + + tcase_add_test(tc, test_blast_empty); + tcase_add_test(tc, test_blast_dot); + tcase_add_test(tc, test_blast_barecr); + tcase_add_test(tc, test_blast_crlf); + + return tc; +} + +Suite +*blast_suite(void) +{ + Suite *s = suite_create("notqmail qmail-remote blast"); + + suite_add_tcase(s, blast_something()); + + return s; +} + +int +main(void) +{ + int number_failed; + + SRunner *sr = srunner_create(blast_suite()); + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + + return number_failed; +}