[exim-cvs] Fix ${readsocket } eol-replacement. Bug 2630

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Exim Git Commits Mailing List
Datum:  
To: exim-cvs
Betreff: [exim-cvs] Fix ${readsocket } eol-replacement. Bug 2630
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