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"
-Each list is expanded as a single string before it is used.
+.new
+Each list, after any leading change-of-separator specification
+(see &<<SECTlistsepchange>>&) is expanded as a single string,
 .cindex "tainted data" tracking
-&*Note*&: As a result, if any componend was tainted then the
-entire result string becomes tainted.
+&*Note*&: As a result, if any component was tainted then the
+entire expansion result string becomes tainted.
+
+Splitting out a leading explicit change-of-separator permits
+one being safely used on a list that has tainted components
+while still detecting the use of a tainted setting.
+The latter is not permitted.
+.wen
 
 &'Exception: the router headers_remove option, where list-item
 splitting is done before string-expansion.'&
@@ -10096,11 +10104,15 @@ leading and trailing quotes are removed from the returned value.
 .cindex "list" "selecting by condition"
 .cindex "expansion" "selecting from list by condition"
 .vindex "&$item$&"
-After expansion, <&'string'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
-For each item
-in this list, its value is placed in &$item$&, and then the condition is
-evaluated.
+.new
+<&'string1'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
+For each item in this list,
+its value is placed in &$item$&, and then the condition is evaluated.
 Any modification of &$value$& by this evaluation is discarded.
 If the condition is true, &$item$& is added to the output as an
 item in a new list; if the condition is false, the item is discarded. The
@@ -10364,8 +10376,12 @@ The <&'number'&> argument must consist entirely of decimal digits,
 apart from an optional leading minus,
 and leading and trailing white space (which is ignored).
 
-After expansion, <&'string1'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
+.new
+The <&'string1'&> argument, after any leading change-of-separator
+(see &<<SECTlistsepchange>>&),
+is expanded and the whole forms the list.
+.wen
+By default, the list separator is a colon.
 
 The first field of the list is numbered one.
 If the number is negative, the fields are
@@ -10465,10 +10481,15 @@ ${lookup nisplus {[name=$local_part],passwd.org_dir:gcos} \
 .vitem &*${map{*&<&'string1'&>&*}{*&<&'string2'&>&*}}*&
 .cindex "expansion" "list creation"
 .vindex "&$item$&"
-After expansion, <&'string1'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
-For each item
-in this list, its value is place in &$item$&, and then <&'string2'&> is
+.new
+<&'string1'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
+For each item in this list,
+its value is place in &$item$&, and then <&'string2'&> is
 expanded and added to the output as an item in a new list. The separator used
 for the output list is the same as the one used for the input, but a separator
 setting is not included in the output. For example:
@@ -10688,9 +10709,15 @@ locks out the use of this expansion item in filter files.
 .cindex "list" "reducing to a scalar"
 .vindex "&$value$&"
 .vindex "&$item$&"
-This operation reduces a list to a single, scalar string. After expansion,
-<&'string1'&> is interpreted as a list, colon-separated by default, but the
-separator can be changed in the usual way (&<<SECTlistsepchange>>&).
+This operation reduces a list to a single, scalar string.
+
+.new
+<&'string1'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
 Then <&'string2'&> is expanded and
 assigned to the &$value$& variable. After this, each item in the <&'string1'&>
 list is assigned to &$item$&, in turn, and <&'string3'&> is expanded for each of
@@ -10847,8 +10874,13 @@ rather than any Unicode-aware character handling.
 .cindex sorting "a list"
 .cindex list sorting
 .cindex expansion "list sorting"
-After expansion, <&'string'&> is interpreted as a list, colon-separated by
-default, but the separator can be changed in the usual way (&<<SECTlistsepchange>>&).
+.new
+<&'string'&> first has the part after any change-of-list-separator
+(see &<<SECTlistsepchange>>&) expanded,
+then the whole is taken as a list.
+.wen
+The default separator for the list is a colon.
+
 The <&'comparator'&> argument is interpreted as the operator
 of a two-argument expansion condition.
 The numeric operators plus ge, gt, le, lt (and ~i variants) are supported.
@@ -11304,7 +11336,8 @@ All measurement is done in bytes and is not UTF-8 aware.
 .cindex "list" "item count"
 .cindex "list" "count of items"
 .cindex "&%listcount%& expansion item"
-The string is interpreted as a list and the number of items is returned.
+The part of the string after any leading change-of-separator is expanded,
+then the whole is interpreted as a list and the number of items is returned.
 
 
 .vitem &*${listnamed:*&<&'name'&>&*}*&&~and&~&*${listnamed_*&<&'type'&>&*:*&<&'name'&>&*}*&
@@ -11925,9 +11958,14 @@ attempt. It is false during any subsequent delivery attempts.
 .cindex "expansion" "&*forall*& condition"
 .cindex "expansion" "&*forany*& condition"
 .vindex "&$item$&"
-These conditions iterate over a list. The first argument is expanded to form
-the list. By default, the list separator is a colon, but it can be changed by
-the normal method (&<<SECTlistsepchange>>&).
+These conditions iterate over a list.
+.new
+The first argument, after any leading change-of-separator
+(see &<<SECTlistsepchange>>&),
+is expanded and the whole forms the list.
+.wen
+By default, the list separator is a colon.
+
 The second argument is interpreted as a condition that is to
 be applied to each item in the list in turn. During the interpretation of the
 condition, the current list item is placed in a variable called &$item$&.
@@ -12004,9 +12042,14 @@ SRS decode.  See SECT &<<SECTSRS>>& for details.
        &*inlisti&~{*&<&'subject'&>&*}{*&<&'list'&>&*}*&
 .cindex "string" "comparison"
 .cindex "list" "iterative conditions"
-Both strings are expanded; the second string is treated as a list of simple
-strings; if the first string is a member of the second, then the condition
-is true.
+The <&'subject'&> string is expanded.
+.new
+The <&'list'&> first has any change-of-list-separator
++(see &<<SECTlistsepchange>>&) retained verbatim,
++then the remainder is expanded.
++.wen
+The whole is treated as a list of simple strings;
+if the subject string is a member of that list, then the condition is true.
 For the case-independent &%inlisti%& condition, case is defined per the system C locale.
 
 These are simpler to use versions of the more powerful &*forany*& condition.
@@ -12199,6 +12242,10 @@ just as easy to use the fact that a lookup is itself a condition, and write:
 
 Note that <&'string2'&> is not itself subject to string expansion, unless
 Exim was built with the EXPAND_LISTMATCH_RHS option.
+.new
+For the latter case, only the part after any leading
+change-of-separator specification is expanded.
+.wen
 
 Consult section &<<SECThoslispatip>>& for further details of these patterns.
 
@@ -12227,9 +12274,10 @@ ${if match_domain{$domain}{+local_domains}{...
 .endd
 .cindex "&`+caseful`&"
 For address lists, the matching starts off caselessly, but the &`+caseful`&
-item can be used, as in all address lists, to cause subsequent items to
-have their local parts matched casefully. Domains are always matched
-caselessly.
+item can be used, as in all address lists, to cause subsequent items
+(including those of referenced named lists)
+to have their local parts matched casefully.
+Domains are always matched caselessly.
 
 The variable &$value$& will be set for a successful match and can be
 used in the success clause of an &%if%& expansion item using the condition.
@@ -12244,6 +12292,10 @@ Any previous &$value$& is restored after the if.
 
 Note that <&'string2'&> is not itself subject to string expansion, unless
 Exim was built with the EXPAND_LISTMATCH_RHS option.
+.new
+For the latter case, only the part after any leading
+change-of-separator specification is expanded.
+.wen
 
 &*Note*&: Host lists are &'not'& supported in this way. This is because
 hosts have two identities: a name and an IP address, and it is not clear
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.
 
+JH/15 Disallow tainted change-of-separator on lists
+
 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. */
-  [ACLC_DNSLISTS] =            { US"dnslists",         ACD_EXP,
+  [ACLC_DNSLISTS] =            { US"dnslists",         0,
                                  FORBIDDEN(0) },
 
   [ACLC_DOMAINS] =             { US"domains",          0,
@@ -786,7 +786,7 @@ Returns:      offset in list, or -1 if not found
 */
 
 static int
-acl_checkcondition(uschar * name, condition_def * list, int end)
+acl_findcondition(uschar * name, condition_def * list, int end)
 {
 for (int start = 0; start < end; )
   {
@@ -994,7 +994,7 @@ while ((s = (*func)()))
 
   /* Handle a condition or modifier. */
 
-  if ((c = acl_checkcondition(name, conditions, nelem(conditions))) < 0)
+  if ((c = acl_findcondition(name, conditions, nelem(conditions))) < 0)
     {
     *error = string_sprintf("unknown ACL condition/modifier in \"%s\"",
       saveline);
@@ -1025,7 +1025,7 @@ while ((s = (*func)()))
   if (conditions[c].flags & ACD_LOAD)
     {                          /* a loadable module supports this condition */
     condition_module * cm;
-    uschar * s = NULL;
+    uschar * t = NULL;
 
     /* Over the list of modules we support, check the list of ACL conditions
     each supports.  This assumes no duplicates. */
@@ -1043,10 +1043,10 @@ while ((s = (*func)()))
       return NULL;
       }
     if (  !cm->info                            /* module not loaded */
-       && !(cm->info = misc_mod_find(cm->mod_name, &s)))
+       && !(cm->info = misc_mod_find(cm->mod_name, &t)))
       {
       *error = string_sprintf("ACL error: failed to find module for '%s': %s",
-                             conditions[c].name, s);
+                             conditions[c].name, t);
       return NULL;
       }
     }
@@ -3350,12 +3350,11 @@ Returns:       OK        - all conditions are met
 */
 
 static int
-acl_check_condition(int verb, acl_condition_block *cb, int where,
-  address_item *addr, int level, BOOL *epp, uschar **user_msgptr,
-  uschar **log_msgptr, int *basic_errno)
+acl_check_condition(int verb, acl_condition_block * cb, int where,
+  address_item * addr, int level, BOOL * epp, uschar ** user_msgptr,
+  uschar ** log_msgptr, int * basic_errno)
 {
-uschar * user_message = NULL;
-uschar * log_message = NULL;
+uschar * user_message = NULL, * log_message = NULL;
 int rc = OK;
 
 for (; cb; cb = cb->next)
@@ -3364,30 +3363,24 @@ for (; cb; cb = cb->next)
   int control_type;
   BOOL textonly = FALSE;
 
-  /* The message and log_message items set up messages to be used in
-  case of rejection. They are expanded later. */
-
-  if (cb->type == ACLC_MESSAGE)
+  switch (cb->type)
     {
-    HDEBUG(D_acl) debug_printf_indent("  message: %s\n", cb->arg);
-    user_message = cb->arg;
-    continue;
-    }
+    /* The message and log_message items set up messages to be used in
+    case of rejection. They are expanded later. */
 
-  if (cb->type == ACLC_LOG_MESSAGE)
-    {
-    HDEBUG(D_acl) debug_printf_indent("l_message: %s\n", cb->arg);
-    log_message = cb->arg;
-    continue;
-    }
+    case ACLC_MESSAGE:
+      HDEBUG(D_acl) debug_printf_indent("  message: %s\n", cb->arg);
+      user_message = cb->arg;  continue;
 
-  /* The endpass "condition" just sets a flag to show it occurred. This is
-  checked at compile time to be on an "accept" or "discard" item. */
+    case ACLC_LOG_MESSAGE:
+      HDEBUG(D_acl) debug_printf_indent("l_message: %s\n", cb->arg);
+      log_message = cb->arg;   continue;
 
-  if (cb->type == ACLC_ENDPASS)
-    {
-    *epp = TRUE;
-    continue;
+    /* The endpass "condition" just sets a flag to show it occurred. This is
+    checked at compile time to be on an "accept" or "discard" item. */
+
+    case ACLC_ENDPASS:
+      *epp = TRUE;             continue;
     }
 
   /* For other conditions and modifiers, the argument is expanded now for some
@@ -4032,7 +4025,7 @@ for (; cb; cb = cb->next)
 #endif
 
     case ACLC_DNSLISTS:
-      rc = verify_check_dnsbl(where, &arg, log_msgptr);
+      rc = verify_check_dnsbl(where, arg, log_msgptr);
       break;
 
     case ACLC_DOMAINS:
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;
 
-    list = override_local_interfaces;
+    /* specifically permit change-of-separator for admins (who should be
+    the only people getting here, but we may as well be careful) */
+
+    list = f.admin_user
+      ? string_copy_taint(override_local_interfaces, GET_UNTAINTED)
+      : override_local_interfaces;
+
     for (int sep = 0; s = string_nextinlist(&list, &sep, NULL, 0); )
       {
       uschar joinstr[4];
@@ -1940,7 +1946,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
       {
       uschar * end;
       default_smtp_port[pct] = Ustrtol(s, &end, 0);
-      if (end != s + Ustrlen(s))
+      if (*end)
         log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "invalid SMTP port: %s", s);
       }
     else
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:
-  where        the acl type
-  listptr      the domain/address/data list
-  log_msgptr   log message on error
+  where                the acl type
+  list         the domain/address/data list
+  log_msgptr   log message on error
 
 Returns:    OK      successful lookup (i.e. the address is on the list), or
                       lookup deferred after +include_unknown
             FAIL    name not found, or no data found for the given type, or
                       lookup deferred after +exclude_unknown (default)
             DEFER   lookup failure, if +defer_unknown was set
+           ERROR   error during expansion
 */
 
 int
-verify_check_dnsbl(int where, const uschar ** listptr, uschar ** log_msgptr)
+verify_check_dnsbl(int where, const uschar * list, uschar ** log_msgptr)
 {
-int sep = 0;
-int defer_return = FAIL;
-const uschar *list = *listptr;
-uschar *domain;
+int sep, defer_return = FAIL;
+uschar * domain;
+const uschar * s = list;
 uschar revadd[128];        /* Long enough for IPv6 address */
 
 /* Indicate that the inverted IP address is not yet set up */
@@ -480,6 +480,21 @@ revadd[0] = 0;
 
 dns_init(FALSE, FALSE, FALSE); /*XXX dnssec? */
 
+/* Expand the list string.  This used to be done by the caller
+but we want to first strip any change-of-list-separator */
+
+sep = matchlist_parse_sep(&s);
+
+if (!(s= expand_cstring(s)))
+  {
+  if (f.expand_string_forcedfail) return OK;
+  *log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s",
+    list, expand_string_message);
+  return f.search_find_defer ? DEFER : ERROR;
+  }
+HDEBUG(D_acl) if (s != list) debug_printf_indent("expanded list: %s\n", s);
+list = s;
+
 /* Loop through all the domains supplied, until something matches */
 
 while ((domain = string_nextinlist(&list, &sep, NULL, 0)))
index e4224dbb1b9ff8ba92e9c3165f2f774fdb9377e8..052c059e8264c3be67840c936fb557a0c9f0d0d2 100644 (file)
@@ -1331,18 +1331,15 @@ return fieldtext;
 
 
 static uschar *
-expand_getlistele(int field, const uschar * list)
+expand_getlistele(int field, const uschar * list, int sep)
 {
 const uschar * tlist = list;
-int sep = 0;
+int sep_l = sep;
 /* Tainted mem for the throwaway element copies */
 uschar * dummy = store_get(2, GET_TAINTED);
 
 if (field < 0)
-  {
-  for (field++; string_nextinlist(&tlist, &sep, dummy, 1); ) field++;
-  sep = 0;
-  }
+  for (field++; string_nextinlist(&tlist, &sep_l, dummy, 1); ) field++;
 if (field == 0) return NULL;
 while (--field > 0 && (string_nextinlist(&list, &sep, dummy, 1))) ;
 return string_nextinlist(&list, &sep, NULL, 0);
@@ -2947,14 +2944,12 @@ switch(cond_type = identify_operator(&s, &opname))
   case ECOND_MATCH_DOMAIN:
   case ECOND_MATCH_IP:
   case ECOND_MATCH_LOCAL_PART:
-#ifndef EXPAND_LISTMATCH_RHS
+  case ECOND_INLIST:
+  case ECOND_INLISTI:
     sub2_honour_dollar = FALSE;
-#endif
     /* FALLTHROUGH */
 
   case ECOND_CRYPTEQ:
-  case ECOND_INLIST:
-  case ECOND_INLISTI:
   case ECOND_MATCH:
 
   case ECOND_NUM_L:     /* Numerical comparisons */
@@ -3088,13 +3083,24 @@ switch(cond_type = identify_operator(&s, &opname))
       }
 
     case ECOND_MATCH_ADDRESS:  /* Match in an address list */
-      rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0,
+      rc = match_address_list(sub[0], TRUE,
+#ifdef EXPAND_LISTMATCH_RHS
+                             TRUE,
+#else
+                             FALSE,
+#endif
+                             &(sub[1]), NULL, -1, 0,
                              CUSS &lookup_value);
       goto MATCHED_SOMETHING;
 
     case ECOND_MATCH_DOMAIN:   /* Match in a domain list */
       rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL,
-       MCL_DOMAIN + MCL_NOEXPAND, TRUE, CUSS &lookup_value);
+#ifdef EXPAND_LISTMATCH_RHS
+                         MCL_DOMAIN,
+#else
+                         MCL_DOMAIN + MCL_NOEXPAND,
+#endif
+                         TRUE, CUSS &lookup_value);
       goto MATCHED_SOMETHING;
 
     case ECOND_MATCH_IP:       /* Match IP address in a host list */
@@ -3120,21 +3126,30 @@ switch(cond_type = identify_operator(&s, &opname))
          cb.host_address + 7 : cb.host_address;
 
        rc = match_check_list(
-              &sub[1],                   /* the list */
-              0,                         /* separator character */
-              &hostlist_anchor,          /* anchor pointer */
-              &nullcache,                /* cache pointer */
-              check_host,                /* function for testing */
-              &cb,                       /* argument for function */
-              MCL_HOST,                  /* type of check */
-              sub[0],                    /* text for debugging */
-              CUSS &lookup_value);       /* where to pass back data */
+               &sub[1],                /* the list */
+               0,                      /* separator character */
+               &hostlist_anchor,       /* anchor pointer */
+               &nullcache,             /* cache pointer */
+               check_host,             /* function for testing */
+               &cb,                    /* argument for function */
+#ifdef EXPAND_LISTMATCH_RHS
+               MCL_HOST,
+#else
+               MCL_HOST + MCL_NOEXPAND,/* type of check */
+#endif
+               sub[0],                 /* text for debugging */
+               CUSS &lookup_value);    /* where to pass back data */
        }
       goto MATCHED_SOMETHING;
 
     case ECOND_MATCH_LOCAL_PART:
       rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL,
-       MCL_LOCALPART + MCL_NOEXPAND, TRUE, CUSS &lookup_value);
+#ifdef EXPAND_LISTMATCH_RHS
+                         MCL_LOCALPART,
+#else
+                         MCL_LOCALPART+ MCL_NOEXPAND,
+#endif
+                         TRUE, CUSS &lookup_value);
       /* Fall through */
       /* VVVVVVVVVVVV */
       MATCHED_SOMETHING:
@@ -3296,12 +3311,18 @@ switch(cond_type = identify_operator(&s, &opname))
     case ECOND_INLISTI:
       {
       const uschar * list = sub[1];
-      int sep = 0;
+      int sep;
       uschar *save_iterate_item = iterate_item;
       int (*compare)(const uschar *, const uschar *);
 
       DEBUG(D_expand) debug_printf_indent("condition: %s  item: %s\n", opname, sub[0]);
 
+      /* grab any listsep spec, then expand the list */
+
+      sep = matchlist_parse_sep(&list);
+      if (!(list = expand_cstring(list)))
+       goto failout;
+
       tempcond = FALSE;
       compare = cond_type == ECOND_INLISTI
         ? strcmpic : (int (*)(const uschar *, const uschar *)) strcmp;
@@ -3392,13 +3413,19 @@ switch(cond_type = identify_operator(&s, &opname))
   FORMANY:
     {
     const uschar * list;
-    int sep = 0;
+    int sep;
     uschar *save_iterate_item = iterate_item;
 
     DEBUG(D_expand) debug_printf_indent("condition: %s\n", opname);
 
+    /* First expand the list, apart from a leading change-of-separator
+    on non-json lists */
+
     Uskip_whitespace(&s);
     if (*s++ != '{') goto COND_FAILED_CURLY_START;     /* }-for-text-editors */
+
+    sep = is_json ? 0 : matchlist_parse_sep(&s);
+
     if (!(sub[0] = expand_string_internal(s,
       ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | (yield ? ESI_NOFLAGS : ESI_SKIPPING),
       &s, resetok, NULL)))
@@ -3413,7 +3440,7 @@ switch(cond_type = identify_operator(&s, &opname))
 
     /* Call eval_condition once, with result discarded (as if scanning a
     "false" part). This allows us to find the end of the condition, because if
-    the list it empty, we won't actually evaluate the condition for real. */
+    the list is empty, we won't actually evaluate the condition for real. */
 
     if (!(s = eval_condition(sub[1], resetok, NULL)))
       {
@@ -3432,6 +3459,8 @@ switch(cond_type = identify_operator(&s, &opname))
       goto failout;
       }
 
+    /* Now scan the list, checking the condition for each item */
+
     if (yield) *yield = !testfor;
     list = sub[0];
     if (is_json) list = dewrap(string_copy(list), US"[]");
@@ -6358,7 +6387,7 @@ while (*s)
 
     case EITEM_LISTEXTRACT:
       {
-      int field_number = 1;
+      int field_number = 1, sep = 0;
       uschar * save_lookup_value = lookup_value, * sub[2];
       int save_expand_nmax =
         save_expand_strings(save_expand_nstring, save_expand_nlength);
@@ -6375,7 +6404,10 @@ while (*s)
          goto EXPAND_FAILED_CURLY;
          }
 
-       sub[i] = expand_string_internal(s+1,
+       s++;
+       if (i == 1) sep = matchlist_parse_sep(&s);
+
+       sub[i] = expand_string_internal(s,
              ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL);
        if (!sub[i])     goto EXPAND_FAILED;                            /*{{*/
        if (*s++ != '}')
@@ -6427,7 +6459,8 @@ while (*s)
       /* Extract the numbered element into $value. If
       skipping, just pretend the extraction failed. */
 
-      lookup_value = flags & ESI_SKIPPING ? NULL : expand_getlistele(field_number, sub[1]);
+      lookup_value = flags & ESI_SKIPPING
+       ? NULL : expand_getlistele(field_number, sub[1], sep);
 
       /* If no string follows, $value gets substituted; otherwise there can
       be yes/no strings, as for lookup or if. */
@@ -6559,7 +6592,7 @@ while (*s)
     case EITEM_MAP:
     case EITEM_REDUCE:
       {
-      int sep = 0, save_ptr = gstring_length(yield);
+      int sep, save_ptr = gstring_length(yield);
       uschar outsep[2] = { '\0', '\0' };
       const uschar *list, *expr, *temp;
       uschar * save_iterate_item = iterate_item;
@@ -6574,6 +6607,9 @@ while (*s)
        }
 
       DEBUG(D_expand) debug_printf_indent("%s: evaluate input list list\n", name);
+      /* Check for a list-sep spec before expansion */
+      sep = matchlist_parse_sep(&s);
+
       if (!(list = expand_string_internal(s,
              ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL)))
        goto EXPAND_FAILED;                                             /*{{*/
@@ -6766,7 +6802,7 @@ while (*s)
 
     case EITEM_SORT:
       {
-      int sep = 0, cond_type;
+      int sep, cond_type;
       const uschar * srclist, * cmp, * xtract;
       uschar * opname, * srcitem;
       const uschar * dstlist = NULL, * dstkeylist = NULL;
@@ -6779,6 +6815,7 @@ while (*s)
        goto EXPAND_FAILED_CURLY;                                       /*}*/
        }
 
+      sep = matchlist_parse_sep(&s);
       srclist = expand_string_internal(s,
              ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL);
       if (!srclist) goto EXPAND_FAILED;                                        /*{{*/
@@ -7545,9 +7582,10 @@ NOT_ITEM: ;
 
       case EOP_LISTCOUNT:
        {
-       int cnt = 0, sep = 0;
+       int cnt = 0, sep;
        uschar * buf = store_get(2, sub);
 
+       sep = matchlist_parse_sep(CUSS &sub);
        while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++;
        yield = string_fmt_append(yield, "%d", cnt);
        break;
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 **);
+extern uschar  matchlist_parse_sep(const uschar **);
 
 extern void    message_start(void);
 extern void    message_tidyup(void);
@@ -643,7 +644,7 @@ extern int     vaguely_random_number_fallback(int);
 #endif
 extern int     verify_address(address_item *, FILE *, int, int, int, int,
                  uschar *, uschar *, BOOL *);
-extern int     verify_check_dnsbl(int, const uschar **, uschar **);
+extern int     verify_check_dnsbl(int, const uschar *, uschar **);
 extern int     verify_check_header_address(uschar **, uschar **, int, int, int,
                  uschar *, uschar *, int, int *);
 extern int     verify_check_headers(uschar **);
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      *
 *************************************************/
@@ -454,14 +485,17 @@ if (!*listptr)
 if the type value is greater than or equal to than MCL_NOEXPAND, do not expand
 the list. */
 
+list = *listptr;
 if (type >= MCL_NOEXPAND)
   {
-  list = *listptr;
   type -= MCL_NOEXPAND;       /* Remove the "no expand" flag */
   textonly_re = TRUE;
   }
 else
   {
+  if (sep <= 0)
+    sep = matchlist_parse_sep(&list);
+
   /* If we are searching a domain list, and $domain is not set, set it to the
   subject that is being sought for the duration of the expansion. */
 
@@ -469,11 +503,11 @@ else
     {
     check_string_block *cb = (check_string_block *)arg;
     deliver_domain = string_copy(cb->subject);
-    list = expand_string_2(*listptr, &textonly_re);
+    list = expand_string_2(list, &textonly_re);
     deliver_domain = NULL;
     }
   else
-    list = expand_string_2(*listptr, &textonly_re);
+    list = expand_string_2(list, &textonly_re);
 
   if (!list)
     {
@@ -1133,8 +1167,7 @@ if (pattern[0] == '@' && pattern[1] == '@')
 
     ss = Ustrrchr(list, ':');
     if (!ss) ss = list; else ss++;
-    Uskip_whitespace(&ss);
-    if (*ss == '>')
+    if (Uskip_whitespace(&ss) == '>')
       {
       *ss++ = 0;
       Uskip_whitespace(&ss);
index 7912bca4a94a13c356c9649da588883d6897f220..059a4e8f0f9a0978155466e36ddcf8ac86d22382 100644 (file)
@@ -1250,9 +1250,9 @@ return s;
 *             Read a name                        *
 *************************************************/
 
-/* The yield is the pointer to the next uschar. Names longer than the
-output space are silently truncated. This function is also used from acl.c when
-parsing ACLs.
+/* The yield is the pointer to the next uschar after the name plus
+and whitespace. Names longer than the output space are silently truncated.
+This function is also used from acl.c when parsing ACLs.
 
 Arguments:
   name      where to put the name
index d4fb23cb63a3666e3af6f96e1371eddf2aae2dde..b370cfacc87fdf9c88c5853b7ae62ad2177257f4 100644 (file)
@@ -923,14 +923,18 @@ to be conservative. */
 
 while (isspace(*s) && *s != sep) s++;
 
-/* A change of separator is permitted, so look for a leading '<' followed by an
-allowed character. */
+/* A change of separator is permitted (assuming untainted source),
+so look for a leading '<' followed by an allowed character. */
 
 if (sep <= 0)
   {
   if (*s == '<' && (ispunct(s[1]) || iscntrl(s[1])))
     {
-    sep = s[1];
+    if (!is_tainted(s))
+      sep = s[1];
+    else DEBUG(D_any) 
+      debug_printf("attempt to use tainted change-of-seperator spec (%s %d)\n",
+                   config_filename, config_lineno);
     if (*++s) ++s;
     while (isspace(*s) && *s != sep) s++;
     }
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}'
+
          # ... 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 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
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
-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
-host in "<
- partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch 
+list separator: '↩
+'
+host in " partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch 
  1.2.3.4"?
  list element: partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
  sender host name required, to match against partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
@@ -588,8 +589,7 @@ host in "<
    in TESTSUITE/aux-fixed/0002.lsearch
  creating new cache entry
  lookup yielded: 
-  host in "<
-  partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch 
+  host in " partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch 
   1.2.3.4"? yes (matched "partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch")
 deny: condition test succeeded in ACL connect1
 end of ACL connect1: DENY
@@ -827,3 +827,49 @@ sender address = CALLER@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 >>>>>>>>>>>>>>>>
+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
->>>                = test.ex/localhost
+>>> expanded list: test.ex/localhost
 >>> dnslists check: test.ex/localhost
 >>> new DNS lookup for localhost.test.ex
 >>> dnslists: wrote cache entry, ttl=3600
@@ -1680,7 +1680,7 @@ LOG: H=(test) [29.29.29.29] F=<a@localhost> rejected RCPT <x@y>
 >>> using ACL "acl_29_29_29"
 >>> processing ACL acl_29_29_29 "deny" (TESTSUITE/test-config 154)
 >>> check dnslists = test.ex/$sender_address_domain
->>>                = test.ex/elsewhere
+>>> expanded list: test.ex/elsewhere
 >>> dnslists check: test.ex/elsewhere
 >>> new DNS lookup for elsewhere.test.ex
 >>> dnslists: wrote cache entry, ttl=3000
@@ -1706,7 +1706,7 @@ LOG: H=(test) [29.29.29.29] F=<a@localhost> rejected RCPT <x@y>
 >>> processing ACL acl_30_30_30 "deny" (TESTSUITE/test-config 161)
 >>>   message: domain=$dnslist_domain\nvalue=$dnslist_value\nmatched=$dnslist_matched\ntext="$dnslist_text"
 >>> check dnslists = test.ex=V4NET.0.0.1,127.0.0.2/$sender_address_domain
->>>                = test.ex=V4NET.0.0.1,127.0.0.2/ten-1
+>>> expanded list: test.ex=V4NET.0.0.1,127.0.0.2/ten-1
 >>> dnslists check: test.ex=V4NET.0.0.1,127.0.0.2/ten-1
 >>> new DNS lookup for ten-1.test.ex
 >>> dnslists: wrote cache entry, ttl=3600
@@ -1719,7 +1719,7 @@ LOG: H=(test) [30.30.30.30] F=<a@ten-1> rejected RCPT <x@y>: domain=test.ex
 >>> processing ACL acl_30_30_30 "deny" (TESTSUITE/test-config 161)
 >>>   message: domain=$dnslist_domain\nvalue=$dnslist_value\nmatched=$dnslist_matched\ntext="$dnslist_text"
 >>> check dnslists = test.ex=V4NET.0.0.1,127.0.0.2/$sender_address_domain
->>>                = test.ex=V4NET.0.0.1,127.0.0.2/ten-2
+>>> expanded list: test.ex=V4NET.0.0.1,127.0.0.2/ten-2
 >>> dnslists check: test.ex=V4NET.0.0.1,127.0.0.2/ten-2
 >>> new DNS lookup for ten-2.test.ex
 >>> dnslists: wrote cache entry, ttl=3600
@@ -1737,7 +1737,7 @@ LOG: H=(test) [30.30.30.30] F=<a@ten-1> rejected RCPT <x@y>: domain=test.ex
 >>> processing ACL acl_30_30_30 "deny" (TESTSUITE/test-config 161)
 >>>   message: domain=$dnslist_domain\nvalue=$dnslist_value\nmatched=$dnslist_matched\ntext="$dnslist_text"
 >>> check dnslists = test.ex=V4NET.0.0.1,127.0.0.2/$sender_address_domain
->>>                = test.ex=V4NET.0.0.1,127.0.0.2/13.12.11.V4NET.rbl
+>>> expanded list: test.ex=V4NET.0.0.1,127.0.0.2/13.12.11.V4NET.rbl
 >>> dnslists check: test.ex=V4NET.0.0.1,127.0.0.2/13.12.11.V4NET.rbl
 >>> new DNS lookup for 13.12.11.V4NET.rbl.test.ex
 >>> dnslists: wrote cache entry, ttl=3
@@ -1761,7 +1761,7 @@ LOG: H=(test) [30.30.30.30] F=<a@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
->>>                = 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
index 81bf94397b7d39d65c6cd6cdb4b62b0e1ec290a4..1dcf8893e3490cd7ddd1f279c9563743659f7ea6 100644 (file)
@@ -7,7 +7,7 @@ routing x@ten
 --------> domainlist1 router <--------
 local_part=x domain=ten
 checking domains
-ten in "<- test1 - test2-test3--4"? no (end of list)
+ten in " test1 - test2-test3--4"? no (end of list)
 ten in domains? yes (end of list)
 calling domainlist1 router
 domainlist1 router called for x@ten
@@ -33,7 +33,7 @@ routing y@two
 --------> domainlist1 router <--------
 local_part=y domain=two
 checking domains
-two in "<- test1 - test2-test3--4"? no (end of list)
+two in " test1 - test2-test3--4"? no (end of list)
 two in domains? yes (end of list)
 calling domainlist1 router
 domainlist1 router called for y@two
@@ -128,7 +128,7 @@ routing x@one
 --------> domainlist1 router <--------
 local_part=x domain=one
 checking domains
-one in "<- test1 - test2-test3--4"? no (end of list)
+one in " test1 - test2-test3--4"? no (end of list)
 one in domains? yes (end of list)
 calling domainlist1 router
 domainlist1 router called for x@one
@@ -168,7 +168,7 @@ routing x@six
 --------> domainlist1 router <--------
 local_part=x domain=six
 checking domains
-six in "<- test1 - test2-test3--4"? no (end of list)
+six in " test1 - test2-test3--4"? no (end of list)
 six in domains? yes (end of list)
 calling domainlist1 router
 domainlist1 router called for x@six
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
-   test.ex in "<; never2.ex ; +n1_domains"?
+   list separator: ';'
+   test.ex in " never2.ex ; +n1_domains"?
    ╎list element: never2.ex
    ╎list element: +n1_domains
    ╎ start sublist n1_domains
    ╎cached no match for +n1_domains
    ╎cached lookup data = NULL
-   test.ex in "<; never2.ex ; +n1_domains"? no (end of list)
+   test.ex in " never2.ex ; +n1_domains"? no (end of list)
   end sublist n2_domains
  list element: !+local_domains
   start sublist local_domains
@@ -408,13 +409,14 @@ test.ex in domains?
  cached lookup data = NULL
  list element: +n2_domains
   start sublist n2_domains
-   test.ex in "<; never2.ex ; +n1_domains"?
+   list separator: ';'
+   test.ex in " never2.ex ; +n1_domains"?
    ╎list element: never2.ex
    ╎list element: +n1_domains
    ╎ start sublist n1_domains
    ╎cached no match for +n1_domains
    ╎cached lookup data = NULL
-   test.ex in "<; never2.ex ; +n1_domains"? no (end of list)
+   test.ex in " never2.ex ; +n1_domains"? no (end of list)
   end sublist n2_domains
  list element: !+local_domains
   start sublist local_domains
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
-  host in "<; V4NET.2.2.2 ; +n1_hosts"?
+   list separator: ';'
+  host in " V4NET.2.2.2 ; +n1_hosts"?
    ╎list element: V4NET.2.2.2
    ╎list element: +n1_hosts
    ╎ start sublist n1_hosts
@@ -96,7 +97,7 @@ host in sender_unqualified_hosts?
    ╎   list element: V4NET.1.1.1
    ╎  host in "V4NET.1.1.1"? no (end of list)
    ╎ end sublist n1_hosts
-  host in "<; V4NET.2.2.2 ; +n1_hosts"? no (end of list)
+  host in " V4NET.2.2.2 ; +n1_hosts"? no (end of list)
   end sublist n2_hosts
 host in sender_unqualified_hosts? yes (end of list)
 host in recipient_unqualified_hosts? no (option unset)
@@ -159,7 +160,8 @@ host in sender_unqualified_hosts?
  cached no match for +lookup_hosts
  list element: !+n2_hosts
   start sublist n2_hosts
-  host in "<; V4NET.2.2.2 ; +n1_hosts"?
+   list separator: ';'
+  host in " V4NET.2.2.2 ; +n1_hosts"?
    ╎list element: V4NET.2.2.2
    ╎list element: +n1_hosts
    ╎ start sublist n1_hosts
@@ -167,7 +169,7 @@ host in sender_unqualified_hosts?
    ╎   list element: V4NET.1.1.1
    ╎  host in "V4NET.1.1.1"? no (end of list)
    ╎ end sublist n1_hosts
-  host in "<; V4NET.2.2.2 ; +n1_hosts"? no (end of list)
+  host in " V4NET.2.2.2 ; +n1_hosts"? no (end of list)
   end sublist n2_hosts
 host in sender_unqualified_hosts? yes (end of list)
 host in recipient_unqualified_hosts? no (option unset)
@@ -230,7 +232,8 @@ host in sender_unqualified_hosts?
  cached no match for +lookup_hosts
  list element: !+n2_hosts
   start sublist n2_hosts
-  host in "<; V4NET.2.2.2 ; +n1_hosts"?
+   list separator: ';'
+  host in " V4NET.2.2.2 ; +n1_hosts"?
    ╎list element: V4NET.2.2.2
    ╎list element: +n1_hosts
    ╎ start sublist n1_hosts
@@ -238,7 +241,7 @@ host in sender_unqualified_hosts?
    ╎   list element: V4NET.1.1.1
    ╎   host in "V4NET.1.1.1"? yes (matched "V4NET.1.1.1")
    ╎ end sublist n1_hosts
-   ╎host in "<; V4NET.2.2.2 ; +n1_hosts"? yes (matched "+n1_hosts")
+   ╎host in " V4NET.2.2.2 ; +n1_hosts"? yes (matched "+n1_hosts")
   end sublist n2_hosts
   host in sender_unqualified_hosts? no (matched "!+n2_hosts")
 host in recipient_unqualified_hosts? no (option unset)
@@ -301,9 +304,10 @@ host in sender_unqualified_hosts?
  cached no match for +lookup_hosts
  list element: !+n2_hosts
   start sublist n2_hosts
-  host in "<; V4NET.2.2.2 ; +n1_hosts"?
+   list separator: ';'
+  host in " V4NET.2.2.2 ; +n1_hosts"?
    ╎list element: V4NET.2.2.2
-   ╎host in "<; V4NET.2.2.2 ; +n1_hosts"? yes (matched "V4NET.2.2.2")
+   ╎host in " V4NET.2.2.2 ; +n1_hosts"? yes (matched "V4NET.2.2.2")
   end sublist n2_hosts
   host in sender_unqualified_hosts? no (matched "!+n2_hosts")
 host in recipient_unqualified_hosts? no (option unset)
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
-   CALLER in "<; never2 ; +n1_localparts"?
+   list separator: ';'
+   CALLER in " never2 ; +n1_localparts"?
    ╎list element: never2
    ╎list element: +n1_localparts
    ╎ start sublist n1_localparts
    ╎cached no match for +n1_localparts
    ╎cached lookup data = NULL
-   CALLER in "<; never2 ; +n1_localparts"? no (end of list)
+   CALLER in " never2 ; +n1_localparts"? no (end of list)
   end sublist n2_localparts
  list element: !+local_localparts
   start sublist local_localparts
@@ -209,13 +210,14 @@ CALLER in local_parts?
  cached lookup data = NULL
  list element: +n2_localparts
   start sublist n2_localparts
-   CALLER in "<; never2 ; +n1_localparts"?
+   list separator: ';'
+   CALLER in " never2 ; +n1_localparts"?
    ╎list element: never2
    ╎list element: +n1_localparts
    ╎ start sublist n1_localparts
    ╎cached no match for +n1_localparts
    ╎cached lookup data = NULL
-   CALLER in "<; never2 ; +n1_localparts"? no (end of list)
+   CALLER in " never2 ; +n1_localparts"? no (end of list)
   end sublist n2_localparts
  list element: !+local_localparts
   start sublist local_localparts
@@ -362,13 +364,14 @@ unknown in local_parts?
  cached lookup data = NULL
  list element: +n2_localparts
   start sublist n2_localparts
-   unknown in "<; never2 ; +n1_localparts"?
+   list separator: ';'
+   unknown in " never2 ; +n1_localparts"?
    ╎list element: never2
    ╎list element: +n1_localparts
    ╎ start sublist n1_localparts
    ╎cached no match for +n1_localparts
    ╎cached lookup data = NULL
-   unknown in "<; never2 ; +n1_localparts"? no (end of list)
+   unknown in " never2 ; +n1_localparts"? no (end of list)
   end sublist n2_localparts
  list element: !+local_localparts
   start sublist local_localparts
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
-   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
-   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
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
->>>  host in "<; fe80::1"?
+>>>  host in " fe80::1"?
 >>>   list element: fe80::1
->>>  host in "<; fe80::1"? no (end of list)
+>>>  host in " fe80::1"? no (end of list)
 >>>  deny: condition test failed in ACL a3
 >>>  end of ACL a3: implicit DENY
 LOG: H=(test) [V4NET.0.0.0] F=<> rejected RCPT <a3@b>
 >>>  using ACL "a4"
 >>>  processing ACL a4 "deny" (TESTSUITE/test-config 26)
 >>>  check hosts = <; fe80:1
->>>  host in "<; fe80:1"?
+>>>  host in " fe80:1"?
 >>>   list element: fe80:1
->>>   host in "<; fe80:1"? no (malformed IPv6 address or address mask: fe80:1)
+>>>   host in " fe80:1"? no (malformed IPv6 address or address mask: fe80:1)
 LOG: list matching forced to fail: malformed IPv6 address or address mask: fe80:1
 >>>   deny: condition test failed in ACL a4
 >>>   end of ACL a4: implicit DENY
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
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
 >>>  list element: 2001:ab8:37f:20:0:0:0:1
->>>  host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "2001:ab8:37f:20:0:0:0:1")
+>>>  host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "2001:ab8:37f:20:0:0:0:1")
 >>> warn: condition test succeeded in ACL check_connect
 LOG: H=[2001:ab8:37f:20::1] Warning: matched hostlist
 >>> processing ACL check_connect "accept" (TESTSUITE/test-config 24)
@@ -43,13 +43,13 @@ LOG: H=[2001:ab8:37f:20::1] rejected connection in "connect" ACL
 >>> processing ACL check_connect "warn" (TESTSUITE/test-config 21)
 >>> l_message: matched hostlist
 >>> check hosts = <; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
 >>>  list element: 2001:ab8:37f:20:0:0:0:1
 >>>  list element: v6.test.ex
 MUNGED: ::1 will be omitted in what follows
 >>> get[host|ipnode]byname[2] looked up these IP addresses:
 >>>   name=v6.test.ex address=V6NET:ffff:836f:a00:a:800:200a:c032
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? no (end of list)
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? no (end of list)
 >>> warn: condition test failed in ACL check_connect
 >>> processing ACL check_connect "accept" (TESTSUITE/test-config 24)
 >>> check condition = ${if eq{$sender_host_address}{2001:0ab8:037f:0020:0000:0000:0000:0001}}
@@ -69,13 +69,13 @@ LOG: H=test3.ipv6.test.ex [V6NET:1234:5:6:7:8:abc:d] rejected connection in "con
 >>> processing ACL check_connect "warn" (TESTSUITE/test-config 21)
 >>> l_message: matched hostlist
 >>> check hosts = <; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex
->>> host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
+>>> host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"?
 >>>  list element: 2001:ab8:37f:20:0:0:0:1
 >>>  list element: v6.test.ex
 MUNGED: ::1 will be omitted in what follows
 >>> get[host|ipnode]byname[2] looked up these IP addresses:
 >>>   name=v6.test.ex address=V6NET:ffff:836f:a00:a:800:200a:c032
->>>  host in "<; 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "v6.test.ex")
+>>>  host in " 2001:ab8:37f:20:0:0:0:1 ; v6.test.ex"? yes (matched "v6.test.ex")
 >>> warn: condition test succeeded in ACL check_connect
 LOG: H=[V6NET:ffff:836f:a00:a:800:200a:c032] Warning: matched hostlist
 >>> processing ACL check_connect "accept" (TESTSUITE/test-config 24)
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
->>> mxt11a.test.ex in "<+ @mx_any/ignore=<;127.0.0.1;::1"?
+>>> mxt11a.test.ex in " @mx_any/ignore=<;127.0.0.1;::1"?
 >>>  list element: @mx_any/ignore=<;127.0.0.1;::1
 >>>  check dnssec require list
 >>>  check dnssec request list
->>>  ::1 in "<;127.0.0.1;::1"?
+>>>  ::1 in "127.0.0.1;::1"?
 >>>   list element: 127.0.0.1
 >>>   list element: ::1
->>>   ::1 in "<;127.0.0.1;::1"? yes (matched "::1")
->>>  127.0.0.1 in "<;127.0.0.1;::1"?
+>>>   ::1 in "127.0.0.1;::1"? yes (matched "::1")
+>>>  127.0.0.1 in "127.0.0.1;::1"?
 >>>   list element: 127.0.0.1
->>>   127.0.0.1 in "<;127.0.0.1;::1"? yes (matched "127.0.0.1")
->>>  V4NET.0.0.1 in "<;127.0.0.1;::1"?
+>>>   127.0.0.1 in "127.0.0.1;::1"? yes (matched "127.0.0.1")
+>>>  V4NET.0.0.1 in "127.0.0.1;::1"?
 >>>   list element: 127.0.0.1
 >>>   list element: ::1
->>>  V4NET.0.0.1 in "<;127.0.0.1;::1"? no (end of list)
+>>>  V4NET.0.0.1 in "127.0.0.1;::1"? no (end of list)
 >>>  ten-1.test.ex in hosts_treat_as_local?
 >>>   list element: other1.test.ex
 >>>  ten-1.test.ex in hosts_treat_as_local? no (end of list)
->>> mxt11a.test.ex in "<+ @mx_any/ignore=<;127.0.0.1;::1"? no (end of list)
+>>> mxt11a.test.ex in " @mx_any/ignore=<;127.0.0.1;::1"? no (end of list)
 >>> require: condition test failed in ACL acl_rcpt_6
 >>> end of ACL acl_rcpt_6: not OK
 LOG: H=(test) [V4NET.1.1.1] F=<x@y> rejected RCPT <6@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  processing ACL check_recipient "warn" (TESTSUITE/test-config 45)
+01:01:01 p1235  processing ACL check_recipient "warn" (TESTSUITE/test-config 46)
 01:01:01 p1235  check set acl_m0 = FAIL4: hostlist
 01:01:01 p1235  check hosts = <& net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='${quote_mysql:$local_part}'
-01:01:01 p1235   ╭considering: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235   ├───────text: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
+01:01:01 p1235  list separator: '&'
+01:01:01 p1235   ╭considering: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235   ├───────text: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
 01:01:01 p1235   ├considering: ${quote_mysql:$local_part}'
 01:01:01 p1235    ╭considering: $local_part}'
 01:01:01 p1235    ├──────value: c
@@ -638,10 +639,10 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235              ╰──(tainted, quoted:mysql)
 01:01:01 p1235   ├considering: '
 01:01:01 p1235   ├───────text: '
-01:01:01 p1235   ├───expanded: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235   ╰─────result: <&░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
+01:01:01 p1235   ├───expanded: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235   ╰─────result: ░net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
 01:01:01 p1235              ╰──(tainted, quoted:mysql)
-01:01:01 p1235  host in "<& net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
+01:01:01 p1235  host in " net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
 01:01:01 p1235   list element: net-mysql;servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
 01:01:01 p1235   search_open: mysql "NULL"
 01:01:01 p1235     cached open
@@ -654,18 +655,19 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235                                (tainted, quoted:mysql)
 01:01:01 p1235   MySQL query: "servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'" opts 'NULL'
 01:01:01 p1235  LOG: MAIN
-01:01:01 p1235    Exim configuration error in ACL verb at line 45 of TESTSUITE/test-config:
+01:01:01 p1235    Exim configuration error in ACL verb at line 46 of TESTSUITE/test-config:
 01:01:01 p1235    WARNING: obsolete syntax used for lookup
 01:01:01 p1235   lookup deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235  host in "<& net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
+01:01:01 p1235  host in " net-mysql;servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
 01:01:01 p1235  warn: condition test deferred in ACL check_recipient
 01:01:01 p1235  LOG: MAIN
-01:01:01 p1235    H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 45 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235  processing ACL check_recipient "warn" (TESTSUITE/test-config 50)
+01:01:01 p1235    H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 46 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
+01:01:01 p1235  processing ACL check_recipient "warn" (TESTSUITE/test-config 51)
 01:01:01 p1235  check set acl_m0 = FAIL5: hostlist
 01:01:01 p1235  check hosts = <& net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='${quote_mysql:$local_part}'
-01:01:01 p1235   ╭considering: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235   ├───────text: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
+01:01:01 p1235  list separator: '&'
+01:01:01 p1235   ╭considering: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235   ├───────text: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='
 01:01:01 p1235   ├considering: ${quote_mysql:$local_part}'
 01:01:01 p1235    ╭considering: $local_part}'
 01:01:01 p1235    ├──────value: c
@@ -678,10 +680,10 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235              ╰──(tainted, quoted:mysql)
 01:01:01 p1235   ├considering: '
 01:01:01 p1235   ├───────text: '
-01:01:01 p1235   ├───expanded: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
-01:01:01 p1235   ╰─────result: <&░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
+01:01:01 p1235   ├───expanded: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='${quote_mysql:$local_part}'
+01:01:01 p1235   ╰─────result: ░net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
 01:01:01 p1235              ╰──(tainted, quoted:mysql)
-01:01:01 p1235  host in "<& net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
+01:01:01 p1235  host in " net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"?
 01:01:01 p1235   list element: net-mysql,servers=127.0.0.1::PORT_N/test/root/pass;░select░*░from░them░where░id='c'
 01:01:01 p1235   search_open: mysql "NULL"
 01:01:01 p1235     cached open
@@ -694,11 +696,11 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235                                (tainted, quoted:mysql)
 01:01:01 p1235   MySQL query: " select * from them where id='c'" opts 'servers=127.0.0.1::PORT_N/test/root/pass'
 01:01:01 p1235   lookup deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235  host in "<& net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
+01:01:01 p1235  host in " net-mysql,servers=127.0.0.1::PORT_N/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
 01:01:01 p1235  warn: condition test deferred in ACL check_recipient
 01:01:01 p1235  LOG: MAIN
-01:01:01 p1235    H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 50 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
-01:01:01 p1235  processing ACL check_recipient "accept" (TESTSUITE/test-config 53)
+01:01:01 p1235    H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 51 of TESTSUITE/test-config): condition test deferred: MySQL server "127.0.0.1:PORT_N/test" is tainted
+01:01:01 p1235  processing ACL check_recipient "accept" (TESTSUITE/test-config 54)
 01:01:01 p1235  check domains = +local_domains
 01:01:01 p1235  d in "+local_domains"?
 01:01:01 p1235   list element: +local_domains
@@ -709,7 +711,7 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235    end sublist local_domains
 01:01:01 p1235  d in "+local_domains"? no (end of list)
 01:01:01 p1235  accept: condition test failed in ACL check_recipient
-01:01:01 p1235  processing ACL check_recipient "accept" (TESTSUITE/test-config 56)
+01:01:01 p1235  processing ACL check_recipient "accept" (TESTSUITE/test-config 57)
 01:01:01 p1235  check hosts = +relay_hosts
 01:01:01 p1235  host in "+relay_hosts"?
 01:01:01 p1235   list element: +relay_hosts
@@ -741,7 +743,7 @@ close MYSQL connection: 127.0.0.1:PORT_N/test/root
 01:01:01 p1235    end sublist relay_hosts
 01:01:01 p1235  host in "+relay_hosts"? no (end of list)
 01:01:01 p1235  accept: condition test failed in ACL check_recipient
-01:01:01 p1235  processing ACL check_recipient "deny" (TESTSUITE/test-config 57)
+01:01:01 p1235  processing ACL check_recipient "deny" (TESTSUITE/test-config 58)
 01:01:01 p1235    message: relay not permitted
 01:01:01 p1235  deny: condition test succeeded in ACL check_recipient
 01:01:01 p1235  end of ACL check_recipient: DENY
@@ -797,7 +799,7 @@ P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
        for ph10@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
@@ -874,7 +876,7 @@ processing address_data
                               (tainted)
 No quoter name for addr
 LOG: MAIN PANIC
-  tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
+  tainted search query is not properly quoted (router r1, TESTSUITE/test-config 69): select name from them where id='ph10' limit 1
  required_quoter_id (mysql) quoting -1 (NULL)
  MySQL query: "select name from them where id='ph10' limit 1" opts 'NULL'
  MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
@@ -919,7 +921,7 @@ appendfile transport entered
                               (tainted)
 No quoter name for addr
 LOG: MAIN
-  tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
+  tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 83): select id from them where id='ph10'
  required_quoter_id (mysql) quoting -1 (NULL)
  MySQL query: "select id from them where id='ph10'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=PORT_N socket=NULL database=test user=root
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}'
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
  list element: net-pgsql;servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
  search_open: pgsql "NULL"
    cached open
@@ -439,14 +440,15 @@ LOG: MAIN
   Exim configuration error in ACL verb at line 44 of TESTSUITE/test-config:
   WARNING: obsolete syntax used for lookup
  lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL check_recipient
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 44 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
 processing ACL check_recipient "warn" (TESTSUITE/test-config 49)
 check set acl_m0 = FAIL: hostlist
 check hosts = <& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
  list element: net-pgsql,servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
  search_open: pgsql "NULL"
    cached open
@@ -459,7 +461,7 @@ host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them
                               (tainted, quoted:pgsql)
  PostgreSQL query: " select * from them where id='c'" opts 'servers=localhost::PORT_N/test/CALLER/'
  lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL check_recipient
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 49 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
@@ -614,7 +616,8 @@ warn: condition test failed in ACL check_recipient
 processing ACL check_recipient "warn" (TESTSUITE/test-config 44)
 check set acl_m0 = FAIL: hostlist
 check hosts = <& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
  list element: net-pgsql;servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
  search_open: pgsql "NULL"
    cached open
@@ -630,14 +633,15 @@ LOG: MAIN
   Exim configuration error in ACL verb at line 44 of TESTSUITE/test-config:
   WARNING: obsolete syntax used for lookup
  lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql;servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL check_recipient
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 44 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
 processing ACL check_recipient "warn" (TESTSUITE/test-config 49)
 check set acl_m0 = FAIL: hostlist
 check hosts = <& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
+list separator: '&'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"?
  list element: net-pgsql,servers=localhost::PORT_N/test/CALLER/;░select░*░from░them░where░id='c'
  search_open: pgsql "NULL"
    cached open
@@ -650,7 +654,7 @@ host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them
                               (tainted, quoted:pgsql)
  PostgreSQL query: " select * from them where id='c'" opts 'servers=localhost::PORT_N/test/CALLER/'
  lookup deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
-host in "<& net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
+host in " net-pgsql,servers=localhost::PORT_N/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL check_recipient
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL 'warn' statement skipped (in ACL check_recipient at line 49 of TESTSUITE/test-config): condition test deferred: PostgreSQL server "localhost:PORT_N/test" is tainted
index 0524afd7b87e0c7bc8b6eab21b99bc19569460ad..abeb2329f83a65432ada91fc73d0069cb6581f74 100644 (file)
@@ -1099,5 +1099,6 @@ xyz
 > in list
 > in list
 > 
-> '${listextract {2} {<. my.target.host.name}}'  =>   'target'
+> variable m0 set
+> '${listextract {2} {my:target:string:list}}'  =>   'target'
 >