* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for matching strings */
if (pattern[0] == '^')
{
- const pcre * re = regex_must_compile(pattern, cb->caseless, FALSE);
+ const pcre2_code * re = regex_must_compile(pattern, cb->caseless, FALSE);
if (expand_setup < 0
- ? pcre_exec(re, NULL, CCS s, Ustrlen(s), 0, PCRE_EOPT, NULL, 0) < 0
+ ? !regex_match(re, s, -1, NULL)
: !regex_match_and_setup(re, s, 0, expand_setup)
)
return FAIL;
void *arg, int type, const uschar *name, const uschar **valueptr)
{
int yield = OK;
-unsigned int *original_cache_bits = *cache_ptr;
-BOOL include_unknown = FALSE;
-BOOL ignore_unknown = FALSE;
-BOOL include_defer = FALSE;
-BOOL ignore_defer = FALSE;
+unsigned int * original_cache_bits = *cache_ptr;
+BOOL include_unknown = FALSE, ignore_unknown = FALSE,
+ include_defer = FALSE, ignore_defer = FALSE;
const uschar *list;
uschar *sss;
uschar *ot = NULL;
HDEBUG(D_any)
{
- uschar *listname = readconf_find_option(listptr);
- if (listname[0] != 0) ot = string_sprintf("%s in %s?", name, listname);
+ uschar * listname = readconf_find_option(listptr);
+ if (*listname) ot = string_sprintf("%s in %s?", name, listname);
}
/* If the list is empty, the answer is no. Skip the debugging output for
if (!*listptr)
{
- HDEBUG(D_lists) if (ot) debug_printf("%s no (option unset)\n", ot);
+ HDEBUG(D_lists) if (ot) debug_printf_indent("%s no (option unset)\n", ot);
return FAIL;
}
{
if (f.expand_string_forcedfail)
{
- HDEBUG(D_lists) debug_printf("expansion of \"%s\" forced failure: "
+ HDEBUG(D_lists) debug_printf_indent("expansion of \"%s\" forced failure: "
"assume not in this list\n", *listptr);
return FAIL;
}
}
/* For an unnamed list, use the expanded version in comments */
+#define LIST_LIMIT_PR 2048
-HDEBUG(D_any) if (!ot) ot = string_sprintf("%s in \"%s\"?", name, list);
+HDEBUG(D_any) if (!ot)
+ {
+ int n, m;
+ gstring * g = string_fmt_append(NULL, "%s in \"%n%.*s%n\"",
+ name, &n, LIST_LIMIT_PR, list, &m);
+ if (m - n >= LIST_LIMIT_PR) g = string_catn(g, US"...", 3);
+ g = string_catn(g, US"?", 1);
+ gstring_release_unused(g);
+ ot = string_from_gstring(g);
+ }
/* Now scan the list and process each item in turn, until one of them matches,
or we hit an error. */
so we use the permanent store pool */
store_pool = POOL_PERM;
- p = store_get(sizeof(namedlist_cacheblock), FALSE);
+ p = store_get(sizeof(namedlist_cacheblock), GET_UNTAINTED);
p->key = string_copy(get_check_key(arg, type));
p->next = nb->cache_data;
nb->cache_data = p;
if (*valueptr)
- DEBUG(D_lists) debug_printf("data from lookup saved for "
+ DEBUG(D_lists) debug_printf_indent("data from lookup saved for "
"cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr);
}
}
else
{
- DEBUG(D_lists) debug_printf("cached %s match for %s\n",
+ DEBUG(D_lists) debug_printf_indent("cached %s match for %s\n",
(bits & (-bits)) == bits ? "yes" : "no", ss);
cached = US" - cached";
*valueptr = p->data;
break;
}
- DEBUG(D_lists) debug_printf("cached lookup data = %s\n", *valueptr);
+ DEBUG(D_lists) debug_printf_indent("cached lookup data = %s\n", *valueptr);
}
}
if ((bits & (-bits)) == bits) /* Only one of the two bits is set */
{
- HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\"%s)\n", ot,
- (yield == OK)? "yes" : "no", sss, cached);
+ HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\"%s)\n", ot,
+ yield == OK ? "yes" : "no", sss, cached);
return yield;
}
}
switch ((func)(arg, ss, valueptr, &error))
{
case OK:
- HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\")\n", ot,
+ HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\")\n", ot,
(yield == OK)? "yes" : "no", sss);
return yield;
error = string_sprintf("DNS lookup of \"%s\" deferred", ss);
if (ignore_defer)
{
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
+ HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_defer\n",
error);
break;
}
case ERROR:
if (ignore_unknown)
{
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
+ HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n",
error);
}
else
{
- HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
+ HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot,
include_unknown? "yes":"no", error);
if (!include_unknown)
{
sss = ss + 1;
}
- ss = filebuffer + Ustrlen(filebuffer); /* trailing space */
+ ss = filebuffer + Ustrlen(filebuffer); /* trailing space */
while (ss > filebuffer && isspace(ss[-1])) ss--;
*ss = 0;
ss = filebuffer;
- while (isspace(*ss)) ss++; /* leading space */
+ while (isspace(*ss)) ss++; /* leading space */
- if (*ss == 0) continue; /* ignore empty */
+ if (!*ss) continue; /* ignore empty */
- file_yield = yield; /* positive yield */
- sss = ss; /* for debugging */
+ file_yield = yield; /* positive yield */
+ sss = ss; /* for debugging */
- if (*ss == '!') /* negation */
+ if (*ss == '!') /* negation */
{
file_yield = (file_yield == OK)? FAIL : OK;
while (isspace((*(++ss))));
{
case OK:
(void)fclose(f);
- HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot,
+ HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\" in %s)\n", ot,
yield == OK ? "yes" : "no", sss, filename);
+
+ /* The "pattern" being matched came from the file; we use a stack-local.
+ Copy it to allocated memory now we know it matched. */
+
+ if (valueptr) *valueptr = string_copy(ss);
return file_yield;
case DEFER:
error = string_sprintf("DNS lookup of %s deferred", ss);
if (ignore_defer)
{
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
+ HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_defer\n",
error);
break;
}
case ERROR: /* host name lookup failed - this can only */
if (ignore_unknown) /* be for an incoming host (not outgoing) */
{
- HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
+ HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n",
error);
}
else
{
- HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
+ HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot,
include_unknown? "yes":"no", error);
(void)fclose(f);
if (!include_unknown)
/* End of list reached: if the last item was negated yield OK, else FAIL. */
HDEBUG(D_lists)
- debug_printf("%s %s (end of list)\n", ot, yield == OK ? "no":"yes");
+ debug_printf_indent("%s %s (end of list)\n", ot, yield == OK ? "no":"yes");
return yield == OK ? FAIL : OK;
/* Something deferred */
static int
check_address(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error)
{
-check_address_block *cb = (check_address_block *)arg;
+check_address_block * cb = (check_address_block *)arg;
check_string_block csb;
int rc;
int expand_inc = 0;
-unsigned int *null = NULL;
-const uschar *listptr;
-uschar *subject = cb->address;
-const uschar *s;
-uschar *pdomain, *sdomain;
-
-DEBUG(D_lists) debug_printf("address match test: subject=%s pattern=%s\n",
+unsigned int * null = NULL;
+const uschar * listptr;
+uschar * subject = cb->address;
+const uschar * s;
+uschar * pdomain, * sdomain;
+uschar * value = NULL;
+
+DEBUG(D_lists) debug_printf_indent("address match test: subject=%s pattern=%s\n",
subject, pattern);
/* Find the subject's domain */
because other patterns expect to have a local part and a domain to match
against. */
-if (*subject == 0) return (*pattern == 0)? OK : FAIL;
+if (!*subject) return *pattern ? FAIL : OK;
/* If the pattern starts with "@@" we have a split lookup, where the domain is
looked up to obtain a list of local parts. If the subject's local part is just
{
int watchdog = 50;
uschar *list, *ss;
- uschar buffer[1024];
if (sdomain == subject + 1 && *subject == '*') return FAIL;
/* Look up the local parts provided by the list; negation is permitted.
If a local part has to begin with !, a regex can be used. */
- while ((ss = string_nextinlist(CUSS &list, &sep, buffer, sizeof(buffer))))
+ while ((ss = string_nextinlist(CUSS &list, &sep, NULL, 0)))
{
int local_yield;
expand_nlength[cb->expand_setup] = sllen - cllen;
expand_inc = 1;
}
+ value = string_copyn(pattern + 1, cllen);
}
else
{
? strncmpic(subject, pattern, sllen) != 0
: Ustrncmp(subject, pattern, sllen) != 0) return FAIL;
}
+ value = string_copyn(pattern, sllen);
}
/* If the local part matched, or was not being checked, check the domain using
listptr = pdomain ? pdomain + 1 : pattern;
if (valueptr) *valueptr = NULL;
-return match_check_list(
- &listptr, /* list of one item */
- UCHAR_MAX+1, /* impossible separator; single item */
- &domainlist_anchor, /* it's a domain list */
- &null, /* ptr to NULL means no caching */
- check_string, /* the function to do one test */
- &csb, /* its data */
- MCL_DOMAIN + MCL_NOEXPAND, /* domain list; don't expand */
- csb.subject, /* string for messages */
- valueptr); /* where to pass back lookup data */
+ {
+ const uschar * dvalue = NULL;
+ rc = match_check_list(
+ &listptr, /* list of one item */
+ UCHAR_MAX+1, /* impossible separator; single item */
+ &domainlist_anchor, /* it's a domain list */
+ &null, /* ptr to NULL means no caching */
+ check_string, /* the function to do one test */
+ &csb, /* its data */
+ MCL_DOMAIN + MCL_NOEXPAND, /* domain list; don't expand */
+ csb.subject, /* string for messages */
+ &dvalue); /* where to pass back lookup data */
+ if (valueptr && (value || dvalue))
+ *valueptr = string_sprintf("%s@%s",
+ value ? value : US"", dvalue ? dvalue : US"");
+ }
+return rc;
}
provided that "caseless" is set. (It is FALSE for calls for matching rewriting
patterns.) Otherwise just the domain is lower cases. A magic item "+caseful" in
the list can be used to restore a caseful copy of the local part from the
-original address. */
+original address.
+Limit the subject address size to avoid mem-exhaustion attacks. The size chosen
+is historical (we used to use big_buffer here). */
-if ((len = Ustrlen(address)) > 255) len = 255;
+if ((len = Ustrlen(address)) > BIG_BUFFER_SIZE) len = BIG_BUFFER_SIZE;
ab.address = string_copyn(address, len);
for (uschar * p = ab.address + len - 1; p >= ab.address; p--)