Gitweb:
https://git.exim.org/exim.git/commitdiff/9d66ba85a9646c0b63c54acf69e186f0e785855d
Commit: 9d66ba85a9646c0b63c54acf69e186f0e785855d
Parent: 347d8633fd5ff7e85fd0f27444d6d1260c2212de
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Tue Nov 19 11:42:40 2024 +0000
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Tue Nov 19 11:42:40 2024 +0000
Taint: reject tainted list-separator change
---
doc/doc-docbook/spec.xfpt | 110 +++++++++++++++++++++++++++++++------------
doc/doc-txt/ChangeLog | 2 +
src/src/acl.c | 57 ++++++++++------------
src/src/daemon.c | 10 +++-
src/src/dnsbl.c | 31 ++++++++----
src/src/expand.c | 100 +++++++++++++++++++++++++++------------
src/src/functions.h | 3 +-
src/src/match.c | 43 +++++++++++++++--
src/src/readconf.c | 6 +--
src/src/string.c | 10 ++--
test/confs/2610 | 1 +
test/log/2610 | 4 +-
test/paniclog/2610 | 2 +-
test/scripts/0000-Basic/0002 | 5 +-
test/stderr/0002 | 54 +++++++++++++++++++--
test/stderr/0023 | 12 ++---
test/stderr/0149 | 8 ++--
test/stderr/0275 | 10 ++--
test/stderr/0277 | 20 ++++----
test/stderr/0278 | 15 +++---
test/stderr/0279 | 5 +-
test/stderr/0475 | 8 ++--
test/stderr/1000 | 12 ++---
test/stderr/1002 | 16 +++----
test/stderr/2610 | 48 ++++++++++---------
test/stderr/2620 | 20 ++++----
test/stdout/0002 | 3 +-
27 files changed, 412 insertions(+), 203 deletions(-)
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 1f90d6c86..ae30cb886 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -8441,10 +8441,18 @@ type of match and is given below as the &*value*& information.
.section "Expansion of lists" "SECTlistexpand"
.cindex "expansion" "of lists"
-Each list is expanded as a single string before it is used.
+.new
+Each list, after any leading change-of-separator specification
+(see &<<SECTlistsepchange>>&) is expanded as a single string,
.cindex "tainted data" tracking
-&*Note*&: As a result, if any componend was tainted then the
-entire result string becomes tainted.
+&*Note*&: As a result, if any component was tainted then the
+entire expansion result string becomes tainted.
+
+Splitting out a leading explicit change-of-separator permits
+one being safely used on a list that has tainted components
+while still detecting the use of a tainted setting.
+The latter is not permitted.
+.wen
&'Exception: the router headers_remove option, where list-item
splitting is done before string-expansion.'&
@@ -10096,11 +10104,15 @@ leading and trailing quotes are removed from the returned value.
.cindex "list" "selecting by condition"
.cindex "expansion" "selecting from list by condition"
.vindex "&$item$&"
-After expansion, <&'string'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
-For each item
-in this list, its value is placed in &$item$&, and then the condition is
-evaluated.
+.new
+<&'string1'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
+For each item in this list,
+its value is placed in &$item$&, and then the condition is evaluated.
Any modification of &$value$& by this evaluation is discarded.
If the condition is true, &$item$& is added to the output as an
item in a new list; if the condition is false, the item is discarded. The
@@ -10364,8 +10376,12 @@ The <&'number'&> argument must consist entirely of decimal digits,
apart from an optional leading minus,
and leading and trailing white space (which is ignored).
-After expansion, <&'string1'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
+.new
+The <&'string1'&> argument, after any leading change-of-separator
+(see &<<SECTlistsepchange>>&),
+is expanded and the whole forms the list.
+.wen
+By default, the list separator is a colon.
The first field of the list is numbered one.
If the number is negative, the fields are
@@ -10465,10 +10481,15 @@ ${lookup nisplus {[name=$local_part],passwd.org_dir:gcos} \
.vitem &*${map{*&<&'string1'&>&*}{*&<&'string2'&>&*}}*&
.cindex "expansion" "list creation"
.vindex "&$item$&"
-After expansion, <&'string1'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
-For each item
-in this list, its value is place in &$item$&, and then <&'string2'&> is
+.new
+<&'string1'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
+For each item in this list,
+its value is place in &$item$&, and then <&'string2'&> is
expanded and added to the output as an item in a new list. The separator used
for the output list is the same as the one used for the input, but a separator
setting is not included in the output. For example:
@@ -10688,9 +10709,15 @@ locks out the use of this expansion item in filter files.
.cindex "list" "reducing to a scalar"
.vindex "&$value$&"
.vindex "&$item$&"
-This operation reduces a list to a single, scalar string. After expansion,
-<&'string1'&> is interpreted as a list, colon-separated by default, but the
-separator can be changed in the usual way (&<<SECTlistsepchange>>&).
+This operation reduces a list to a single, scalar string.
+
+.new
+<&'string1'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
Then <&'string2'&> is expanded and
assigned to the &$value$& variable. After this, each item in the <&'string1'&>
list is assigned to &$item$&, in turn, and <&'string3'&> is expanded for each of
@@ -10847,8 +10874,13 @@ rather than any Unicode-aware character handling.
.cindex sorting "a list"
.cindex list sorting
.cindex expansion "list sorting"
-After expansion, <&'string'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
+.new
+<&'string'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
The <&'comparator'&> argument is interpreted as the operator
of a two-argument expansion condition.
The numeric operators plus ge, gt, le, lt (and ~i variants) are supported.
@@ -11304,7 +11336,8 @@ All measurement is done in bytes and is not UTF-8 aware.
.cindex "list" "item count"
.cindex "list" "count of items"
.cindex "&%listcount%& expansion item"
-The string is interpreted as a list and the number of items is returned.
+The part of the string after any leading change-of-separator is expanded,
+then the whole is interpreted as a list and the number of items is returned.
.vitem &*${listnamed:*&<&'name'&>&*}*&&~and&~&*${listnamed_*&<&'type'&>&*:*&<&'name'&>&*}*&
@@ -11925,9 +11958,14 @@ attempt. It is false during any subsequent delivery attempts.
.cindex "expansion" "&*forall*& condition"
.cindex "expansion" "&*forany*& condition"
.vindex "&$item$&"
-These conditions iterate over a list. The first argument is expanded to form
-the list. By default, the list separator is a colon, but it can be changed by
-the normal method (&<<SECTlistsepchange>>&).
+These conditions iterate over a list.
+.new
+The first argument, after any leading change-of-separator
+(see &<<SECTlistsepchange>>&),
+is expanded and the whole forms the list.
+.wen
+By default, the list separator is a colon.
+
The second argument is interpreted as a condition that is to
be applied to each item in the list in turn. During the interpretation of the
condition, the current list item is placed in a variable called &$item$&.
@@ -12004,9 +12042,14 @@ SRS decode. See SECT &<<SECTSRS>>& for details.
&*inlisti&~{*&<&'subject'&>&*}{*&<&'list'&>&*}*&
.cindex "string" "comparison"
.cindex "list" "iterative conditions"
-Both strings are expanded; the second string is treated as a list of simple
-strings; if the first string is a member of the second, then the condition
-is true.
+The <&'subject'&> string is expanded.
+.new
+The <&'list'&> first has any change-of-list-separator
++(see &<<SECTlistsepchange>>&) retained verbatim,
++then the remainder is expanded.
++.wen
+The whole is treated as a list of simple strings;
+if the subject string is a member of that list, then the condition is true.
For the case-independent &%inlisti%& condition, case is defined per the system C locale.
These are simpler to use versions of the more powerful &*forany*& condition.
@@ -12199,6 +12242,10 @@ just as easy to use the fact that a lookup is itself a condition, and write:
Note that <&'string2'&> is not itself subject to string expansion, unless
Exim was built with the EXPAND_LISTMATCH_RHS option.
+.new
+For the latter case, only the part after any leading
+change-of-separator specification is expanded.
+.wen
Consult section &<<SECThoslispatip>>& for further details of these patterns.
@@ -12227,9 +12274,10 @@ ${if match_domain{$domain}{+local_domains}{...
.endd
.cindex "&`+caseful`&"
For address lists, the matching starts off caselessly, but the &`+caseful`&
-item can be used, as in all address lists, to cause subsequent items to
-have their local parts matched casefully. Domains are always matched
-caselessly.
+item can be used, as in all address lists, to cause subsequent items
+(including those of referenced named lists)
+to have their local parts matched casefully.
+Domains are always matched caselessly.
The variable &$value$& will be set for a successful match and can be
used in the success clause of an &%if%& expansion item using the condition.
@@ -12244,6 +12292,10 @@ Any previous &$value$& is restored after the if.
Note that <&'string2'&> is not itself subject to string expansion, unless
Exim was built with the EXPAND_LISTMATCH_RHS option.
+.new
+For the latter case, only the part after any leading
+change-of-separator specification is expanded.
+.wen
&*Note*&: Host lists are &'not'& supported in this way. This is because
hosts have two identities: a name and an IP address, and it is not clear
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index bd4fd1921..c9f7a4375 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -67,6 +67,8 @@ JH/14 Bug 3116: Fix crash in dkim signing. On kernels supporting immutable
memory segments, a write was done into one when a constant string was
configured for a transport's dkim private key.
+JH/15 Disallow tainted change-of-separator on lists
+
Exim version 4.98
-----------------
diff --git a/src/src/acl.c b/src/src/acl.c
index 88d09479c..3f35a4946 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -241,7 +241,7 @@ static condition_def conditions[] = {
/* Explicit key lookups can be made in non-smtp ACLs so pass
always and check in the verify processing itself. */
- [ACLC_DNSLISTS] = { US"dnslists", ACD_EXP,
+ [ACLC_DNSLISTS] = { US"dnslists", 0,
FORBIDDEN(0) },
[ACLC_DOMAINS] = { US"domains", 0,
@@ -786,7 +786,7 @@ Returns: offset in list, or -1 if not found
*/
static int
-acl_checkcondition(uschar * name, condition_def * list, int end)
+acl_findcondition(uschar * name, condition_def * list, int end)
{
for (int start = 0; start < end; )
{
@@ -994,7 +994,7 @@ while ((s = (*func)()))
/* Handle a condition or modifier. */
- if ((c = acl_checkcondition(name, conditions, nelem(conditions))) < 0)
+ if ((c = acl_findcondition(name, conditions, nelem(conditions))) < 0)
{
*error = string_sprintf("unknown ACL condition/modifier in \"%s\"",
saveline);
@@ -1025,7 +1025,7 @@ while ((s = (*func)()))
if (conditions[c].flags & ACD_LOAD)
{ /* a loadable module supports this condition */
condition_module * cm;
- uschar * s = NULL;
+ uschar * t = NULL;
/* Over the list of modules we support, check the list of ACL conditions
each supports. This assumes no duplicates. */
@@ -1043,10 +1043,10 @@ while ((s = (*func)()))
return NULL;
}
if ( !cm->info /* module not loaded */
- && !(cm->info = misc_mod_find(cm->mod_name, &s)))
+ && !(cm->info = misc_mod_find(cm->mod_name, &t)))
{
*error = string_sprintf("ACL error: failed to find module for '%s': %s",
- conditions[c].name, s);
+ conditions[c].name, t);
return NULL;
}
}
@@ -3350,12 +3350,11 @@ Returns: OK - all conditions are met
*/
static int
-acl_check_condition(int verb, acl_condition_block *cb, int where,
- address_item *addr, int level, BOOL *epp, uschar **user_msgptr,
- uschar **log_msgptr, int *basic_errno)
+acl_check_condition(int verb, acl_condition_block * cb, int where,
+ address_item * addr, int level, BOOL * epp, uschar ** user_msgptr,
+ uschar ** log_msgptr, int * basic_errno)
{
-uschar * user_message = NULL;
-uschar * log_message = NULL;
+uschar * user_message = NULL, * log_message = NULL;
int rc = OK;
for (; cb; cb = cb->next)
@@ -3364,30 +3363,24 @@ for (; cb; cb = cb->next)
int control_type;
BOOL textonly = FALSE;
- /* The message and log_message items set up messages to be used in
- case of rejection. They are expanded later. */
-
- if (cb->type == ACLC_MESSAGE)
+ switch (cb->type)
{
- HDEBUG(D_acl) debug_printf_indent(" message: %s\n", cb->arg);
- user_message = cb->arg;
- continue;
- }
+ /* The message and log_message items set up messages to be used in
+ case of rejection. They are expanded later. */
- if (cb->type == ACLC_LOG_MESSAGE)
- {
- HDEBUG(D_acl) debug_printf_indent("l_message: %s\n", cb->arg);
- log_message = cb->arg;
- continue;
- }
+ case ACLC_MESSAGE:
+ HDEBUG(D_acl) debug_printf_indent(" message: %s\n", cb->arg);
+ user_message = cb->arg; continue;
- /* The endpass "condition" just sets a flag to show it occurred. This is
- checked at compile time to be on an "accept" or "discard" item. */
+ case ACLC_LOG_MESSAGE:
+ HDEBUG(D_acl) debug_printf_indent("l_message: %s\n", cb->arg);
+ log_message = cb->arg; continue;
- if (cb->type == ACLC_ENDPASS)
- {
- *epp = TRUE;
- continue;
+ /* The endpass "condition" just sets a flag to show it occurred. This is
+ checked at compile time to be on an "accept" or "discard" item. */
+
+ case ACLC_ENDPASS:
+ *epp = TRUE; continue;
}
/* For other conditions and modifiers, the argument is expanded now for some
@@ -4032,7 +4025,7 @@ for (; cb; cb = cb->next)
#endif
case ACLC_DNSLISTS:
- rc = verify_check_dnsbl(where, &arg, log_msgptr);
+ rc = verify_check_dnsbl(where, arg, log_msgptr);
break;
case ACLC_DOMAINS:
diff --git a/src/src/daemon.c b/src/src/daemon.c
index 4272dae7a..0c6ed4da0 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -1893,7 +1893,13 @@ if (f.daemon_listen && !f.inetd_wait_mode)
if (!override_pid_file_path) write_pid = FALSE;
- list = override_local_interfaces;
+ /* specifically permit change-of-separator for admins (who should be
+ the only people getting here, but we may as well be careful) */
+
+ list = f.admin_user
+ ? string_copy_taint(override_local_interfaces, GET_UNTAINTED)
+ : override_local_interfaces;
+
for (int sep = 0; s = string_nextinlist(&list, &sep, NULL, 0); )
{
uschar joinstr[4];
@@ -1940,7 +1946,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
{
uschar * end;
default_smtp_port[pct] = Ustrtol(s, &end, 0);
- if (end != s + Ustrlen(s))
+ if (*end)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "invalid SMTP port: %s", s);
}
else
diff --git a/src/src/dnsbl.c b/src/src/dnsbl.c
index 1172d6183..8901b11ff 100644
--- a/src/src/dnsbl.c
+++ b/src/src/dnsbl.c
@@ -452,24 +452,24 @@ Note: an address for testing DUL is 192.203.178.4
Note: a domain for testing RFCI is example.tld.dsn.rfc-ignorant.org
Arguments:
- where the acl type
- listptr the domain/address/data list
- log_msgptr log message on error
+ where the acl type
+ list the domain/address/data list
+ log_msgptr log message on error
Returns: OK successful lookup (i.e. the address is on the list), or
lookup deferred after +include_unknown
FAIL name not found, or no data found for the given type, or
lookup deferred after +exclude_unknown (default)
DEFER lookup failure, if +defer_unknown was set
+ ERROR error during expansion
*/
int
-verify_check_dnsbl(int where, const uschar ** listptr, uschar ** log_msgptr)
+verify_check_dnsbl(int where, const uschar * list, uschar ** log_msgptr)
{
-int sep = 0;
-int defer_return = FAIL;
-const uschar *list = *listptr;
-uschar *domain;
+int sep, defer_return = FAIL;
+uschar * domain;
+const uschar * s = list;
uschar revadd[128]; /* Long enough for IPv6 address */
/* Indicate that the inverted IP address is not yet set up */
@@ -480,6 +480,21 @@ revadd[0] = 0;
dns_init(FALSE, FALSE, FALSE); /*XXX dnssec? */
+/* Expand the list string. This used to be done by the caller
+but we want to first strip any change-of-list-separator */
+
+sep = matchlist_parse_sep(&s);
+
+if (!(s= expand_cstring(s)))
+ {
+ if (f.expand_string_forcedfail) return OK;
+ *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s",
+ list, expand_string_message);
+ return f.search_find_defer ? DEFER : ERROR;
+ }
+HDEBUG(D_acl) if (s != list) debug_printf_indent("expanded list: %s\n", s);
+list = s;
+
/* Loop through all the domains supplied, until something matches */
while ((domain = string_nextinlist(&list, &sep, NULL, 0)))
diff --git a/src/src/expand.c b/src/src/expand.c
index e4224dbb1..052c059e8 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -1331,18 +1331,15 @@ return fieldtext;
static uschar *
-expand_getlistele(int field, const uschar * list)
+expand_getlistele(int field, const uschar * list, int sep)
{
const uschar * tlist = list;
-int sep = 0;
+int sep_l = sep;
/* Tainted mem for the throwaway element copies */
uschar * dummy = store_get(2, GET_TAINTED);
if (field < 0)
- {
- for (field++; string_nextinlist(&tlist, &sep, dummy, 1); ) field++;
- sep = 0;
- }
+ for (field++; string_nextinlist(&tlist, &sep_l, dummy, 1); ) field++;
if (field == 0) return NULL;
while (--field > 0 && (string_nextinlist(&list, &sep, dummy, 1))) ;
return string_nextinlist(&list, &sep, NULL, 0);
@@ -2947,14 +2944,12 @@ switch(cond_type = identify_operator(&s, &opname))
case ECOND_MATCH_DOMAIN:
case ECOND_MATCH_IP:
case ECOND_MATCH_LOCAL_PART:
-#ifndef EXPAND_LISTMATCH_RHS
+ case ECOND_INLIST:
+ case ECOND_INLISTI:
sub2_honour_dollar = FALSE;
-#endif
/* FALLTHROUGH */
case ECOND_CRYPTEQ:
- case ECOND_INLIST:
- case ECOND_INLISTI:
case ECOND_MATCH:
case ECOND_NUM_L: /* Numerical comparisons */
@@ -3088,13 +3083,24 @@ switch(cond_type = identify_operator(&s, &opname))
}
case ECOND_MATCH_ADDRESS: /* Match in an address list */
- rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0,
+ rc = match_address_list(sub[0], TRUE,
+#ifdef EXPAND_LISTMATCH_RHS
+ TRUE,
+#else
+ FALSE,
+#endif
+ &(sub[1]), NULL, -1, 0,
CUSS &lookup_value);
goto MATCHED_SOMETHING;
case ECOND_MATCH_DOMAIN: /* Match in a domain list */
rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL,
- MCL_DOMAIN + MCL_NOEXPAND, TRUE, CUSS &lookup_value);
+#ifdef EXPAND_LISTMATCH_RHS
+ MCL_DOMAIN,
+#else
+ MCL_DOMAIN + MCL_NOEXPAND,
+#endif
+ TRUE, CUSS &lookup_value);
goto MATCHED_SOMETHING;
case ECOND_MATCH_IP: /* Match IP address in a host list */
@@ -3120,21 +3126,30 @@ switch(cond_type = identify_operator(&s, &opname))
cb.host_address + 7 : cb.host_address;
rc = match_check_list(
- &sub[1], /* the list */
- 0, /* separator character */
- &hostlist_anchor, /* anchor pointer */
- &nullcache, /* cache pointer */
- check_host, /* function for testing */
- &cb, /* argument for function */
- MCL_HOST, /* type of check */
- sub[0], /* text for debugging */
- CUSS &lookup_value); /* where to pass back data */
+ &sub[1], /* the list */
+ 0, /* separator character */
+ &hostlist_anchor, /* anchor pointer */
+ &nullcache, /* cache pointer */
+ check_host, /* function for testing */
+ &cb, /* argument for function */
+#ifdef EXPAND_LISTMATCH_RHS
+ MCL_HOST,
+#else
+ MCL_HOST + MCL_NOEXPAND,/* type of check */
+#endif
+ sub[0], /* text for debugging */
+ CUSS &lookup_value); /* where to pass back data */
}
goto MATCHED_SOMETHING;
case ECOND_MATCH_LOCAL_PART:
rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL,
- MCL_LOCALPART + MCL_NOEXPAND, TRUE, CUSS &lookup_value);
+#ifdef EXPAND_LISTMATCH_RHS
+ MCL_LOCALPART,
+#else
+ MCL_LOCALPART+ MCL_NOEXPAND,
+#endif
+ TRUE, CUSS &lookup_value);
/* Fall through */
/* VVVVVVVVVVVV */
MATCHED_SOMETHING:
@@ -3296,12 +3311,18 @@ switch(cond_type = identify_operator(&s, &opname))
case ECOND_INLISTI:
{
const uschar * list = sub[1];
- int sep = 0;
+ int sep;
uschar *save_iterate_item = iterate_item;
int (*compare)(const uschar *, const uschar *);
DEBUG(D_expand) debug_printf_indent("condition: %s item: %s\n", opname, sub[0]);
+ /* grab any listsep spec, then expand the list */
+
+ sep = matchlist_parse_sep(&list);
+ if (!(list = expand_cstring(list)))
+ goto failout;
+
tempcond = FALSE;
compare = cond_type == ECOND_INLISTI
? strcmpic : (int (*)(const uschar *, const uschar *)) strcmp;
@@ -3392,13 +3413,19 @@ switch(cond_type = identify_operator(&s, &opname))
FORMANY:
{
const uschar * list;
- int sep = 0;
+ int sep;
uschar *save_iterate_item = iterate_item;
DEBUG(D_expand) debug_printf_indent("condition: %s\n", opname);
+ /* First expand the list, apart from a leading change-of-separator
+ on non-json lists */
+
Uskip_whitespace(&s);
if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */
+
+ sep = is_json ? 0 : matchlist_parse_sep(&s);
+
if (!(sub[0] = expand_string_internal(s,
ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | (yield ? ESI_NOFLAGS : ESI_SKIPPING),
&s, resetok, NULL)))
@@ -3413,7 +3440,7 @@ switch(cond_type = identify_operator(&s, &opname))
/* Call eval_condition once, with result discarded (as if scanning a
"false" part). This allows us to find the end of the condition, because if
- the list it empty, we won't actually evaluate the condition for real. */
+ the list is empty, we won't actually evaluate the condition for real. */
if (!(s = eval_condition(sub[1], resetok, NULL)))
{
@@ -3432,6 +3459,8 @@ switch(cond_type = identify_operator(&s, &opname))
goto failout;
}
+ /* Now scan the list, checking the condition for each item */
+
if (yield) *yield = !testfor;
list = sub[0];
if (is_json) list = dewrap(string_copy(list), US"[]");
@@ -6358,7 +6387,7 @@ while (*s)
case EITEM_LISTEXTRACT:
{
- int field_number = 1;
+ int field_number = 1, sep = 0;
uschar * save_lookup_value = lookup_value, * sub[2];
int save_expand_nmax =
save_expand_strings(save_expand_nstring, save_expand_nlength);
@@ -6375,7 +6404,10 @@ while (*s)
goto EXPAND_FAILED_CURLY;
}
- sub[i] = expand_string_internal(s+1,
+ s++;
+ if (i == 1) sep = matchlist_parse_sep(&s);
+
+ sub[i] = expand_string_internal(s,
ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL);
if (!sub[i]) goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
@@ -6427,7 +6459,8 @@ while (*s)
/* Extract the numbered element into $value. If
skipping, just pretend the extraction failed. */
- lookup_value = flags & ESI_SKIPPING ? NULL : expand_getlistele(field_number, sub[1]);
+ lookup_value = flags & ESI_SKIPPING
+ ? NULL : expand_getlistele(field_number, sub[1], sep);
/* If no string follows, $value gets substituted; otherwise there can
be yes/no strings, as for lookup or if. */
@@ -6559,7 +6592,7 @@ while (*s)
case EITEM_MAP:
case EITEM_REDUCE:
{
- int sep = 0, save_ptr = gstring_length(yield);
+ int sep, save_ptr = gstring_length(yield);
uschar outsep[2] = { '\0', '\0' };
const uschar *list, *expr, *temp;
uschar * save_iterate_item = iterate_item;
@@ -6574,6 +6607,9 @@ while (*s)
}
DEBUG(D_expand) debug_printf_indent("%s: evaluate input list list\n", name);
+ /* Check for a list-sep spec before expansion */
+ sep = matchlist_parse_sep(&s);
+
if (!(list = expand_string_internal(s,
ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL)))
goto EXPAND_FAILED; /*{{*/
@@ -6766,7 +6802,7 @@ while (*s)
case EITEM_SORT:
{
- int sep = 0, cond_type;
+ int sep, cond_type;
const uschar * srclist, * cmp, * xtract;
uschar * opname, * srcitem;
const uschar * dstlist = NULL, * dstkeylist = NULL;
@@ -6779,6 +6815,7 @@ while (*s)
goto EXPAND_FAILED_CURLY; /*}*/
}
+ sep = matchlist_parse_sep(&s);
srclist = expand_string_internal(s,
ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL);
if (!srclist) goto EXPAND_FAILED; /*{{*/
@@ -7545,9 +7582,10 @@ NOT_ITEM: ;
case EOP_LISTCOUNT:
{
- int cnt = 0, sep = 0;
+ int cnt = 0, sep;
uschar * buf = store_get(2, sub);
+ sep = matchlist_parse_sep(CUSS &sub);
while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++;
yield = string_fmt_append(yield, "%d", cnt);
break;
diff --git a/src/src/functions.h b/src/src/functions.h
index 11a4b6657..5f26c3dd1 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -321,6 +321,7 @@ extern int match_isinlist(const uschar *, const uschar * const *, int,
tree_node **, unsigned int *, int, BOOL, const uschar **);
extern int match_check_string(const uschar *, const uschar *, int, mcs_flags,
const uschar **);
+extern uschar matchlist_parse_sep(const uschar **);
extern void message_start(void);
extern void message_tidyup(void);
@@ -643,7 +644,7 @@ extern int vaguely_random_number_fallback(int);
#endif
extern int verify_address(address_item *, FILE *, int, int, int, int,
uschar *, uschar *, BOOL *);
-extern int verify_check_dnsbl(int, const uschar **, uschar **);
+extern int verify_check_dnsbl(int, const uschar *, uschar **);
extern int verify_check_header_address(uschar **, uschar **, int, int, int,
uschar *, uschar *, int, int *);
extern int verify_check_headers(uschar **);
diff --git a/src/src/match.c b/src/src/match.c
index 252efc6c2..5670388ea 100644
--- a/src/src/match.c
+++ b/src/src/match.c
@@ -370,6 +370,37 @@ return US""; /* In practice, should never happen */
+/* Check for a change-of-separator specification on the head of a list.
+Handle interpretation of backslash-char, in the same way that expansion would.
+
+Argument: listp pointer to list-pointer, updated on return to
+ next char after the spec if there is one; else unchaged
+
+Return: separator char, or zero for no spec
+*/
+
+uschar
+matchlist_parse_sep(const uschar ** listp)
+{
+const uschar * list = *listp;
+if (Uskip_whitespace(&list) == '<')
+ {
+ const uschar * s = list+1;
+ uschar c = *s == '\\' ? string_interpret_escape(&s) : *s;
+ if (ispunct(c) || iscntrl(c))
+ {
+ DEBUG(D_lists)
+ {
+ uschar s[2] = {0}; *s = c;
+ debug_printf_indent("list separator: '%W'\n", s);
+ }
+ *listp = s+1; /* next char after the change-of-separator */
+ return c;
+ }
+ }
+return 0;
+}
+
/*************************************************
* Scan list and run matching function *
*************************************************/
@@ -454,14 +485,17 @@ if (!*listptr)
if the type value is greater than or equal to than MCL_NOEXPAND, do not expand
the list. */
+list = *listptr;
if (type >= MCL_NOEXPAND)
{
- list = *listptr;
type -= MCL_NOEXPAND; /* Remove the "no expand" flag */
textonly_re = TRUE;
}
else
{
+ if (sep <= 0)
+ sep = matchlist_parse_sep(&list);
+
/* If we are searching a domain list, and $domain is not set, set it to the
subject that is being sought for the duration of the expansion. */
@@ -469,11 +503,11 @@ else
{
check_string_block *cb = (check_string_block *)arg;
deliver_domain = string_copy(cb->subject);
- list = expand_string_2(*listptr, &textonly_re);
+ list = expand_string_2(list, &textonly_re);
deliver_domain = NULL;
}
else
- list = expand_string_2(*listptr, &textonly_re);
+ list = expand_string_2(list, &textonly_re);
if (!list)
{
@@ -1133,8 +1167,7 @@ if (pattern[0] == '@' && pattern[1] == '@')
ss = Ustrrchr(list, ':');
if (!ss) ss = list; else ss++;
- Uskip_whitespace(&ss);
- if (*ss == '>')
+ if (Uskip_whitespace(&ss) == '>')
{
*ss++ = 0;
Uskip_whitespace(&ss);
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 7912bca4a..059a4e8f0 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -1250,9 +1250,9 @@ return s;
* Read a name *
*************************************************/
-/* The yield is the pointer to the next uschar. Names longer than the
-output space are silently truncated. This function is also used from acl.c when
-parsing ACLs.
+/* The yield is the pointer to the next uschar after the name plus
+and whitespace. Names longer than the output space are silently truncated.
+This function is also used from acl.c when parsing ACLs.
Arguments:
name where to put the name
diff --git a/src/src/string.c b/src/src/string.c
index d4fb23cb6..b370cfacc 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -923,14 +923,18 @@ to be conservative. */
while (isspace(*s) && *s != sep) s++;
-/* A change of separator is permitted, so look for a leading '<' followed by an
-allowed character. */
+/* A change of separator is permitted (assuming untainted source),
+so look for a leading '<' followed by an allowed character. */
if (sep <= 0)
{
if (*s == '<' && (ispunct(s[1]) || iscntrl(s[1])))
{
- sep = s[1];
+ if (!is_tainted(s))
+ sep = s[1];
+ else DEBUG(D_any)
+ debug_printf("attempt to use tainted change-of-seperator spec (%s %d)\n",
+ config_filename, config_lineno);
if (*++s) ++s;
while (isspace(*s) && *s != sep) s++;
}
diff --git a/test/confs/2610 b/test/confs/2610
index 94be1b91f..71a3f4284 100644
--- a/test/confs/2610
+++ b/test/confs/2610
@@ -41,6 +41,7 @@ check_recipient:
# In list-style lookup, tainted lookup string is ok if server spec comes from main-option
warn set acl_m0 = ok: hostlist
hosts = net-mysql;select * from them where id='${quote_mysql:$local_part}'
+
# ... but setting a per-query servers spec fails due to the taint
warn set acl_m0 = FAIL4: hostlist
hosts = <& net-mysql;servers=SSPEC; select * from them where id='${quote_mysql:$local_part}'
diff --git a/test/log/2610 b/test/log/2610
index 4acbbd873..cd8b2a915 100644
--- a/test/log/2610
+++ b/test/log/2610
@@ -1,5 +1,5 @@
1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 69): select name from them where id='ph10' limit 1
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 83): select id from them where id='ph10'
1999-03-02 09:44:33 10HmaX-000000005vi-0000 => ph10 <ph10@???> R=r1 T=t1
1999-03-02 09:44:33 10HmaX-000000005vi-0000 Completed
diff --git a/test/paniclog/2610 b/test/paniclog/2610
index 917a0a801..29493f888 100644
--- a/test/paniclog/2610
+++ b/test/paniclog/2610
@@ -1 +1 @@
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 69): select name from them where id='ph10' limit 1
diff --git a/test/scripts/0000-Basic/0002 b/test/scripts/0000-Basic/0002
index 0ed3e0dff..6e0d6dce6 100644
--- a/test/scripts/0000-Basic/0002
+++ b/test/scripts/0000-Basic/0002
@@ -1153,6 +1153,7 @@ ${if inlist{aa}{aa} {in list}{not in list}}
${if !inlist{aa}{aa} {not in list}{in list}}
****
# listextract from tainted list
-exim -be -oMs my.target.host.name
-'\${listextract {2} {<. $sender_host_name}}' => '${listextract {2} {<. $sender_host_name}}'
+exim -d-all+expand -be
+set,t acl_m0 = my:target:string:list
+'\${listextract {2} {$acl_m0}}' => '${listextract {2} {$acl_m0}}'
****
diff --git a/test/stderr/0002 b/test/stderr/0002
index 8b6a1a446..2a3ef8742 100644
--- a/test/stderr/0002
+++ b/test/stderr/0002
@@ -554,8 +554,9 @@ host in helo_accept_junk_hosts? no (option unset)
using ACL "connect1"
processing ACL connect1 "deny" (TESTSUITE/test-config 45)
check hosts = <\n partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch \n 1.2.3.4
-host in "<
- partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
+list separator: '↩
+'
+host in " partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
1.2.3.4"?
list element: partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
sender host name required, to match against partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
@@ -588,8 +589,7 @@ host in "<
in TESTSUITE/aux-fixed/0002.lsearch
creating new cache entry
lookup yielded:
- host in "<
- partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
+ host in " partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
1.2.3.4"? yes (matched "partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch")
deny: condition test succeeded in ACL connect1
end of ACL connect1: DENY
@@ -827,3 +827,49 @@ sender address = CALLER@???
╎ ::1 in "<; aaaa:bbbb"? no (malformed IPv6 address or address mask: aaaa:bbbb)
search_tidyup called
>>>>>>>>>>>>>>>> Exim pid=p1240 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+Hints DB:
+environment after trimming:
+ USER=CALLER
+configuration file is TESTSUITE/test-config
+admin user
+dropping to exim gid; retaining priv uid
+try option gecos_pattern
+try option gecos_name
+try option unknown_login
+ ╭considering: '\${listextract░{2}░{$acl_m0}}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├───────text: '
+ ├considering: \${listextract░{2}░{$acl_m0}}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├backslashed: '\$'
+ ├considering: {listextract░{2}░{$acl_m0}}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├───────text: {listextract░{2
+ ├considering: }░{$acl_m0}}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├───────text: }░{
+ ├considering: $acl_m0}}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├──────value: my:target:string:list
+ ╰──(tainted)
+ ├considering: }}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├───────text: }
+ ├considering: }'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ├───────text: }'░░=>░░░'
+ ├considering: ${listextract░{2}░{$acl_m0}}'
+ ╭considering: 2}░{$acl_m0}}'
+ ├───────text: 2
+ ├considering: }░{$acl_m0}}'
+ ├───expanded: 2
+ ╰─────result: 2
+ ╭considering: $acl_m0}}'
+ ├──────value: my:target:string:list
+ ╰──(tainted)
+ ├considering: }}'
+ ├───expanded: $acl_m0
+ ╰─────result: my:target:string:list
+ ╰──(tainted)
+ ├───item-res: target
+ ╰──(tainted)
+ ├considering: '
+ ├───────text: '
+ ├───expanded: '\${listextract░{2}░{$acl_m0}}'░░=>░░░'${listextract░{2}░{$acl_m0}}'
+ ╰─────result: '${listextract░{2}░{my:target:string:list}}'░░=>░░░'target'
+ ╰──(tainted)
+>>>>>>>>>>>>>>>> Exim pid=p1241 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/0023 b/test/stderr/0023
index d825511b9..fe86a317d 100644
--- a/test/stderr/0023
+++ b/test/stderr/0023
@@ -1668,7 +1668,7 @@ LOG: H=(test) [V4NET.99.99.96] F=<> temporarily rejected RCPT <x@y>: host lookup
>>> using ACL "acl_29_29_29"
>>> processing ACL acl_29_29_29 "deny" (TESTSUITE/test-config 154)
>>> check dnslists = test.ex/$sender_address_domain
->>> = test.ex/localhost
+>>> expanded list: test.ex/localhost
>>> dnslists check: test.ex/localhost
>>> new DNS lookup for localhost.test.ex
>>> dnslists: wrote cache entry, ttl=3600
@@ -1680,7 +1680,7 @@ LOG: H=(test) [29.29.29.29] F=<a@localhost> rejected RCPT <x@y>
>>> using ACL "acl_29_29_29"
>>> processing ACL acl_29_29_29 "deny" (TESTSUITE/test-config 154)
>>> check dnslists = test.ex/$sender_address_domain
->>> = test.ex/elsewhere
+>>> expanded list: test.ex/elsewhere
>>> dnslists check: test.ex/elsewhere
>>> new DNS lookup for elsewhere.test.ex
>>> dnslists: wrote cache entry, ttl=3000
@@ -1706,7 +1706,7 @@ LOG: H=(test) [29.29.29.29] F=<a@localhost> rejected RCPT <x@y>
>>> processing ACL acl_30_30_30 "deny" (TESTSUITE/test-config 161)
>>> message: domain=$dnslist_domain\nvalue=$dnslist_value\nmatched=$dnslist_matched\ntext="$dnslist_text"
>>> check dnslists = test.ex=V4NET.0.0.1,127.0.0.2/$sender_address_domain
->>> = test.ex=V4NET.0.0.1,127.0.0.2/ten-1
+>>> expanded list: test.ex=V4NET.0.0.1,127.0.0.2/ten-1
>>> dnslists check: test.ex=V4NET.0.0.1,127.0.0.2/ten-1
>>> new DNS lookup for ten-1.test.ex
>>> dnslists: wrote cache entry, ttl=3600
@@ -1719,7 +1719,7 @@ LOG: H=(test) [30.30.30.30] F=<a@ten-1> rejected RCPT <x@y>: domain=test.ex
>>> processing ACL acl_30_30_30 "deny" (TESTSUITE/test-config 161)
>>> message: domain=$dnslist_domain\nvalue=$dnslist_value\nmatched=$dnslist_matched\ntext="$dnslist_text"
>>> check dnslists = test.ex=V4NET.0.0.1,127.0.0.2/$sender_address_domain
->>> = test.ex=V4NET.0.0.1,127.0.0.2/ten-2
+>>> expanded list: test.ex=V4NET.0.0.1,127.0.0.2/ten-2
>>> dnslists check: test.ex=V4NET.0.0.1,127.0.0.2/ten-2
>>> new DNS lookup for ten-2.test.ex
>>> dnslists: wrote cache entry, ttl=3600
@@ -1737,7 +1737,7 @@ LOG: H=(test) [30.30.30.30] F=<a@ten-1> rejected RCPT <x@y>: domain=test.ex
>>> processing ACL acl_30_30_30 "deny" (TESTSUITE/test-config 161)
>>> message: domain=$dnslist_domain\nvalue=$dnslist_value\nmatched=$dnslist_matched\ntext="$dnslist_text"
>>> check dnslists = test.ex=V4NET.0.0.1,127.0.0.2/$sender_address_domain
->>> = test.ex=V4NET.0.0.1,127.0.0.2/13.12.11.V4NET.rbl
+>>> expanded list: test.ex=V4NET.0.0.1,127.0.0.2/13.12.11.V4NET.rbl
>>> dnslists check: test.ex=V4NET.0.0.1,127.0.0.2/13.12.11.V4NET.rbl
>>> new DNS lookup for 13.12.11.V4NET.rbl.test.ex
>>> dnslists: wrote cache entry, ttl=3
@@ -1761,7 +1761,7 @@ LOG: H=(test) [30.30.30.30] F=<a@???> rejected RCPT <x@y>: domain
>>> using ACL "acl_31_31_31"
>>> processing ACL acl_31_31_31 "deny" (TESTSUITE/test-config 167)
>>> check dnslists = test.ex/$sender_address_domain+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END
->>> = test.ex/y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END
+>>> expanded list: test.ex/y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END
>>> dnslists check: test.ex/y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END
LOG: dnslist query is too long (ignored): y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END.test.ex...
>>> deny: condition test failed in ACL acl_31_31_31
diff --git a/test/stderr/0149 b/test/stderr/0149
index 81bf94397..1dcf8893e 100644
--- a/test/stderr/0149
+++ b/test/stderr/0149
@@ -7,7 +7,7 @@ routing x@ten
--------> domainlist1 router <--------
local_part=x domain=ten
checking domains
-ten in "<- test1 - test2-test3--4"? no (end of list)
+ten in " test1 - test2-test3--4"? no (end of list)
ten in domains? yes (end of list)
calling domainlist1 router
domainlist1 router called for x@ten
@@ -33,7 +33,7 @@ routing y@two
--------> domainlist1 router <--------
local_part=y domain=two
checking domains
-two in "<- test1 - test2-test3--4"? no (end of list)
+two in " test1 - test2-test3--4"? no (end of list)
two in domains? yes (end of list)
calling domainlist1 router
domainlist1 router called for y@two
@@ -128,7 +128,7 @@ routing x@one
--------> domainlist1 router <--------
local_part=x domain=one
checking domains
-one in "<- test1 - test2-test3--4"? no (end of list)
+one in " test1 - test2-test3--4"? no (end of list)
one in domains? yes (end of list)
calling domainlist1 router
domainlist1 router called for x@one
@@ -168,7 +168,7 @@ routing x@six
--------> domainlist1 router <--------
local_part=x domain=six
checking domains
-six in "<- test1 - test2-test3--4"? no (end of list)
+six in " test1 - test2-test3--4"? no (end of list)
six in domains? yes (end of list)
calling domainlist1 router
domainlist1 router called for x@six
diff --git a/test/stderr/0275 b/test/stderr/0275
index f5891bb9a..d8ee843ae 100644
--- a/test/stderr/0275
+++ b/test/stderr/0275
@@ -145,13 +145,14 @@ test.ex in domains?
cached lookup data = NULL
list element: +n2_domains
start sublist n2_domains
- test.ex in "<; never2.ex ; +n1_domains"?
+ list separator: ';'
+ test.ex in " never2.ex ; +n1_domains"?
╎list element: never2.ex
╎list element: +n1_domains
╎ start sublist n1_domains
╎cached no match for +n1_domains
╎cached lookup data = NULL
- test.ex in "<; never2.ex ; +n1_domains"? no (end of list)
+ test.ex in " never2.ex ; +n1_domains"? no (end of list)
end sublist n2_domains
list element: !+local_domains
start sublist local_domains
@@ -408,13 +409,14 @@ test.ex in domains?
cached lookup data = NULL
list element: +n2_domains
start sublist n2_domains
- test.ex in "<; never2.ex ; +n1_domains"?
+ list separator: ';'
+ test.ex in " never2.ex ; +n1_domains"?
╎list element: never2.ex
╎list element: +n1_domains
╎ start sublist n1_domains
╎cached no match for +n1_domains
╎cached lookup data = NULL
- test.ex in "<; never2.ex ; +n1_domains"? no (end of list)
+ test.ex in " never2.ex ; +n1_domains"? no (end of list)
end sublist n2_domains
list element: !+local_domains
start sublist local_domains
diff --git a/test/stderr/0277 b/test/stderr/0277
index b92d4d832..ecf66e185 100644
--- a/test/stderr/0277
+++ b/test/stderr/0277
@@ -88,7 +88,8 @@ host in sender_unqualified_hosts?
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
╎list element: +n1_hosts
╎ start sublist n1_hosts
@@ -96,7 +97,7 @@ host in sender_unqualified_hosts?
╎ list element: V4NET.1.1.1
╎ host in "V4NET.1.1.1"? no (end of list)
╎ end sublist n1_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"? no (end of list)
+ host in " V4NET.2.2.2 ; +n1_hosts"? no (end of list)
end sublist n2_hosts
host in sender_unqualified_hosts? yes (end of list)
host in recipient_unqualified_hosts? no (option unset)
@@ -159,7 +160,8 @@ host in sender_unqualified_hosts?
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
╎list element: +n1_hosts
╎ start sublist n1_hosts
@@ -167,7 +169,7 @@ host in sender_unqualified_hosts?
╎ list element: V4NET.1.1.1
╎ host in "V4NET.1.1.1"? no (end of list)
╎ end sublist n1_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"? no (end of list)
+ host in " V4NET.2.2.2 ; +n1_hosts"? no (end of list)
end sublist n2_hosts
host in sender_unqualified_hosts? yes (end of list)
host in recipient_unqualified_hosts? no (option unset)
@@ -230,7 +232,8 @@ host in sender_unqualified_hosts?
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
╎list element: +n1_hosts
╎ start sublist n1_hosts
@@ -238,7 +241,7 @@ host in sender_unqualified_hosts?
╎ list element: V4NET.1.1.1
╎ host in "V4NET.1.1.1"? yes (matched "V4NET.1.1.1")
╎ end sublist n1_hosts
- ╎host in "<; V4NET.2.2.2 ; +n1_hosts"? yes (matched "+n1_hosts")
+ ╎host in " V4NET.2.2.2 ; +n1_hosts"? yes (matched "+n1_hosts")
end sublist n2_hosts
host in sender_unqualified_hosts? no (matched "!+n2_hosts")
host in recipient_unqualified_hosts? no (option unset)
@@ -301,9 +304,10 @@ host in sender_unqualified_hosts?
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
- ╎host in "<; V4NET.2.2.2 ; +n1_hosts"? yes (matched "V4NET.2.2.2")
+ ╎host in " V4NET.2.2.2 ; +n1_hosts"? yes (matched "V4NET.2.2.2")
end sublist n2_hosts
host in sender_unqualified_hosts? no (matched "!+n2_hosts")
host in recipient_unqualified_hosts? no (option unset)
diff --git a/test/stderr/0278 b/test/stderr/0278
index fd94ee0c0..08709b257 100644
--- a/test/stderr/0278
+++ b/test/stderr/0278
@@ -51,13 +51,14 @@ CALLER in local_parts?
cached lookup data = NULL
list element: +n2_localparts
start sublist n2_localparts
- CALLER in "<; never2 ; +n1_localparts"?
+ list separator: ';'
+ CALLER in " never2 ; +n1_localparts"?
╎list element: never2
╎list element: +n1_localparts
╎ start sublist n1_localparts
╎cached no match for +n1_localparts
╎cached lookup data = NULL
- CALLER in "<; never2 ; +n1_localparts"? no (end of list)
+ CALLER in " never2 ; +n1_localparts"? no (end of list)
end sublist n2_localparts
list element: !+local_localparts
start sublist local_localparts
@@ -209,13 +210,14 @@ CALLER in local_parts?
cached lookup data = NULL
list element: +n2_localparts
start sublist n2_localparts
- CALLER in "<; never2 ; +n1_localparts"?
+ list separator: ';'
+ CALLER in " never2 ; +n1_localparts"?
╎list element: never2
╎list element: +n1_localparts
╎ start sublist n1_localparts
╎cached no match for +n1_localparts
╎cached lookup data = NULL
- CALLER in "<; never2 ; +n1_localparts"? no (end of list)
+ CALLER in " never2 ; +n1_localparts"? no (end of list)
end sublist n2_localparts
list element: !+local_localparts
start sublist local_localparts
@@ -362,13 +364,14 @@ unknown in local_parts?
cached lookup data = NULL
list element: +n2_localparts
start sublist n2_localparts
- unknown in "<; never2 ; +n1_localparts"?
+ list separator: ';'
+ unknown in " never2 ; +n1_localparts"?
╎list element: never2
╎list element: +n1_localparts
╎ start sublist n1_localparts
╎cached no match for +n1_localparts
╎cached lookup data = NULL
- unknown in "<; never2 ; +n1_localparts"? no (end of list)
+ unknown in " never2 ; +n1_localparts"? no (end of list)
end sublist n2_localparts
list element: !+local_localparts
start sublist local_localparts
diff --git a/test/stderr/0279 b/test/stderr/0279
index bbd876568..9088c39fe 100644
--- a/test/stderr/0279
+++ b/test/stderr/0279
@@ -68,14 +68,15 @@ CALLER@??? in senders?
cached lookup data = NULL
list element: +n2_addresses
start sublist n2_addresses
- CALLER@??? in "<; never2@??? ; +n1_addresses"?
+ list separator: ';'
+ CALLER@??? in " never2@??? ; +n1_addresses"?
╎list element: never2@???
╎address match test: subject=CALLER@??? pattern=never2@???
╎list element: +n1_addresses
╎ start sublist n1_addresses
╎cached no match for +n1_addresses
╎cached lookup data = NULL
- CALLER@??? in "<; never2@??? ; +n1_addresses"? no (end of list)
+ CALLER@??? in " never2@??? ; +n1_addresses"? no (end of list)
end sublist n2_addresses
list element: !+local_addresses
start sublist local_addresses
diff --git a/test/stderr/0475 b/test/stderr/0475
index 34053c1e3..bb601718a 100644
--- a/test/stderr/0475
+++ b/test/stderr/0475
@@ -33,18 +33,18 @@ LOG: H=(test) [V4NET.0.0.0] F=<> rejected RCPT <a2@b>
>>> using ACL "a3"
>>> processing ACL a3 "deny" (TESTSUITE/test-config 23)
>>> check hosts = <; fe80::1
->>> host in "<; fe80::1"?
+>>> host in " fe80::1"?
>>> list element: fe80::1
->>> host in "<; fe80::1"? no (end of list)
+>>> host in " fe80::1"? no (end of list)
>>> deny: condition test failed in ACL a3
>>> end of ACL a3: implicit DENY
LOG: H=(test) [V4NET.0.0.0] F=<> rejected RCPT <a3@b>
>>> using ACL "a4"
>>> processing ACL a4 "deny" (TESTSUITE/test-config 26)
>>> check hosts = <; fe80:1
->>> host in "<; fe80:1"?
+>>> host in " fe80:1"?
>>> list element: fe80:1
->>> host in "<; fe80:1"? no (malformed IPv6 address or address mask: fe80:1)
+>>> host in " fe80:1"? no (malformed IPv6 address or address mask: fe80:1)
LOG: list matching forced to fail: malformed IPv6 address or address mask: fe80:1
>>> deny: condition test failed in ACL a4
>>> end of ACL a4: implicit DENY
diff --git a/test/stderr/1000 b/test/stderr/1000
index 5f289462d..46bffdf92 100644
--- a/test/stderr/1000
+++ b/test/stderr/1000
@@ -10,9 +10,9 @@
>>> processing ACL check_connect "warn" (TESTSUITE/test-config 21)
>>> l_message: matched hostlist
>>> check hosts = <; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
>>> list element: 2001:ab8:37f:20:0:0:0:1
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "2001:ab8:37f:20:0:0:0:1")
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "2001:ab8:37f:20:0:0:0:1")
>>> warn: condition test succeeded in ACL check_connect
LOG: H=[2001:ab8:37f:20::1] Warning: matched hostlist
>>> processing ACL check_connect "accept" (TESTSUITE/test-config 24)
@@ -43,13 +43,13 @@ LOG: H=[2001:ab8:37f:20::1] rejected connection in "connect" ACL
>>> processing ACL check_connect "warn" (TESTSUITE/test-config 21)
>>> l_message: matched hostlist
>>> check hosts = <; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
>>> list element: 2001:ab8:37f:20:0:0:0:1
>>> list element: v6.test.ex
MUNGED: ::1 will be omitted in what follows
>>> get[host|ipnode]byname[2] looked up these IP addresses:
>>> name=v6.test.ex address=V6NET:ffff:836f:a00:a:800:200a:c032
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? no (end of list)
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? no (end of list)
>>> warn: condition test failed in ACL check_connect
>>> processing ACL check_connect "accept" (TESTSUITE/test-config 24)
>>> check condition = ${if eq{$sender_host_address}{2001:0ab8:037f:0020:0000:0000:0000:0001}}
@@ -69,13 +69,13 @@ LOG: H=test3.ipv6.test.ex [V6NET:1234:5:6:7:8:abc:d] rejected connection in "con
>>> processing ACL check_connect "warn" (TESTSUITE/test-config 21)
>>> l_message: matched hostlist
>>> check hosts = <; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
>>> list element: 2001:ab8:37f:20:0:0:0:1
>>> list element: v6.test.ex
MUNGED: ::1 will be omitted in what follows
>>> get[host|ipnode]byname[2] looked up these IP addresses:
>>> name=v6.test.ex address=V6NET:ffff:836f:a00:a:800:200a:c032
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "v6.test.ex")
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "v6.test.ex")
>>> warn: condition test succeeded in ACL check_connect
LOG: H=[V6NET:ffff:836f:a00:a:800:200a:c032] Warning: matched hostlist
>>> processing ACL check_connect "accept" (TESTSUITE/test-config 24)
diff --git a/test/stderr/1002 b/test/stderr/1002
index efaeb0e17..eb9d3ac21 100644
--- a/test/stderr/1002
+++ b/test/stderr/1002
@@ -26,25 +26,25 @@
>>> processing ACL acl_rcpt_6 "require" (TESTSUITE/test-config 44)
>>> message: domain doesn't match @mx_any/ignore=<;127.0.0.1;::1
>>> check domains = <+ @mx_any/ignore=<;127.0.0.1;::1
->>> mxt11a.test.ex in "<+ @mx_any/ignore=<;127.0.0.1;::1"?
+>>> mxt11a.test.ex in " @mx_any/ignore=<;127.0.0.1;::1"?
>>> list element: @mx_any/ignore=<;127.0.0.1;::1
>>> check dnssec require list
>>> check dnssec request list
->>> ::1 in "<;127.0.0.1;::1"?
+>>> ::1 in "127.0.0.1;::1"?
>>> list element: 127.0.0.1
>>> list element: ::1
->>> ::1 in "<;127.0.0.1;::1"? yes (matched "::1")
->>> 127.0.0.1 in "<;127.0.0.1;::1"?
+>>> ::1 in "127.0.0.1;::1"? yes (matched "::1")
+>>> 127.0.0.1 in "127.0.0.1;::1"?
>>> list element: 127.0.0.1
->>> 127.0.0.1 in "<;127.0.0.1;::1"? yes (matched "127.0.0.1")
->>> V4NET.0.0.1 in "<;127.0.0.1;::1"?
+>>> 127.0.0.1 in "127.0.0.1;::1"? yes (matched "127.0.0.1")
+>>> V4NET.0.0.1 in "127.0.0.1;::1"?
>>> list element: 127.0.0.1
>>> list element: ::1
->>> V4NET.0.0.1 in "<;127.0.0.1;::1"? no (end of list)
+>>> V4NET.0.0.1 in "127.0.0.1;::1"? no (end of list)
>>> ten-1.test.ex in hosts_treat_as_local?
>>> list element: other1.test.ex
>>> ten-1.test.ex in hosts_treat_as_local? no (end of list)
->>> mxt11a.test.ex in "<+ @mx_any/ignore=<;127.0.0.1;::1"? no (end of list)
+>>> mxt11a.test.ex in " @mx_any/ignore=<;127.0.0.1;::1"? no (end of list)
>>> require: condition test failed in ACL acl_rcpt_6
>>> end of ACL acl_rcpt_6: not OK
LOG: H=(test) [V4NET.1.1.1] F=<x@y> rejected RCPT <6@???>: domain doesn't match @mx_any/ignore=<;127.0.0.1;::1
diff --git a/test/stderr/2610 b/test/stderr/2610
index dc54f12bc..af6db6216 100644
--- a/test/stderr/2610
+++ b/test/stderr/2610
@@ -621,11 +621,12 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 lookup failed
01:01:01 p1235 host in "net-mysql;select * from them where id='c'"? no (end of list)
01:01:01 p1235 warn: condition test failed in ACL check_recipient
-01:01:01 p1235 processing ACL check_recipient "warn" (TESTSUITE/test-config 45)
+01:01:01 p1235 processing ACL check_recipient "warn" (TESTSUITE/test-config 46)
01:01:01 p1235 check set acl_m0 = FAIL4: hostlist
01:01:01 p1235 check hosts = <& net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='${quote_mysql:$local_part}'
-01:01:01 p1235 ╭considering: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235 ├───────text: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
+01:01:01 p1235 list separator: '&'
+01:01:01 p1235 ╭considering: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235 ├───────text: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
01:01:01 p1235 ├considering: ${quote_mysql:$local_part}'
01:01:01 p1235 ╭considering: $local_part}'
01:01:01 p1235 ├──────value: c
@@ -638,10 +639,10 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 ╰──(tainted, quoted:mysql)
01:01:01 p1235 ├considering: '
01:01:01 p1235 ├───────text: '
-01:01:01 p1235 ├───expanded: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235 ╰─────result: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
+01:01:01 p1235 ├───expanded: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235 ╰─────result: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
01:01:01 p1235 ╰──(tainted, quoted:mysql)
-01:01:01 p1235 host in "<& net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
+01:01:01 p1235 host in " net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
01:01:01 p1235 list element: net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
01:01:01 p1235 search_open: mysql "NULL"
01:01:01 p1235 cached open
@@ -654,18 +655,19 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 (tainted, quoted:mysql)
01:01:01 p1235 MySQL query: "servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'" opts 'NULL'
01:01:01 p1235 LOG: MAIN
-01:01:01 p1235 Exim configuration error in ACL verb at line 45 of TESTSUITE/test-config:
+01:01:01 p1235 Exim configuration error in ACL verb at line 46 of TESTSUITE/test-config:
01:01:01 p1235 WARNING: obsolete syntax used for lookup
01:01:01 p1235 lookup deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235 host in "<& net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
+01:01:01 p1235 host in " net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
01:01:01 p1235 warn: condition test deferred in ACL check_recipient
01:01:01 p1235 LOG: MAIN
-01:01:01 p1235 H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 45 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235 processing ACL check_recipient "warn" (TESTSUITE/test-config 50)
+01:01:01 p1235 H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 46 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
+01:01:01 p1235 processing ACL check_recipient "warn" (TESTSUITE/test-config 51)
01:01:01 p1235 check set acl_m0 = FAIL5: hostlist
01:01:01 p1235 check hosts = <& net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='${quote_mysql:$local_part}'
-01:01:01 p1235 ╭considering: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235 ├───────text: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
+01:01:01 p1235 list separator: '&'
+01:01:01 p1235 ╭considering: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235 ├───────text: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
01:01:01 p1235 ├considering: ${quote_mysql:$local_part}'
01:01:01 p1235 ╭considering: $local_part}'
01:01:01 p1235 ├──────value: c
@@ -678,10 +680,10 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 ╰──(tainted, quoted:mysql)
01:01:01 p1235 ├considering: '
01:01:01 p1235 ├───────text: '
-01:01:01 p1235 ├───expanded: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235 ╰─────result: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
+01:01:01 p1235 ├───expanded: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235 ╰─────result: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
01:01:01 p1235 ╰──(tainted, quoted:mysql)
-01:01:01 p1235 host in "<& net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
+01:01:01 p1235 host in " net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
01:01:01 p1235 list element: net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
01:01:01 p1235 search_open: mysql "NULL"
01:01:01 p1235 cached open
@@ -694,11 +696,11 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 (tainted, quoted:mysql)
01:01:01 p1235 MySQL query: " select * from them where id='c'" opts 'servers=127.0.0.1::PORT_N/test/root/pass'
01:01:01 p1235 lookup deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235 host in "<& net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
+01:01:01 p1235 host in " net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
01:01:01 p1235 warn: condition test deferred in ACL check_recipient
01:01:01 p1235 LOG: MAIN
-01:01:01 p1235 H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 50 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235 processing ACL check_recipient "accept" (TESTSUITE/test-config 53)
+01:01:01 p1235 H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 51 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
+01:01:01 p1235 processing ACL check_recipient "accept" (TESTSUITE/test-config 54)
01:01:01 p1235 check domains = +local_domains
01:01:01 p1235 d in "+local_domains"?
01:01:01 p1235 list element: +local_domains
@@ -709,7 +711,7 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 end sublist local_domains
01:01:01 p1235 d in "+local_domains"? no (end of list)
01:01:01 p1235 accept: condition test failed in ACL check_recipient
-01:01:01 p1235 processing ACL check_recipient "accept" (TESTSUITE/test-config 56)
+01:01:01 p1235 processing ACL check_recipient "accept" (TESTSUITE/test-config 57)
01:01:01 p1235 check hosts = +relay_hosts
01:01:01 p1235 host in "+relay_hosts"?
01:01:01 p1235 list element: +relay_hosts
@@ -741,7 +743,7 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
01:01:01 p1235 end sublist relay_hosts
01:01:01 p1235 host in "+relay_hosts"? no (end of list)
01:01:01 p1235 accept: condition test failed in ACL check_recipient
-01:01:01 p1235 processing ACL check_recipient "deny" (TESTSUITE/test-config 57)
+01:01:01 p1235 processing ACL check_recipient "deny" (TESTSUITE/test-config 58)
01:01:01 p1235 message: relay not permitted
01:01:01 p1235 deny: condition test succeeded in ACL check_recipient
01:01:01 p1235 end of ACL check_recipient: DENY
@@ -797,7 +799,7 @@ P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
for ph10@???;
Tue, 2 Mar 1999 09:44:33 +0000
using ACL "check_notsmtp"
-processing ACL check_notsmtp "accept" (TESTSUITE/test-config 60)
+processing ACL check_notsmtp "accept" (TESTSUITE/test-config 61)
check set acl_m_qtest = ${quote_mysql:$recipients}
= ph10@???
accept: condition test succeeded in ACL check_notsmtp
@@ -874,7 +876,7 @@ processing address_data
(tainted)
No quoter name for addr
LOG: MAIN PANIC
- tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
+ tainted search query is not properly quoted (router r1, TESTSUITE/test-config 69): select name from them where id='ph10' limit 1
required_quoter_id (mysql) quoting -1 (NULL)
MySQL query: "select name from them where id='ph10' limit 1" opts 'NULL'
MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
@@ -919,7 +921,7 @@ appendfile transport entered
(tainted)
No quoter name for addr
LOG: MAIN
- tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
+ tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 83): select id from them where id='ph10'
required_quoter_id (mysql) quoting -1 (NULL)
MySQL query: "select id from them where id='ph10'" opts 'NULL'
MYSQL new connection: host=127.0.0.1 port=PORT_N socket=NULL database=test user=root
diff --git a/test/stderr/2620 b/test/stderr/2620
index fe7459356..05f2f445e 100644
--- a/test/stderr/2620
+++ b/test/stderr/2620
@@ -423,7 +423,8 @@ warn: condition test failed in ACL check_recipient
processing ACL check_recipient "warn" (TESTSUITE/test-config 44)
check set acl_m0 = FAIL: hostlist
check hosts = <& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
list element: net-pgsql;servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
search_open: pgsql "NULL"
cached open
@@ -439,14 +440,15 @@ LOG: MAIN
Exim configuration error in ACL verb at line 44 of TESTSUITE/test-config:
WARNING: obsolete syntax used for lookup
lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
warn: condition test deferred in ACL check_recipient
LOG: MAIN
H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 44 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
processing ACL check_recipient "warn" (TESTSUITE/test-config 49)
check set acl_m0 = FAIL: hostlist
check hosts = <& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
list element: net-pgsql,servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
search_open: pgsql "NULL"
cached open
@@ -459,7 +461,7 @@ host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them
(tainted, quoted:pgsql)
PostgreSQL query: " select * from them where id='c'" opts 'servers=localhost::PORT_N/test/CALLER/'
lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
warn: condition test deferred in ACL check_recipient
LOG: MAIN
H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 49 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
@@ -614,7 +616,8 @@ warn: condition test failed in ACL check_recipient
processing ACL check_recipient "warn" (TESTSUITE/test-config 44)
check set acl_m0 = FAIL: hostlist
check hosts = <& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
list element: net-pgsql;servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
search_open: pgsql "NULL"
cached open
@@ -630,14 +633,15 @@ LOG: MAIN
Exim configuration error in ACL verb at line 44 of TESTSUITE/test-config:
WARNING: obsolete syntax used for lookup
lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
warn: condition test deferred in ACL check_recipient
LOG: MAIN
H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 44 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
processing ACL check_recipient "warn" (TESTSUITE/test-config 49)
check set acl_m0 = FAIL: hostlist
check hosts = <& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
list element: net-pgsql,servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
search_open: pgsql "NULL"
cached open
@@ -650,7 +654,7 @@ host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them
(tainted, quoted:pgsql)
PostgreSQL query: " select * from them where id='c'" opts 'servers=localhost::PORT_N/test/CALLER/'
lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
warn: condition test deferred in ACL check_recipient
LOG: MAIN
H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 49 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
diff --git a/test/stdout/0002 b/test/stdout/0002
index 0524afd7b..abeb2329f 100644
--- a/test/stdout/0002
+++ b/test/stdout/0002
@@ -1099,5 +1099,6 @@ xyz
> in list
> in list
>
-> '${listextract {2} {<. my.target.host.name}}' => 'target'
+> variable m0 set
+> '${listextract {2} {my:target:string:list}}' => 'target'
>
--
## subscription configuration (requires account):
##
https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at
http://www.exim.org/
## Please use the Wiki with this list -
http://wiki.exim.org/