DNS: explicit alloc/free of workspace
[exim.git] / src / src / acl.c
index 2a52ce7b25bb00bc2fae9fcd3a53efa5cad04219..2f20821c2ae4dabb086a597a126787ec2d86c3dd 100644 (file)
@@ -1186,8 +1186,6 @@ acl_verify_reverse(uschar **user_msgptr, uschar **log_msgptr)
 {
 int rc;
 
-user_msgptr = user_msgptr;  /* stop compiler warning */
-
 /* Previous success */
 
 if (sender_host_name != NULL) return OK;
@@ -1315,11 +1313,12 @@ acl_verify_csa(const uschar *domain)
 tree_node *t;
 const uschar *found;
 int priority, weight, port;
-dns_answer * dnsa = store_get_dns_answer();
+dns_answer * dnsa;
 dns_scan dnss;
 dns_record *rr;
-int rc, type;
-uschar target[256];
+int rc, type, yield;
+#define TARGET_SIZE 256
+uschar * target = store_get(TARGET_SIZE, TRUE);
 
 /* 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
@@ -1327,8 +1326,8 @@ 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 (!domain) domain = sender_host_address;
+if (!sender_host_address) 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
@@ -1358,8 +1357,8 @@ 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;
+if ((t = tree_search(csa_cache, domain)))
+  return t->data.val;
 
 t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), is_tainted(domain));
 Ustrcpy(t->name, domain);
@@ -1368,23 +1367,26 @@ Ustrcpy(t->name, domain);
 /* Now we are ready to do the actual DNS lookup(s). */
 
 found = domain;
+dnsa = store_get_dns_answer();
 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;
+    yield = CSA_DEFER_SRV;
+    goto out;
 
   /* If we found nothing, the client's authorization is unknown. */
 
   case DNS_NOMATCH:
   case DNS_NODATA:
-  return t->data.val = CSA_UNKNOWN;
+    yield = CSA_UNKNOWN;
+    goto out;
 
   /* We got something! Go on to look at the reply in more detail. */
 
   case DNS_SUCCEED:
-  break;
+    break;
   }
 
 /* Scan the reply for well-formed CSA SRV records. */
@@ -1415,7 +1417,10 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
   SRV records of their own. */
 
   if (Ustrcmp(found, domain) != 0)
-    return t->data.val = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN;
+    {
+    yield = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN;
+    goto out;
+    }
 
   /* 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
@@ -1423,7 +1428,11 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
   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)
+    {
+    yield = CSA_FAIL_DOMAIN;
+    goto out;
+    }
 
   if (weight > 2) continue;
 
@@ -1432,7 +1441,7 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
   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));
+    (DN_EXPAND_ARG4_TYPE)target, TARGET_SIZE);
 
   DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target);
 
@@ -1441,7 +1450,11 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
 
 /* If we didn't break the loop then no appropriate records were found. */
 
-if (!rr) return t->data.val = CSA_UNKNOWN;
+if (!rr)
+  {
+  yield = CSA_UNKNOWN;
+  goto out;
+  }
 
 /* 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
@@ -1449,7 +1462,11 @@ 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;
+if (Ustrcmp(target, "") == 0)
+  {
+  yield = CSA_FAIL_NOADDR;
+  goto out;
+  }
 
 /* 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.
@@ -1457,7 +1474,11 @@ 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;
+if (rc != CSA_FAIL_NOADDR)
+  {
+  yield = rc;
+  goto out;
+  }
 
 /* The DNS lookup type corresponds to the IP version used by the client. */
 
@@ -1475,13 +1496,18 @@ switch (dns_lookup(dnsa, target, type, NULL))
   /* If something bad happened (most commonly DNS_AGAIN), defer. */
 
   default:
-    return t->data.val = CSA_DEFER_ADDR;
+    yield = CSA_DEFER_ADDR;
+    break;
 
   /* 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;
+    if (rc != CSA_FAIL_NOADDR)
+      {
+      yield = rc;
+      break;
+      }
     /* else fall through */
 
   /* If the target has no IP addresses, the client cannot have an authorized
@@ -1490,8 +1516,14 @@ switch (dns_lookup(dnsa, target, type, NULL))
 
   case DNS_NOMATCH:
   case DNS_NODATA:
-    return t->data.val = CSA_FAIL_NOADDR;
+    yield = CSA_FAIL_NOADDR;
+    break;
   }
+
+out:
+
+store_free_dns_answer(dnsa);
+return t->data.val = yield;
 }
 
 
@@ -1517,14 +1549,14 @@ static verify_type_t verify_type_list[] = {
     { US"certificate",         VERIFY_CERT,            (unsigned)~0,   TRUE,  0 },
     { US"helo",                        VERIFY_HELO,            (unsigned)~0,   TRUE,  0 },
     { US"csa",                 VERIFY_CSA,             (unsigned)~0,   FALSE, 0 },
-    { US"header_syntax",       VERIFY_HDR_SYNTAX,      ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 },
-    { US"not_blind",           VERIFY_NOT_BLIND,       ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 },
-    { US"header_sender",       VERIFY_HDR_SNDR,        ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 },
+    { US"header_syntax",       VERIFY_HDR_SYNTAX,      ACL_BITS_HAVEDATA, TRUE, 0 },
+    { US"not_blind",           VERIFY_NOT_BLIND,       ACL_BITS_HAVEDATA, FALSE, 0 },
+    { US"header_sender",       VERIFY_HDR_SNDR,        ACL_BITS_HAVEDATA, FALSE, 0 },
     { US"sender",              VERIFY_SNDR,            ACL_BIT_MAIL | ACL_BIT_RCPT
                        | ACL_BIT_PREDATA | ACL_BIT_DATA | ACL_BIT_NOTSMTP,
                                                                                FALSE, 6 },
     { US"recipient",           VERIFY_RCPT,            ACL_BIT_RCPT,   FALSE, 0 },
-    { US"header_names_ascii",  VERIFY_HDR_NAMES_ASCII, ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 },
+    { US"header_names_ascii",  VERIFY_HDR_NAMES_ASCII, ACL_BITS_HAVEDATA, TRUE, 0 },
 #ifdef EXPERIMENTAL_ARC
     { US"arc",                 VERIFY_ARC,             ACL_BIT_DATA,   FALSE , 0 },
 #endif
@@ -1789,7 +1821,7 @@ switch(vp->value)
 /* Remaining items are optional; they apply to sender and recipient
 verification, including "header sender" verification. */
 
-while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+while ((ss = string_nextinlist(&list, &sep, NULL, 0)))
   {
   if (strcmpic(ss, US"defer_ok") == 0) defer_ok = TRUE;
   else if (strcmpic(ss, US"no_details") == 0) no_details = TRUE;
@@ -1946,7 +1978,8 @@ if (quota)
       {
       if (!*user_msgptr && *log_msgptr)
         *user_msgptr = string_sprintf("Rejected after %s: %s",
-           smtp_names[smtp_connection_had[smtp_ch_index-1]], *log_msgptr);
+           smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]],
+           *log_msgptr);
       if (rc == DEFER) f.acl_temp_details = TRUE;
       }
     }
@@ -3270,8 +3303,7 @@ for (; cb; cb = cb->next)
              {
              const uschar *pp = p + 6;
              while (*pp) pp++;
-             submission_name = string_copy(parse_fix_phrase(p+6, pp-p-6,
-               big_buffer, big_buffer_size));
+             submission_name = parse_fix_phrase(p+6, pp-p-6);
              p = pp;
              }
            else break;
@@ -3335,37 +3367,41 @@ for (; cb; cb = cb->next)
            the case where both sides handle prdr and this-node prdr acl
            is "accept" */
            ignored = US"PRDR active";
+         else if (f.deliver_freeze)
+           ignored = US"frozen";
+         else if (f.queue_only_policy)
+           ignored = US"queue-only";
+         else if (fake_response == FAIL)
+           ignored = US"fakereject";
+         else if (rcpt_count != 1)
+           ignored = US"nonfirst rcpt";
+         else if (cutthrough.delivery)
+           ignored = US"repeated";
+         else if (cutthrough.callout_hold_only)
+           {
+           DEBUG(D_acl)
+             debug_printf_indent(" cutthrough request upgrades callout hold\n");
+           cutthrough.callout_hold_only = FALSE;
+           cutthrough.delivery = TRUE; /* control accepted */
+           }
          else
            {
-           if (f.deliver_freeze)
-             ignored = US"frozen";
-           else if (f.queue_only_policy)
-             ignored = US"queue-only";
-           else if (fake_response == FAIL)
-             ignored = US"fakereject";
-           else
+           cutthrough.delivery = TRUE; /* control accepted */
+           while (*p == '/')
              {
-             if (rcpt_count == 1)
+             const uschar * pp = p+1;
+             if (Ustrncmp(pp, "defer=", 6) == 0)
                {
-               cutthrough.delivery = TRUE;     /* control accepted */
-               while (*p == '/')
-                 {
-                 const uschar * pp = p+1;
-                 if (Ustrncmp(pp, "defer=", 6) == 0)
-                   {
-                   pp += 6;
-                   if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE;
-                   /* else if (Ustrncmp(pp, "spool") == 0) ;   default */
-                   }
-                 else
-                   while (*pp && *pp != '/') pp++;
-                 p = pp;
-                 }
+               pp += 6;
+               if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE;
+               /* else if (Ustrncmp(pp, "spool") == 0) ;       default */
                }
              else
-               ignored = US"nonfirst rcpt";
+               while (*pp && *pp != '/') pp++;
+             p = pp;
              }
            }
+
          DEBUG(D_acl) if (ignored)
            debug_printf(" cutthrough request ignored on %s item\n", ignored);
          }
@@ -3506,14 +3542,14 @@ for (; cb; cb = cb->next)
     case ACLC_DKIM_SIGNER:
     if (dkim_cur_signer)
       rc = match_isinlist(dkim_cur_signer,
-                          &arg,0,NULL,NULL,MCL_STRING,TRUE,NULL);
+                          &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
     else
       rc = FAIL;
     break;
 
     case ACLC_DKIM_STATUS:
     rc = match_isinlist(dkim_verify_status,
-                        &arg,0,NULL,NULL,MCL_STRING,TRUE,NULL);
+                        &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
     break;
     #endif
 
@@ -3525,7 +3561,7 @@ for (; cb; cb = cb->next)
     /* used long way of dmarc_exim_expand_query() in case we need more
      * view into the process in the future. */
     rc = match_isinlist(dmarc_exim_expand_query(DMARC_VERIFY_STATUS),
-                        &arg,0,NULL,NULL,MCL_STRING,TRUE,NULL);
+                        &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
     break;
 #endif
 
@@ -4541,7 +4577,8 @@ switch (where)
     /* Drop cutthrough conns, and drop heldopen verify conns if
     the previous was not DATA */
     {
-    uschar prev = smtp_connection_had[smtp_ch_index-2];
+    uschar prev =
+      smtp_connection_had[SMTP_HBUFF_PREV(SMTP_HBUFF_PREV(smtp_ch_index))];
     BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT);
 
     cancel_cutthrough_connection(dropverify, US"quit or conndrop");