From: Jeremy Harris Date: Tue, 19 Nov 2024 18:30:03 +0000 (+0000) Subject: Taint: reject or log more tainted list metadata elements X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/982854f86c4acc7779b6b65094ba557a9fcd50d6 Taint: reject or log more tainted list metadata elements --- diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index ae30cb886..c8f765905 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -8635,6 +8635,11 @@ domainlist dom2 = !a.b : *.b where &'x.y'& does not match. It's best to avoid negation altogether in referenced lists if you can. +.new +The list item which references a named list (&"+"&) +may not be tainted. +.wen + .cindex "hiding named list values" .cindex "named lists" "hiding value of" Some named list definitions may contain sensitive data, for example, passwords for @@ -8739,6 +8744,9 @@ possible to use the same configuration file on several different hosts that differ only in their names. The value for a match will be the primary host name. +.new +The pattern may not be tainted. +.wen .next @@ -8754,6 +8762,9 @@ In today's Internet, the use of domain literals is controversial; see the &%allow_domain_literals%& main option. The value for a match will be the string &`@[]`&. +.new +The pattern may not be tainted. +.wen .next @@ -8770,6 +8781,10 @@ local host, and the second only when no primary MX target is the local host, but a secondary MX target is. &"Primary"& means an MX record with the lowest preference value &-- there may of course be more than one of them. +.new +The pattern may not be tainted. +.wen + The MX lookup that takes place when matching a pattern of this type is performed with the resolver options for widening names turned off. Thus, for example, a single-component domain will &'not'& be expanded by adding the @@ -9605,6 +9620,12 @@ lower case. However, although independent matches on the domain alone are still performed caselessly, regular expressions that match against an entire address become case-sensitive after &"+caseful"& has been seen. +.new +This string may not be tainted. +To do caseful matching on list elements whic are tainted, +place them in a named list. +.wen + .section "Local part lists" "SECTlocparlis" @@ -9622,6 +9643,12 @@ matching in the local part list, but not elsewhere in the router. If &%caseful_local_part%& is set true in a router, matching in the &%local_parts%& option is case-sensitive from the start. +.new +This string may not be tainted. +To do caseful matching on list elements whic are tainted, +place them in a named list. +.wen + If a local part list is indirected to a file (see section &<>&), comments are handled in the same way as address lists &-- they are recognized only if the # is preceded by white space or the start of the line. diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index c9f7a4375..37cc3b77d 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -67,7 +67,18 @@ 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 +JH/15 Disallow tainted metadata in lists. + - Change-of-separator prefixes are handled specially when they are + explicit text; only the remainder of the list is expanded. A change-of- + separator resulting from expansion will not take effect if tainted. + - Elements starting with a plus-sign (named-list inclusion, + case-interpretation etc) and (hostlist) @[] (et al) are not handled + specially and are still operative at this time - but warnings are logged; + if any of these are needed in a list with a tainted element (which taints + the entire list at string-expansion time) then a named-list can be used + for that element. + - Exclamation-marks ("!" signifying negation) are not checked for taint + at this time. Exim version 4.98 ----------------- diff --git a/src/src/expand.c b/src/src/expand.c index 052c059e8..3e8f73d89 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -4548,7 +4548,7 @@ for (int fill = 11 - Ustrlen(what); fill > 0; fill--) debug_printf("%V", "-"); debug_printf("%s: %.*W\n", what, nchar, value); -if (is_tainted(value)) +if (nchar > 0 && is_tainted(value)) debug_printf_indent("%V %V(tainted)\n", flags & ESI_SKIPPING ? "|" : " ", "\\__"); } diff --git a/src/src/match.c b/src/src/match.c index 5670388ea..636ccc203 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -36,6 +36,16 @@ typedef struct check_address_block { +static BOOL +is_tainted_metadata(const uschar * s) +{ +/* Not enforcing for now, only logging; will enforce in a future release */ +if (is_tainted(s)) + log_write(0, LOG_MAIN|LOG_PANIC, + "attempt to use tainted list metadata %s", s); +return FALSE; +} + /************************************************* * Generalized string match * *************************************************/ @@ -170,6 +180,9 @@ just fall through - the match will fail. */ if (cb->flags & MCS_AT_SPECIAL && pattern[0] == '@') { + if (is_tainted_metadata(pattern)) + return DEFER; + if (pattern[1] == 0) { pattern = primary_hostname; @@ -572,10 +585,12 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { if (Ustrcmp(ss, "+caseful") == 0) { - check_address_block *cb = (check_address_block *)arg; - uschar *at = Ustrrchr(cb->origaddress, '@'); + check_address_block * cb = (check_address_block *)arg; + uschar * at; + + if (is_tainted_metadata(ss)) goto BAD_TAINT; - if (at) + if ((at = Ustrrchr(cb->origaddress, '@'))) Ustrncpy(cb->address, cb->origaddress, at - cb->origaddress); cb->flags &= ~MCS_CASELESS; continue; @@ -588,7 +603,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { if (Ustrcmp(ss, "+caseful") == 0) { - check_string_block *cb = (check_string_block *)arg; + check_string_block * cb = (check_string_block *)arg; + if (is_tainted_metadata(ss)) goto BAD_TAINT; Ustrcpy(US cb->subject, cb->origsubject); cb->flags &= ~MCS_CASELESS; continue; @@ -601,6 +617,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) else if (type == MCL_HOST && *ss == '+') { + if (is_tainted_metadata(ss)) goto BAD_TAINT; if (Ustrcmp(ss, "+include_unknown") == 0) { include_unknown = TRUE; @@ -628,7 +645,16 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) } /* Starting with ! specifies a negative item. It is theoretically possible - for a local part to start with !. In that case, a regex has to be used. */ + for a local part to start with !. In that case, a regex has to be used. + + XXX It would be good to disallow a tainted ! here, but the sequence + "! $tainted_var" is liable to be frequently used, and requiring a + named-list as a workaround would mean a lot of churn. Unfortunately, + some attacker can feed "!badthing" into a variable that some overworked + admin has used in a list... + Maybe we could intro another meta prefix char, which does not negate the + element match result (but still protects against a ! in $tainted_var) ? + Of course, this would still require churn in configs. */ if (*ss == '!') { @@ -775,6 +801,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) HDEBUG(D_lists) { debug_printf_indent(" start sublist %s\n", ss+1); expand_level += 2; } + if (is_tainted_metadata(ss)) goto BAD_TAINT; if (!(t = tree_search(*anchorptr, ss+1))) { log_write(0, LOG_MAIN|LOG_PANIC, "unknown named%s list \"%s\"", @@ -963,6 +990,7 @@ return yield == OK ? FAIL : OK; /* Something deferred */ +BAD_TAINT: DEFER_RETURN: HDEBUG(D_any) { diff --git a/src/src/string.c b/src/src/string.c index b370cfacc..4c582c65d 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -952,7 +952,7 @@ if (!*s) return NULL; sep_is_special = iscntrl(sep); /* Handle the case when a buffer is provided. */ -/*XXX need to also deal with qouted-requirements mismatch */ +/*XXX need to also deal with quoted-requirements mismatch */ if (buffer) { diff --git a/test/confs/2202 b/test/confs/2202 index 64c638d9a..7a1ddcbc8 100644 --- a/test/confs/2202 +++ b/test/confs/2202 @@ -10,6 +10,10 @@ acl_smtp_vrfy = vrfy acl_smtp_rcpt = rcpt disable_ipv6 +# need to use this sublist due to taint +hostlist goodhosts = *.$sender_address_domain : $sender_address_domain : \ + ${lookup dnsdb{>:defer_never,mxh=$sender_address_domain}} + .ifdef DNS_RECURSE hosts_treat_as_local = test.again.dns domainlist try_again_dns_list = @mx_any @@ -29,9 +33,6 @@ vrfy: .endif rcpt: - accept hosts = +ignore_unknown : \ - *.$sender_address_domain : \ - $sender_address_domain : \ - ${lookup dnsdb{>:defer_never,mxh=$sender_address_domain}} + accept hosts = +ignore_unknown : +goodhosts # End diff --git a/test/stderr/0632 b/test/stderr/0632 index 8855f4e38..339bca7b6 100644 --- a/test/stderr/0632 +++ b/test/stderr/0632 @@ -377,7 +377,6 @@ p1235 ├───expanded: ░($tls_in_ver) p1235 ├─────result: ◀skipped▶ p1235 ╰───skipping: result is not used p1235 ├───item-res: -p1235 ╰──(tainted) p1235 ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ p1235 ␉}}(Exim░$version_number)↩ p1235 ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -414,7 +413,6 @@ p1235 ␉ p1235 ├─────result: ◀skipped▶ p1235 ╰───skipping: result is not used p1235 ├───item-res: -p1235 ╰──(tainted) p1235 ├considering: (Exim░$version_number)↩ p1235 ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ p1235 ␉}}id░$message_exim_id${if░def:received_for░{↩ @@ -854,7 +852,6 @@ p1236 ├───expanded: ░($tls_in_ver) p1236 ├─────result: ◀skipped▶ p1236 ╰───skipping: result is not used p1236 ├───item-res: -p1236 ╰──(tainted) p1236 ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ p1236 ␉}}(Exim░$version_number)↩ p1236 ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -891,7 +888,6 @@ p1236 ␉ p1236 ├─────result: ◀skipped▶ p1236 ╰───skipping: result is not used p1236 ├───item-res: -p1236 ╰──(tainted) p1236 ├considering: (Exim░$version_number)↩ p1236 ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ p1236 ␉}}id░$message_exim_id${if░def:received_for░{↩ diff --git a/test/stderr/2202 b/test/stderr/2202 index 12b9bbf5d..d6e38f3a8 100644 --- a/test/stderr/2202 +++ b/test/stderr/2202 @@ -38,69 +38,73 @@ log directory space = nnnnnK inodes = nnnnn check_space = 10240K inodes = 100 SMTP>> 250 OK SMTP<< rcpt to: using ACL "rcpt" -processing ACL rcpt "accept" (TESTSUITE/test-config 35) -check hosts = +ignore_unknown : *.$sender_address_domain : $sender_address_domain : ${lookup dnsdb{>:defer_never,mxh=$sender_address_domain}} - search_open: dnsdb "NULL" - search_find: file="NULL" - key=">:defer_never,mxh=cioce.test.again.dns" partial=-1 affix=NULL starflags=0 opts=NULL - LRU list: - internal_search_find: file="NULL" - type=dnsdb key=">:defer_never,mxh=cioce.test.again.dns" opts=NULL - database lookup required for >:defer_never,mxh=cioce.test.again.dns - (tainted) - dnsdb key: cioce.test.again.dns - DNS lookup of cioce.test.again.dns (MX) using fakens - DNS lookup of cioce.test.again.dns (MX) gave TRY_AGAIN - cioce.test.again.dns in dns_again_means_nonexist? - list element: * - cioce.test.again.dns in dns_again_means_nonexist? yes (matched "*") - cioce.test.again.dns is in dns_again_means_nonexist: returning DNS_NOMATCH - DNS: couldn't fake dnsa len - DNS: no SOA record found for neg-TTL - writing neg-cache entry for cioce.test.again.dns-MX-xxxx, ttl -1 - creating new cache entry - lookup failed -host in "+ignore_unknown : *.cioce.test.again.dns : cioce.test.again.dns : "? +processing ACL rcpt "accept" (TESTSUITE/test-config 36) +check hosts = +ignore_unknown : +goodhosts +host in "+ignore_unknown : +goodhosts"? list element: +ignore_unknown - list element: *.cioce.test.again.dns - sender host name required, to match against *.cioce.test.again.dns - looking up host name for ip4.ip4.ip4.ip4 - DNS lookup of ip4-reverse.in-addr.arpa (PTR) using fakens - DNS lookup of ip4-reverse.in-addr.arpa (PTR) succeeded - Reverse DNS security status: unverified - IP address lookup yielded "the.local.host.name" - check dnssec require list - ╎the.local.host.name not in empty list (option unset? cannot trace name) - check dnssec request list - ╎the.local.host.name not in empty list (option unset? cannot trace name) - DNS lookup of the.local.host.name (A) using fakens - DNS lookup of the.local.host.name (A) succeeded - local host found for non-MX address - the.local.host.name ip4.ip4.ip4.ip4 mx=-1 sort=xx - checking addresses for the.local.host.name - Forward DNS security status: unverified + list element: +goodhosts + start sublist goodhosts + ╎search_open: dnsdb "NULL" + ╎search_find: file="NULL" + ╎ key=">:defer_never,mxh=cioce.test.again.dns" partial=-1 affix=NULL starflags=0 opts=NULL + ╎LRU list: + ╎internal_search_find: file="NULL" + ╎ type=dnsdb key=">:defer_never,mxh=cioce.test.again.dns" opts=NULL + ╎database lookup required for >:defer_never,mxh=cioce.test.again.dns + ╎ (tainted) + ╎dnsdb key: cioce.test.again.dns + ╎DNS lookup of cioce.test.again.dns (MX) using fakens + ╎DNS lookup of cioce.test.again.dns (MX) gave TRY_AGAIN + ╎cioce.test.again.dns in dns_again_means_nonexist? + ╎ list element: * + ╎ cioce.test.again.dns in dns_again_means_nonexist? yes (matched "*") + ╎cioce.test.again.dns is in dns_again_means_nonexist: returning DNS_NOMATCH + ╎DNS: couldn't fake dnsa len + ╎DNS: no SOA record found for neg-TTL + ╎ writing neg-cache entry for cioce.test.again.dns-MX-xxxx, ttl -1 + ╎creating new cache entry + ╎lookup failed + host in "*.cioce.test.again.dns : cioce.test.again.dns : "? + ╎list element: *.cioce.test.again.dns + ╎sender host name required, to match against *.cioce.test.again.dns + ╎ looking up host name for ip4.ip4.ip4.ip4 + ╎ DNS lookup of ip4-reverse.in-addr.arpa (PTR) using fakens + ╎ DNS lookup of ip4-reverse.in-addr.arpa (PTR) succeeded + ╎ Reverse DNS security status: unverified + ╎ IP address lookup yielded "the.local.host.name" + ╎ check dnssec require list + ╎ the.local.host.name not in empty list (option unset? cannot trace name) + ╎ check dnssec request list + ╎ the.local.host.name not in empty list (option unset? cannot trace name) + ╎ DNS lookup of the.local.host.name (A) using fakens + ╎ DNS lookup of the.local.host.name (A) succeeded + ╎ local host found for non-MX address + ╎ the.local.host.name ip4.ip4.ip4.ip4 mx=-1 sort=-151 + ╎ checking addresses for the.local.host.name + ╎ Forward DNS security status: unverified ip4.ip4.ip4.ip4 OK - sender_fullhost = the.local.host.name (test) [ip4.ip4.ip4.ip4] - sender_rcvhost = the.local.host.name ([ip4.ip4.ip4.ip4] helo=test) - list element: cioce.test.again.dns - using host_fake_gethostbyname for cioce.test.again.dns (IPv4) - DNS lookup of cioce.test.again.dns (A) using fakens - DNS lookup of cioce.test.again.dns (A) gave TRY_AGAIN - cioce.test.again.dns in dns_again_means_nonexist? - list element: * - cioce.test.again.dns in dns_again_means_nonexist? yes (matched "*") - cioce.test.again.dns is in dns_again_means_nonexist: returning DNS_NOMATCH - DNS: couldn't fake dnsa len - DNS: no SOA record found for neg-TTL - writing neg-cache entry for cioce.test.again.dns-A-xxxx, ttl -1 - host_fake_gethostbyname(af=inet) returned 1 (HOST_NOT_FOUND) - no IP address found for host cioce.test.again.dns (during SMTP connection from the.local.host.name (test) [ip4.ip4.ip4.ip4]) + ╎sender_fullhost = the.local.host.name (test) [ip4.ip4.ip4.ip4] + ╎sender_rcvhost = the.local.host.name ([ip4.ip4.ip4.ip4] helo=test) + ╎list element: cioce.test.again.dns + ╎using host_fake_gethostbyname for cioce.test.again.dns (IPv4) + ╎DNS lookup of cioce.test.again.dns (A) using fakens + ╎DNS lookup of cioce.test.again.dns (A) gave TRY_AGAIN + ╎cioce.test.again.dns in dns_again_means_nonexist? + ╎ list element: * + ╎ cioce.test.again.dns in dns_again_means_nonexist? yes (matched "*") + ╎cioce.test.again.dns is in dns_again_means_nonexist: returning DNS_NOMATCH + ╎DNS: couldn't fake dnsa len + ╎DNS: no SOA record found for neg-TTL + ╎ writing neg-cache entry for cioce.test.again.dns-A-xxxx, ttl -1 + ╎host_fake_gethostbyname(af=inet) returned 1 (HOST_NOT_FOUND) + ╎no IP address found for host cioce.test.again.dns (during SMTP connection from the.local.host.name (test) [ip4.ip4.ip4.ip4]) LOG: host_lookup_failed MAIN no IP address found for host cioce.test.again.dns (during SMTP connection from the.local.host.name (test) [ip4.ip4.ip4.ip4]) - failed to find IP address for cioce.test.again.dns: item ignored by +ignore_unknown -host in "+ignore_unknown : *.cioce.test.again.dns : cioce.test.again.dns : "? no (end of list) -accept: condition test failed in ACL rcpt -end of ACL rcpt: implicit DENY + ╎host in "*.cioce.test.again.dns : cioce.test.again.dns : "? no (failed to find IP address for cioce.test.again.dns) + end sublist goodhosts + host in "+ignore_unknown : +goodhosts"? no (end of list) + accept: condition test failed in ACL rcpt + end of ACL rcpt: implicit DENY SMTP>> 550 Administrative prohibition LOG: MAIN REJECT H=the.local.host.name (test) [ip4.ip4.ip4.ip4] F= rejected RCPT @@ -108,7 +112,7 @@ SMTP<< quit SMTP>> 221 myhost.test.ex closing connection LOG: smtp_connection MAIN SMTP connection from the.local.host.name (test) [ip4.ip4.ip4.ip4] D=qqs closed by QUIT -search_tidyup called + search_tidyup called >>>>>>>>>>>>>>>> Exim pid=p1234 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>> Exim version x.yz .... Hints DB: @@ -140,7 +144,7 @@ host in smtp_accept_max_nonmail_hosts? list element: * host in smtp_accept_max_nonmail_hosts? yes (matched "*") using ACL "vrfy" -processing ACL vrfy "warn" (TESTSUITE/test-config 28) +processing ACL vrfy "warn" (TESTSUITE/test-config 32) check domains = +try_again_dns_list test.again.dns in "+try_again_dns_list"? list element: +try_again_dns_list diff --git a/test/stderr/5410 b/test/stderr/5410 index dce73fa67..bd1e5d26f 100644 --- a/test/stderr/5410 +++ b/test/stderr/5410 @@ -531,7 +531,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ ␉}}(Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -568,7 +567,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: (Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ ␉}}id░$message_exim_id${if░def:received_for░{↩ @@ -1158,7 +1156,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ ␉}}(Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -1195,7 +1192,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: (Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ ␉}}id░$message_exim_id${if░def:received_for░{↩ @@ -1785,7 +1781,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ ␉}}(Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -1822,7 +1817,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: (Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ ␉}}id░$message_exim_id${if░def:received_for░{↩ diff --git a/test/stderr/5420 b/test/stderr/5420 index b96d91def..6fad569ad 100644 --- a/test/stderr/5420 +++ b/test/stderr/5420 @@ -31,6 +31,7 @@ try option acl_smtp_helo list element: * in limits_advertise_hosts? yes (matched "*") in dsn_advertise_hosts? no (option unset) +try option acl_smtp_atrn try option acl_smtp_etrn try option acl_smtp_vrfy try option acl_smtp_expn @@ -530,7 +531,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ ␉}}(Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -567,7 +567,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: (Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ ␉}}id░$message_exim_id${if░def:received_for░{↩ @@ -708,6 +707,7 @@ try option acl_smtp_helo list element: * in limits_advertise_hosts? yes (matched "*") in dsn_advertise_hosts? no (option unset) +try option acl_smtp_atrn try option acl_smtp_etrn try option acl_smtp_vrfy try option acl_smtp_expn @@ -1156,7 +1156,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ ␉}}(Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -1193,7 +1192,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: (Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ ␉}}id░$message_exim_id${if░def:received_for░{↩ @@ -1334,6 +1332,7 @@ try option acl_smtp_helo list element: * in limits_advertise_hosts? yes (matched "*") in dsn_advertise_hosts? no (option unset) +try option acl_smtp_atrn try option acl_smtp_etrn try option acl_smtp_vrfy try option acl_smtp_expn @@ -1782,7 +1781,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: ${if░def:tls_in_cipher_std░{░tls░$tls_in_cipher_std↩ ␉}}(Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ @@ -1819,7 +1817,6 @@ try option received_header_text ├─────result: ◀skipped▶ ╰───skipping: result is not used ├───item-res: - ╰──(tainted) ├considering: (Exim░$version_number)↩ ␉${if░def:sender_address░{(envelope-from░<$sender_address>)↩ ␉}}id░$message_exim_id${if░def:received_for░{↩