X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fmatch.c;h=3547e467fb52ffe5f116d9e956b4552f2fef360f;hb=7cd171b76e5bd3cb825c2a8720bc1fe4ad9b37e0;hp=218944530acff9e7112e55996a0b1375a8ec4b00;hpb=953a9f896e50fb554a2f5cc702c606e053209026;p=exim.git diff --git a/src/src/match.c b/src/src/match.c index 218944530..3547e467f 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/match.c,v 1.14 2006/04/04 10:01:20 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2006 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for matching strings */ @@ -17,8 +15,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 +28,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; @@ -74,7 +72,8 @@ Arguments: returns ERROR) Contents of the argument block: - subject the subject string to be checked + origsubject the subject in its original casing + subject the subject string to be checked, lowercased if caseless expand_setup if < 0, don't set up any numeric expansion variables; if = 0, set $0 to whole subject, and either $1 to what matches * or @@ -93,13 +92,13 @@ 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; -uschar *s = cb->subject; +const uschar *affix; +uschar *s; uschar *filename = NULL; uschar *keyquery, *result, *semicolon; void *handle; @@ -108,6 +107,12 @@ error = error; /* Keep clever compilers from complaining */ if (valueptr != NULL) *valueptr = NULL; /* For non-lookup matches */ +/* For regular expressions, use cb->origsubject rather than cb->subject so that +it works if the pattern uses (?-i) to turn off case-independence, overriding +"caseless". */ + +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. */ @@ -126,7 +131,7 @@ 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 + pcre_exec(re, NULL, CCS s, Ustrlen(s), 0, PCRE_EOPT, NULL, 0) >= 0 : regex_match_and_setup(re, s, 0, expand_setup) )? @@ -187,8 +192,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) @@ -216,6 +221,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 */ @@ -330,8 +336,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; @@ -359,7 +365,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) @@ -429,15 +435,17 @@ 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]; @@ -474,7 +482,19 @@ if (type >= MCL_NOEXPAND) } else { - list = expand_string(*listptr); + /* 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) + { + check_string_block *cb = (check_string_block *)arg; + deliver_domain = string_copy(cb->subject); + list = expand_cstring(*listptr); + deliver_domain = NULL; + } + + else list = expand_cstring(*listptr); + if (list == NULL) { if (expand_string_forcedfail) @@ -534,10 +554,11 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) } } - /* 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) { @@ -551,6 +572,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 @@ -667,7 +700,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) cached = US" - cached"; if (valueptr != NULL) { - uschar *key = get_check_key(arg, type); + const uschar *key = get_check_key(arg, type); namedlist_cacheblock *p; for (p = nb->cache_data; p != NULL; p = p->next) { @@ -696,7 +729,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) else { - uschar *error; + uschar *error = NULL; switch ((func)(arg, ss, valueptr, &error)) { case OK: @@ -705,6 +738,20 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) return yield; case DEFER: + if (error == NULL) + 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 @@ -804,7 +851,20 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) return file_yield; case DEFER: + if (error == NULL) + 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 */ @@ -892,8 +952,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; @@ -939,20 +1000,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 */ @@ -1010,7 +1072,8 @@ 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; + const uschar *key; + uschar *list, *ss; uschar buffer[1024]; if (sdomain == subject + 1 && *subject == '*') return FAIL; @@ -1023,7 +1086,7 @@ if (pattern[0] == '@' && pattern[1] == '@') 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. */ @@ -1042,8 +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(&list, &sep, buffer, sizeof(buffer))) - != NULL) + while ((ss = string_nextinlist(CUSS &list, &sep, buffer, sizeof(buffer)))) { int local_yield; @@ -1218,9 +1280,9 @@ 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;