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:
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;
+}