CVE-2020-28015+28021: New-line injection into spool header file
[exim.git] / src / src / dns.c
index c68698786c3240f648a439a6740329d666689853..490eb883d3d53eaf85f33063fd2e7bf148e37c43 100644 (file)
@@ -691,9 +691,11 @@ packet length has been lost inside libresolv, so we have to guess a
 replacement value. (The only way to fix this properly would be to
 re-implement res_search() and res_query() so that they don't muddle their
 success and packet length return values.) For added safety we only reset
-the packet length if the packet header looks plausible. */
+the packet length if the packet header looks plausible.
 
-static void
+Return TRUE iff it seemed ok */
+
+static BOOL
 fake_dnsa_len_for_fail(dns_answer * dnsa, int type)
 {
 const HEADER * h = (const HEADER *)dnsa->answer;
@@ -710,7 +712,11 @@ if (  h->qr == 1                           /* a response */
   DEBUG(D_dns) debug_printf("faking res_search(%s) response length as %d\n",
     dns_text_type(type), (int)sizeof(dnsa->answer));
   dnsa->answerlen = sizeof(dnsa->answer);
+  return TRUE;
   }
+DEBUG(D_dns) debug_printf("DNS: couldn't fake dnsa len\n");
+/* Maybe we should just do a second lookup for an SOA? */
+return FALSE;
 }
 
 
@@ -724,37 +730,37 @@ dns_expire_from_soa(dns_answer * dnsa, int type)
 {
 dns_scan dnss;
 
-fake_dnsa_len_for_fail(dnsa, type);
+if (fake_dnsa_len_for_fail(dnsa, type))
+  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
+       rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
+      ) if (rr->type == T_SOA)
+    {
+    const uschar * p = rr->data;
+    uschar discard_buf[256];
+    int len;
+    unsigned long ttl;
+
+    /* Skip the mname & rname strings */
+
+    if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
+       p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
+      break;
+    p += len;
+    if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
+       p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
+      break;
+    p += len;
+
+    /* Skip the SOA serial, refresh, retry & expire.  Grab the TTL */
+
+    if (p > dnsa->answer + dnsa->answerlen - 5 * INT32SZ)
+      break;
+    p += 4 * INT32SZ;
+    GETLONG(ttl, p);
+
+    return time(NULL) + ttl;
+    }
 
-for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
-     rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
-    ) if (rr->type == T_SOA)
-  {
-  const uschar * p = rr->data;
-  uschar discard_buf[256];
-  int len;
-  unsigned long ttl;
-
-  /* Skip the mname & rname strings */
-
-  if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
-      p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
-    break;
-  p += len;
-  if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
-      p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
-    break;
-  p += len;
-
-  /* Skip the SOA serial, refresh, retry & expire.  Grab the TTL */
-
-  if (p > dnsa->answer + dnsa->answerlen - 5 * INT32SZ)
-    break;
-  p += 4 * INT32SZ;
-  GETLONG(ttl, p);
-
-  return time(NULL) + ttl;
-  }
 DEBUG(D_dns) debug_printf("DNS: no SOA record found for neg-TTL\n");
 return 0;
 }
@@ -1199,18 +1205,7 @@ switch (type)
     If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
     the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
 
-    if (rc == DNS_NOMATCH)
-      {
-      fake_dnsa_len_for_fail(dnsa, T_CSA);
-
-      for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
-          rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
-         )
-       if (rr->type != T_SOA) continue;
-       else if (strcmpic(rr->name, US"") == 0 ||
-                strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
-       else break;
-      }
+    if (rc == DNS_NOMATCH) return DNS_NOMATCH;
 
     for (i = 0; i < limit; i++)
       {