X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/183389fae10672e8d5ffb1f14f23a179798f483a..6259ba7148cd408d4704850c206dfc2248d2d1cc:/src/src/match.c diff --git a/src/src/match.c b/src/src/match.c index bf8cb3b98..0d2cdb57d 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -3,7 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim Maintainers 2020 */ +/* Copyright (c) The Exim Maintainers 2020 - 2021 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for matching strings */ @@ -128,9 +128,9 @@ required. */ 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; @@ -432,11 +432,9 @@ match_check_list(const uschar **listptr, int sep, tree_node **anchorptr, 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; @@ -445,8 +443,8 @@ 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 @@ -454,7 +452,7 @@ an unnamed list. */ 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; } @@ -487,7 +485,7 @@ else { 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; } @@ -498,8 +496,18 @@ else } /* 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. */ @@ -659,7 +667,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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)); @@ -669,7 +677,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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); } } @@ -681,7 +689,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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"; @@ -695,7 +703,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) *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); } } @@ -704,8 +712,8 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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; } } @@ -718,7 +726,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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; @@ -727,7 +735,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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; } @@ -747,12 +755,12 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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) { @@ -809,19 +817,19 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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)))); @@ -831,8 +839,13 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { 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: @@ -840,7 +853,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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; } @@ -855,12 +868,12 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) 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) @@ -886,7 +899,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) /* 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 */ @@ -992,17 +1005,18 @@ Returns: OK for a match 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 */ @@ -1051,7 +1065,7 @@ if (*s == ';') 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 @@ -1061,7 +1075,6 @@ if (pattern[0] == '@' && pattern[1] == '@') { int watchdog = 50; uschar *list, *ss; - uschar buffer[1024]; if (sdomain == subject + 1 && *subject == '*') return FAIL; @@ -1092,7 +1105,7 @@ if (pattern[0] == '@' && pattern[1] == '@') /* 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; @@ -1174,6 +1187,7 @@ if (pdomain != NULL) expand_nlength[cb->expand_setup] = sllen - cllen; expand_inc = 1; } + value = string_copyn(pattern + 1, cllen); } else { @@ -1182,6 +1196,7 @@ if (pdomain != NULL) ? 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 @@ -1206,16 +1221,23 @@ csb.at_is_special = TRUE; 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; } @@ -1270,8 +1292,8 @@ 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. -Limit the subject address size to avoid mem-exhastion attacks. The size chosen -is historical (we used to use big_buffer her). */ +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)) > BIG_BUFFER_SIZE) len = BIG_BUFFER_SIZE; ab.address = string_copyn(address, len);