X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fmatch.c;h=db02b37bd519c3c050e8aa413681361b00a0dc9f;hp=01b52ed0e0c77bb49e2d179a5166a34095a55078;hb=a368cc11b211657f86f2495002823bc09b71a9f1;hpb=184e88237dea64ce48076cdd0184612d057cbafd diff --git a/src/src/match.c b/src/src/match.c index 01b52ed0e..db02b37bd 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -1,10 +1,9 @@ -/* $Cambridge: exim/src/src/match.c,v 1.17 2007/01/08 10:50:18 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* 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 */ @@ -17,8 +16,8 @@ strings, domains, and local parts. */ typedef struct check_string_block { - uschar *origsubject; /* caseful; keep these two first, in */ - uschar *subject; /* step with the block below */ + const uschar *origsubject; /* caseful; keep these two first, in */ + const uschar *subject; /* step with the block below */ int expand_setup; BOOL use_partial; BOOL caseless; @@ -30,7 +29,7 @@ typedef struct check_string_block { addresses. */ typedef struct check_address_block { - uschar *origaddress; /* caseful; keep these two first, in */ + const uschar *origaddress; /* caseful; keep these two first, in */ uschar *address; /* step with the block above */ int expand_setup; BOOL caseless; @@ -94,12 +93,12 @@ Returns: OK if matched */ static int -check_string(void *arg, uschar *pattern, uschar **valueptr, uschar **error) +check_string(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error) { -check_string_block *cb = (check_string_block *)arg; +const check_string_block *cb = arg; int search_type, partial, affixlen, starflags; int expand_setup = cb->expand_setup; -uschar *affix; +const uschar * affix, * opts; uschar *s; uschar *filename = NULL; uschar *keyquery, *result, *semicolon; @@ -113,7 +112,7 @@ if (valueptr != NULL) *valueptr = NULL; /* For non-lookup matches */ it works if the pattern uses (?-i) to turn off case-independence, overriding "caseless". */ -s = (pattern[0] == '^')? cb->origsubject : cb->subject; +s = string_copy(pattern[0] == '^' ? cb->origsubject : cb->subject); /* If required to set up $0, initialize the data but don't turn on by setting expand_nmax until the match is assured. */ @@ -121,7 +120,7 @@ expand_nmax until the match is assured. */ expand_nmax = -1; if (expand_setup == 0) { - expand_nstring[0] = s; + expand_nstring[0] = s; /* $0 (might be) the matched subject in full */ expand_nlength[0] = Ustrlen(s); } else if (expand_setup > 0) expand_setup--; @@ -131,35 +130,38 @@ required. */ if (pattern[0] == '^') { - const pcre *re = regex_must_compile(pattern, cb->caseless, FALSE); - return ((expand_setup < 0)? - pcre_exec(re, NULL, CS s, Ustrlen(s), 0, PCRE_EOPT, NULL, 0) >= 0 - : - regex_match_and_setup(re, s, 0, expand_setup) - )? - OK : FAIL; + const pcre * 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_and_setup(re, s, 0, expand_setup) + ) + return FAIL; + /* assume the above wrote $0, $n... TODO: CHECK THAT !! */ + if (valueptr) *valueptr = pattern; /* "value" gets the RE */ + return OK; } /* Tail match */ if (pattern[0] == '*') { - BOOL yield; int slen = Ustrlen(s); int patlen; /* Sun compiler doesn't like non-constant initializer */ patlen = Ustrlen(++pattern); if (patlen > slen) return FAIL; - yield = cb->caseless? - (strncmpic(s + slen - patlen, pattern, patlen) == 0) : - (Ustrncmp(s + slen - patlen, pattern, patlen) == 0); - if (yield && expand_setup >= 0) + if (cb->caseless + ? strncmpic(s + slen - patlen, pattern, patlen) != 0 + : Ustrncmp(s + slen - patlen, pattern, patlen) != 0) + return FAIL; + if (expand_setup >= 0) { - expand_nstring[++expand_setup] = s; + expand_nstring[++expand_setup] = s; /* write a $n, the matched subject variable-part */ expand_nlength[expand_setup] = slen - patlen; expand_nmax = expand_setup; } - return yield? OK : FAIL; + if (valueptr) *valueptr = pattern; /* "value" gets the pattern */ + return OK; } /* Match a special item starting with @ if so enabled. On its own, "@" matches @@ -177,13 +179,16 @@ if (cb->at_is_special && pattern[0] == '@') if (Ustrcmp(pattern, "@[]") == 0) { - ip_address_item *ip; int slen = Ustrlen(s); - if (s[0] != '[' && s[slen-1] != ']') return FAIL; - for (ip = host_find_interfaces(); ip != NULL; ip = ip->next) + if (s[0] != '[' && s[slen-1] != ']') return FAIL; /*XXX should this be || ? */ + for (ip_address_item * ip = host_find_interfaces(); ip; ip = ip->next) if (Ustrncmp(ip->address, s+1, slen - 2) == 0 && ip->address[slen - 2] == 0) + { +/* I see no reason not to return $0, the matchd IP. if (expand_setup >= 0) expand_nmax = expand_setup; */ + if (valueptr) *valueptr = pattern; /* "value" gets the pattern */ return OK; + } return FAIL; } @@ -194,8 +199,8 @@ if (cb->at_is_special && pattern[0] == '@') BOOL prim = FALSE; BOOL secy = FALSE; BOOL removed = FALSE; - uschar *ss = pattern + 4; - uschar *ignore_target_hosts = NULL; + const uschar *ss = pattern + 4; + const uschar *ignore_target_hosts = NULL; if (strncmpic(ss, US"any", 3) == 0) ss += 3; else if (strncmpic(ss, US"primary", 7) == 0) @@ -211,7 +216,7 @@ if (cb->at_is_special && pattern[0] == '@') else goto NOT_AT_SPECIAL; if (strncmpic(ss, US"/ignore=", 8) == 0) ignore_target_hosts = ss + 8; - else if (*ss != 0) goto NOT_AT_SPECIAL; + else if (*ss) goto NOT_AT_SPECIAL; h.next = NULL; h.name = s; @@ -223,6 +228,7 @@ if (cb->at_is_special && pattern[0] == '@') NULL, /* service name not relevant */ NULL, /* srv_fail_domains not relevant */ NULL, /* mx_fail_domains not relevant */ + NULL, /* no dnssec request/require XXX ? */ NULL, /* no feedback FQDN */ &removed); /* feedback if local removed */ @@ -232,9 +238,12 @@ if (cb->at_is_special && pattern[0] == '@') return DEFER; } - if (rc == HOST_FOUND_LOCAL && !secy) return OK; - if (prim) return FAIL; - return removed? OK : FAIL; + if (rc != HOST_FOUND_LOCAL || secy) + if (prim || !removed) return FAIL; + +/* again, $0 getting the subject, the matched IP. if (expand_setup >= 0) expand_nmax = expand_setup; */ + if (valueptr) *valueptr = pattern; /* "vaulue" gets the patterm */ + return OK; /*** The above line used to be the following line, but this is incorrect, because host_find_bydns() may return HOST_NOT_FOUND if it removed some MX @@ -254,10 +263,15 @@ NOT_AT_SPECIAL: if ((semicolon = Ustrchr(pattern, ';')) == NULL) { - BOOL yield = cb->caseless? - (strcmpic(s, pattern) == 0) : (Ustrcmp(s, pattern) == 0); - if (yield && expand_setup >= 0) expand_nmax = expand_setup; - return yield? OK : FAIL; + if (cb->caseless ? strcmpic(s, pattern) != 0 : Ustrcmp(s, pattern) != 0) + return FAIL; + if (expand_setup >= 0) expand_nmax = expand_setup; /* Original code! $0 gets the matched subject */ + if (valueptr) *valueptr = pattern; /* "value" gets the pattern */ + return OK; + +/* +XXX looks like $0 may be usable +*/ } /* Otherwise we have a lookup item. The lookup type, including partial, etc. is @@ -265,7 +279,7 @@ the part of the string preceding the semicolon. */ *semicolon = 0; search_type = search_findtype_partial(pattern, &partial, &affix, &affixlen, - &starflags); + &starflags, &opts); *semicolon = ';'; if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message); @@ -278,14 +292,14 @@ if (!cb->use_partial) partial = -1; /* Set the parameters for the three different kinds of lookup. */ keyquery = semicolon + 1; -while (isspace(*keyquery)) keyquery++; +Uskip_whitespace(&keyquery); if (mac_islookup(search_type, lookup_absfilequery)) { filename = keyquery; - while (*keyquery != 0 && !isspace(*keyquery)) keyquery++; + while (*keyquery && !isspace(*keyquery)) keyquery++; filename = string_copyn(filename, keyquery - filename); - while (isspace(*keyquery)) keyquery++; + Uskip_whitespace(&keyquery); } else if (!mac_islookup(search_type, lookup_querystyle)) @@ -298,14 +312,13 @@ else if (!mac_islookup(search_type, lookup_querystyle)) for; partial matching is all handled inside search_find(). Note that there is no search_close() because of the caching arrangements. */ -handle = search_open(filename, search_type, 0, NULL, NULL); -if (handle == NULL) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", - search_error_message); +if (!(handle = search_open(filename, search_type, 0, NULL, NULL))) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message); result = search_find(handle, filename, keyquery, partial, affix, affixlen, - starflags, &expand_setup); + starflags, &expand_setup, opts); -if (result == NULL) return search_find_defer? DEFER : FAIL; -if (valueptr != NULL) *valueptr = result; +if (!result) return f.search_find_defer ? DEFER : FAIL; +if (valueptr) *valueptr = result; expand_nmax = expand_setup; return OK; @@ -337,8 +350,8 @@ Returns: OK if matched */ int -match_check_string(uschar *s, uschar *pattern, int expand_setup, - BOOL use_partial, BOOL caseless, BOOL at_is_special, uschar **valueptr) +match_check_string(const uschar *s, const uschar *pattern, int expand_setup, + BOOL use_partial, BOOL caseless, BOOL at_is_special, const uschar **valueptr) { check_string_block cb; cb.origsubject = s; @@ -366,7 +379,7 @@ Arguments: type MCL_STRING, MCL_DOMAIN, MCL_HOST, MCL_ADDRESS, or MCL_LOCALPART */ -static uschar * +static const uschar * get_check_key(void *arg, int type) { switch(type) @@ -374,13 +387,13 @@ switch(type) case MCL_STRING: case MCL_DOMAIN: case MCL_LOCALPART: - return ((check_string_block *)arg)->subject; + return ((check_string_block *)arg)->subject; case MCL_HOST: - return ((check_host_block *)arg)->host_address; + return ((check_host_block *)arg)->host_address; case MCL_ADDRESS: - return ((check_address_block *)arg)->address; + return ((check_address_block *)arg)->address; } return US""; /* In practice, should never happen */ } @@ -436,18 +449,19 @@ Returns: OK if matched a non-negated item */ int -match_check_list(uschar **listptr, int sep, tree_node **anchorptr, - unsigned int **cache_ptr, int (*func)(void *,uschar *,uschar **,uschar **), - void *arg, int type, uschar *name, uschar **valueptr) +match_check_list(const uschar **listptr, int sep, tree_node **anchorptr, + unsigned int **cache_ptr, int (*func)(void *,const uschar *,const uschar **,uschar **), + 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; -uschar *list; +BOOL include_defer = FALSE; +BOOL ignore_defer = FALSE; +const uschar *list; uschar *sss; uschar *ot = NULL; -uschar buffer[1024]; /* Save time by not scanning for the option name when we don't need it. */ @@ -460,12 +474,9 @@ HDEBUG(D_any) /* If the list is empty, the answer is no. Skip the debugging output for an unnamed list. */ -if (*listptr == NULL) +if (!*listptr) { - HDEBUG(D_lists) - { - if (ot != NULL) debug_printf("%s no (option unset)\n", ot); - } + HDEBUG(D_lists) if (ot) debug_printf("%s no (option unset)\n", ot); return FAIL; } @@ -484,19 +495,19 @@ else /* 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. */ - if (type == MCL_DOMAIN && deliver_domain == NULL) + if (type == MCL_DOMAIN && !deliver_domain) { check_string_block *cb = (check_string_block *)arg; - deliver_domain = cb->subject; - list = expand_string(*listptr); + deliver_domain = string_copy(cb->subject); + list = expand_cstring(*listptr); deliver_domain = NULL; } + else + list = expand_cstring(*listptr); - else list = expand_string(*listptr); - - if (list == NULL) + if (!list) { - if (expand_string_forcedfail) + if (f.expand_string_forcedfail) { HDEBUG(D_lists) debug_printf("expansion of \"%s\" forced failure: " "assume not in this list\n", *listptr); @@ -510,17 +521,14 @@ else /* For an unnamed list, use the expanded version in comments */ -HDEBUG(D_any) - { - if (ot == NULL) ot = string_sprintf("%s in \"%s\"?", name, list); - } +HDEBUG(D_any) if (!ot) ot = string_sprintf("%s in \"%s\"?", name, list); /* Now scan the list and process each item in turn, until one of them matches, or we hit an error. */ -while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) +while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { - uschar *ss = sss; + uschar * ss = sss; /* Address lists may contain +caseful, to restore caseful matching of the local part. We have to know the layout of the control block, unfortunately. @@ -533,7 +541,8 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) { check_address_block *cb = (check_address_block *)arg; uschar *at = Ustrrchr(cb->origaddress, '@'); - if (at != NULL) + + if (at) Ustrncpy(cb->address, cb->origaddress, at - cb->origaddress); cb->caseless = FALSE; continue; @@ -547,16 +556,17 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) if (Ustrcmp(ss, "+caseful") == 0) { check_string_block *cb = (check_string_block *)arg; - Ustrcpy(cb->subject, cb->origsubject); + Ustrcpy(US cb->subject, cb->origsubject); cb->caseless = FALSE; continue; } } - /* If the host item is "+include_unknown", remember it in case there's a - subsequent failed reverse lookup. */ + /* If the host item is "+include_unknown" or "+ignore_unknown", remember it + in case there's a subsequent failed reverse lookup. There is similar + processing for "defer". */ - else if (type == MCL_HOST) + else if (type == MCL_HOST && *ss == '+') { if (Ustrcmp(ss, "+include_unknown") == 0) { @@ -570,6 +580,18 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) include_unknown = FALSE; continue; } + if (Ustrcmp(ss, "+include_defer") == 0) + { + include_defer = TRUE; + ignore_defer = FALSE; + continue; + } + if (Ustrcmp(ss, "+ignore_defer") == 0) + { + ignore_defer = TRUE; + include_defer = FALSE; + continue; + } } /* Starting with ! specifies a negative item. It is theoretically possible @@ -580,7 +602,8 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) yield = FAIL; while (isspace((*(++ss)))); } - else yield = OK; + else + yield = OK; /* If the item does not begin with '/', it might be a + item for a named list. Otherwise, it is just a single list entry that has to be matched. @@ -588,7 +611,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) if (*ss != '/') { - if (*ss == '+' && anchorptr != NULL) + if (*ss == '+' && anchorptr) { int bits = 0; int offset = 0; @@ -596,15 +619,18 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) unsigned int *use_cache_bits = original_cache_bits; uschar *cached = US""; namedlist_block *nb; - tree_node *t = tree_search(*anchorptr, ss+1); - - if (t == NULL) - log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unknown named%s list \"%s\"", - (type == MCL_DOMAIN)? " domain" : - (type == MCL_HOST)? " host" : - (type == MCL_ADDRESS)? " address" : - (type == MCL_LOCALPART)? " local part" : "", + tree_node * t; + + if (!(t = tree_search(*anchorptr, ss+1))) + { + log_write(0, LOG_MAIN|LOG_PANIC, "unknown named%s list \"%s\"", + type == MCL_DOMAIN ? " domain" : + type == MCL_HOST ? " host" : + type == MCL_ADDRESS ? " address" : + type == MCL_LOCALPART ? " local part" : "", ss); + return DEFER; + } nb = t->data.ptr; /* If the list number is negative, it means that this list is not @@ -616,7 +642,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) because the pointer may be NULL from the start if caching is not required. */ - if (use_cache_bits != NULL) + if (use_cache_bits) { offset = (nb->number)/16; shift = ((nb->number)%16)*2; @@ -640,15 +666,13 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) wasn't before. Ensure that this is passed up to the next level. Otherwise, remember the result of the search in the cache. */ - if (use_cache_bits == NULL) - { + if (!use_cache_bits) *cache_ptr = NULL; - } else { use_cache_bits[offset] |= bits << shift; - if (valueptr != NULL) + if (valueptr) { int old_pool = store_pool; namedlist_cacheblock *p; @@ -657,20 +681,18 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) so we use the permanent store pool */ store_pool = POOL_PERM; - p = store_get(sizeof(namedlist_cacheblock)); + p = store_get(sizeof(namedlist_cacheblock), FALSE); p->key = string_copy(get_check_key(arg, type)); - p->data = (*valueptr == NULL)? NULL : string_copy(*valueptr); + p->data = *valueptr ? string_copy(*valueptr) : NULL; store_pool = old_pool; p->next = nb->cache_data; nb->cache_data = p; - if (*valueptr != NULL) - { + if (*valueptr) DEBUG(D_lists) debug_printf("data from lookup saved for " - "cache for %s: %s\n", ss, *valueptr); - } + "cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr); } } } @@ -682,20 +704,19 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) else { DEBUG(D_lists) debug_printf("cached %s match for %s\n", - ((bits & (-bits)) == bits)? "yes" : "no", ss); + (bits & (-bits)) == bits ? "yes" : "no", ss); + cached = US" - cached"; - if (valueptr != NULL) + if (valueptr) { - uschar *key = get_check_key(arg, type); - namedlist_cacheblock *p; - for (p = nb->cache_data; p != NULL; p = p->next) - { + const uschar *key = get_check_key(arg, type); + + for (namedlist_cacheblock * p = nb->cache_data; p; p = p->next) if (Ustrcmp(key, p->key) == 0) { *valueptr = p->data; break; } - } DEBUG(D_lists) debug_printf("cached lookup data = %s\n", *valueptr); } } @@ -715,16 +736,30 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) else { - uschar *error; + uschar * error = NULL; switch ((func)(arg, ss, valueptr, &error)) { case OK: - HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\")\n", ot, - (yield == OK)? "yes" : "no", sss); - return yield; + HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\")\n", ot, + (yield == OK)? "yes" : "no", sss); + return yield; case DEFER: - goto DEFER_RETURN; + if (!error) + error = string_sprintf("DNS lookup of \"%s\" deferred", ss); + if (ignore_defer) + { + HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n", + error); + break; + } + if (include_defer) + { + log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error); + return OK; + } + if (!search_error_message) search_error_message = error; + goto DEFER_RETURN; /* The ERROR return occurs when checking hosts, when either a forward or reverse lookup has failed. It can also occur in a match_ip list if a @@ -732,24 +767,24 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) which it was. */ case ERROR: - if (ignore_unknown) - { - HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n", - error); - } - else - { - HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot, - include_unknown? "yes":"no", error); - if (!include_unknown) - { - if ((log_extra_selector & LX_unknown_in_list) != 0) - log_write(0, LOG_MAIN, "list matching forced to fail: %s", error); - return FAIL; - } - log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error); - return OK; - } + if (ignore_unknown) + { + HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n", + error); + } + else + { + HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot, + include_unknown? "yes":"no", error); + if (!include_unknown) + { + if (LOGGING(unknown_in_list)) + log_write(0, LOG_MAIN, "list matching forced to fail: %s", error); + return FAIL; + } + log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error); + return OK; + } } } } @@ -760,16 +795,16 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) else { int file_yield = yield; /* In case empty file */ - uschar *filename = ss; - FILE *f = Ufopen(filename, "rb"); + uschar * filename = ss; + FILE * f = Ufopen(filename, "rb"); uschar filebuffer[1024]; /* ot will be null in non-debugging cases, and anyway, we get better wording by reworking it. */ - if (f == NULL) + if (!f) { - uschar *listname = readconf_find_option(listptr); + uschar * listname = readconf_find_option(listptr); if (listname[0] == 0) listname = string_sprintf("\"%s\"", *listptr); log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", @@ -817,35 +852,48 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) switch ((func)(arg, ss, valueptr, &error)) { case OK: - (void)fclose(f); - HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot, - (yield == OK)? "yes" : "no", sss, filename); - return file_yield; + (void)fclose(f); + HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot, + yield == OK ? "yes" : "no", sss, filename); + return file_yield; case DEFER: - (void)fclose(f); - goto DEFER_RETURN; - - 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", - error); - } - else - { - HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot, - include_unknown? "yes":"no", error); - (void)fclose(f); - if (!include_unknown) - { - if ((log_extra_selector & LX_unknown_in_list) != 0) - log_write(0, LOG_MAIN, "list matching forced to fail: %s", error); - return FAIL; - } - log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error); - return OK; - } + if (!error) + error = string_sprintf("DNS lookup of %s deferred", ss); + if (ignore_defer) + { + HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n", + error); + break; + } + (void)fclose(f); + if (include_defer) + { + log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error); + return OK; + } + goto DEFER_RETURN; + + 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", + error); + } + else + { + HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot, + include_unknown? "yes":"no", error); + (void)fclose(f); + if (!include_unknown) + { + if (LOGGING(unknown_in_list)) + log_write(0, LOG_MAIN, "list matching forced to fail: %s", error); + return FAIL; + } + log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error); + return OK; + } } } @@ -860,8 +908,8 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) /* 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"); -return (yield == OK)? FAIL : OK; + debug_printf("%s %s (end of list)\n", ot, yield == OK ? "no":"yes"); +return yield == OK ? FAIL : OK; /* Something deferred */ @@ -911,8 +959,9 @@ Returns: OK if matched a non-negated item */ int -match_isinlist(uschar *s, uschar **listptr, int sep, tree_node **anchorptr, - unsigned int *cache_bits, int type, BOOL caseless, uschar **valueptr) +match_isinlist(const uschar *s, const uschar **listptr, int sep, + tree_node **anchorptr, + unsigned int *cache_bits, int type, BOOL caseless, const uschar **valueptr) { unsigned int *local_cache_bits = cache_bits; check_string_block cb; @@ -958,20 +1007,21 @@ Returns: OK for a match */ static int -check_address(void *arg, uschar *pattern, uschar **valueptr, uschar **error) +check_address(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error) { check_address_block *cb = (check_address_block *)arg; check_string_block csb; int rc; int expand_inc = 0; unsigned int *null = NULL; -uschar *listptr; +const uschar *listptr; uschar *subject = cb->address; -uschar *s, *pdomain, *sdomain; +const uschar *s; +uschar *pdomain, *sdomain; error = error; /* Keep clever compilers from complaining */ -DEBUG(D_lists) debug_printf("address match: subject=%s pattern=%s\n", +DEBUG(D_lists) debug_printf("address match test: subject=%s pattern=%s\n", subject, pattern); /* Find the subject's domain */ @@ -1029,7 +1079,7 @@ looked up to obtain a list of local parts. If the subject's local part is just if (pattern[0] == '@' && pattern[1] == '@') { int watchdog = 50; - uschar *list, *key, *ss; + uschar *list, *ss; uschar buffer[1024]; if (sdomain == subject + 1 && *subject == '*') return FAIL; @@ -1037,12 +1087,12 @@ if (pattern[0] == '@' && pattern[1] == '@') /* Loop for handling chains. The last item in any list may be of the form ">name" in order to chain on to another list. */ - for (key = sdomain + 1; key != NULL && watchdog-- > 0; ) + for (const uschar * key = sdomain + 1; key && watchdog-- > 0; ) { int sep = 0; if ((rc = match_check_string(key, pattern + 2, -1, TRUE, FALSE, FALSE, - &list)) != OK) return rc; + CUSS &list)) != OK) return rc; /* Check for chaining from the last item; set up the next key if one is found. */ @@ -1061,8 +1111,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(&list, &sep, buffer, sizeof(buffer))) - != NULL) + while ((ss = string_nextinlist(CUSS &list, &sep, buffer, sizeof(buffer)))) { int local_yield; @@ -1134,16 +1183,10 @@ if (pdomain != NULL) { int cllen = pllen - 1; if (sllen < cllen) return FAIL; - if (cb->caseless) - { - if (strncmpic(subject+sllen-cllen, pattern + 1, cllen) != 0) + if (cb->caseless + ? strncmpic(subject+sllen-cllen, pattern + 1, cllen) != 0 + : Ustrncmp(subject+sllen-cllen, pattern + 1, cllen) != 0) return FAIL; - } - else - { - if (Ustrncmp(subject+sllen-cllen, pattern + 1, cllen) != 0) - return FAIL; - } if (cb->expand_setup > 0) { expand_nstring[cb->expand_setup] = subject; @@ -1154,14 +1197,9 @@ if (pdomain != NULL) else { if (sllen != pllen) return FAIL; - if (cb->caseless) - { - if (strncmpic(subject, pattern, sllen) != 0) return FAIL; - } - else - { - if (Ustrncmp(subject, pattern, sllen) != 0) return FAIL; - } + if (cb->caseless + ? strncmpic(subject, pattern, sllen) != 0 + : Ustrncmp(subject, pattern, sllen) != 0) return FAIL; } } @@ -1170,7 +1208,7 @@ the generalized function, which supports file lookups (which may defer). The original code read as follows: return match_check_string(sdomain + 1, - (pdomain == NULL)? pattern : pdomain + 1, + pdomain ? pdomain + 1 : pattern, cb->expand_setup + expand_inc, TRUE, cb->caseless, TRUE, NULL); This supported only literal domains and *.x.y patterns. In order to allow for @@ -1178,14 +1216,14 @@ named domain lists (so that you can right, for example, "senders=+xxxx"), it was changed to use the list scanning function. */ csb.origsubject = sdomain + 1; -csb.subject = (cb->caseless)? string_copylc(sdomain+1) : string_copy(sdomain+1); +csb.subject = cb->caseless ? string_copylc(sdomain+1) : string_copy(sdomain+1); csb.expand_setup = cb->expand_setup + expand_inc; csb.use_partial = TRUE; csb.caseless = cb->caseless; csb.at_is_special = TRUE; -listptr = (pdomain == NULL)? pattern : pdomain + 1; -if (valueptr != NULL) *valueptr = NULL; +listptr = pdomain ? pdomain + 1 : pattern; +if (valueptr) *valueptr = NULL; return match_check_list( &listptr, /* list of one item */ @@ -1237,13 +1275,13 @@ Returns: OK for a positive match, or end list after a negation; */ int -match_address_list(uschar *address, BOOL caseless, BOOL expand, - uschar **listptr, unsigned int *cache_bits, int expand_setup, int sep, - uschar **valueptr) +match_address_list(const uschar *address, BOOL caseless, BOOL expand, + const uschar **listptr, unsigned int *cache_bits, int expand_setup, int sep, + const uschar **valueptr) { -uschar *p; check_address_block ab; unsigned int *local_cache_bits = cache_bits; +int len; /* RFC 2505 recommends that for spam checking, local parts should be caselessly compared. Therefore, Exim now forces the entire address into lower case here, @@ -1252,8 +1290,10 @@ 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. */ -sprintf(CS big_buffer, "%.*s", big_buffer_size - 1, address); -for (p = big_buffer + Ustrlen(big_buffer) - 1; p >= big_buffer; p--) +if ((len = Ustrlen(address)) > 255) len = 255; +ab.address = string_copyn(address, len); + +for (uschar * p = ab.address + len - 1; p >= ab.address; p--) { if (!caseless && *p == '@') break; *p = tolower(*p); @@ -1274,7 +1314,7 @@ if (expand_setup == 0) /* Set up the data to be passed ultimately to check_address. */ ab.origaddress = address; -ab.address = big_buffer; +/* ab.address is above */ ab.expand_setup = expand_setup; ab.caseless = caseless; @@ -1283,4 +1323,25 @@ return match_check_list(listptr, sep, &addresslist_anchor, &local_cache_bits, valueptr); } +/* Simpler version of match_address_list; always caseless, expanding, +no cache bits, no value-return. + +Arguments: + address address to test + listptr list to check against + sep separator character for the list; + may be 0 to get separator from the list; + may be UCHAR_MAX+1 for one-item list + +Returns: OK for a positive match, or end list after a negation; + FAIL for a negative match, or end list after non-negation; + DEFER if a lookup deferred +*/ + +int +match_address_list_basic(const uschar *address, const uschar **listptr, int sep) +{ +return match_address_list(address, TRUE, TRUE, listptr, NULL, -1, sep, NULL); +} + /* End of match.c */