tidying
[exim.git] / src / src / verify.c
index 2634e755275b92b28aeb49193391c8dad42e4155..8a4867b94e945c15a52d277df2ebedff39001eee 100644 (file)
@@ -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 SUPPORT_I18N
-BOOL utf8_offered = FALSE;
-#endif
+uschar peer_offered = 0;
 
 new_domain_record.result = ccache_unknown;
 new_domain_record.postmaster_result = ccache_unknown;
@@ -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 */
@@ -641,12 +640,14 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
       if (host->dnssec == DS_YES)
        {
-       if(  (  dane_required
-            || verify_check_given_host(&ob->hosts_try_dane, host) == OK
-            )
-         && (rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK
+       if(  dane_required
+         || verify_check_given_host(&ob->hosts_try_dane, host) == OK
          )
-         return rc;
+         {
+         if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required)) != OK)
+           return rc;
+         dane = TRUE;
+         }
        }
       else if (dane_required)
        {
@@ -711,7 +712,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 +731,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 +774,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
        )
@@ -780,8 +794,10 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       if (!smtps && !smtp_read_response(&inblock, buffer2, sizeof(buffer2), '2',
                        ob->command_timeout))
         {
-        if (errno != 0 || buffer2[0] == 0 ||
-               (buffer2[0] == '4' && !ob->tls_tempfail_tryclear))
+        if (  errno != 0
+          || buffer2[0] == 0
+          || buffer2[0] == '4' && !ob->tls_tempfail_tryclear
+          )
          {
          Ustrncpy(responsebuffer, buffer2, sizeof(responsebuffer));
          done= FALSE;
@@ -815,24 +831,10 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
            (void) event_raise(addr->transport->event_action,
                                    US"tcp:close", NULL);
 # endif
-# ifdef EXPERIMENTAL_DANE
-           if (dane)
-             {
-             if (!dane_required)
-               {
-               log_write(0, LOG_MAIN, "DANE attempt failed;"
-                 " trying CA-root TLS to %s [%s] (not in hosts_require_dane)",
-                 host->name, host->address);
-               dane = FALSE;
-               goto tls_negotiate;
-               }
-             }
-           else
-# endif
-             if (  ob->tls_tempfail_tryclear
-                && !smtps
-                && verify_check_given_host(&ob->hosts_require_tls, host) != OK
-                )
+           if (  ob->tls_tempfail_tryclear
+              && !smtps
+              && verify_check_given_host(&ob->hosts_require_tls, host) != OK
+              )
              {
              log_write(0, LOG_MAIN, "TLS session failure:"
                " delivering unencrypted to %s [%s] (not in hosts_require_tls)",
@@ -875,8 +877,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 +888,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)
@@ -927,17 +928,8 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 #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 +937,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),
@@ -978,11 +970,11 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         (smtp_write_command(&outblock, FALSE,
 #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),
@@ -1902,7 +1894,7 @@ if (address[0] == 0) return OK;
 
 /* Flip the legacy TLS-related variables over to the outbound set in case
 they're used in the context of a transport used by verification. Reset them
-at exit from this routine. */
+at exit from this routine (so no returns allowed from here on). */
 
 tls_modify_variables(&tls_out);
 
@@ -1911,6 +1903,10 @@ while verifying a sender address (a nice bit of self-reference there). */
 
 save_sender = sender_address;
 
+/* Observability variable for router/transport use */
+
+verify_mode = is_recipient ? US"R" : US"S";
+
 /* Update the address structure with the possibly qualified and rewritten
 address. Set it up as the starting address on the chain of new addresses. */
 
@@ -1926,7 +1922,7 @@ If an address generates more than one child, the loop is used only when
 full_info is set, and this can only be set locally. Remote enquiries just get
 information about the top level address, not anything that it generated. */
 
-while (addr_new != NULL)
+while (addr_new)
   {
   int rc;
   address_item *addr = addr_new;
@@ -1975,15 +1971,15 @@ while (addr_new != NULL)
 
   /* Just in case some router parameter refers to it. */
 
-  return_path = (addr->prop.errors_address != NULL)?
-    addr->prop.errors_address : sender_address;
+  return_path = addr->prop.errors_address
+    addr->prop.errors_address : sender_address;
 
   /* Split the address into domain and local part, handling the %-hack if
   necessary, and then route it. While routing a sender address, set
   $sender_address to <> because that is what it will be if we were trying to
   send a bounce to the sender. */
 
-  if (routed != NULL) *routed = FALSE;
+  if (routed) *routed = FALSE;
   if ((rc = deliver_split_address(addr)) == OK)
     {
     if (!is_recipient) sender_address = null_sender;
@@ -2000,11 +1996,11 @@ while (addr_new != NULL)
 
   if (rc == OK)
     {
-    if (routed != NULL) *routed = TRUE;
+    if (routed) *routed = TRUE;
     if (callout > 0)
       {
-      host_item *host_list = addr->host_list;
       transport_instance * tp;
+      host_item * host_list = addr->host_list;
 
       /* Make up some data for use in the case where there is no remote
       transport. */
@@ -2034,7 +2030,7 @@ while (addr_new != NULL)
         transport is configured to override the router's hosts, we must build a
         host list of the transport's hosts, and find the IP addresses */
 
-        if (tf.hosts != NULL && (host_list == NULL || tf.hosts_override))
+        if (tf.hosts && (!host_list || tf.hosts_override))
           {
           uschar *s;
           const uschar *save_deliver_domain = deliver_domain;
@@ -2048,7 +2044,7 @@ while (addr_new != NULL)
           deliver_domain = save_deliver_domain;
           deliver_localpart = save_deliver_localpart;
 
-          if (s == NULL)
+          if (!s)
             {
             log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
               "\"%s\" in %s transport for callout: %s", tf.hosts,
@@ -2070,7 +2066,7 @@ while (addr_new != NULL)
             if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
             if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
 
-            for (host = host_list; host != NULL; host = nexthost)
+            for (host = host_list; host; host = nexthost)
               {
               nexthost = host->next;
               if (tf.gethostbyname ||
@@ -2097,7 +2093,7 @@ while (addr_new != NULL)
       /* 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)
+      if (host_list)
         {
         HDEBUG(D_verify) debug_printf("Attempting full verification using callout\n");
         if (host_checking && !host_checking_callout)
@@ -2111,10 +2107,8 @@ while (addr_new != NULL)
 #ifdef SUPPORT_TLS
          deliver_set_expansions(addr);
 #endif
-         verify_mode = is_recipient ? US"R" : US"S";
           rc = do_callout(addr, host_list, &tf, callout, callout_overall,
             callout_connect, options, se_mailfrom, pm_mailfrom);
-         verify_mode = NULL;
           }
         }
       else
@@ -2140,24 +2134,24 @@ while (addr_new != NULL)
   if (rc == FAIL)
     {
     allok = FALSE;
-    if (f != NULL)
+    if (f)
       {
       address_item *p = addr->parent;
 
       respond_printf(f, "%s%s %s", ko_prefix,
-        full_info? addr->address : address,
-        address_test_mode? "is undeliverable" : "failed to verify");
+        full_info ? addr->address : address,
+        address_test_mode ? "is undeliverable" : "failed to verify");
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
           respond_printf(f, ": %s", strerror(addr->basic_errno));
-        if (addr->message != NULL)
+        if (addr->message)
           respond_printf(f, ": %s", addr->message);
         }
 
       /* Show parents iff doing full info */
 
-      if (full_info) while (p != NULL)
+      if (full_info) while (p)
         {
         respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
@@ -2167,11 +2161,11 @@ while (addr_new != NULL)
     cancel_cutthrough_connection("routing hard fail");
 
     if (!full_info)
-    {
+      {
       yield = copy_error(vaddr, addr, FAIL);
       goto out;
-    }
-    else yield = FAIL;
+      }
+    yield = FAIL;
     }
 
   /* Soft failure */
@@ -2179,7 +2173,7 @@ while (addr_new != NULL)
   else if (rc == DEFER)
     {
     allok = FALSE;
-    if (f != NULL)
+    if (f)
       {
       address_item *p = addr->parent;
       respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
@@ -2188,7 +2182,7 @@ while (addr_new != NULL)
         {
         if (addr->basic_errno > 0)
           respond_printf(f, ": %s", strerror(addr->basic_errno));
-        if (addr->message != NULL)
+        if (addr->message)
           respond_printf(f, ": %s", addr->message);
         else if (addr->basic_errno <= 0)
           respond_printf(f, ": unknown error");
@@ -2196,7 +2190,7 @@ while (addr_new != NULL)
 
       /* Show parents iff doing full info */
 
-      if (full_info) while (p != NULL)
+      if (full_info) while (p)
         {
         respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
@@ -2210,7 +2204,7 @@ while (addr_new != NULL)
       yield = copy_error(vaddr, addr, DEFER);
       goto out;
       }
-    else if (yield == OK) yield = DEFER;
+    if (yield == OK) yield = DEFER;
     }
 
   /* If we are handling EXPN, we do not want to continue to route beyond
@@ -2219,20 +2213,20 @@ while (addr_new != NULL)
   else if (expn)
     {
     uschar *ok_prefix = US"250-";
-    if (addr_new == NULL)
-      {
-      if (addr_local == NULL && addr_remote == NULL)
+
+    if (!addr_new)
+      if (!addr_local && !addr_remote)
         respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
       else
         respond_printf(f, "250 <%s>\r\n", address);
-      }
-    else while (addr_new != NULL)
+
+    else do
       {
       address_item *addr2 = addr_new;
       addr_new = addr2->next;
-      if (addr_new == NULL) ok_prefix = US"250 ";
+      if (!addr_new) ok_prefix = US"250 ";
       respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
-      }
+      } while (addr_new);
     yield = OK;
     goto out;
     }
@@ -2254,16 +2248,19 @@ while (addr_new != NULL)
     just a single new address as a special case, and continues on to verify the
     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 */
-         ||                              /* OR */
-         (addr_new != NULL &&            /* At least one new address AND */
-          success_on_redirect)))         /* success_on_redirect is set */
+    if (  !full_info                   /* Stop if short info wanted AND */
+       && (  (  !addr_new              /* No new address OR */
+             || addr_new->next         /* More than one new address OR */
+            || testflag(addr_new, af_pfr)      /* New address is pfr */
+            )
+          ||                           /* OR */
+             (  addr_new               /* 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");
+      if (f) fprintf(f, "%s %s\n",
+        address, address_test_mode ? "is deliverable" : "verified");
 
       /* If we have carried on to verify a child address, we want the value
       of $address_data to be that of the child */
@@ -2284,7 +2281,7 @@ If there are no local and no remote addresses, and there were no pipes, files,
 or autoreplies, and there were no errors or deferments, the message is to be
 discarded, usually because of the use of :blackhole: in an alias file. */
 
-if (allok && addr_local == NULL && addr_remote == NULL)
+if (allok && !addr_local && !addr_remote)
   {
   fprintf(f, "mail to %s is discarded\n", address);
   goto out;
@@ -2365,6 +2362,7 @@ for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
 the -bv or -bt case). */
 
 out:
+verify_mode = NULL;
 tls_modify_variables(&tls_in);
 
 return yield;