-/* $Cambridge: exim/src/src/match.c,v 1.4 2005/01/04 13:31:41 ph10 Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for matching strings */
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
int search_type, partial, affixlen, starflags;
int expand_setup = cb->expand_setup;
uschar *affix;
-uschar *s = cb->subject;
+uschar *s;
uschar *filename = NULL;
uschar *keyquery, *result, *semicolon;
void *handle;
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 = (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. */
int slen = Ustrlen(s);
if (s[0] != '[' && s[slen-1] != ']') return FAIL;
for (ip = host_find_interfaces(); ip != NULL; ip = ip->next)
- if (Ustrncmp(ip->address, s+1, slen - 2) == 0) return OK;
+ if (Ustrncmp(ip->address, s+1, slen - 2) == 0
+ && ip->address[slen - 2] == 0)
+ return OK;
return FAIL;
}
if (!cb->use_partial) partial = -1;
-/* Set the parameters for the two different kinds of lookup. */
+/* Set the parameters for the three different kinds of lookup. */
keyquery = semicolon + 1;
while (isspace(*keyquery)) keyquery++;
-if (!mac_islookup(search_type, lookup_querystyle))
+if (mac_islookup(search_type, lookup_absfilequery))
+ {
+ filename = keyquery;
+ while (*keyquery != 0 && !isspace(*keyquery)) keyquery++;
+ filename = string_copyn(filename, keyquery - filename);
+ while (isspace(*keyquery)) keyquery++;
+ }
+
+else if (!mac_islookup(search_type, lookup_querystyle))
{
filename = keyquery;
keyquery = s;
FAIL if expansion force-failed
FAIL if matched a negated item
FAIL if hit end of list after a non-negated item
- DEFER if a lookup deferred or expansion failed
+ DEFER if a something deferred or expansion failed
*/
int
unsigned int *original_cache_bits = *cache_ptr;
BOOL include_unknown = FALSE;
BOOL ignore_unknown = FALSE;
+BOOL include_defer = FALSE;
+BOOL ignore_defer = FALSE;
uschar *list;
uschar *sss;
uschar *ot = NULL;
}
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 = cb->subject;
+ list = expand_string(*listptr);
+ deliver_domain = NULL;
+ }
+
+ else list = expand_string(*listptr);
+
if (list == NULL)
{
if (expand_string_forcedfail)
}
}
- /* 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)
{
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
else
{
- uschar *error;
+ uschar *error = NULL;
switch ((func)(arg, ss, valueptr, &error))
{
case OK:
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;
+ }
goto DEFER_RETURN;
- /* The ERROR return occurs only when checking hosts, when either a
- forward or reverse lookup has failed. The error string gives details of
+ /* 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
+ non-IP address item is encountered. The error string gives details of
which it was. */
case ERROR:
if (ignore_unknown)
{
- HDEBUG(D_lists) debug_printf("%s: item ignored by +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) return FAIL;
+ 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;
}
switch ((func)(arg, ss, valueptr, &error))
{
case OK:
- fclose(f);
+ (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:
- fclose(f);
+ 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 */
if (ignore_unknown) /* be for an incoming host (not outgoing) */
{
- HDEBUG(D_lists) debug_printf("%s: item ignored by +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);
- fclose(f);
- if (!include_unknown) return FAIL;
+ (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;
}
for the file, in case this is the last item in the list. */
yield = file_yield;
- fclose(f);
+ (void)fclose(f);
}
} /* Loop for the next item on the top-level list */
debug_printf("%s %s (end of list)\n", ot, (yield == OK)? "no":"yes");
return (yield == OK)? FAIL : OK;
-/* Handle lookup defer */
+/* Something deferred */
DEFER_RETURN:
-HDEBUG(D_lists) debug_printf("%s lookup deferred for %s\n", ot, sss);
+HDEBUG(D_lists) debug_printf("%s list match deferred for %s\n", ot, sss);
return DEFER;
}
DEBUG(D_lists) debug_printf("address match: subject=%s pattern=%s\n",
subject, pattern);
-/* Handle a regular expression, which must match the entire incoming address.
+/* Find the subject's domain */
+
+sdomain = Ustrrchr(subject, '@');
+
+/* The only case where a subject may not have a domain is if the subject is
+empty. Otherwise, a subject with no domain is a serious configuration error. */
+
+if (sdomain == NULL && *subject != 0)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "no @ found in the subject of an "
+ "address list match: subject=\"%s\" pattern=\"%s\"", subject, pattern);
+ return FAIL;
+ }
+
+/* Handle a regular expression, which must match the entire incoming address.
This may be the empty address. */
if (*pattern == '^')
if (*s == '*') s++;
if (*s == '@') s++;
-/* If it is a straight lookup, do a lookup for the whole address. This may be
+/* If it is a straight lookup, do a lookup for the whole address. This may be
the empty address. Partial matching doesn't make sense here, so we ignore it,
but write a panic log entry. However, *@ matching will be honoured. */
valueptr);
}
-/* For the remaining cases, an empty subject matches only an empty pattern,
-because other patterns expect to have a local part and a domain to match
+/* For the remaining cases, an empty subject matches only an empty pattern,
+because other patterns expect to have a local part and a domain to match
against. */
if (*subject == 0) return (*pattern == 0)? OK : FAIL;
-/* Find the subject's domain */
-
-sdomain = Ustrrchr(subject, '@');
-
/* 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
"*" (called from retry) the match always fails. */