Update one test to avoid prodding the live Exim for a callout (can now
[exim.git] / src / src / verify.c
index c727177b55f45c3b0f9d85624e9c752b1646006a..010ea84f1ca38a73352c960e0d44b41d6695ce51 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.23 2005/07/23 20:46:42 tom Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.27 2005/09/14 09:40:55 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -152,6 +152,7 @@ BOOL done = FALSE;
 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;
@@ -409,18 +410,24 @@ for (host = host_list; host != NULL && !done; host = host->next)
 
   host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
 
-  /* Expand and interpret the interface and port strings. This has to
-  be delayed till now, because they may expand differently for different
-  hosts. If there's a failure, log it, but carry on with the defaults. */
+  /* Expand and interpret the interface and port strings. The latter will not
+  be used if there is a host-specific port (e.g. from a manualroute router).
+  This has to be delayed till now, because they may expand differently for
+  different hosts. If there's a failure, log it, but carry on with the
+  defaults. */
 
   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 */
 
@@ -1053,13 +1060,16 @@ while (addr_new != NULL)
         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)
             {
@@ -1445,6 +1455,89 @@ return OK;
 
 
 
+/*************************************************
+*          Check for blind recipients            *
+*************************************************/
+
+/* This function checks that every (envelope) recipient is mentioned in either
+the To: or Cc: header lines, thus detecting blind carbon copies.
+
+There are two ways of scanning that could be used: either scan the header lines
+and tick off the recipients, or scan the recipients and check the header lines.
+The original proposed patch did the former, but I have chosen to do the latter,
+because (a) it requires no memory and (b) will use fewer resources when there
+are many addresses in To: and/or Cc: and only one or two envelope recipients.
+
+Arguments:   none
+Returns:     OK    if there are no blind recipients
+             FAIL  if there is at least one blind recipient
+*/
+
+int
+verify_check_notblind(void)
+{
+int i;
+for (i = 0; i < recipients_count; i++)
+  {
+  header_line *h;
+  BOOL found = FALSE;
+  uschar *address = recipients_list[i].address;
+
+  for (h = header_list; !found && h != NULL; h = h->next)
+    {
+    uschar *colon, *s;
+
+    if (h->type != htype_to && h->type != htype_cc) continue;
+
+    colon = Ustrchr(h->text, ':');
+    s = colon + 1;
+    while (isspace(*s)) s++;
+
+    parse_allow_group = TRUE;     /* Allow group syntax */
+
+    /* Loop for multiple addresses in the header */
+
+    while (*s != 0)
+      {
+      uschar *ss = parse_find_address_end(s, FALSE);
+      uschar *recipient,*errmess;
+      int terminator = *ss;
+      int start, end, domain;
+
+      /* Temporarily terminate the string at this point, and extract the
+      operative address within. */
+
+      *ss = 0;
+      recipient = parse_extract_address(s,&errmess,&start,&end,&domain,FALSE);
+      *ss = terminator;
+
+      /* If we found a valid recipient that has a domain, compare it with the
+      envelope recipient. Local parts are compared case-sensitively, domains
+      case-insensitively. By comparing from the start with length "domain", we
+      include the "@" at the end, which ensures that we are comparing the whole
+      local part of each address. */
+
+      if (recipient != NULL && domain != 0)
+        {
+        found = Ustrncmp(recipient, address, domain) == 0 &&
+                strcmpic(recipient + domain, address + domain) == 0;
+        if (found) break;
+        }
+
+      /* Advance to the next address */
+
+      s = ss + (terminator? 1:0);
+      while (isspace(*s)) s++;
+      }   /* Next address */
+    }     /* Next header (if found is false) */
+
+  if (!found) return FAIL;
+  }       /* Next recipient */
+
+return OK;
+}
+
+
 
 /*************************************************
 *          Find if verified sender               *
@@ -1938,13 +2031,22 @@ if (iplookup)
   if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
     search_error_message);
 
-  /* 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. */
+  /* 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. */
 
-  if (mac_islookup(search_type, lookup_querystyle))
+  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;
@@ -2047,7 +2149,7 @@ if ((semicolon = Ustrchr(ss, ';')) != NULL)
       search_error_message, ss);
     return DEFER;
     }
-  isquery = mac_islookup(id, lookup_querystyle);
+  isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery);
   }
 
 if (isquery)