From 18a352ae8a799bb7be3a03b14bbf3ce9e0ba4945 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Fri, 14 Aug 2020 13:09:53 +0100 Subject: [PATCH 28/37] Fix ${readsocket } eol-replacement. Bug 2630 (cherry picked from commit 7f83b348ccf4cd815e9758ab9ca1012e66324e9d) --- doc/ChangeLog | 4 ++++ src/expand.c | 11 +++++++---- src/functions.h | 2 +- src/lookups/readsock.c | 6 ++++-- src/macros.h | 6 ++++-- src/readconf.c | 4 ++-- src/string.c | 30 +++++++++++++++++----------- diff --git doc/ChangeLog doc/ChangeLog index 703f4b9ee..2d2dc1f9f 100644 --- doc/ChangeLog +++ doc/ChangeLog @@ -78,6 +78,10 @@ JH/18 Bug 2617: Fix a taint trap in parse_fix_phrase(). Previously when the rewrite with the "h" flag, by using the "-F" command-line option, or by using a "name=" option on a control=submission ACL modifier. +JH/21 Bug 2630: Fix 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 src/expand.c src/expand.c index 791222324..bb9fd79ef 100644 --- src/expand.c +++ src/expand.c @@ -4920,7 +4920,7 @@ while (*s != 0) { 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; @@ -5334,11 +5334,14 @@ while (*s != 0) 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 src/functions.h src/functions.h index f4d1622dc..51bb17a09 100644 --- src/functions.h +++ src/functions.h @@ -529,7 +529,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 src/lookups/readsock.c src/lookups/readsock.c index c2088b7a5..cfc9b4ad8 100644 --- src/lookups/readsock.c +++ 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 src/macros.h src/macros.h index a507bbf83..2378773cb 100644 --- src/macros.h +++ 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 src/readconf.c src/readconf.c index 0d0769c88..948fa2403 100644 --- src/readconf.c +++ 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 src/string.c src/string.c index 5acee1b00..f91a6a428 100644 --- src/string.c +++ 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) @@ -947,7 +952,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); } -- 2.28.0