[exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog NewSt…

Góra strony
Delete this message
Reply to this message
Autor: Philip Hazel
Data:  
Dla: exim-cvs
Temat: [exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog NewStuff exim/exim-src/src acl.c dns.c exim.h expand.c globals.c globals.h macros.h readconf.c version.c exim/exim-src/src/lookups dnsdb.c exi
ph10 2005/05/10 11:19:12 BST

  Modified files:
    exim-doc/doc-txt     ChangeLog NewStuff 
    exim-src/src         acl.c dns.c exim.h expand.c globals.c 
                         globals.h macros.h readconf.c version.c 
    exim-src/src/lookups dnsdb.c 
    exim-test-orig/AutoTest/confs 002 
    exim-test-orig/AutoTest/scripts 082 
    exim-test-orig/AutoTest/stdout 001 002 082 
    exim-test-orig/DNSzones db.test.ex 
  Added files:
    exim-test-orig/AutoTest/confs 613 
    exim-test-orig/AutoTest/scripts 613 
    exim-test-orig/AutoTest/stderr 613 
    exim-test-orig/AutoTest/stdout 613 
  Log:
  1. Update version.
  2. Apply Tony's CSA patch (with some fixes) and add simple test.


  Revision  Changes    Path
  1.134     +6 -0      exim/exim-doc/doc-txt/ChangeLog
  1.40      +60 -0     exim/exim-doc/doc-txt/NewStuff
  1.29      +349 -0    exim/exim-src/src/acl.c
  1.6       +157 -8    exim/exim-src/src/dns.c
  1.12      +10 -3     exim/exim-src/src/exim.h
  1.21      +1 -0      exim/exim-src/src/expand.c
  1.24      +4 -0      exim/exim-src/src/globals.c
  1.16      +4 -0      exim/exim-src/src/globals.h
  1.11      +55 -18    exim/exim-src/src/lookups/dnsdb.c
  1.13      +1 -1      exim/exim-src/src/macros.h
  1.8       +2 -0      exim/exim-src/src/readconf.c
  1.8       +1 -1      exim/exim-src/src/version.c
  1.9       +2 -0      exim/exim-test-orig/AutoTest/confs/002
  1.1       +26 -0     exim/exim-test-orig/AutoTest/confs/613 (new)
  1.12      +3 -0      exim/exim-test-orig/AutoTest/scripts/082
  1.1       +18 -0     exim/exim-test-orig/AutoTest/scripts/613 (new)
  1.1       +52 -0     exim/exim-test-orig/AutoTest/stderr/613 (new)
  1.11      +2 -0      exim/exim-test-orig/AutoTest/stdout/001
  1.9       +2 -0      exim/exim-test-orig/AutoTest/stdout/002
  1.12      +3 -0      exim/exim-test-orig/AutoTest/stdout/082
  1.1       +36 -0     exim/exim-test-orig/AutoTest/stdout/613 (new)
  1.3       +11 -1     exim/exim-test-orig/DNSzones/db.test.ex


  Index: ChangeLog
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/ChangeLog,v
  retrieving revision 1.133
  retrieving revision 1.134
  diff -u -r1.133 -r1.134
  --- ChangeLog    4 May 2005 10:17:28 -0000    1.133
  +++ ChangeLog    10 May 2005 10:19:11 -0000    1.134
  @@ -1,7 +1,13 @@
  -$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.133 2005/05/04 10:17:28 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.134 2005/05/10 10:19:11 ph10 Exp $


Change log file for Exim from version 4.21
-------------------------------------------
+
+
+Exim version 4.52
+-----------------
+
+TF/01 Added support for Client SMTP Authorization. See NewStuff for details.


Exim version 4.51

  Index: NewStuff
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/NewStuff,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- NewStuff    3 May 2005 14:20:00 -0000    1.39
  +++ NewStuff    10 May 2005 10:19:11 -0000    1.40
  @@ -1,4 +1,4 @@
  -$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.39 2005/05/03 14:20:00 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/NewStuff,v 1.40 2005/05/10 10:19:11 ph10 Exp $


   New Features in Exim
   --------------------
  @@ -7,6 +7,66 @@
   but have not yet made it into the main manual (which is most conveniently
   updated when there is a relatively large batch of changes). The doc/ChangeLog
   file contains a listing of all changes, including bug fixes.
  +
  +
  +Exim version 4.52
  +-----------------
  +
  +TF/01 Support for checking Client SMTP Authorization has been added. CSA is a
  +      system which allows a site to advertise which machines are and are not
  +      permitted to send email. This is done by placing special SRV records in
  +      the DNS, which are looked up using the client's HELO domain. At this
  +      time CSA is still an Internet-Draft.
  +
  +      Client SMTP Authorization checks are performed by the ACL condition
  +      verify=csa. This will fail if the client is not authorized. If there is
  +      a DNS problem, or if no valid CSA SRV record is found, or if the client
  +      is authorized, the condition succeeds. These three cases can be
  +      distinguished using the expansion variable $csa_status, which can take
  +      one of the values "fail", "defer", "unknown", or "ok". The condition
  +      does not itself defer because that would be likely to cause problems
  +      for legitimate email.
  +
  +      The error messages produced by the CSA code include slightly more
  +      detail. If $csa_status is "defer" this may be because of problems
  +      looking up the CSA SRV record, or problems looking up the CSA target
  +      address record. There are four reasons for $csa_status being "fail":
  +      the client's host name is explicitly not authorized; the client's IP
  +      address does not match any of the CSA target IP addresses; the client's
  +      host name is authorized but it has no valid target IP addresses (e.g.
  +      the target's addresses are IPv6 and the client is using IPv4); or the
  +      client's host name has no CSA SRV record but a parent domain has
  +      asserted that all subdomains must be explicitly authorized.
  +
  +      The verify=csa condition can take an argument which is the domain to
  +      use for the DNS query. The default is verify=csa/$sender_helo_name.
  +
  +      This implementation includes an extension to CSA. If the query domain
  +      is an address literal such as [192.0.2.95], or if it is a bare IP
  +      address, Exim will search for CSA SRV records in the reverse DNS as if
  +      the HELO domain was e.g. 95.2.0.192.in-addr.arpa. Therefore it is
  +      meaningful to say, for example, verify=csa/$sender_host_address - in
  +      fact, this is the check that Exim performs if the client does not say
  +      HELO. This extension can be turned off by setting the main
  +      configuration option dns_csa_use_reverse = false.
  +
  +      If a CSA SRV record is not found for the domain itself, then a search
  +      is performed through its parent domains for a record which might be
  +      making assertions about subdomains. The maximum depth of this search is
  +      limited using the main configuration option dns_csa_search_limit, which
  +      takes the value 5 by default. Exim does not look for CSA SRV records in
  +      a top level domain, so the default settings handle HELO domains as long
  +      as seven (hostname.five.four.three.two.one.com) which encompasses the
  +      vast majority of legitimate HELO domains.
  +
  +      The dnsdb lookup also has support for CSA. Although dnsdb already
  +      supports SRV lookups, this is not sufficient because of the extra
  +      parent domain search behaviour of CSA, and (as with PTR lookups)
  +      dnsdb also turns IP addresses into lookups in the reverse DNS space.
  +      The result of ${lookup dnsdb {csa=$sender_helo_name} } has two
  +      space-separated fields: an authorization code and a target host name.
  +      The authorization code can be "Y" for yes, "N" for no, "X" for explicit
  +      authorization required but absent, or "?" for unknown.



Version 4.51

  Index: acl.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/acl.c,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- acl.c    6 Apr 2005 14:03:53 -0000    1.28
  +++ acl.c    10 May 2005 10:19:11 -0000    1.29
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/acl.c,v 1.28 2005/04/06 14:03:53 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/acl.c,v 1.29 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -505,6 +505,45 @@
     { US"submission",             CONTROL_SUBMISSION, TRUE}
     };


+/* Support data structures for Client SMTP Authorization. acl_verify_csa()
+caches its result in a tree to avoid repeated DNS queries. The result is an
+integer code which is used as an index into the following tables of
+explanatory strings and verification return codes. */
+
+static tree_node *csa_cache = NULL;
+
+enum { CSA_UNKNOWN, CSA_OK, CSA_DEFER_SRV, CSA_DEFER_ADDR,
+ CSA_FAIL_EXPLICIT, CSA_FAIL_DOMAIN, CSA_FAIL_NOADDR, CSA_FAIL_MISMATCH };
+
+/* The acl_verify_csa() return code is translated into an acl_verify() return
+code using the following table. It is OK unless the client is definitely not
+authorized. This is because CSA is supposed to be optional for sending sites,
+so recipients should not be too strict about checking it - especially because
+DNS problems are quite likely to occur. It's possible to use $csa_status in
+further ACL conditions to distinguish ok, unknown, and defer if required, but
+the aim is to make the usual configuration simple. */
+
+static int csa_return_code[] = {
+ OK, OK, OK, OK,
+ FAIL, FAIL, FAIL, FAIL
+};
+
+static uschar *csa_status_string[] = {
+ US"unknown", US"ok", US"defer", US"defer",
+ US"fail", US"fail", US"fail", US"fail"
+};
+
+static uschar *csa_reason_string[] = {
+ US"unknown",
+ US"ok",
+ US"deferred (SRV lookup failed)",
+ US"deferred (target address lookup failed)",
+ US"failed (explicit authorization required)",
+ US"failed (host name not authorized)",
+ US"failed (no authorized addresses)",
+ US"failed (client address mismatch)"
+};
+
/* Enable recursion between acl_check_internal() and acl_check_condition() */

static int acl_check_internal(int, address_item *, uschar *, int, uschar **,
@@ -938,6 +977,303 @@


   /*************************************************
  +*   Check client IP address matches CSA target   *
  +*************************************************/
  +
  +/* Called from acl_verify_csa() below. This routine scans a section of a DNS
  +response for address records belonging to the CSA target hostname. The section
  +is specified by the reset argument, either RESET_ADDITIONAL or RESET_ANSWERS.
  +If one of the addresses matches the client's IP address, then the client is
  +authorized by CSA. If there are target IP addresses but none of them match
  +then the client is using an unauthorized IP address. If there are no target IP
  +addresses then the client cannot be using an authorized IP address. (This is
  +an odd configuration - why didn't the SRV record have a weight of 1 instead?)
  +
  +Arguments:
  +  dnsa       the DNS answer block
  +  dnss       a DNS scan block for us to use
  +  reset      option specifing what portion to scan, as described above
  +  target     the target hostname to use for matching RR names
  +
  +Returns:     CSA_OK             successfully authorized
  +             CSA_FAIL_MISMATCH  addresses found but none matched
  +             CSA_FAIL_NOADDR    no target addresses found
  +*/
  +
  +static int
  +acl_verify_csa_address(dns_answer *dnsa, dns_scan *dnss, int reset,
  +                       uschar *target)
  +{
  +dns_record *rr;
  +dns_address *da;
  +
  +BOOL target_found = FALSE;
  +
  +for (rr = dns_next_rr(dnsa, dnss, reset);
  +     rr != NULL;
  +     rr = dns_next_rr(dnsa, dnss, RESET_NEXT))
  +  {
  +  /* Check this is an address RR for the target hostname. */
  +
  +  if (rr->type != T_A
  +    #if HAVE_IPV6
  +      && rr->type != T_AAAA
  +      #ifdef SUPPORT_A6
  +        && rr->type != T_A6
  +      #endif
  +    #endif
  +  ) continue;
  +
  +  if (strcmpic(target, rr->name) != 0) continue;
  +
  +  target_found = TRUE;
  +
  +  /* Turn the target address RR into a list of textual IP addresses and scan
  +  the list. There may be more than one if it is an A6 RR. */
  +
  +  for (da = dns_address_from_rr(dnsa, rr); da != NULL; da = da->next)
  +    {
  +    /* If the client IP address matches the target IP address, it's good! */
  +
  +    DEBUG(D_acl) debug_printf("CSA target address is %s\n", da->address);
  +
  +    if (strcmpic(sender_host_address, da->address) == 0) return CSA_OK;
  +    }
  +  }
  +
  +/* If we found some target addresses but none of them matched, the client is
  +using an unauthorized IP address, otherwise the target has no authorized IP
  +addresses. */
  +
  +if (target_found) return CSA_FAIL_MISMATCH;
  +else return CSA_FAIL_NOADDR;
  +}
  +
  +
  +
  +/*************************************************
  +*       Verify Client SMTP Authorization         *
  +*************************************************/
  +
  +/* Called from acl_verify() below. This routine calls dns_lookup_special()
  +to find the CSA SRV record corresponding to the domain argument, or
  +$sender_helo_name if no argument is provided. It then checks that the
  +client is authorized, and that its IP address corresponds to the SRV
  +target's address by calling acl_verify_csa_address() above. The address
  +should have been returned in the DNS response's ADDITIONAL section, but if
  +not we perform another DNS lookup to get it.
  +
  +Arguments:
  +  domain    pointer to optional parameter following verify = csa
  +
  +Returns:    CSA_UNKNOWN    no valid CSA record found
  +            CSA_OK         successfully authorized
  +            CSA_FAIL_*     client is definitely not authorized
  +            CSA_DEFER_*    there was a DNS problem
  +*/
  +
  +static int
  +acl_verify_csa(uschar *domain)
  +{
  +tree_node *t;
  +uschar *found, *p;
  +int priority, weight, port;
  +dns_answer dnsa;
  +dns_scan dnss;
  +dns_record *rr;
  +int rc, type;
  +uschar target[256];
  +
  +/* Work out the domain we are using for the CSA lookup. The default is the
  +client's HELO domain. If the client has not said HELO, use its IP address
  +instead. If it's a local client (exim -bs), CSA isn't applicable. */
  +
  +while (isspace(*domain) && *domain != '\0') ++domain;
  +if (*domain == '\0') domain = sender_helo_name;
  +if (domain == NULL) domain = sender_host_address;
  +if (sender_host_address == NULL) return CSA_UNKNOWN;
  +
  +/* If we have an address literal, strip off the framing ready for turning it
  +into a domain. The framing consists of matched square brackets possibly
  +containing a keyword and a colon before the actual IP address. */
  +
  +if (domain[0] == '[')
  +  {
  +  uschar *start = Ustrchr(domain, ':');
  +  if (start == NULL) start = domain;
  +  domain = string_copyn(start + 1, Ustrlen(start) - 2);
  +  }
  +
  +/* Turn domains that look like bare IP addresses into domains in the reverse
  +DNS. This code also deals with address literals and $sender_host_address. It's
  +not quite kosher to treat bare domains such as EHLO 192.0.2.57 the same as
  +address literals, but it's probably the most friendly thing to do. This is an
  +extension to CSA, so we allow it to be turned off for proper conformance. */
  +
  +if (string_is_ip_address(domain, NULL))
  +  {
  +  if (!dns_csa_use_reverse) return CSA_UNKNOWN;
  +  dns_build_reverse(domain, target);
  +  domain = target;
  +  }
  +
  +/* Find out if we've already done the CSA check for this domain. If we have,
  +return the same result again. Otherwise build a new cached result structure
  +for this domain. The name is filled in now, and the value is filled in when
  +we return from this function. */
  +
  +t = tree_search(csa_cache, domain);
  +if (t != NULL) return t->data.val;
  +
  +t = store_get_perm(sizeof(tree_node) + Ustrlen(domain));
  +Ustrcpy(t->name, domain);
  +(void)tree_insertnode(&csa_cache, t);
  +
  +/* Now we are ready to do the actual DNS lookup(s). */
  +
  +switch (dns_special_lookup(&dnsa, domain, T_CSA, &found))
  +  {
  +  /* If something bad happened (most commonly DNS_AGAIN), defer. */
  +
  +  default:
  +  return t->data.val = CSA_DEFER_SRV;
  +
  +  /* If we found nothing, the client's authorization is unknown. */
  +
  +  case DNS_NOMATCH:
  +  case DNS_NODATA:
  +  return t->data.val = CSA_UNKNOWN;
  +
  +  /* We got something! Go on to look at the reply in more detail. */
  +
  +  case DNS_SUCCEED:
  +  break;
  +  }
  +
  +/* Scan the reply for well-formed CSA SRV records. */
  +
  +for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
  +     rr != NULL;
  +     rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
  +  {
  +  if (rr->type != T_SRV) continue;
  +
  +  /* Extract the numerical SRV fields (p is incremented) */
  +
  +  p = rr->data;
  +  GETSHORT(priority, p);
  +  GETSHORT(weight, p);
  +  GETSHORT(port, p);
  +
  +  DEBUG(D_acl)
  +    debug_printf("CSA priority=%d weight=%d port=%d\n", priority, weight, port);
  +
  +  /* Check the CSA version number */
  +
  +  if (priority != 1) continue;
  +
  +  /* If the domain does not have a CSA SRV record of its own (i.e. the domain
  +  found by dns_special_lookup() is a parent of the one we asked for), we check
  +  the subdomain assertions in the port field. At the moment there's only one
  +  assertion: legitimate SMTP clients are all explicitly authorized with CSA
  +  SRV records of their own. */
  +
  +  if (found != domain)
  +    {
  +    if (port & 1)
  +      return t->data.val = CSA_FAIL_EXPLICIT;
  +    else
  +      return t->data.val = CSA_UNKNOWN;
  +    }
  +
  +  /* This CSA SRV record refers directly to our domain, so we check the value
  +  in the weight field to work out the domain's authorization. 0 and 1 are
  +  unauthorized; 3 means the client is authorized but we can't check the IP
  +  address in order to authenticate it, so we treat it as unknown; values
  +  greater than 3 are undefined. */
  +
  +  if (weight < 2) return t->data.val = CSA_FAIL_DOMAIN;
  +
  +  if (weight > 2) continue;
  +
  +  /* Weight == 2, which means the domain is authorized. We must check that the
  +  client's IP address is listed as one of the SRV target addresses. Save the
  +  target hostname then break to scan the additional data for its addresses. */
  +
  +  (void)dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
  +    (DN_EXPAND_ARG4_TYPE)target, sizeof(target));
  +
  +  DEBUG(D_acl) debug_printf("CSA target is %s\n", target);
  +
  +  break;
  +  }
  +
  +/* If we didn't break the loop then no appropriate records were found. */
  +
  +if (rr == NULL) return t->data.val = CSA_UNKNOWN;
  +
  +/* Do not check addresses if the target is ".", in accordance with RFC 2782.
  +A target of "." indicates there are no valid addresses, so the client cannot
  +be authorized. (This is an odd configuration because weight=2 target=. is
  +equivalent to weight=1, but we check for it in order to keep load off the
  +root name servers.) Note that dn_expand() turns "." into "". */
  +
  +if (Ustrcmp(target, "") == 0) return t->data.val = CSA_FAIL_NOADDR;
  +
  +/* Scan the additional section of the CSA SRV reply for addresses belonging
  +to the target. If the name server didn't return any additional data (e.g.
  +because it does not fully support SRV records), we need to do another lookup
  +to obtain the target addresses; otherwise we have a definitive result. */
  +
  +rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ADDITIONAL, target);
  +if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
  +
  +/* The DNS lookup type corresponds to the IP version used by the client. */
  +
  +#if HAVE_IPV6
  +if (Ustrchr(sender_host_address, ':') != NULL)
  +  type = T_AAAA;
  +else
  +#endif /* HAVE_IPV6 */
  +  type = T_A;
  +
  +
  +#if HAVE_IPV6 && defined(SUPPORT_A6)
  +DNS_LOOKUP_AGAIN:
  +#endif
  +
  +switch (dns_lookup(&dnsa, target, type, NULL))
  +  {
  +  /* If something bad happened (most commonly DNS_AGAIN), defer. */
  +
  +  default:
  +  return t->data.val = CSA_DEFER_ADDR;
  +
  +  /* If the query succeeded, scan the addresses and return the result. */
  +
  +  case DNS_SUCCEED:
  +  rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ANSWERS, target);
  +  if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
  +  /* else fall through */
  +
  +  /* If the target has no IP addresses, the client cannot have an authorized
  +  IP address. However, if the target site uses A6 records (not AAAA records)
  +  we have to do yet another lookup in order to check them. */
  +
  +  case DNS_NOMATCH:
  +  case DNS_NODATA:
  +
  +  #if HAVE_IPV6 && defined(SUPPORT_A6)
  +  if (type == T_AAAA) { type = T_A6; goto DNS_LOOKUP_AGAIN; }
  +  #endif
  +
  +  return t->data.val = CSA_FAIL_NOADDR;
  +  }
  +}
  +
  +
  +
  +/*************************************************
   *     Handle verification (address & other)      *
   *************************************************/


  @@ -1017,6 +1353,19 @@
     {
     if (slash != NULL) goto NO_OPTIONS;
     return helo_verified? OK : FAIL;
  +  }
  +
  +/* Do Client SMTP Authorization checks in a separate function, and turn the
  +result code into user-friendly strings. */
  +
  +if (strcmpic(ss, US"csa") == 0)
  +  {
  +  rc = acl_verify_csa(list);
  +  *log_msgptr = *user_msgptr = string_sprintf("client SMTP authorization %s",
  +                                              csa_reason_string[rc]);
  +  csa_status = csa_status_string[rc];
  +  DEBUG(D_acl) debug_printf("CSA result %s\n", csa_status);
  +  return csa_return_code[rc];
     }


/* Check that all relevant header lines have the correct syntax. If there is

  Index: dns.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/dns.c,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- dns.c    17 Feb 2005 11:58:26 -0000    1.5
  +++ dns.c    10 May 2005 10:19:11 -0000    1.6
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/dns.c,v 1.5 2005/02/17 11:58:26 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/dns.c,v 1.6 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -153,9 +153,9 @@
   *************************************************/


/* Call this with reset == RESET_ANSWERS to scan the answer block, reset ==
-RESET_ADDITIONAL to scan the additional records, and reset == RESET_NEXT to
-get the next record. The result is in static storage which must be copied if
-it is to be preserved.
+RESET_AUTHORITY to scan the authority records, reset == RESET_ADDITIONAL to
+scan the additional records, and reset == RESET_NEXT to get the next record.
+The result is in static storage which must be copied if it is to be preserved.

   Arguments:
     dnsa      pointer to dns answer block
  @@ -192,12 +192,14 @@


     dnss->rrcount = ntohs(h->ancount);


  -  /* Skip over answers and NS records if wanting to look at the additional
  +  /* Skip over answers if we want to look at the authority section. Also skip
  +  the NS records (i.e. authority section) if wanting to look at the additional
     records. */


  -  if (reset == RESET_ADDITIONAL)
  +  if (reset == RESET_ADDITIONAL) dnss->rrcount += ntohs(h->nscount);
  +
  +  if (reset == RESET_AUTHORITY || reset == RESET_ADDITIONAL)
       {
  -    dnss->rrcount += ntohs(h->nscount);
       while (dnss->rrcount-- > 0)
         {
         namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
  @@ -207,11 +209,11 @@
         GETSHORT(dnss->srr.size, dnss->aptr); /* size of data portion */
         dnss->aptr += dnss->srr.size;         /* skip over it */
         }
  -    dnss->rrcount = ntohs(h->arcount);
  +    dnss->rrcount = (reset == RESET_AUTHORITY)
  +      ? ntohs(h->nscount) : ntohs(h->arcount);
       }
     }


-
/* The variable dnss->aptr is now pointing at the next RR, and dnss->rrcount
contains the number of RR records left. */

  @@ -666,6 +668,153 @@
       if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc;
       while (*d != 0 && *d != '.') d++;
       if (*d++ == 0) break;
  +    }
  +  return DNS_NOMATCH;
  +  }
  +
  +/* Try to look up the Client SMTP Authorization SRV record for the name. If
  +there isn't one, search from the top downwards for a CSA record in a parent
  +domain, which might be making assertions about subdomains. If we find a record
  +we set fully_qualified_name to whichever lookup succeeded, so that the caller
  +can tell whether to look at the explicit authorization field or the subdomain
  +assertion field. */
  +
  +if (type == T_CSA)
  +  {
  +  uschar *srvname, *namesuff, *tld, *p;
  +  int priority, weight, port;
  +  int limit, rc, i;
  +  BOOL ipv6;
  +  dns_record *rr;
  +  dns_scan dnss;
  +
  +  DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name);
  +
  +  srvname = string_sprintf("_client._smtp.%s", name);
  +  rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
  +  if (rc == DNS_SUCCEED || rc == DNS_AGAIN)
  +    {
  +    if (rc == DNS_SUCCEED) *fully_qualified_name = name;
  +    return rc;
  +    }
  +
  +  /* Search for CSA subdomain assertion SRV records from the top downwards,
  +  starting with the 2nd level domain. This order maximizes cache-friendliness.
  +  We skip the top level domains to avoid loading their nameservers and because
  +  we know they'll never have CSA SRV records. */
  +
  +  namesuff = Ustrrchr(name, '.');
  +  if (namesuff == NULL) return DNS_NOMATCH;
  +  tld = namesuff + 1;
  +  ipv6 = FALSE;
  +  limit = dns_csa_search_limit;
  +
  +  /* Use more appropriate search parameters if we are in the reverse DNS. */
  +
  +  if (strcmpic(namesuff, US".arpa") == 0)
  +    {
  +    if (namesuff - 8 > name && strcmpic(namesuff - 8, US".in-addr.arpa") == 0)
  +      {
  +      namesuff -= 8;
  +      tld = namesuff + 1;
  +      limit = 3;
  +      }
  +    else if (namesuff - 4 > name && strcmpic(namesuff - 4, US".ip6.arpa") == 0)
  +      {
  +      namesuff -= 4;
  +      tld = namesuff + 1;
  +      ipv6 = TRUE;
  +      limit = 3;
  +      }
  +    }
  +
  +  DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld);
  +
  +  /* Do not perform the search if the top level or 2nd level domains do not
  +  exist. This is quite common, and when it occurs all the search queries would
  +  go to the root or TLD name servers, which is not friendly. So we check the
  +  AUTHORITY section; if it contains the root's SOA record or the TLD's SOA then
  +  the TLD or the 2LD (respectively) doesn't exist and we can skip the search.
  +  If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
  +  the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
  +
  +  if (rc == DNS_NOMATCH)
  +    {
  +    /* This is really gross. The successful return value from res_search() is
  +    the packet length, which is stored in dnsa->answerlen. If we get a
  +    negative DNS reply then res_search() returns -1, which causes the bounds
  +    checks for name decompression to fail when it is treated as a packet
  +    length, which in turn causes the authority search to fail. The correct
  +    packet length has been lost inside libresolv, so we have to guess a
  +    replacement value. (The only way to fix this properly would be to
  +    re-implement res_search() and res_query() so that they don't muddle their
  +    success and packet length return values.) For added safety we only reset
  +    the packet length if the packet header looks plausible. */
  +
  +    HEADER *h = (HEADER *)dnsa->answer;
  +    if (h->qr == 1 && h->opcode == QUERY && h->tc == 0
  +        && (h->rcode == NOERROR || h->rcode == NXDOMAIN)
  +        && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0
  +        && ntohs(h->nscount) >= 1)
  +      dnsa->answerlen = MAXPACKET;
  +
  +    for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
  +         rr != NULL;
  +         rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
  +      if (rr->type != T_SOA) continue;
  +      else if (strcmpic(rr->name, US"") == 0 ||
  +               strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
  +      else break;
  +    }
  +
  +  for (i = 0; i < limit; i++)
  +    {
  +    if (ipv6)
  +      {
  +      /* Scan through the IPv6 reverse DNS in chunks of 16 bits worth of IP
  +      address, i.e. 4 hex chars and 4 dots, i.e. 8 chars. */
  +      namesuff -= 8;
  +      if (namesuff <= name) return DNS_NOMATCH;
  +      }
  +    else
  +      /* Find the start of the preceding domain name label. */
  +      do
  +        if (--namesuff <= name) return DNS_NOMATCH;
  +      while (*namesuff != '.');
  +
  +    DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1);
  +
  +    srvname = string_sprintf("_client._smtp.%s", namesuff + 1);
  +    rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
  +    if (rc == DNS_AGAIN) return rc;
  +    if (rc != DNS_SUCCEED) continue;
  +
  +    /* Check that the SRV record we have found is worth returning. We don't
  +    just return the first one we find, because some lower level SRV record
  +    might make stricter assertions than its parent domain. */
  +
  +    for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
  +         rr != NULL;
  +         rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
  +      {
  +      if (rr->type != T_SRV) continue;
  +
  +      /* Extract the numerical SRV fields (p is incremented) */
  +      p = rr->data;
  +      GETSHORT(priority, p);
  +      GETSHORT(weight, p);
  +      GETSHORT(port, p);
  +
  +      /* Check the CSA version number */
  +      if (priority != 1) continue;
  +
  +      /* If it's making an interesting assertion, return this response. */
  +      if (port & 1)
  +        {
  +        *fully_qualified_name = namesuff + 1;
  +        return DNS_SUCCEED;
  +        }
  +      }
       }
     return DNS_NOMATCH;
     }


  Index: exim.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/exim.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- exim.h    27 Apr 2005 10:00:18 -0000    1.11
  +++ exim.h    10 May 2005 10:19:11 -0000    1.12
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/exim.h,v 1.11 2005/04/27 10:00:18 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/exim.h,v 1.12 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -280,12 +280,19 @@
   #define T_SRV 33
   #endif


-/* We use the private type T_ZNS for retrieving the nameservers for the
-enclosing zone of a domain, and the private type T_MXH for retrieving
-the MX hostnames only (without their priorities). */
+/* We define a few private types for special DNS lookups:
+
+ . T_ZNS gets the nameservers of the enclosing zone of a domain
+
+ . T_MXH gets the MX hostnames only (without their priorities)
+
+ . T_CSA gets the domain's Client SMTP Authorization SRV record
+
+*/

#define T_ZNS (-1)
#define T_MXH (-2)
+#define T_CSA (-3)

/* The resolv.h header defines __P(x) on some Solaris 2.5.1 systems (without
checking that it is already defined, in fact). This conflicts with other

  Index: expand.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/expand.c,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- expand.c    28 Apr 2005 13:29:27 -0000    1.20
  +++ expand.c    10 May 2005 10:19:11 -0000    1.21
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/expand.c,v 1.20 2005/04/28 13:29:27 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/expand.c,v 1.21 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -333,6 +333,7 @@
     { "caller_uid",          vtype_uid,         &real_uid },
     { "compile_date",        vtype_stringptr,   &version_date },
     { "compile_number",      vtype_stringptr,   &version_cnumber },
  +  { "csa_status",          vtype_stringptr,   &csa_status },
   #ifdef WITH_OLD_DEMIME
     { "demime_errorlevel",   vtype_int,         &demime_errorlevel },
     { "demime_reason",       vtype_stringptr,   &demime_reason },


  Index: globals.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.c,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- globals.c    3 May 2005 14:20:01 -0000    1.23
  +++ globals.c    10 May 2005 10:19:11 -0000    1.24
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.c,v 1.23 2005/05/03 14:20:01 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.c,v 1.24 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -385,6 +385,8 @@
   int     continue_sequence      = 1;
   uschar *continue_transport     = NULL;


  +uschar *csa_status             = NULL;
  +
   BOOL    daemon_listen          = FALSE;
   uschar *daemon_smtp_port       = US"smtp";
   BOOL    debug_daemon           = FALSE;
  @@ -473,6 +475,8 @@
   #endif


   uschar *dns_again_means_nonexist = NULL;
  +int     dns_csa_search_limit   = 5;
  +BOOL    dns_csa_use_reverse    = TRUE;
   uschar *dns_ipv4_lookup        = NULL;
   int     dns_retrans            = 0;
   int     dns_retry              = 0;


  Index: globals.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.h,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- globals.h    3 May 2005 14:20:01 -0000    1.15
  +++ globals.h    10 May 2005 10:19:11 -0000    1.16
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.h,v 1.15 2005/05/03 14:20:01 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.h,v 1.16 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -214,6 +214,8 @@
   extern int     continue_sequence;      /* Sequence num for continued delivery */
   extern uschar *continue_transport;     /* Transport for continued delivery */


  +extern uschar *csa_status;             /* Client SMTP Authorization result */
  +
   extern BOOL    daemon_listen;          /* True if listening required */
   extern uschar *daemon_smtp_port;       /* Can be a list of ports */
   extern BOOL    debug_daemon;           /* Debug the daemon process only */
  @@ -271,6 +273,8 @@
   #endif


   extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
  +extern int     dns_csa_search_limit;   /* How deep to search for CSA SRV records */
  +extern BOOL    dns_csa_use_reverse;    /* Check CSA in reverse DNS? (non-standard) */
   extern uschar *dns_ipv4_lookup;        /* For these domains, don't look for AAAA (or A6) */
   extern int     dns_retrans;            /* Retransmission time setting */
   extern int     dns_retry;              /* Number of retries */


  Index: macros.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/macros.h,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- macros.h    7 Apr 2005 10:54:54 -0000    1.12
  +++ macros.h    10 May 2005 10:19:11 -0000    1.13
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/macros.h,v 1.12 2005/04/07 10:54:54 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/macros.h,v 1.13 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -178,7 +178,7 @@


/* Options for dns_next_rr */

-enum { RESET_NEXT, RESET_ANSWERS, RESET_ADDITIONAL };
+enum { RESET_NEXT, RESET_ANSWERS, RESET_AUTHORITY, RESET_ADDITIONAL };

/* Argument values for the time-of-day function */


  Index: readconf.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/readconf.c,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- readconf.c    5 Apr 2005 13:58:35 -0000    1.7
  +++ readconf.c    10 May 2005 10:19:11 -0000    1.8
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/readconf.c,v 1.7 2005/04/05 13:58:35 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/readconf.c,v 1.8 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -193,6 +193,8 @@
     { "delivery_date_remove",     opt_bool,        &delivery_date_remove },
     { "dns_again_means_nonexist", opt_stringptr,   &dns_again_means_nonexist },
     { "dns_check_names_pattern",  opt_stringptr,   &check_dns_names_pattern },
  +  { "dns_csa_search_limit",     opt_int,         &dns_csa_search_limit },
  +  { "dns_csa_use_reverse",      opt_bool,        &dns_csa_use_reverse },
     { "dns_ipv4_lookup",          opt_stringptr,   &dns_ipv4_lookup },
     { "dns_retrans",              opt_time,        &dns_retrans },
     { "dns_retry",                opt_int,         &dns_retry },


  Index: version.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/version.c,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- version.c    1 Mar 2005 10:21:44 -0000    1.7
  +++ version.c    10 May 2005 10:19:11 -0000    1.8
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/version.c,v 1.7 2005/03/01 10:21:44 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/version.c,v 1.8 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -12,7 +12,7 @@
   #include "exim.h"



-#define THIS_VERSION "4.51"
+#define THIS_VERSION "4.52"


/* The header file cnumber.h contains a single line containing the

  Index: dnsdb.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/lookups/dnsdb.c,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- dnsdb.c    17 Feb 2005 11:58:27 -0000    1.10
  +++ dnsdb.c    10 May 2005 10:19:11 -0000    1.11
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/lookups/dnsdb.c,v 1.10 2005/02/17 11:58:27 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/lookups/dnsdb.c,v 1.11 2005/05/10 10:19:11 ph10 Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -31,6 +31,7 @@
     #endif
   #endif
     "cname",
  +  "csa",
     "mx",
     "mxh",
     "ns",
  @@ -49,6 +50,7 @@
     #endif
   #endif
     T_CNAME,
  +  T_CSA,     /* Private type for "Client SMTP Authorization". */
     T_MX,
     T_MXH,     /* Private type for "MX hostnames" */
     T_NS,
  @@ -112,7 +114,7 @@
   int type = T_TXT;
   int failrc = FAIL;
   uschar *outsep = US"\n";
  -uschar *equals, *domain;
  +uschar *equals, *domain, *found;
   uschar buffer[256];


   /* Because we're the working in the search pool, we try to reclaim as much
  @@ -228,15 +230,18 @@
           != NULL)
     {
     uschar rbuffer[256];
  -  int searchtype = (type == T_ZNS)? T_NS :          /* record type we want */
  -                   (type == T_MXH)? T_MX : type;
  +  int searchtype = (type == T_CSA)? T_SRV :         /* record type we want */
  +                   (type == T_MXH)? T_MX :
  +                   (type == T_ZNS)? T_NS : type;
  +
  +  /* If the type is PTR or CSA, we have to construct the relevant magic lookup
  +  key if the original is an IP address (some experimental protocols are using
  +  PTR records for different purposes where the key string is a host name, and
  +  Exim's extended CSA can be keyed by domains or IP addresses). This code for
  +  doing the reversal is now in a separate function. */


  -  /* If the type is PTR, we have to construct the relevant magic lookup key if
  -  the original is an IP address (some experimental protocols are using PTR
  -  records for different purposes where the key string is a host name). This
  -  code for doing the reversal is now in a separate function. */
  -
  -  if (type == T_PTR && string_is_ip_address(domain, NULL) > 0)
  +  if ((type == T_PTR || type == T_CSA) &&
  +      string_is_ip_address(domain, NULL) > 0)
       {
       dns_build_reverse(domain, rbuffer);
       domain = rbuffer;
  @@ -252,7 +257,8 @@
     continue with the next domain. In the case of DEFER, adjust the final
     "nothing found" result, but carry on to the next domain. */


- rc = dns_special_lookup(&dnsa, domain, type, NULL);
+ found = domain;
+ rc = dns_special_lookup(&dnsa, domain, type, &found);

     if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue;
     if (rc != DNS_SUCCEED)
  @@ -300,32 +306,63 @@
         yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1),
           (rr->data)[0]);
         }
  -    else   /* T_CNAME, T_MX, T_MXH, T_NS, T_SRV, T_PTR */
  +    else   /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */
         {
  -      int num;
  +      int priority, weight, port;
         uschar s[264];
         uschar *p = (uschar *)(rr->data);


         if (type == T_MXH)
           {
           /* mxh ignores the priority number and includes only the hostnames */
  -        GETSHORT(num, p);            /* pointer is advanced */
  +        GETSHORT(priority, p);
           }
         else if (type == T_MX)
           {
  -        GETSHORT(num, p);            /* pointer is advanced */
  -        sprintf(CS s, "%d ", num);
  +        GETSHORT(priority, p);
  +        sprintf(CS s, "%d ", priority);
           yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
           }
         else if (type == T_SRV)
           {
  -        int weight, port;
  -        GETSHORT(num, p);            /* pointer is advanced */
  +        GETSHORT(priority, p);
           GETSHORT(weight, p);
           GETSHORT(port, p);
  -        sprintf(CS s, "%d %d %d ", num, weight, port);
  +        sprintf(CS s, "%d %d %d ", priority, weight, port);
           yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
           }
  +      else if (type == T_CSA)
  +        {
  +        /* See acl_verify_csa() for more comments about CSA. */
  +
  +        GETSHORT(priority, p);
  +        GETSHORT(weight, p);
  +        GETSHORT(port, p);
  +
  +        if (priority != 1) continue;      /* CSA version must be 1 */
  +
  +        /* If the CSA record we found is not the one we asked for, analyse
  +        the subdomain assertions in the port field, else analyse the direct
  +        authorization status in the weight field. */
  +
  +        if (found != domain)
  +          {
  +          if (port & 1) *s = 'X';         /* explicit authorization required */
  +          else *s = '?';                  /* no subdomain assertions here */
  +          }
  +        else
  +          {
  +          if (weight < 2) *s = 'N';       /* not authorized */
  +          else if (weight == 2) *s = 'Y'; /* authorized */
  +          else if (weight == 3) *s = '?'; /* unauthorizable */
  +          else continue;                  /* invalid */
  +          }
  +
  +        s[1] = ' ';
  +        yield = string_cat(yield, &size, &ptr, s, 2);
  +        }
  +
  +      /* GETSHORT() has advanced the pointer to the target domain. */


         rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
           (DN_EXPAND_ARG4_TYPE)(s), sizeof(s));


Index: 613
====================================================================
# Exim test configuration 613

# Macros are set externally in order to get the path
# of the Exim that is being tested, and the directory
# in which the test data lives.

exim_path = EXIM_PATH
primary_hostname = myhost.test.ex
spool_directory = DIR/spool

# ----- Main settings -----

acl_smtp_mail = check_mail
qualify_domain = test.ex


# ----- ACL -----

begin acl

  check_mail:
    accept  endpass
            message = CSA status is $csa_status
            verify = csa


# End

  Index: 002
  ===================================================================
  RCS file: /home/cvs/exim/exim-test-orig/AutoTest/confs/002,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- 002    3 May 2005 14:20:01 -0000    1.8
  +++ 002    10 May 2005 10:19:11 -0000    1.9
  @@ -64,6 +64,8 @@
   dns_ipv4_lookup = *
   dns_retrans = 0s
   dns_retry = 0
  +dns_csa_search_limit = 3
  +dns_csa_use_reverse = no
   drop_cr
   envelope_to_remove
   errors_copy =


  Index: 613
  ====================================================================
  0 Simple CSA test
  exim -bh 10.9.8.7
  ehlo csa1.test.ex
  mail from:<>
  rset
  ehlo csa2.test.ex
  mail from:<>
  quit
  ****               
  0
  exim -bh 10.9.8.8
  ehlo csa1.test.ex
  mail from:<>
  rset
  ehlo csa2.test.ex
  mail from:<>
  quit
  ****               


  Index: 082
  ===================================================================
  RCS file: /home/cvs/exim/exim-test-orig/AutoTest/scripts/082,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- 082    28 Apr 2005 13:29:27 -0000    1.11
  +++ 082    10 May 2005 10:19:11 -0000    1.12
  @@ -448,6 +448,9 @@
   srv=_smtp._tcp.srv01.test.ex     ${lookup dnsdb{srv=_smtp._tcp.srv01.test.ex}{$value}{fail}}
   srv=_smtp._tcp.nosmtp.test.ex    ${lookup dnsdb{srv=_smtp._tcp.nosmtp.test.ex}{$value}{fail}}


  +csa=csa1.test.ex           ${lookup dnsdb{csa=csa1.test.ex}}
  +csa=csa2.test.ex           ${lookup dnsdb{csa=csa2.test.ex}}
  +
   # DNS lookups with multiple items


   ten-1:ten2                 ${lookup dnsdb{a=ten-1.test.ex:ten-2.test.ex}}


Index: 613
====================================================================
>>> host in hosts_connection_nolog? no (option unset)
>>> host in host_lookup? no (option unset)
>>> host in host_reject_connection? no (option unset)
>>> host in sender_unqualified_hosts? no (option unset)
>>> host in recipient_unqualified_hosts? no (option unset)
>>> host in helo_verify_hosts? no (option unset)
>>> host in helo_try_verify_hosts? no (option unset)
>>> host in helo_accept_junk_hosts? no (option unset)
>>> csa1.test.ex in helo_lookup_domains? no (end of list)
>>> host in pipelining_advertise_hosts? yes (matched "*")
>>> host in tls_advertise_hosts? no (option unset)
>>> using ACL "check_mail"
>>> processing "accept"
>>> check verify = csa
>>> accept: condition test succeeded
>>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
>>> csa2.test.ex in helo_lookup_domains? no (end of list)
>>> host in pipelining_advertise_hosts? yes (matched "*")
>>> host in tls_advertise_hosts? no (option unset)
>>> using ACL "check_mail"
>>> processing "accept"
>>> check verify = csa
>>> accept: condition test failed
>>> accept: endpass encountered - denying access

LOG: H=(csa2.test.ex) [10.9.8.7] rejected MAIL <>: client SMTP authorization failed (host name not authorized)
>>> host in hosts_connection_nolog? no (option unset)
>>> host in host_lookup? no (option unset)
>>> host in host_reject_connection? no (option unset)
>>> host in sender_unqualified_hosts? no (option unset)
>>> host in recipient_unqualified_hosts? no (option unset)
>>> host in helo_verify_hosts? no (option unset)
>>> host in helo_try_verify_hosts? no (option unset)
>>> host in helo_accept_junk_hosts? no (option unset)
>>> csa1.test.ex in helo_lookup_domains? no (end of list)
>>> host in pipelining_advertise_hosts? yes (matched "*")
>>> host in tls_advertise_hosts? no (option unset)
>>> using ACL "check_mail"
>>> processing "accept"
>>> check verify = csa
>>> accept: condition test failed
>>> accept: endpass encountered - denying access

LOG: H=(csa1.test.ex) [10.9.8.8] rejected MAIL <>: client SMTP authorization failed (client address mismatch)
>>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
>>> csa2.test.ex in helo_lookup_domains? no (end of list)
>>> host in pipelining_advertise_hosts? yes (matched "*")
>>> host in tls_advertise_hosts? no (option unset)
>>> using ACL "check_mail"
>>> processing "accept"
>>> check verify = csa
>>> accept: condition test failed
>>> accept: endpass encountered - denying access

LOG: H=(csa2.test.ex) [10.9.8.8] rejected MAIL <>: client SMTP authorization failed (host name not authorized)

Index: 613
====================================================================

**** SMTP testing session as if from host 10.9.8.7
**** but without any ident (RFC 1413) callback.
**** This is not for real!

220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250-myhost.test.ex Hello csa1.test.ex [10.9.8.7]
250-SIZE 52428800
250-PIPELINING
250 HELP
250 OK
250 Reset OK
250-myhost.test.ex Hello csa2.test.ex [10.9.8.7]
250-SIZE 52428800
250-PIPELINING
250 HELP
550 CSA status is fail
221 myhost.test.ex closing connection

**** SMTP testing session as if from host 10.9.8.8
**** but without any ident (RFC 1413) callback.
**** This is not for real!

220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250-myhost.test.ex Hello csa1.test.ex [10.9.8.8]
250-SIZE 52428800
250-PIPELINING
250 HELP
550 CSA status is fail
250 Reset OK
250-myhost.test.ex Hello csa2.test.ex [10.9.8.8]
250-SIZE 52428800
250-PIPELINING
250 HELP
550 CSA status is fail
221 myhost.test.ex closing connection

  Index: 001
  ===================================================================
  RCS file: /home/cvs/exim/exim-test-orig/AutoTest/stdout/001,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- 001    3 May 2005 14:20:02 -0000    1.10
  +++ 001    10 May 2005 10:19:11 -0000    1.11
  @@ -46,6 +46,8 @@
   delivery_date_remove
   dns_again_means_nonexist = 
   dns_check_names_pattern = (?i)^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$
  +dns_csa_search_limit = 5
  +dns_csa_use_reverse
   dns_ipv4_lookup = 
   dns_retrans = 0s
   dns_retry = 0


  Index: 002
  ===================================================================
  RCS file: /home/cvs/exim/exim-test-orig/AutoTest/stdout/002,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- 002    3 May 2005 14:20:02 -0000    1.8
  +++ 002    10 May 2005 10:19:11 -0000    1.9
  @@ -46,6 +46,8 @@
   delivery_date_remove
   dns_again_means_nonexist = *.esri.com:jeni.com
   dns_check_names_pattern = ^.*$
  +dns_csa_search_limit = 3
  +no_dns_csa_use_reverse
   dns_ipv4_lookup = *
   dns_retrans = 0s
   dns_retry = 0


  Index: 082
  ===================================================================
  RCS file: /home/cvs/exim/exim-test-orig/AutoTest/stdout/082,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- 082    28 Apr 2005 13:29:27 -0000    1.11
  +++ 082    10 May 2005 10:19:11 -0000    1.12
  @@ -444,6 +444,9 @@
   > srv=_smtp._tcp.srv01.test.ex     0 0 25 ten-1.test.ex
   > srv=_smtp._tcp.nosmtp.test.ex    0 0 0 

>
  +> csa=csa1.test.ex           Y csa1.test.ex
  +> csa=csa2.test.ex           N csa2.test.ex
  +> 
   > # DNS lookups with multiple items

>
   > ten-1:ten2                 10.0.0.1


  Index: db.test.ex
  ===================================================================
  RCS file: /home/cvs/exim/exim-test-orig/DNSzones/db.test.ex,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- db.test.ex    22 Dec 2004 10:27:23 -0000    1.2
  +++ db.test.ex    10 May 2005 10:19:12 -0000    1.3
  @@ -8,7 +8,7 @@


              NS      xoanon.csi.cam.ac.uk.


-; $Cambridge: exim/exim-test-orig/DNSzones/db.test.ex,v 1.2 2004/12/22 10:27:23 ph10 Exp $
+; $Cambridge: exim/exim-test-orig/DNSzones/db.test.ex,v 1.3 2005/05/10 10:19:12 ph10 Exp $

; This is a testing zone file for use on xoanon.csi.cam.ac.uk when testing
; DNS handling in Exim. This is a fake zone of no real use. The zone name
@@ -320,6 +320,16 @@
_smtp._tcp.nosmtp SRV 0 0 0 .

   _smtp2._tcp.srv03   SRV  0 0 88 ten-4.test.ex.
  +
  +
  +; -------- With some for CSA testing plus their A records -------
  +
  +_client._smtp.csa1  SRV  1 2 0  csa1.test.ex.
  +_client._smtp.csa2  SRV  1 1 0  csa2.test.ex.
  +
  +csa1         A   10.9.8.7
  +csa2         A   10.9.8.8    
  +


; -------- A domain with a huge number of IP addresses -------
; Something like this was once actually seen in the wild, but it didn't