summaryrefslogtreecommitdiffstats
path: root/debian/patches/76-14-Lookups-Fix-dnsdb-lookup-of-multi-chunk-TXT.-Bug-305.patch
blob: 7b9eb6e2168827dbe70547b6a8581cdd88e2be07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
From 79670d3c32ccb37fe06f25d8192943b58606a32a Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Fri, 17 Nov 2023 16:55:17 +0000
Subject: [PATCH] Lookups: Fix dnsdb lookup of multi-chunk TXT.  Bug 3054

Broken=by: f6b1f8e7d642
---
 doc/ChangeLog        |  6 ++++-
 src/dns.c                |  4 +++-
 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(-)

--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -87,10 +87,13 @@ JH/34 Bug 3013: Fix use of $recipients w
 JH/35 Bug 3014: GnuTLS: fix expiry date for an auto-generated server
       certificate.  Find and fix by Andreas Metzler.
 
 JH/39 Bug 3023: Fix crash induced by some combinations of zero-length strings
       and ${tr...}.  Found and diagnosed by Heiko Schlichting.
+ 
+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.96
 -----------------
 
 JH/01 Move the wait-for-next-tick (needed for unique message IDs) from
--- a/src/dns.c
+++ b/src/dns.c
@@ -428,11 +428,13 @@ TRACE trace = "R-namelen";
 namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr,
   (DN_EXPAND_ARG4_TYPE) &dnss->srr.name, DNS_MAXNAME);
 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;
 
 /* Check space for type, class, TTL & data-size-word */
--- a/src/lookups/dnsdb.c
+++ b/src/lookups/dnsdb.c
@@ -390,46 +390,36 @@ while ((domain = string_nextinlist(&keys
           }
         continue;
         }
 
       /* 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
-          {
-          /* output all items */
-          int data_offset = 0;
-          while (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;
 	else
 	  {