-/* $Cambridge: exim/src/src/verify.c,v 1.18 2005/05/31 10:58:18 ph10 Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.25 2005/08/22 10:49:04 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
uschar *address_key;
uschar *from_address;
uschar *random_local_part = NULL;
+uschar *save_deliver_domain = deliver_domain;
uschar **failure_ptr = is_recipient?
&recipient_verify_failure : &sender_verify_failure;
open_db dbblock;
deliver_host = host->name;
deliver_host_address = host->address;
+ deliver_domain = addr->domain;
if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
US"callout") ||
!smtp_get_port(tf->port, addr, &port, US"callout"))
log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
addr->message);
deliver_host = deliver_host_address = NULL;
+ deliver_domain = save_deliver_domain;
/* Set HELO string according to the protocol */
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
'2', callout) &&
- smtp_write_command(&outblock, FALSE, "MAIL FROM:<>\r\n") >= 0 &&
+ smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
+ from_address) >= 0 &&
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
'2', callout);
}
if (new_domain_record.random_result != ccache_accept && done)
{
+ /* Get the rcpt_include_affixes flag from the transport if there is one,
+ but assume FALSE if there is not. */
+
done =
smtp_write_command(&outblock, FALSE, "RCPT TO:<%.1000s>\r\n",
transport_rcpt_address(addr,
- addr->transport->rcpt_include_affixes)) >= 0 &&
+ (addr->transport == NULL)? FALSE :
+ addr->transport->rcpt_include_affixes)) >= 0 &&
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
'2', callout);
}
}
} /* Random not accepted */
- } /* MAIL FROM:<> accepted */
+ } /* MAIL FROM: accepted */
/* For any failure of the main check, other than a negative response, we just
close the connection and carry on. We can identify a negative response by the
/* End the SMTP conversation and close the connection. */
if (send_quit) (void)smtp_write_command(&outblock, FALSE, "QUIT\r\n");
- close(inblock.sock);
+ (void)close(inblock.sock);
} /* Loop through all hosts, while !done */
/* If we get here with done == TRUE, a successful callout happened, and yield
However, there may be domain-specific information to cache in both cases.
The value of the result field in the new_domain record is ccache_unknown if
-there was an error before or with MAIL FROM:<>, and errno was not zero,
+there was an error before or with MAIL FROM:, and errno was not zero,
implying some kind of I/O error. We don't want to write the cache in that case.
Otherwise the value is ccache_accept or ccache_reject. */
rewriting and messages from callouts
vopt_qualify => qualify an unqualified address; else error
vopt_expn => called from SMTP EXPN command
+ vopt_success_on_redirect => when a new address is generated
+ the verification instantly succeeds
These ones are used by do_callout() -- the options variable
is passed to it.
BOOL full_info = (f == NULL)? FALSE : (debug_selector != 0);
BOOL is_recipient = (options & vopt_is_recipient) != 0;
BOOL expn = (options & vopt_expn) != 0;
+BOOL success_on_redirect = (options & vopt_success_on_redirect) != 0;
int i;
int yield = OK;
int verify_type = expn? v_expn :
if (tf.hosts != NULL && (host_list == NULL || tf.hosts_override))
{
uschar *s;
+ uschar *save_deliver_domain = deliver_domain;
+ uschar *save_deliver_localpart = deliver_localpart;
host_list = NULL; /* Ignore the router's hosts */
deliver_domain = addr->domain;
deliver_localpart = addr->local_part;
s = expand_string(tf.hosts);
- deliver_domain = deliver_localpart = NULL;
+ deliver_domain = save_deliver_domain;
+ deliver_localpart = save_deliver_localpart;
if (s == NULL)
{
generated address. */
if (!full_info && /* Stop if short info wanted AND */
- (addr_new == NULL || /* No new address OR */
- addr_new->next != NULL || /* More than one new address OR */
- testflag(addr_new, af_pfr))) /* New address is pfr */
+ (((addr_new == NULL || /* No new address OR */
+ addr_new->next != NULL || /* More than one new address OR */
+ testflag(addr_new, af_pfr))) /* New address is pfr */
+ || /* OR */
+ (addr_new != NULL && /* At least one new address AND */
+ success_on_redirect))) /* success_on_redirect is set */
{
if (f != NULL) fprintf(f, "%s %s\n", address,
address_test_mode? "is deliverable" : "verified");
DEBUG(D_ident) debug_printf("sender_ident = %s\n", sender_ident);
END_OFF:
-close(sock);
+(void)close(sock);
return;
}
error for error message when returning ERROR
The block contains:
- host_name the host name or NULL, implying use sender_host_name and
- sender_host_aliases, looking them up if required
+ host_name (a) the host name, or
+ (b) NULL, implying use sender_host_name and
+ sender_host_aliases, looking them up if required, or
+ (c) the empty string, meaning that only IP address matches
+ are permitted
host_address the host address
host_ipv4 the IPv4 address taken from an IPv6 one
Returns: OK matched
FAIL did not match
DEFER lookup deferred
- ERROR failed to find the host name or IP address
- unknown lookup type specified
+ ERROR (a) failed to find the host name or IP address, or
+ (b) unknown lookup type specified, or
+ (c) host name encountered when only IP addresses are
+ being matched
*/
-static int
+int
check_host(void *arg, uschar *ss, uschar **valueptr, uschar **error)
{
check_host_block *cb = (check_host_block *)arg;
+int mlen = -1;
int maskoffset;
+BOOL iplookup = FALSE;
BOOL isquery = FALSE;
-uschar *semicolon, *t;
+BOOL isiponly = cb->host_name != NULL && cb->host_name[0] == 0;
+uschar *t = ss;
+uschar *semicolon;
uschar **aliases;
/* Optimize for the special case when the pattern is "*". */
if (cb->host_address[0] == 0) return (*ss == 0)? OK : FAIL;
if (*ss == 0) return FAIL;
-/* If the pattern is precisely "@" then match against the primary host name;
-if it's "@[]" match against the local host's IP addresses. */
+/* If the pattern is precisely "@" then match against the primary host name,
+provided that host name matching is permitted; if it's "@[]" match against the
+local host's IP addresses. */
if (*ss == '@')
{
- if (ss[1] == 0) ss = primary_hostname;
+ if (ss[1] == 0)
+ {
+ if (isiponly) return ERROR;
+ ss = primary_hostname;
+ }
else if (Ustrcmp(ss, "@[]") == 0)
{
ip_address_item *ip;
if (string_is_ip_address(ss, &maskoffset) > 0)
return (host_is_in_net(cb->host_address, ss, maskoffset)? OK : FAIL);
-/* If the item is of the form net[n]-lookup;<file|query> then it is a lookup on
-a masked IP network, in textual form. The net- stuff really only applies to
-single-key lookups where the key is implicit. For query-style lookups the key
-is specified in the query. From release 4.30, the use of net- for query style
-is no longer needed, but we retain it for backward compatibility. */
+/* See if there is a semicolon in the pattern */
+
+semicolon = Ustrchr(ss, ';');
-if (Ustrncmp(ss, "net", 3) == 0 && (semicolon = Ustrchr(ss, ';')) != NULL)
+/* If we are doing an IP address only match, then all lookups must be IP
+address lookups. */
+
+if (isiponly)
{
- int mlen = 0;
- for (t = ss + 3; isdigit(*t); t++) mlen = mlen * 10 + *t - '0';
- if (*t++ == '-')
- {
- int insize;
- int search_type;
- int incoming[4];
- void *handle;
- uschar *filename, *key, *result;
- uschar buffer[64];
+ iplookup = semicolon != NULL;
+ }
- /* If no mask was supplied, set a negative value */
+/* Otherwise, if the item is of the form net[n]-lookup;<file|query> then it is
+a lookup on a masked IP network, in textual form. The net- stuff really only
+applies to single-key lookups where the key is implicit. For query-style
+lookups the key is specified in the query. From release 4.30, the use of net-
+for query style is no longer needed, but we retain it for backward
+compatibility. */
- if (mlen == 0 && t == ss+4) mlen = -1;
+else if (Ustrncmp(ss, "net", 3) == 0 && semicolon != NULL)
+ {
+ mlen = 0;
+ for (t = ss + 3; isdigit(*t); t++) mlen = mlen * 10 + *t - '0';
+ if (mlen == 0 && t == ss+3) mlen = -1; /* No mask supplied */
+ iplookup = (*t++ == '-');
+ }
- /* Find the search type */
+/* Do the IP address lookup if that is indeed what we have */
- search_type = search_findtype(t, semicolon - t);
+if (iplookup)
+ {
+ int insize;
+ int search_type;
+ int incoming[4];
+ void *handle;
+ uschar *filename, *key, *result;
+ uschar buffer[64];
- if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
- search_error_message);
+ /* Find the search type */
- /* Adjust parameters for the type of lookup. For a query-style
- lookup, there is no file name, and the "key" is just the query. For
- a single-key lookup, the key is the current IP address, masked
- appropriately, and reconverted to text form, with the mask appended.
- For IPv6 addresses, specify dot separators instead of colons. */
+ search_type = search_findtype(t, semicolon - t);
- if (mac_islookup(search_type, lookup_querystyle))
- {
- filename = NULL;
- key = semicolon + 1;
- }
- else
- {
- insize = host_aton(cb->host_address, incoming);
- host_mask(insize, incoming, mlen);
- (void)host_nmtoa(insize, incoming, mlen, buffer, '.');
- key = buffer;
- filename = semicolon + 1;
- }
+ if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
+ search_error_message);
- /* Now do the actual lookup; note that there is no search_close() because
- of the caching arrangements. */
+ /* Adjust parameters for the type of lookup. For a query-style lookup, there
+ is no file name, and the "key" is just the query. For query-style with a file
+ name, we have to fish the file off the start of the query. For a single-key
+ lookup, the key is the current IP address, masked appropriately, and
+ reconverted to text form, with the mask appended. For IPv6 addresses, specify
+ dot separators instead of colons. */
- handle = search_open(filename, search_type, 0, NULL, NULL);
- if (handle == NULL) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
- search_error_message);
- result = search_find(handle, filename, key, -1, NULL, 0, 0, NULL);
- if (valueptr != NULL) *valueptr = result;
- return (result != NULL)? OK : search_find_defer? DEFER: FAIL;
+ if (mac_islookup(search_type, lookup_absfilequery))
+ {
+ filename = semicolon + 1;
+ key = filename;
+ while (*key != 0 && !isspace(*key)) key++;
+ filename = string_copyn(filename, key - filename);
+ while (isspace(*key)) key++;
+ }
+ else if (mac_islookup(search_type, lookup_querystyle))
+ {
+ filename = NULL;
+ key = semicolon + 1;
+ }
+ else
+ {
+ insize = host_aton(cb->host_address, incoming);
+ host_mask(insize, incoming, mlen);
+ (void)host_nmtoa(insize, incoming, mlen, buffer, '.');
+ key = buffer;
+ filename = semicolon + 1;
}
+
+ /* Now do the actual lookup; 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);
+ result = search_find(handle, filename, key, -1, NULL, 0, 0, NULL);
+ if (valueptr != NULL) *valueptr = result;
+ return (result != NULL)? OK : search_find_defer? DEFER: FAIL;
}
/* The pattern is not an IP address or network reference of any kind. That is,
-it is a host name pattern. Check the characters of the pattern to see if they
-comprise only letters, digits, full stops, and hyphens (the constituents of
-domain names). Allow underscores, as they are all too commonly found. Sigh.
-Also, if allow_utf8_domains is set, allow top-bit characters. */
+it is a host name pattern. If this is an IP only match, there's an error in the
+host list. */
+
+if (isiponly)
+ {
+ *error = US"cannot match host name in match_ip list";
+ return ERROR;
+ }
+
+/* Check the characters of the pattern to see if they comprise only letters,
+digits, full stops, and hyphens (the constituents of domain names). Allow
+underscores, as they are all too commonly found. Sigh. Also, if
+allow_utf8_domains is set, allow top-bit characters. */
for (t = ss; *t != 0; t++)
if (!isalnum(*t) && *t != '.' && *t != '-' && *t != '_' &&
search_error_message, ss);
return DEFER;
}
- isquery = mac_islookup(id, lookup_querystyle);
+ isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery);
}
if (isquery)