Multi-recipient cutthrough delivery. Bug 1542
[exim.git] / src / src / acl.c
index 6e635fbf190c4a557f657087b4698ee673e57364..06c1c494c09f71579548c6894a7d9629e6eaf961 100644 (file)
@@ -1550,7 +1550,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
   assertion: legitimate SMTP clients are all explicitly authorized with CSA
   SRV records of their own. */
 
-  if (found != domain)
+  if (Ustrcmp(found, domain) != 0)
     {
     if (port & 1)
       return t->data.val = CSA_FAIL_EXPLICIT;
@@ -2352,7 +2352,10 @@ rate measurement as opposed to rate limiting. */
 
 sender_rate_limit = string_nextinlist(&arg, &sep, NULL, 0);
 if (sender_rate_limit == NULL)
+  {
   limit = -1.0;
+  ss = NULL;   /* compiler quietening */
+  }
 else
   {
   limit = Ustrtod(sender_rate_limit, &ss);
@@ -2979,7 +2982,7 @@ uschar *debug_opts = NULL;
 uschar *p = NULL;
 int rc = OK;
 #ifdef WITH_CONTENT_SCAN
-int sep = '/';
+int sep = -'/';
 #endif
 
 for (; cb != NULL; cb = cb->next)
@@ -3351,19 +3354,27 @@ for (; cb != NULL; cb = cb->next)
       break;
 
       case CONTROL_CUTTHROUGH_DELIVERY:
-      if (deliver_freeze)
-        *log_msgptr = US"frozen";
-      else if (queue_only_policy)
-        *log_msgptr = US"queue-only";
-      else if (fake_response == FAIL)
-        *log_msgptr = US"fakereject";
+      if (prdr_requested)
+       /* Too hard to think about for now.  We might in future cutthrough
+       the case where both sides handle prdr and this-node prdr acl
+       is "accept" */
+        *log_msgptr = string_sprintf(US"PRDR on %s reception\n", arg);
       else
        {
-       cutthrough_delivery = TRUE;
-       break;
+       if (deliver_freeze)
+         *log_msgptr = US"frozen";
+       else if (queue_only_policy)
+         *log_msgptr = US"queue-only";
+       else if (fake_response == FAIL)
+         *log_msgptr = US"fakereject";
+       else
+         {
+         if (rcpt_count == 1) cutthrough.delivery = TRUE;
+         break;
+         }
+       *log_msgptr = string_sprintf("\"control=%s\" on %s item",
+                                     arg, *log_msgptr);
        }
-      *log_msgptr = string_sprintf("\"control=%s\" on %s item",
-                                   arg, *log_msgptr);
       return ERROR;
       }
     break;
@@ -3580,21 +3591,28 @@ for (; cb != NULL; cb = cb->next)
     break;
 
     #ifdef WITH_CONTENT_SCAN
-    case ACLC_MALWARE:
+    case ACLC_MALWARE:                 /* Run the malware backend. */
       {
       /* Separate the regular expression and any optional parameters. */
       uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size);
-      /* Run the malware backend. */
-      rc = malware(&ss);
-      /* Modify return code based upon the existance of options. */
-      while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
-            != NULL) {
-        if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
-          {
-          /* FAIL so that the message is passed to the next ACL */
-          rc = FAIL;
-          }
-        }
+      uschar *opt;
+      BOOL defer_ok = FALSE;
+      int timeout = 0;
+
+      while ((opt = string_nextinlist(&arg, &sep, NULL, 0)))
+        if (strcmpic(opt, US"defer_ok") == 0)
+         defer_ok = TRUE;
+       else if (  strncmpic(opt, US"tmo=", 4) == 0
+               && (timeout = readconf_readtime(opt+4, '\0', FALSE)) < 0
+               )
+         {
+         *log_msgptr = string_sprintf("bad timeout value in '%s'", opt);
+         return ERROR;
+         }
+
+      rc = malware(ss, timeout);
+      if (rc == DEFER && defer_ok)
+       rc = FAIL;      /* FAIL so that the message is passed to the next ACL */
       }
     break;
 
@@ -4129,7 +4147,11 @@ while (acl != NULL)
   switch(acl->verb)
     {
     case ACL_ACCEPT:
-    if (cond == OK || cond == DISCARD) return cond;
+    if (cond == OK || cond == DISCARD)
+      {
+      HDEBUG(D_acl) debug_printf("end of %s: ACCEPT\n", acl_name);
+      return cond;
+      }
     if (endpass_seen)
       {
       HDEBUG(D_acl) debug_printf("accept: endpass encountered - denying access\n");
@@ -4140,17 +4162,26 @@ while (acl != NULL)
     case ACL_DEFER:
     if (cond == OK)
       {
+      HDEBUG(D_acl) debug_printf("end of %s: DEFER\n", acl_name);
       acl_temp_details = TRUE;
       return DEFER;
       }
     break;
 
     case ACL_DENY:
-    if (cond == OK) return FAIL;
+    if (cond == OK)
+      {
+      HDEBUG(D_acl) debug_printf("end of %s: DENY\n", acl_name);
+      return FAIL;
+      }
     break;
 
     case ACL_DISCARD:
-    if (cond == OK || cond == DISCARD) return DISCARD;
+    if (cond == OK || cond == DISCARD)
+      {
+      HDEBUG(D_acl) debug_printf("end of %s: DISCARD\n", acl_name);
+      return DISCARD;
+      }
     if (endpass_seen)
       {
       HDEBUG(D_acl) debug_printf("discard: endpass encountered - denying access\n");
@@ -4159,11 +4190,19 @@ while (acl != NULL)
     break;
 
     case ACL_DROP:
-    if (cond == OK) return FAIL_DROP;
+    if (cond == OK)
+      {
+      HDEBUG(D_acl) debug_printf("end of %s: DROP\n", acl_name);
+      return FAIL_DROP;
+      }
     break;
 
     case ACL_REQUIRE:
-    if (cond != OK) return cond;
+    if (cond != OK)
+      {
+      HDEBUG(D_acl) debug_printf("end of %s: not OK\n", acl_name);
+      return cond;
+      }
     break;
 
     case ACL_WARN:
@@ -4320,9 +4359,9 @@ ratelimiters_cmd = NULL;
 log_reject_target = LOG_MAIN|LOG_REJECT;
 
 #ifndef DISABLE_PRDR
-if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR )
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR)
 #else
-if (where == ACL_WHERE_RCPT )
+if (where == ACL_WHERE_RCPT)
 #endif
   {
   adb = address_defaults;
@@ -4366,9 +4405,7 @@ case ACL_WHERE_RCPT:
 #ifndef DISABLE_PRDR
 case ACL_WHERE_PRDR:
 #endif
-  if( rcpt_count > 1 )
-    cancel_cutthrough_connection("more than one recipient");
-  else if (rc == OK  &&  cutthrough_delivery  &&  cutthrough_fd < 0)
+  if (rc == OK  &&  cutthrough.delivery  && rcpt_count > cutthrough.nrcpt)
     open_cutthrough_connection(addr);
   break;