Taint: reject tainted list-separator change
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 19 Nov 2024 11:42:40 +0000 (11:42 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 19 Nov 2024 11:42:40 +0000 (11:42 +0000)
27 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/acl.c
src/src/daemon.c
src/src/dnsbl.c
src/src/expand.c
src/src/functions.h
src/src/match.c
src/src/readconf.c
src/src/string.c
test/confs/2610
test/log/2610
test/paniclog/2610
test/scripts/0000-Basic/0002
test/stderr/0002
test/stderr/0023
test/stderr/0149
test/stderr/0275
test/stderr/0277
test/stderr/0278
test/stderr/0279
test/stderr/0475
test/stderr/1000
test/stderr/1002
test/stderr/2610
test/stderr/2620
test/stdout/0002

index 1f90d6c86d124981ba50bbc3f8887c52a5667218..ae30cb88653a9c77f03df2c1b2036084e0f92df6 100644 (file)
@@ -8441,10 +8441,18 @@ type of match and is given below as the &*value*& information.
 
 .section "Expansion of lists" "SECTlistexpand"
 .cindex "expansion" "of lists"
 
 .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
 .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.'&
 
 &'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$&"
 .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
 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).
 
 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
 
 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$&"
 .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:
 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$&"
 .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
 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"
 .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.
 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"
 .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'&>&*}*&
 
 
 .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$&"
 .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$&.
 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"
        &*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.
 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.
 
 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.
 
 
 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`&
 .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.
 
 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.
 
 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
 
 &*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
index bd4fd192189472cb82448b14ec7d61c13cd8437b..c9f7a4375711bc8dcdde36402d200f6ed6297620 100644 (file)
@@ -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.
 
       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
 -----------------
 
 Exim version 4.98
 -----------------
 
index 88d09479ce08ed8a1635a9dbee1336f0ebe38c26..3f35a49466e3cbbc36fc961b3b17b44997e69180 100644 (file)
@@ -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. */
 
   /* 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,
                                  FORBIDDEN(0) },
 
   [ACLC_DOMAINS] =             { US"domains",          0,
@@ -786,7 +786,7 @@ Returns:      offset in list, or -1 if not found
 */
 
 static int
 */
 
 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; )
   {
 {
 for (int start = 0; start < end; )
   {
@@ -994,7 +994,7 @@ while ((s = (*func)()))
 
   /* Handle a condition or modifier. */
 
 
   /* 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);
     {
     *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;
   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. */
 
     /* 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 */
       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",
       {
       *error = string_sprintf("ACL error: failed to find module for '%s': %s",
-                             conditions[c].name, s);
+                             conditions[c].name, t);
       return NULL;
       }
     }
       return NULL;
       }
     }
@@ -3350,12 +3350,11 @@ Returns:       OK        - all conditions are met
 */
 
 static int
 */
 
 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)
 int rc = OK;
 
 for (; cb; cb = cb->next)
@@ -3364,30 +3363,24 @@ for (; cb; cb = cb->next)
   int control_type;
   BOOL textonly = FALSE;
 
   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
     }
 
   /* 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:
 #endif
 
     case ACLC_DNSLISTS:
-      rc = verify_check_dnsbl(where, &arg, log_msgptr);
+      rc = verify_check_dnsbl(where, arg, log_msgptr);
       break;
 
     case ACLC_DOMAINS:
       break;
 
     case ACLC_DOMAINS:
index 4272dae7a54bd89f6031e757985127c8246ca9ab..0c6ed4da0a27484b76db76fe8843e792e87defb1 100644 (file)
@@ -1893,7 +1893,13 @@ if (f.daemon_listen && !f.inetd_wait_mode)
 
     if (!override_pid_file_path) write_pid = FALSE;
 
 
     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];
     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);
       {
       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
         log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "invalid SMTP port: %s", s);
       }
     else
index 1172d61833e4d54a09e40a8bb18a3857976d90ab..8901b11ff8ce404b3f689b490d29a3bde6f07c93 100644 (file)
@@ -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:
 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
 
 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
 */
 
 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 */
 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? */
 
 
 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)))
 /* Loop through all the domains supplied, until something matches */
 
 while ((domain = string_nextinlist(&list, &sep, NULL, 0)))
index e4224dbb1b9ff8ba92e9c3165f2f774fdb9377e8..052c059e8264c3be67840c936fb557a0c9f0d0d2 100644 (file)
@@ -1331,18 +1331,15 @@ return fieldtext;
 
 
 static uschar *
 
 
 static uschar *
-expand_getlistele(int field, const uschar * list)
+expand_getlistele(int field, const uschar * list, int sep)
 {
 const uschar * tlist = list;
 {
 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)
 /* 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);
 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:
   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;
     sub2_honour_dollar = FALSE;
-#endif
     /* FALLTHROUGH */
 
   case ECOND_CRYPTEQ:
     /* FALLTHROUGH */
 
   case ECOND_CRYPTEQ:
-  case ECOND_INLIST:
-  case ECOND_INLISTI:
   case ECOND_MATCH:
 
   case ECOND_NUM_L:     /* Numerical comparisons */
   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 */
       }
 
     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,
                              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 */
       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(
          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,
        }
       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:
       /* Fall through */
       /* VVVVVVVVVVVV */
       MATCHED_SOMETHING:
@@ -3296,12 +3311,18 @@ switch(cond_type = identify_operator(&s, &opname))
     case ECOND_INLISTI:
       {
       const uschar * list = sub[1];
     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]);
 
       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;
       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;
   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);
 
     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 */
     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)))
     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
 
     /* 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)))
       {
 
     if (!(s = eval_condition(sub[1], resetok, NULL)))
       {
@@ -3432,6 +3459,8 @@ switch(cond_type = identify_operator(&s, &opname))
       goto failout;
       }
 
       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"[]");
     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:
       {
 
     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);
       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;
          }
 
          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++ != '}')
              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. */
 
       /* 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. */
 
       /* 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:
       {
     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;
       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);
        }
 
       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;                                             /*{{*/
       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:
       {
 
     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;
       const uschar * srclist, * cmp, * xtract;
       uschar * opname, * srcitem;
       const uschar * dstlist = NULL, * dstkeylist = NULL;
@@ -6779,6 +6815,7 @@ while (*s)
        goto EXPAND_FAILED_CURLY;                                       /*}*/
        }
 
        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;                                        /*{{*/
       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:
        {
 
       case EOP_LISTCOUNT:
        {
-       int cnt = 0, sep = 0;
+       int cnt = 0, sep;
        uschar * buf = store_get(2, sub);
 
        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;
        while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++;
        yield = string_fmt_append(yield, "%d", cnt);
        break;
index 11a4b66578c849588026bbcbbcfc9d6489dcd96b..5f26c3dd16ba26bcb922a6fb819253ca63c4bfe7 100644 (file)
@@ -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 **);
                 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);
 
 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 *);
 #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 **);
 extern int     verify_check_header_address(uschar **, uschar **, int, int, int,
                  uschar *, uschar *, int, int *);
 extern int     verify_check_headers(uschar **);
index 252efc6c214a7891aad093b538ff71ecc71c62a1..5670388eaa1ebf55c2558a9a41d1f981241c9cb9 100644 (file)
@@ -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      *
 *************************************************/
 /*************************************************
 *       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. */
 
 if the type value is greater than or equal to than MCL_NOEXPAND, do not expand
 the list. */
 
+list = *listptr;
 if (type >= MCL_NOEXPAND)
   {
 if (type >= MCL_NOEXPAND)
   {
-  list = *listptr;
   type -= MCL_NOEXPAND;       /* Remove the "no expand" flag */
   textonly_re = TRUE;
   }
 else
   {
   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. */
 
   /* 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);
     {
     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
     deliver_domain = NULL;
     }
   else
-    list = expand_string_2(*listptr, &textonly_re);
+    list = expand_string_2(list, &textonly_re);
 
   if (!list)
     {
 
   if (!list)
     {
@@ -1133,8 +1167,7 @@ if (pattern[0] == '@' && pattern[1] == '@')
 
     ss = Ustrrchr(list, ':');
     if (!ss) ss = list; else ss++;
 
     ss = Ustrrchr(list, ':');
     if (!ss) ss = list; else ss++;
-    Uskip_whitespace(&ss);
-    if (*ss == '>')
+    if (Uskip_whitespace(&ss) == '>')
       {
       *ss++ = 0;
       Uskip_whitespace(&ss);
       {
       *ss++ = 0;
       Uskip_whitespace(&ss);
index 7912bca4a94a13c356c9649da588883d6897f220..059a4e8f0f9a0978155466e36ddcf8ac86d22382 100644 (file)
@@ -1250,9 +1250,9 @@ return s;
 *             Read a name                        *
 *************************************************/
 
 *             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
 
 Arguments:
   name      where to put the name
index d4fb23cb63a3666e3af6f96e1371eddf2aae2dde..b370cfacc87fdf9c88c5853b7ae62ad2177257f4 100644 (file)
@@ -923,14 +923,18 @@ to be conservative. */
 
 while (isspace(*s) && *s != sep) s++;
 
 
 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])))
     {
 
 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++;
     }
     if (*++s) ++s;
     while (isspace(*s) && *s != sep) s++;
     }
index 94be1b91fab418347499c2efcd556226db206b6c..71a3f4284dc4f76cd3f51c8d8d6ac833109338f1 100644 (file)
@@ -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}'
          # 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}'
          # ... 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}'
index 4acbbd873bbcf241b1b326a65b8e7125e4b2bbf6..cd8b2a915bdd3affb2f4cf1c6af3a6b3982a681c 100644 (file)
@@ -1,5 +1,5 @@
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= CALLER@myhost.test.ex 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@myhost.test.ex> R=r1 T=t1
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 Completed
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 => ph10 <ph10@myhost.test.ex> R=r1 T=t1
 1999-03-02 09:44:33 10HmaX-000000005vi-0000 Completed
index 917a0a8015de38c73def45214a5ea24298ee0eac..29493f88862d050f9c391279b7fb53f77d2f4414 100644 (file)
@@ -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
index 0ed3e0dffa674c7da4d96a6f65f4822190949044..6e0d6dce6c9e747fff8344f085b53768c337a0eb 100644 (file)
@@ -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
 ${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}}'
 ****
 ****
index 8b6a1a44674a809f335a5e2d8162b467e185c6e7..2a3ef874287a781b11ccdca0fccc9ae60894deef 100644 (file)
@@ -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
 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
  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: 
    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
   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@myhost.test.ex
    ╎ ::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 >>>>>>>>>>>>>>>>
    ╎ ::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 >>>>>>>>>>>>>>>>
index d825511b94988d3d61db21bb3bad3b10ec640224..fe86a317d2a928da5bfcb93a8e128976bc70b9e7 100644 (file)
@@ -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
 >>> 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
 >>> 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
 >>> 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
 >>> 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
 >>> 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
 >>> 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
 >>> 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
 >>> 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
 >>> 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
 >>> 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@13.12.11.V4NET.rbl> 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
 >>> 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
 >>> 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
index 81bf94397b7d39d65c6cd6cdb4b62b0e1ec290a4..1dcf8893e3490cd7ddd1f279c9563743659f7ea6 100644 (file)
@@ -7,7 +7,7 @@ routing x@ten
 --------> domainlist1 router <--------
 local_part=x domain=ten
 checking domains
 --------> 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
 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
 --------> 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
 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
 --------> 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
 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
 --------> 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
 six in domains? yes (end of list)
 calling domainlist1 router
 domainlist1 router called for x@six
index f5891bb9ae1caa4dda1c3d6a9e103246ee527de7..d8ee843aede3e782d0785dc102b544357c2002be 100644 (file)
@@ -145,13 +145,14 @@ test.ex in domains?
  cached lookup data = NULL
  list element: +n2_domains
   start sublist n2_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
    ╎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
   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
  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
    ╎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
   end sublist n2_domains
  list element: !+local_domains
   start sublist local_domains
index b92d4d832fc767f5e7e016f4f3a68f70d118d2cf..ecf66e1856e3e12cff47d293a1378ec186fc3369 100644 (file)
@@ -88,7 +88,8 @@ host in sender_unqualified_hosts?
  cached no match for +lookup_hosts
  list element: !+n2_hosts
   start sublist n2_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
    ╎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
    ╎   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)
   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
  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
    ╎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
    ╎   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)
   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
  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
    ╎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
    ╎   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)
   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
  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: 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)
   end sublist n2_hosts
   host in sender_unqualified_hosts? no (matched "!+n2_hosts")
 host in recipient_unqualified_hosts? no (option unset)
index fd94ee0c007bbd621df606920ccf39633c39fd29..08709b25750f82cd9353308b4fd9d7c46cd882e8 100644 (file)
@@ -51,13 +51,14 @@ CALLER in local_parts?
  cached lookup data = NULL
  list element: +n2_localparts
   start sublist n2_localparts
  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
    ╎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
   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
  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
    ╎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
   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
  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
    ╎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
   end sublist n2_localparts
  list element: !+local_localparts
   start sublist local_localparts
index bbd8765683c4ab9345d76b23971d40366898c5b8..9088c39fe459aec94aa63e98772fc842d03bb42c 100644 (file)
@@ -68,14 +68,15 @@ CALLER@test.ex in senders?
  cached lookup data = NULL
  list element: +n2_addresses
   start sublist n2_addresses
  cached lookup data = NULL
  list element: +n2_addresses
   start sublist n2_addresses
-   CALLER@test.ex in "<; never2@test.ex ; +n1_addresses"?
+   list separator: ';'
+   CALLER@test.ex in " never2@test.ex ; +n1_addresses"?
    ╎list element: never2@test.ex
    ╎address match test: subject=CALLER@test.ex pattern=never2@test.ex
    ╎list element: +n1_addresses
    ╎ start sublist n1_addresses
    ╎cached no match for +n1_addresses
    ╎cached lookup data = NULL
    ╎list element: never2@test.ex
    ╎address match test: subject=CALLER@test.ex pattern=never2@test.ex
    ╎list element: +n1_addresses
    ╎ start sublist n1_addresses
    ╎cached no match for +n1_addresses
    ╎cached lookup data = NULL
-   CALLER@test.ex in "<; never2@test.ex ; +n1_addresses"? no (end of list)
+   CALLER@test.ex in " never2@test.ex ; +n1_addresses"? no (end of list)
   end sublist n2_addresses
  list element: !+local_addresses
   start sublist local_addresses
   end sublist n2_addresses
  list element: !+local_addresses
   start sublist local_addresses
index 34053c1e3c91ce2ff6d6250a43eef0e3b6dcd358..bb601718ab964c7c7007afec9ef2393f9438b5e1 100644 (file)
@@ -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
 >>>  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
 >>>   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
 >>>  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
 >>>   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
 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
index 5f289462d7e2060389114d7fa17ce189a3260e00..46bffdf92c2d46d058083699eca5075fbae41792 100644 (file)
@@ -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
 >>> 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: 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)
 >>> 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
 >>> 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
 >>>  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}}
 >>> 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
 >>> 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
 >>>  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)
 >>> 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)
index efaeb0e17bd90f8eb1e7147854b89fac010bb3a5..eb9d3ac215178fe9b0c107828b038672afe5cffe 100644 (file)
 >>> 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
 >>> 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
 >>>  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
 >>>   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
 >>>   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
 >>>   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)
 >>>  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@mxt11a.test.ex>: domain doesn't match @mx_any/ignore=<;127.0.0.1;::1
 >>> 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@mxt11a.test.ex>: domain doesn't match @mx_any/ignore=<;127.0.0.1;::1
index dc54f12bc6ff6d494bb9666f0429d3a0b0075717..af6db6216e6752197b00e4606b18a75bd9794f4e 100644 (file)
@@ -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   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  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
 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              ╰──(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              ╰──(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
 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                                (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    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  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  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
 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              ╰──(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              ╰──(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
 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                                (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  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
 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    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
 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    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
 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@myhost.test.ex;
        Tue, 2 Mar 1999 09:44:33 +0000
 using ACL "check_notsmtp"
        for ph10@myhost.test.ex;
        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@myhost.test.ex
 accept: condition test succeeded in ACL check_notsmtp
 check set acl_m_qtest = ${quote_mysql:$recipients}
                       = ph10@myhost.test.ex
 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)
 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
  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)
 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
  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
index fe745935632919eaa928bb675651845e1cacdf72..05f2f445e933e6de0ae6eba4f7925608f2e4f2e4 100644 (file)
@@ -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}'
 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
  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
   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}'
 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
  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
                               (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
 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}'
 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
  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
   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}'
 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
  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
                               (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
 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
index 0524afd7b87e0c7bc8b6eab21b99bc19569460ad..abeb2329f83a65432ada91fc73d0069cb6581f74 100644 (file)
@@ -1099,5 +1099,6 @@ xyz
 > in list
 > in list
 > 
 > in list
 > in list
 > 
-> '${listextract {2} {<. my.target.host.name}}'  =>   'target'
+> variable m0 set
+> '${listextract {2} {my:target:string:list}}'  =>   'target'
 > 
 >