Support /defer_ok on verify=reverse_host_lookup. Bug 344
[exim.git] / src / src / acl.c
index fe1e254bdc4e0532ac7ee34d6265692891315567..f0716e0168693adeeab61e8c2f25a5eb8d7fa009 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;
@@ -1662,7 +1662,7 @@ typedef struct {
   unsigned alt_opt_sep;                /* >0 Non-/ option separator (custom parser) */
   } verify_type_t;
 static verify_type_t verify_type_list[] = {
-    { US"reverse_host_lookup", VERIFY_REV_HOST_LKUP,   ~0,     TRUE, 0 },
+    { US"reverse_host_lookup", VERIFY_REV_HOST_LKUP,   ~0,     FALSE, 0 },
     { US"certificate",         VERIFY_CERT,            ~0,     TRUE, 0 },
     { US"helo",                        VERIFY_HELO,            ~0,     TRUE, 0 },
     { US"csa",                 VERIFY_CSA,             ~0,     FALSE, 0 },
@@ -1783,7 +1783,11 @@ switch(vp->value)
   {
   case VERIFY_REV_HOST_LKUP:
     if (sender_host_address == NULL) return OK;
-    return acl_verify_reverse(user_msgptr, log_msgptr);
+    if ((rc = acl_verify_reverse(user_msgptr, log_msgptr)) == DEFER)
+      while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+       if (strcmpic(ss, US"defer_ok") == 0)
+         return OK;
+    return rc;
 
   case VERIFY_CERT:
     /* TLS certificate verification is done at STARTTLS time; here we just
@@ -2352,7 +2356,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 +2986,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 +3358,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 +3595,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;
 
@@ -4341,9 +4363,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;
@@ -4387,9 +4409,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;