Gitweb:
https://git.exim.org/exim.git/commitdiff/7f83b348ccf4cd815e9758ab9ca1012e66324e9d
Commit: 7f83b348ccf4cd815e9758ab9ca1012e66324e9d
Parent: cebf4027931177cc70106a84e19705f2085a09f5
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Fri Aug 14 13:09:53 2020 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Fri Aug 14 14:10:06 2020 +0100
Fix ${readsocket } eol-replacement. Bug 2630
---
doc/doc-txt/ChangeLog | 4 ++++
src/src/expand.c | 11 +++++++----
src/src/functions.h | 2 +-
src/src/lookups/readsock.c | 6 ++++--
src/src/macros.h | 6 ++++--
src/src/readconf.c | 4 ++--
src/src/string.c | 30 +++++++++++++++++++-----------
test/scripts/0000-Basic/0373 | 28 +++++++++++++++++++++++++++-
test/stdout/0373 | 38 ++++++++++++++++++++++++++++++++++++++
9 files changed, 106 insertions(+), 23 deletions(-)
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index d56ff24..8c4126e 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -100,6 +100,10 @@ JH/20 Bug 2631: ACL dnslist conditions now ignore and log any lookups returns
not in 127.0.0.0/8 to help in spotting list domains taken over by a
domain-parking registrar.
+JH/21 Bug 2630: Fix trace eol-replacement string for the ${readsocket }
+ expansion. Previously when a whitespace character was specified it
+ was not inserted after removing the newline.
+
Exim version 4.94
-----------------
diff --git a/src/src/expand.c b/src/src/expand.c
index 7b8462e..9bb30de 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -4916,7 +4916,7 @@ while (*s)
{
expand_string_message =
string_sprintf("lookup of \"%s\" gave DEFER: %s",
- string_printing2(key, FALSE), search_error_message);
+ string_printing2(key, SP_TAB), search_error_message);
goto EXPAND_FAILED;
}
if (expand_setup > 0) expand_nmax = expand_setup;
@@ -5330,11 +5330,14 @@ while (*s)
while ((item = string_nextinlist(&list, &sep, NULL, 0)))
g = string_append_listele(g, ',', item);
- /* possibly plus an EOL string */
+ /* possibly plus an EOL string. Process with escapes, to protect
+ from list-processing. The only current user of eol= in search
+ options is the readsock expansion. */
+
if (sub_arg[3] && *sub_arg[3])
g = string_append_listele(g, ',',
- string_sprintf("eol=%s", sub_arg[3]));
-
+ string_sprintf("eol=%s",
+ string_printing2(sub_arg[3], SP_TAB|SP_SPACE)));
}
/* Gat a (possibly cached) handle for the connection */
diff --git a/src/src/functions.h b/src/src/functions.h
index f56ab3e..e5cf7f1 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -532,7 +532,7 @@ extern int string_is_ip_address(const uschar *, int *);
#ifdef SUPPORT_I18N
extern BOOL string_is_utf8(const uschar *);
#endif
-extern const uschar *string_printing2(const uschar *, BOOL);
+extern const uschar *string_printing2(const uschar *, int);
extern uschar *string_split_message(uschar *);
extern uschar *string_unprinting(uschar *);
#ifdef SUPPORT_I18N
diff --git a/src/src/lookups/readsock.c b/src/src/lookups/readsock.c
index c2088b7..cfc9b4a 100644
--- a/src/src/lookups/readsock.c
+++ b/src/src/lookups/readsock.c
@@ -186,7 +186,9 @@ FILE * fp;
gstring * yield;
int ret = DEFER;
-DEBUG(D_lookup) debug_printf_indent("readsock: file=\"%s\" key=\"%s\" len=%d opts=\"%s\"\n", filename, keystring, length, opts);
+DEBUG(D_lookup)
+ debug_printf_indent("readsock: file=\"%s\" key=\"%s\" len=%d opts=\"%s\"\n",
+ filename, keystring, length, opts);
/* Parse options */
@@ -200,7 +202,7 @@ if (opts) for (uschar * s; s = string_nextinlist(&opts, &sep, NULL, 0); )
lf.do_tls = TRUE;
#endif
else if (Ustrncmp(s, "eol=", 4) == 0)
- eol = s + 4;
+ eol = string_unprinting(s + 4);
else if (Ustrcmp(s, "cache=yes") == 0)
lf.cache = TRUE;
else if (Ustrcmp(s, "send=no") == 0)
diff --git a/src/src/macros.h b/src/src/macros.h
index 4c5279f..baac435 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -41,9 +41,11 @@ manipulate them. */
/* For almost all calls to convert things to printing characters, we want to
-allow tabs. A macro just makes life a bit easier. */
+allow tabs & spaces. A macro just makes life a bit easier. */
-#define string_printing(s) string_printing2((s), TRUE)
+#define string_printing(s) string_printing2((s), 0)
+#define SP_TAB BIT(0)
+#define SP_SPACE BIT(1)
/* We need a special return code for "no recipients and failed to send an error
diff --git a/src/src/readconf.c b/src/src/readconf.c
index e3c9ed7..dabe863 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -1546,7 +1546,7 @@ if (flags & opt_fn_print)
{
if (flags & opt_fn_print_label) printf("%s = ", name);
printf("%s\n", smtp_receive_timeout_s
- ? string_printing2(smtp_receive_timeout_s, FALSE)
+ ? string_printing2(smtp_receive_timeout_s, SP_TAB)
: readconf_printtime(smtp_receive_timeout));
}
else if (*str == '$')
@@ -2463,7 +2463,7 @@ switch(ol->type & opt_mask)
case opt_rewrite: /* Show the text value */
s = *(USS value);
if (!no_labels) printf("%s = ", name);
- printf("%s\n", s ? string_printing2(s, FALSE) : US"");
+ printf("%s\n", s ? string_printing2(s, SP_TAB) : US"");
break;
case opt_int:
diff --git a/src/src/string.c b/src/src/string.c
index 1b08e7f..53ff0a8 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -281,17 +281,17 @@ return ch;
/* This function is called for critical strings. It checks for any
non-printing characters, and if any are found, it makes a new copy
of the string with suitable escape sequences. It is most often called by the
-macro string_printing(), which sets allow_tab TRUE.
+macro string_printing(), which sets flags to 0.
Arguments:
s the input string
- allow_tab TRUE to allow tab as a printing character
+ flags Bit 0: convert tabs. Bit 1: convert spaces.
Returns: string with non-printers encoded as printing sequences
*/
const uschar *
-string_printing2(const uschar *s, BOOL allow_tab)
+string_printing2(const uschar *s, int flags)
{
int nonprintcount = 0;
int length = 0;
@@ -301,7 +301,10 @@ uschar *ss, *tt;
while (*t != 0)
{
int c = *t++;
- if (!mac_isprint(c) || (!allow_tab && c == '\t')) nonprintcount++;
+ if ( !mac_isprint(c)
+ || flags & SP_TAB && c == '\t'
+ || flags & SP_SPACE && c == ' '
+ ) nonprintcount++;
length++;
}
@@ -310,17 +313,19 @@ if (nonprintcount == 0) return s;
/* Get a new block of store guaranteed big enough to hold the
expanded string. */
-ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
+tt = ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
/* Copy everything, escaping non printers. */
-t = s;
-tt = ss;
-
-while (*t != 0)
+for (t = s; *t; )
{
int c = *t;
- if (mac_isprint(c) && (allow_tab || c != '\t')) *tt++ = *t++; else
+ if ( mac_isprint(c)
+ && (!(flags & SP_TAB) || c != '\t')
+ && (!(flags & SP_SPACE) || c != ' ')
+ )
+ *tt++ = *t++;
+ else
{
*tt++ = '\\';
switch (*t)
@@ -944,7 +949,10 @@ else
s = ss;
if (!*s || *++s != sep || sep_is_special) break;
}
- while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--;
+ /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */
+ while ( g->ptr > 0 && isspace(g->s[g->ptr-1])
+ && (g->ptr == 1 || g->s[g->ptr-2] != '\\') )
+ g->ptr--;
buffer = string_from_gstring(g);
gstring_release_unused(g);
}
diff --git a/test/scripts/0000-Basic/0373 b/test/scripts/0000-Basic/0373
index 5d8bbee..37c98e0 100644
--- a/test/scripts/0000-Basic/0373
+++ b/test/scripts/0000-Basic/0373
@@ -60,7 +60,7 @@ quit
#
# Tests of IPv4 sockets
#
-server PORT_S 11
+server PORT_S 17
QUERY-1
>LF>ANSWER-1
>*eof
@@ -89,6 +89,24 @@ QUERY-10
>*eof
>LF>ANSWER-11
>*eof
+QUERY-12
+>>ANSWER-12\x0d\x0aANSWER-12\x0d\x0a
+>*eof
+QUERY-13
+>>ANSWER-13\x0d\x0aANSWER-13\x0d\x0a
+>*eof
+QUERY-14
+>>ANSWER-14\x0d\x0aANSWER-14\x0d\x0a
+>*eof
+QUERY-15
+>>ANSWER-15\x0d\x0aANSWER-15\x0d\x0a
+>*eof
+QUERY-16
+>>ANSWER-16\x0d\x0aANSWER-16\x0d\x0a
+>*eof
+QUERY-17
+>>ANSWER-17\x0d\x0aANSWER-17\x0d\x0a
+>*eof
****
millisleep 500
exim -be
@@ -104,6 +122,14 @@ ipv4 cases
9 sock error >>${readsocket{inet:127.0.0.1:PORT_S}{QUERY-9\n}{1s}{}{sock error}}<<
10 ANSWER-10\\n >>${readsocket{inet:badloop:PORT_S}{QUERY-10\n}}<<
11 ANSWER-11 >>${readsocket{inet:thisloop:PORT_S}{QUERY-11\n}{2s:shutdown=no}}<<
+
+eol-replacement arg
+12 ANSWER-12x2 (no arg) >>${escape:${readsocket{inet:127.0.0.1:PORT_S}{QUERY-12\n}{2s}}}<<
+13 ANSWER-13x2 (empty arg) >>${escape:${readsocket{inet:127.0.0.1:PORT_S}{QUERY-13\n}{2s}{}}}<<
+14 ANSWER-14x2 X >>${escape:${readsocket{inet:127.0.0.1:PORT_S}{QUERY-14\n}{2s}{X}}}<<
+15 ANSWER-15x2 XYZZY >>${escape:${readsocket{inet:127.0.0.1:PORT_S}{QUERY-15\n}{2s}{XYZZY}}}<<
+16 ANSWER-16x2 (space) >>${escape:${readsocket{inet:127.0.0.1:PORT_S}{QUERY-16\n}{2s}{ }}}<<
+17 ANSWER-17x2 (newline) >>${escape:${readsocket{inet:127.0.0.1:PORT_S}{QUERY-17\n}{2s}{\n}}}<<
****
#
exim -be
diff --git a/test/stdout/0373 b/test/stdout/0373
index 513f364..1e97d0d 100644
--- a/test/stdout/0373
+++ b/test/stdout/0373
@@ -30,6 +30,14 @@
<<
> 11 ANSWER-11 >><<
>
+> eol-replacement arg
+> 12 ANSWER-12x2 (no arg) >>ANSWER-12\r\nANSWER-12\r\n<<
+> 13 ANSWER-13x2 (empty arg) >>ANSWER-13\r\nANSWER-13\r\n<<
+> 14 ANSWER-14x2 X >>ANSWER-14\rXANSWER-14\rX<<
+> 15 ANSWER-15x2 XYZZY >>ANSWER-15\rXYZZYANSWER-15\rXYZZY<<
+> 16 ANSWER-16x2 (space) >>ANSWER-16\r ANSWER-16\r <<
+> 17 ANSWER-17x2 (newline) >>ANSWER-17\r\nANSWER-17\r\n<<
+>
> Failed: failed to connect to any address for 127.0.0.1: Connection refused
>
> caching of response value
@@ -144,6 +152,36 @@ Listening on port 1224 ...
Connection request from [ip4.ip4.ip4.ip4]
>LF>ANSWER-11
>*eof
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+QUERY-12
+>>ANSWER-12\x0d\x0aANSWER-12\x0d\x0a
+>*eof
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+QUERY-13
+>>ANSWER-13\x0d\x0aANSWER-13\x0d\x0a
+>*eof
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+QUERY-14
+>>ANSWER-14\x0d\x0aANSWER-14\x0d\x0a
+>*eof
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+QUERY-15
+>>ANSWER-15\x0d\x0aANSWER-15\x0d\x0a
+>*eof
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+QUERY-16
+>>ANSWER-16\x0d\x0aANSWER-16\x0d\x0a
+>*eof
+Listening on port 1224 ...
+Connection request from [127.0.0.1]
+QUERY-17
+>>ANSWER-17\x0d\x0aANSWER-17\x0d\x0a
+>*eof
End of script
Listening on TESTSUITE/test-socket ...
Connection request