[exim-cvs] Lookups: Fix dnsdb lookup of multi-chunk TXT. Bu…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] Lookups: Fix dnsdb lookup of multi-chunk TXT. Bug 3054
Gitweb: https://git.exim.org/exim.git/commitdiff/79670d3c32ccb37fe06f25d8192943b58606a32a
Commit:     79670d3c32ccb37fe06f25d8192943b58606a32a
Parent:     9643095d7cae6866b716d361a45c9a95f605040c
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Fri Nov 17 16:55:17 2023 +0000
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Fri Nov 17 16:55:17 2023 +0000


    Lookups: Fix dnsdb lookup of multi-chunk TXT.  Bug 3054


    Broken=by: f6b1f8e7d642
---
 doc/doc-txt/ChangeLog        |  6 +++++-
 src/src/dns.c                |  4 +++-
 src/src/lookups/dnsdb.c      | 45 +++++++++++++++++++-------------------------
 test/dnszones-src/db.test.ex |  1 +
 test/scripts/2200-dnsdb/2200 |  1 +
 test/src/fakens.c            |  1 +
 test/stdout/2200             |  1 +
 7 files changed, 31 insertions(+), 28 deletions(-)


diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 9d23e8db2..1663f8552 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -24,13 +24,17 @@ JH/04 Bug 3039: Fix handling of of an empty log_reject_target, with
       a connection_reject log_selector, under tls_on_connect.  Previously
       with this combination, when the connect ACL rejected, a spurious
       paniclog entry was made.
-JH/04 Fix TLS resumption for TLS-on-connect.  This was broken by the advent
+
+JH/05 Fix TLS resumption for TLS-on-connect.  This was broken by the advent
       of loadbalancer-detection for resumption, in 4.96 - which tries to
       use the EHLO response. SMTPS does not have one at the time it is starting
       TLS.  Change the default for the smtp transport host_name_extract option
       to be a static string, for TLS-on-connect cases; meaning that resumption
       will always be attempted (unless deliberately overriden).


+JH/06 Bug 3054: Fix dnsdb lookup for a TXT record with multiple chunks.  This
+      was broken by hardening introduced for Bug 3033.
+



Exim version 4.97
diff --git a/src/src/dns.c b/src/src/dns.c
index a652dcd31..74c5a58c5 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -431,7 +431,9 @@ namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr,
if (namelen < 0) goto null_return;

/* Move the pointer past the name and fill in the rest of the data structure
-from the following bytes. */
+from the following bytes. We seem to be assuming here that the RR blob passed
+to us by the resolver library is the same as that defined for an RR by RFC 1035
+section 3.2.1 */

 TRACE trace = "R-name";
 if (dnss_inc_aptr(dnsa, dnss, namelen)) goto null_return;
diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c
index ff51dec23..8288896ca 100644
--- a/src/src/lookups/dnsdb.c
+++ b/src/src/lookups/dnsdb.c
@@ -387,38 +387,31 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
         }


       /* Other kinds of record just have one piece of data each, but there may be
-      several of them, of course. */
+      several of them, of course.  TXT & SPF can have data in multiple chunks. */


       if (yield->ptr) yield = string_catn(yield, outsep, 1);


       if (type == T_TXT || type == T_SPF)
-        {
-        if (!outsep2)            /* output only the first item of data */
+    for (unsigned data_offset = 0; data_offset + 1 < rr->size; )
       {
-      uschar n = (rr->data)[0];
-      /* size byte + data bytes must not excced the RRs length */
-      if (n + 1 <= rr->size)
-        yield = string_catn(yield, US (rr->data+1), n);
+      uschar chunk_len = (rr->data)[data_offset];
+      int remain;
+
+      if (outsep2 && *outsep2 && data_offset != 0)
+        yield = string_catn(yield, outsep2, 1);
+
+      /* Apparently there are resolvers that do not check RRs before passing
+      them on, and glibc fails to do so.  So every application must...
+      Check for chunk len exceeding RR */
+
+      remain = rr->size - ++data_offset;
+      if (chunk_len > remain)
+        chunk_len = remain;
+      yield = string_catn(yield, US ((rr->data) + data_offset), chunk_len);
+      data_offset += chunk_len;
+
+      if (!outsep2) break;        /* output only the first chunk of the RR */
       }
-        else
-          for (unsigned data_offset = 0; data_offset < rr->size; )
-            {
-            uschar chunk_len = (rr->data)[data_offset];
-        int remain = rr->size - data_offset;
-
-        /* Apparently there are resolvers that do not check RRs before passing
-        them on, and glibc fails to do so.  So every application must...
-        Check for chunk len exceeding RR */
-
-        if (chunk_len > remain)
-          chunk_len = remain;
-
-            if (*outsep2  && data_offset != 0)
-              yield = string_catn(yield, outsep2, 1);
-            yield = string_catn(yield, US ((rr->data) + ++data_offset), --chunk_len);
-            data_offset += chunk_len;
-            }
-        }
       else if (type == T_TLSA)
     if (rr->size < 3)
       continue;
diff --git a/test/dnszones-src/db.test.ex b/test/dnszones-src/db.test.ex
index 6ff1a6af4..94ac98608 100644
--- a/test/dnszones-src/db.test.ex
+++ b/test/dnszones-src/db.test.ex
@@ -24,6 +24,7 @@ test.ex.     SOA     exim.test.ex. hostmaster.exim.test.ex 1430683638 1200 120 6


 test.ex.     TXT     "A TXT record for test.ex."
 s/lash       TXT     "A TXT record for s/lash.test.ex."
+long         TXT     "This is a max-length chunk 789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234" "A short chunk" "A final chunk"


 cname        CNAME   test.ex.


diff --git a/test/scripts/2200-dnsdb/2200 b/test/scripts/2200-dnsdb/2200
index 96c8dc7ec..4b89a7338 100644
--- a/test/scripts/2200-dnsdb/2200
+++ b/test/scripts/2200-dnsdb/2200
@@ -4,6 +4,7 @@ exim -be
 test.ex                    ${lookup dnsdb{test.ex}{$value}fail}
 s/lash.test.ex             ${lookup dnsdb{s/lash.test.ex}{$value}fail}
 txt=test.ex                ${lookup dnsdb{txt=test.ex}{$value}fail}
+txt=long.test.ex           ${lookup dnsdb{>\n; txt=long.test.ex}{$value}fail}
 a=black-1.test.ex          ${lookup dnsdb{a=black-1.test.ex}{$value}fail}
 xxx=test.ex                ${lookup dnsdb{xxx=test.ex}{$value}fail}
 a=localhost.test.ex        ${lookup dnsdb{a=localhost.test.ex}{$value}fail}
diff --git a/test/src/fakens.c b/test/src/fakens.c
index 2c82c5a82..0de4e60c2 100644
--- a/test/src/fakens.c
+++ b/test/src/fakens.c
@@ -541,6 +541,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
       while (*p != 0 && *p != '"') *pk++ = *p++;
       *pp = pk - pp - 1;
       break;
+      /*XXX need a way of doing multi-chunk TXT RRs */


     case ns_t_tlsa:
       pk = bytefield(&p, pk);   /* usage */
diff --git a/test/stdout/2200 b/test/stdout/2200
index 766d433ef..8d02a903e 100644
--- a/test/stdout/2200
+++ b/test/stdout/2200
@@ -1,6 +1,7 @@

 > test.ex                    A TXT record for test.ex.
 > s/lash.test.ex             A TXT record for s/lash.test.ex.
 > txt=test.ex                A TXT record for test.ex.

+> txt=long.test.ex           This is a max-length chunk 789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234A short chunkA final chunk

 > a=black-1.test.ex          V4NET.11.12.13
 > Failed: lookup of "xxx=test.ex" gave DEFER: unsupported DNS record type
 > a=localhost.test.ex        127.0.0.1


--
## subscription configuration (requires account):
## https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/