.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.'&
.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
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
.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:
.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
.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.
.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'&>&*}*&
.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$&.
&*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.
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.
.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.
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
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
-----------------
/* 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,
*/
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; )
{
/* 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);
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. */
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;
}
}
*/
static int
-acl_check_condition(int verb, acl_condition_block *cb, int where,
- address_item *addr, int level, BOOL *epp, uschar **user_msgptr,
- uschar **log_msgptr, int *basic_errno)
+acl_check_condition(int verb, acl_condition_block * cb, int where,
+ address_item * addr, int level, BOOL * epp, uschar ** user_msgptr,
+ uschar ** log_msgptr, int * basic_errno)
{
-uschar * user_message = NULL;
-uschar * log_message = NULL;
+uschar * user_message = NULL, * log_message = NULL;
int rc = OK;
for (; cb; cb = cb->next)
int 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
#endif
case ACLC_DNSLISTS:
- rc = verify_check_dnsbl(where, &arg, log_msgptr);
+ rc = verify_check_dnsbl(where, arg, log_msgptr);
break;
case ACLC_DOMAINS:
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];
{
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
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 */
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)))
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);
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 */
}
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 */
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:
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;
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)))
/* 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)))
{
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"[]");
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);
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++ != '}')
/* 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. */
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;
}
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; /*{{*/
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;
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; /*{{*/
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;
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);
#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 **);
+/* 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 *
*************************************************/
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. */
{
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)
{
ss = Ustrrchr(list, ':');
if (!ss) ss = list; else ss++;
- Uskip_whitespace(&ss);
- if (*ss == '>')
+ if (Uskip_whitespace(&ss) == '>')
{
*ss++ = 0;
Uskip_whitespace(&ss);
* 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
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++;
}
# 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}'
1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 69): select name from them where id='ph10' limit 1
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 83): select id from them where id='ph10'
1999-03-02 09:44:33 10HmaX-000000005vi-0000 => ph10 <ph10@myhost.test.ex> R=r1 T=t1
1999-03-02 09:44:33 10HmaX-000000005vi-0000 Completed
-1999-03-02 09:44:33 10HmaX-000000005vi-0000 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
${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}}'
****
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
in TESTSUITE/aux-fixed/0002.lsearch
creating new cache entry
lookup yielded:
- host in "<
- partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
+ host in " partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch
1.2.3.4"? yes (matched "partial-lsearch;TESTSUITE/aux-fixed/0002.lsearch")
deny: condition test succeeded in ACL connect1
end of ACL connect1: DENY
╎ ::1 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 >>>>>>>>>>>>>>>>
>>> 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
>>> 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
>>> 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
>>> 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
>>> 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
>>> 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
--------> 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
--------> 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
--------> 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
--------> 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
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
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
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
╎list element: +n1_hosts
╎ start sublist n1_hosts
╎ list element: V4NET.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)
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
╎list element: +n1_hosts
╎ start sublist n1_hosts
╎ list element: V4NET.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)
cached no match for +lookup_hosts
list element: !+n2_hosts
start sublist n2_hosts
- host in "<; V4NET.2.2.2 ; +n1_hosts"?
+ list separator: ';'
+ host in " V4NET.2.2.2 ; +n1_hosts"?
╎list element: V4NET.2.2.2
╎list element: +n1_hosts
╎ start sublist n1_hosts
╎ list element: V4NET.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)
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)
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
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
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
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
>>> 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
>>> 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)
>>> 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}}
>>> 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)
>>> 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
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
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
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
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
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
01:01:01 p1235 end sublist local_domains
01:01:01 p1235 d in "+local_domains"? no (end of list)
01:01:01 p1235 accept: condition test failed in ACL check_recipient
-01:01:01 p1235 processing ACL check_recipient "accept" (TESTSUITE/test-config 56)
+01:01:01 p1235 processing ACL check_recipient "accept" (TESTSUITE/test-config 57)
01:01:01 p1235 check hosts = +relay_hosts
01:01:01 p1235 host in "+relay_hosts"?
01:01:01 p1235 list element: +relay_hosts
01:01:01 p1235 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
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
(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
(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
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
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
(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
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
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
(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
> in list
> in list
>
-> '${listextract {2} {<. my.target.host.name}}' => 'target'
+> variable m0 set
+> '${listextract {2} {my:target:string:list}}' => 'target'
>