Canonicize IPv6 addresses that are supplied via -bh or -bhc.
[users/jgh/exim.git] / src / src / verify.c
index 8b24fb48a0b532f235d1744686844dd88597046f..cd2ae666c8f15b4661ed92a89c1d9f7b197bb65c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.2 2004/11/04 12:19:48 ph10 Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.6 2004/11/18 11:17:33 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -151,6 +151,8 @@ BOOL done = FALSE;
 uschar *address_key;
 uschar *from_address;
 uschar *random_local_part = NULL;
+uschar **failure_ptr = is_recipient? 
+  &recipient_verify_failure : &sender_verify_failure;
 open_db dbblock;
 open_db *dbm_file = NULL;
 dbdata_callout_cache new_domain_record;
@@ -236,6 +238,7 @@ if (dbm_file != NULL)
       setflag(addr, af_verify_nsfail);
       addr->user_message = US"(result of an earlier callout reused).";
       yield = FAIL;
+      *failure_ptr = US"mail"; 
       goto END_CALLOUT;
       }
 
@@ -282,6 +285,7 @@ if (dbm_file != NULL)
           debug_printf("callout cache: domain does not accept "
             "RCPT TO:<postmaster@domain>\n");
         yield = FAIL;
+        *failure_ptr = US"postmaster"; 
         setflag(addr, af_verify_pmfail);
         addr->user_message = US"(result of earlier verification reused).";
         goto END_CALLOUT;
@@ -330,6 +334,7 @@ if (dbm_file != NULL)
       HDEBUG(D_verify)
         debug_printf("callout cache: address record is negative\n");
       addr->user_message = US"Previous (cached) callout verification failure";
+      *failure_ptr = US"recipient"; 
       yield = FAIL;
       }
     goto END_CALLOUT;
@@ -476,6 +481,7 @@ for (host = host_list; host != NULL && !done; host = host->next)
 
   if (!done)
     {
+    *failure_ptr = US"mail"; 
     if (errno == 0 && responsebuffer[0] == '5')
       {
       setflag(addr, af_verify_nsfail);
@@ -550,7 +556,10 @@ for (host = host_list; host != NULL && !done; host = host->next)
       if (done)
         new_address_record.result = ccache_accept;
       else if (errno == 0 && responsebuffer[0] == '5')
+        {
+        *failure_ptr = US"recipient";  
         new_address_record.result = ccache_reject;
+        } 
 
       /* Do postmaster check if requested */
 
@@ -577,6 +586,7 @@ for (host = host_list; host != NULL && !done; host = host->next)
           new_domain_record.postmaster_result = ccache_accept;
         else if (errno == 0 && responsebuffer[0] == '5')
           {
+          *failure_ptr = US"postmaster"; 
           setflag(addr, af_verify_pmfail);
           new_domain_record.postmaster_result = ccache_reject;
           }
@@ -810,7 +820,6 @@ BOOL allok = TRUE;
 BOOL full_info = (f == NULL)? FALSE : (debug_selector != 0);
 BOOL is_recipient = (options & vopt_is_recipient) != 0;
 BOOL expn         = (options & vopt_expn) != 0;
-
 int i;
 int yield = OK;
 int verify_type = expn? v_expn :
@@ -821,11 +830,17 @@ address_item *addr_new = NULL;
 address_item *addr_remote = NULL;
 address_item *addr_local = NULL;
 address_item *addr_succeed = NULL;
+uschar **failure_ptr = is_recipient? 
+  &recipient_verify_failure : &sender_verify_failure;
 uschar *ko_prefix, *cr;
 uschar *address = vaddr->address;
 uschar *save_sender;
 uschar null_sender[] = { 0 };             /* Ensure writeable memory */
 
+/* Clear, just in case */
+
+*failure_ptr = NULL;
+
 /* Set up a prefix and suffix for error message which allow us to use the same
 output statements both in EXPN mode (where an SMTP response is needed) and when
 debugging with an output file. */
@@ -846,6 +861,7 @@ if (parse_find_at(address) == NULL)
     if (f != NULL)
       fprintf(f, "%sA domain is required for \"%s\"%s\n", ko_prefix, address,
         cr);
+    *failure_ptr = US"qualify";     
     return FAIL;
     }
   address = rewrite_address_qualify(address, is_recipient);
@@ -1021,14 +1037,18 @@ while (addr_new != NULL)
           else
             {
             uschar *canonical_name;
-            host_item *host;
+            host_item *host, *nexthost;
             host_build_hostlist(&host_list, s, tf.hosts_randomize);
 
             /* Just ignore failures to find a host address. If we don't manage
-            to find any addresses, the callout will defer. */
+            to find any addresses, the callout will defer. Note that more than 
+            one address may be found for a single host, which will result in 
+            additional host items being inserted into the chain. Hence we must 
+            save the next host first. */
 
-            for (host = host_list; host != NULL; host = host->next)
+            for (host = host_list; host != NULL; host = nexthost)
               {
+              nexthost = host->next;
               if (tf.gethostbyname || string_is_ip_address(host->name, NULL))
                 (void)host_find_byname(host, NULL, &canonical_name, TRUE);
               else
@@ -1044,7 +1064,8 @@ while (addr_new != NULL)
           }
         }
 
-      /* Can only do a callout if we have at least one host! */
+      /* Can only do a callout if we have at least one host! If the callout 
+      fails, it will have set ${sender,recipient}_verify_failure. */
 
       if (host_list != NULL)
         {
@@ -1068,6 +1089,10 @@ while (addr_new != NULL)
         }
       }
     }
+    
+  /* Otherwise, any failure is a routing failure */
+  
+  else *failure_ptr = US"route"; 
 
   /* A router may return REROUTED if it has set up a child address as a result
   of a change of domain name (typically from widening). In this case we always
@@ -1255,7 +1280,10 @@ else for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
     }
   }
 
-return yield;  /* Will be DEFER or FAIL if any one address has */
+/* Will be DEFER or FAIL if any one address has, only for full_info (which is 
+the -bv or -bt case). */
+
+return yield;  
 }
 
 
@@ -1838,7 +1866,8 @@ if (Ustrncmp(ss, "net", 3) == 0 && (semicolon = Ustrchr(ss, ';')) != NULL)
     /* 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. */
+    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))
       {
@@ -1849,7 +1878,7 @@ if (Ustrncmp(ss, "net", 3) == 0 && (semicolon = Ustrchr(ss, ';')) != NULL)
       {
       insize = host_aton(cb->host_address, incoming);
       host_mask(insize, incoming, mlen);
-      (void)host_nmtoa(insize, incoming, mlen, buffer);
+      (void)host_nmtoa(insize, incoming, mlen, buffer, '.');
       key = buffer;
       filename = semicolon + 1;
       }
@@ -2026,7 +2055,9 @@ int
 verify_check_this_host(uschar **listptr, unsigned int *cache_bits,
   uschar *host_name, uschar *host_address, uschar **valueptr)
 {
+int rc;
 unsigned int *local_cache_bits = cache_bits;
+uschar *save_host_address = deliver_host_address;
 check_host_block cb;
 cb.host_name = host_name;
 cb.host_address = host_address;
@@ -2040,9 +2071,26 @@ addresses. */
 cb.host_ipv4 = (Ustrncmp(host_address, "::ffff:", 7) == 0)?
   host_address + 7 : host_address;
 
-return match_check_list(listptr, 0, &hostlist_anchor, &local_cache_bits,
-  check_host, &cb, MCL_HOST,
-  (host_address == sender_host_address)? US"host" : host_address, valueptr);
+/* During the running of the check, put the IP address into $host_address. In 
+the case of calls from the smtp transport, it will already be there. However, 
+in other calls (e.g. when testing ignore_target_hosts), it won't. Just to be on 
+the safe side, any existing setting is preserved, though as I write this
+(November 2004) I can't see any cases where it is actually needed. */
+
+deliver_host_address = host_address;
+rc = match_check_list(
+       listptr,                                /* the list */
+       0,                                      /* separator character */
+       &hostlist_anchor,                       /* anchor pointer */
+       &local_cache_bits,                      /* cache pointer */
+       check_host,                             /* function for testing */
+       &cb,                                    /* argument for function */
+       MCL_HOST,                               /* type of check */
+       (host_address == sender_host_address)? 
+         US"host" : host_address,              /* text for debugging */
+       valueptr);                              /* where to pass back data */
+deliver_host_address = save_host_address;
+return rc; 
 }