Cleanup redundant definition of PATH_MAX
[exim.git] / src / src / verify.c
index 6c228abbf55f9d6d7d5a97f1da46625b3c145595..f64057fd1fb6b657bf7440f3193d2fb38f508e2a 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with verifying things. The original code for callout
@@ -174,9 +174,7 @@ dbdata_callout_cache new_domain_record;
 dbdata_callout_cache_address new_address_record;
 host_item *host;
 time_t callout_start_time;
-#ifdef EXPERIMENTAL_INTERNATIONAL
-BOOL utf8_offered = FALSE;
-#endif
+uschar peer_offered = 0;
 
 new_domain_record.result = ccache_unknown;
 new_domain_record.postmaster_result = ccache_unknown;
@@ -458,7 +456,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
             && port == cutthrough.host.port
             )
            {
-           uschar * resp;
+           uschar * resp = NULL;
 
            /* Match!  Send the RCPT TO, append the addr, set done */
            done =
@@ -485,7 +483,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
            else
              {
              cancel_cutthrough_connection("recipient rejected");
-             if (errno == ETIMEDOUT)
+             if (!resp || errno == ETIMEDOUT)
                {
                HDEBUG(D_verify) debug_printf("SMTP timeout\n");
                }
@@ -542,6 +540,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
     uschar inbuffer[4096];
     uschar outbuffer[1024];
     uschar responsebuffer[4096];
+    uschar * size_str;
 
     clearflag(addr, af_verify_pmfail);  /* postmaster callout flag */
     clearflag(addr, af_verify_nsfail);  /* null sender callout flag */
@@ -687,7 +686,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       if (!(done= smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), '2', callout)))
         goto RESPONSE_FAILED;
 
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
       lookup_dnssec_authenticated = host->dnssec==DS_YES ? US"yes"
        : host->dnssec==DS_NO ? US"no" : NULL;
       if (event_raise(addr->transport->event_action,
@@ -711,7 +710,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 #ifdef SUPPORT_TLS
     if (smtps  &&  tls_out.active < 0) /* ssl-on-connect, first pass */
       {
-      tls_offered = TRUE;
+      peer_offered &= ~PEER_OFFERED_TLS;
       ob->tls_tempfail_tryclear = FALSE;
       }
     else                               /* all other cases */
@@ -730,27 +729,40 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
          goto RESPONSE_FAILED;
          }
 #ifdef SUPPORT_TLS
-        tls_offered = FALSE;
+       peer_offered &= ~PEER_OFFERED_TLS;
 #endif
         esmtp = FALSE;
         goto esmtp_retry;                      /* fallback to HELO */
         }
 
       /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
-#ifdef SUPPORT_TLS
-      if (esmtp && !suppress_tls &&  tls_out.active < 0)
-       {
-       if (regex_STARTTLS == NULL) regex_STARTTLS =
-         regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
 
-       tls_offered = pcre_exec(regex_STARTTLS, NULL, CS responsebuffer,
-                     Ustrlen(responsebuffer), 0, PCRE_EOPT, NULL, 0) >= 0;
-       }
-      else
-        tls_offered = FALSE;
+      peer_offered = esmtp
+       ? ehlo_response(responsebuffer, sizeof(responsebuffer),
+               (!suppress_tls && tls_out.active < 0 ? PEER_OFFERED_TLS : 0)
+             | 0       /* no IGNQ */
+             | 0       /* no PRDR */
+#ifdef SUPPORT_I18N
+             | (addr->prop.utf8_msg && !addr->prop.utf8_downcvt
+               ? PEER_OFFERED_UTF8 : 0)
 #endif
+             | 0       /* no DSN */
+             | 0       /* no PIPE */
+
+             /* only care about SIZE if we have size from inbound */
+             | (message_size > 0 && ob->size_addition >= 0
+               ? PEER_OFFERED_SIZE : 0)
+           )
+       : 0;
       }
 
+    size_str = peer_offered & PEER_OFFERED_SIZE
+      ? string_sprintf(" SIZE=%d", message_size + ob->size_addition) : US"";
+
+#ifdef SUPPORT_TLS
+    tls_offered = !!(peer_offered & PEER_OFFERED_TLS);
+#endif
+
     /* If TLS is available on this connection attempt to
     start up a TLS session, unless the host is in hosts_avoid_tls. If successful,
     send another EHLO - the server may give a different answer in secure mode. We
@@ -760,7 +772,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
     for error analysis. */
 
 #ifdef SUPPORT_TLS
-    if (  tls_offered
+    if (  peer_offered & PEER_OFFERED_TLS
        && verify_check_given_host(&ob->hosts_avoid_tls, host) != OK
        && verify_check_given_host(&ob->hosts_verify_avoid_tls, host) != OK
        )
@@ -811,7 +823,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
          if (rc == DEFER)
            {
            (void)close(inblock.sock);
-# ifdef EXPERIMENTAL_EVENT
+# ifndef DISABLE_EVENT
            (void) event_raise(addr->transport->event_action,
                                    US"tcp:close", NULL);
 # endif
@@ -875,8 +887,9 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         log_write(0, LOG_MAIN,
          "H=%s [%s]: a TLS session is required for this host, but %s",
           host->name, host->address,
-         tls_offered ? "an attempt to start TLS failed"
-                     : "the server did not offer TLS support");
+         peer_offered & PEER_OFFERED_TLS
+         ? "an attempt to start TLS failed"
+         : "the server did not offer TLS support");
         done= FALSE;
         goto TLS_FAILED;
         }
@@ -885,8 +898,6 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     done = TRUE; /* so far so good; have response to HELO */
 
-    /*XXX the EHLO response would be analyzed here for IGNOREQUOTA, SIZE, PIPELINING */
-
     /* For now, transport_filter by cutthrough-delivery is not supported */
     /* Need proper integration with the proper transport mechanism. */
     if (cutthrough.delivery)
@@ -924,20 +935,11 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         }
       }
 
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
     else if (  addr->prop.utf8_msg
            && !addr->prop.utf8_downcvt
-           && !(  esmtp
-               && (  regex_UTF8
-                  || ( (regex_UTF8 = regex_must_compile(
-                         US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE)),
-                     TRUE
-                  )  )
-               && (  (utf8_offered = pcre_exec(regex_UTF8, NULL,
-                           CS responsebuffer, Ustrlen(responsebuffer),
-                           0, PCRE_EOPT, NULL, 0) >= 0)
-                  || addr->prop.utf8_downcvt_maybe
-           )   )  )
+           && !(peer_offered & PEER_OFFERED_UTF8)
+           )
       {
       HDEBUG(D_acl|D_v) debug_printf("utf8 required but not offered\n");
       errno = ERRNO_UTF8_FWD;
@@ -945,7 +947,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       done = FALSE;
       }
     else if (  addr->prop.utf8_msg
-           && (addr->prop.utf8_downcvt || !utf8_offered)
+           && (addr->prop.utf8_downcvt || !(peer_offered & PEER_OFFERED_UTF8))
            && (setflag(addr, af_utf8_downcvt),
                from_address = string_address_utf8_to_alabel(from_address,
                                      &addr->message),
@@ -976,13 +978,13 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     /* Send the MAIL command */
         (smtp_write_command(&outblock, FALSE,
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
          addr->prop.utf8_msg && !addr->prop.utf8_downcvt
-         ? "MAIL FROM:<%s>%s SMTPUTF8\r\n"
+         ? "MAIL FROM:<%s>%s%s SMTPUTF8\r\n"
          :
 #endif
-           "MAIL FROM:<%s>%s\r\n",
-          from_address, responsebuffer) >= 0)
+           "MAIL FROM:<%s>%s%s\r\n",
+          from_address, responsebuffer, size_str) >= 0)
       )  &&
 
       smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
@@ -1022,7 +1024,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       {
       const uschar * rcpt_domain = addr->domain;
 
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
       uschar * errstr = NULL;
       if (  testflag(addr, af_utf8_downcvt)
         && (rcpt_domain = string_domain_utf8_to_alabel(rcpt_domain,
@@ -1084,7 +1086,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
               '2', callout) &&
 
             smtp_write_command(&outblock, FALSE,
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
              addr->prop.utf8_msg && !addr->prop.utf8_downcvt
              ? "MAIL FROM:<%s> SMTPUTF8\r\n"
              :
@@ -1103,7 +1105,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
            tls_close(FALSE, TRUE);
 #endif
            (void)close(inblock.sock);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
            (void) event_raise(addr->transport->event_action,
                              US"tcp:close", NULL);
 #endif
@@ -1124,7 +1126,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
        uschar * rcpt = transport_rcpt_address(addr,
               addr->transport ? addr->transport->rcpt_include_affixes : FALSE);
 
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        /*XXX should the conversion be moved into transport_rcpt_address() ? */
        uschar * dummy_errstr = NULL;
        if (  testflag(addr, af_utf8_downcvt)
@@ -1229,7 +1231,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         HDEBUG(D_verify) debug_printf("SMTP timeout\n");
         send_quit = FALSE;
         }
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
       else if (errno == ERRNO_UTF8_FWD)
        {
        extern int acl_where;   /* src/acl.c */
@@ -1312,7 +1314,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       tls_close(FALSE, TRUE);
 #endif
       (void)close(inblock.sock);
-#ifdef EXPERIMENTAL_EVENT
+#ifndef DISABLE_EVENT
       (void) event_raise(addr->transport->event_action, US"tcp:close", NULL);
 #endif
       }
@@ -1413,10 +1415,11 @@ return yield;
 /* Called after recipient-acl to get a cutthrough connection open when
    one was requested and a recipient-verify wasn't subsequently done.
 */
-void
+int
 open_cutthrough_connection( address_item * addr )
 {
 address_item addr2;
+int rc;
 
 /* Use a recipient-verify-callout to set up the cutthrough connection. */
 /* We must use a copy of the address for verification, because it might
@@ -1425,12 +1428,12 @@ get rewritten. */
 addr2 = *addr;
 HDEBUG(D_acl) debug_printf("----------- %s cutthrough setup ------------\n",
   rcpt_count > 1 ? "more" : "start");
-(void) verify_address(&addr2, NULL,
+rc= verify_address(&addr2, NULL,
        vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache,
        CUTTHROUGH_CMD_TIMEOUT, -1, -1,
        NULL, NULL, NULL);
 HDEBUG(D_acl) debug_printf("----------- end cutthrough setup ------------\n");
-return;
+return rc;
 }
 
 
@@ -3190,9 +3193,9 @@ if (iplookup)
   /* 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);
+  if (!(handle = search_open(filename, search_type, 0, NULL, 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;
@@ -3876,7 +3879,9 @@ Note: an address for testing DUL is 192.203.178.4
 Note: a domain for testing RFCI is example.tld.dsn.rfc-ignorant.org
 
 Arguments:
+  where        the acl type
   listptr      the domain/address/data list
+  log_msgptr   log message on error
 
 Returns:    OK      successful lookup (i.e. the address is on the list), or
                       lookup deferred after +include_unknown
@@ -3886,7 +3891,7 @@ Returns:    OK      successful lookup (i.e. the address is on the list), or
 */
 
 int
-verify_check_dnsbl(const uschar **listptr)
+verify_check_dnsbl(int where, const uschar ** listptr, uschar ** log_msgptr)
 {
 int sep = 0;
 int defer_return = FAIL;
@@ -3933,21 +3938,19 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
 
   /* See if there's explicit data to be looked up */
 
-  key = Ustrchr(domain, '/');
-  if (key != NULL) *key++ = 0;
+  if ((key = Ustrchr(domain, '/'))) *key++ = 0;
 
   /* See if there's a list of addresses supplied after the domain name. This is
   introduced by an = or a & character; if preceded by = we require all matches
   and if preceded by ! we invert the result. */
 
-  iplist = Ustrchr(domain, '=');
-  if (iplist == NULL)
+  if (!(iplist = Ustrchr(domain, '=')))
     {
     bitmask = TRUE;
     iplist = Ustrchr(domain, '&');
     }
 
-  if (iplist != NULL)                          /* Found either = or & */
+  if (iplist)                                 /* Found either = or & */
     {
     if (iplist > domain && iplist[-1] == '!')  /* Handle preceding ! */
       {
@@ -3966,6 +3969,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
       }
     }
 
+
   /* If there is a comma in the domain, it indicates that a second domain for
   looking up TXT records is provided, before the main domain. Otherwise we must
   set domain_txt == domain. */
@@ -4011,6 +4015,13 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
 
   if (key == NULL)
     {
+    if (where == ACL_WHERE_NOTSMTP_START || where == ACL_WHERE_NOTSMTP)
+      {
+      *log_msgptr = string_sprintf
+       ("cannot test auto-keyed dnslists condition in %s ACL",
+         acl_wherenames[where]);
+      return ERROR;
+      }
     if (sender_host_address == NULL) return FAIL;    /* can never match */
     if (revadd[0] == 0) invert_address(revadd, sender_host_address);
     rc = one_check_dnsbl(domain, domain_txt, sender_host_address, revadd,