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