Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/librpc/ndr/ndr_dns.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   manipulate dns name structures
5
6
   Copyright (C) 2010 Kai Blin  <kai@samba.org>
7
8
   Heavily based on nbtname.c which is:
9
10
   Copyright (C) Andrew Tridgell 2005
11
12
   This program is free software; you can redistribute it and/or modify
13
   it under the terms of the GNU General Public License as published by
14
   the Free Software Foundation; either version 3 of the License, or
15
   (at your option) any later version.
16
17
   This program is distributed in the hope that it will be useful,
18
   but WITHOUT ANY WARRANTY; without even the implied warranty of
19
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
   GNU General Public License for more details.
21
22
   You should have received a copy of the GNU General Public License
23
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
*/
25
26
/*
27
  see rfc1002 for the detailed format of compressed names
28
*/
29
30
#include "includes.h"
31
#include "librpc/gen_ndr/ndr_dns.h"
32
#include "librpc/gen_ndr/ndr_misc.h"
33
#include "librpc/gen_ndr/ndr_dnsp.h"
34
#include "system/locale.h"
35
#include "lib/util/util_net.h"
36
#include "ndr_dns_utils.h"
37
38
/* don't allow an unlimited number of name components */
39
7.48M
#define MAX_COMPONENTS 128
40
41
/**
42
  print a dns string
43
*/
44
_PUBLIC_ void ndr_print_dns_string(struct ndr_print *ndr,
45
           const char *name,
46
           const char *s)
47
965k
{
48
965k
  ndr_print_string(ndr, name, s);
49
965k
}
50
51
/*
52
  pull one component of a dns_string
53
*/
54
static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr,
55
              uint8_t **component,
56
              uint32_t *offset,
57
              uint32_t *max_offset)
58
3.82M
{
59
3.82M
  uint8_t len;
60
3.82M
  unsigned int loops = 0;
61
3.85M
  while (loops < 5) {
62
3.85M
    if (*offset >= ndr->data_size) {
63
276
      return ndr_pull_error(ndr, NDR_ERR_STRING,
64
276
          "BAD DNS NAME component, bad offset");
65
276
    }
66
3.85M
    len = ndr->data[*offset];
67
3.85M
    if (len == 0) {
68
3.66M
      *offset += 1;
69
3.66M
      *max_offset = MAX(*max_offset, *offset);
70
3.66M
      *component = NULL;
71
3.66M
      return NDR_ERR_SUCCESS;
72
3.66M
    }
73
193k
    if ((len & 0xC0) == 0xC0) {
74
      /* its a label pointer */
75
39.5k
      if (1 + *offset >= ndr->data_size) {
76
7
        return ndr_pull_error(ndr, NDR_ERR_STRING,
77
7
            "BAD DNS NAME component, " \
78
7
            "bad label offset");
79
7
      }
80
39.5k
      *max_offset = MAX(*max_offset, *offset + 2);
81
39.5k
      *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
82
39.5k
      *max_offset = MAX(*max_offset, *offset);
83
39.5k
      loops++;
84
39.5k
      continue;
85
39.5k
    }
86
153k
    if ((len & 0xC0) != 0) {
87
      /* its a reserved length field */
88
12
      return ndr_pull_error(ndr, NDR_ERR_STRING,
89
12
                "BAD DNS NAME component, " \
90
12
                "reserved length field: 0x%02"PRIx8,
91
12
                (len &0xC));
92
12
    }
93
153k
    if (*offset + len + 1 > ndr->data_size) {
94
16
      return ndr_pull_error(ndr, NDR_ERR_STRING,
95
16
                "BAD DNS NAME component, "\
96
16
                "length too long");
97
16
    }
98
153k
    *component = (uint8_t*)talloc_strndup(ndr,
99
153k
        (const char *)&ndr->data[1 + *offset], len);
100
153k
    NDR_ERR_HAVE_NO_MEMORY(*component);
101
153k
    *offset += len + 1;
102
153k
    *max_offset = MAX(*max_offset, *offset);
103
153k
    return NDR_ERR_SUCCESS;
104
153k
  }
105
106
  /* too many pointers */
107
5
  return ndr_pull_error(ndr, NDR_ERR_STRING,
108
3.82M
            "BAD DNS NAME component, too many pointers");
109
3.82M
}
110
111
/**
112
  pull a dns_string from the wire
113
*/
114
_PUBLIC_ enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr,
115
                 ndr_flags_type ndr_flags,
116
                 const char **s)
117
3.66M
{
118
3.66M
  uint32_t offset = ndr->offset;
119
3.66M
  uint32_t max_offset = offset;
120
3.66M
  unsigned num_components;
121
3.66M
  char *name;
122
123
3.66M
  if (!(ndr_flags & NDR_SCALARS)) {
124
0
    return NDR_ERR_SUCCESS;
125
0
  }
126
127
3.66M
  name = talloc_strdup(ndr->current_mem_ctx, "");
128
129
  /* break up name into a list of components */
130
3.82M
  for (num_components=0; num_components<MAX_COMPONENTS;
131
3.82M
       num_components++) {
132
3.82M
    uint8_t *component = NULL;
133
3.82M
    NDR_CHECK(ndr_pull_component(ndr, &component, &offset,
134
3.82M
               &max_offset));
135
3.82M
    if (component == NULL) break;
136
153k
    if (num_components > 0) {
137
31.7k
      name = talloc_asprintf_append_buffer(name, ".%s",
138
31.7k
                   component);
139
122k
    } else {
140
122k
      name = talloc_asprintf_append_buffer(name, "%s",
141
122k
                   component);
142
122k
    }
143
153k
    NDR_ERR_HAVE_NO_MEMORY(name);
144
153k
  }
145
3.66M
  if (num_components == MAX_COMPONENTS) {
146
30
    return ndr_pull_error(ndr, NDR_ERR_STRING,
147
30
              "BAD DNS NAME too many components");
148
30
  }
149
150
3.66M
  (*s) = name;
151
3.66M
  ndr->offset = max_offset;
152
153
3.66M
  return NDR_ERR_SUCCESS;
154
3.66M
}
155
156
/**
157
  push a dns string to the wire
158
*/
159
_PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
160
                 ndr_flags_type ndr_flags,
161
                 const char *s)
162
859k
{
163
859k
  return ndr_push_dns_string_list(ndr,
164
859k
          &ndr->dns_string_list,
165
859k
          ndr_flags,
166
859k
          s,
167
859k
          false);
168
859k
}
169
170
_PUBLIC_ enum ndr_err_code ndr_pull_dns_txt_record(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dns_txt_record *r)
171
2.16k
{
172
2.16k
  NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
173
2.16k
  if (ndr_flags & NDR_SCALARS) {
174
2.16k
    enum ndr_err_code ndr_err;
175
2.16k
    uint32_t data_size = ndr->data_size;
176
2.16k
    uint32_t record_size = 0;
177
2.16k
    ndr_err = ndr_token_retrieve(&ndr->array_size_list, r,
178
2.16k
               &record_size);
179
2.16k
    if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
180
2.03k
      NDR_PULL_NEED_BYTES(ndr, record_size);
181
1.96k
      ndr->data_size = ndr->offset + record_size;
182
1.96k
    }
183
2.09k
    NDR_CHECK(ndr_pull_align(ndr, 1));
184
2.09k
    NDR_CHECK(ndr_pull_dnsp_string_list(ndr, NDR_SCALARS, &r->txt));
185
2.02k
    NDR_CHECK(ndr_pull_trailer_align(ndr, 1));
186
2.02k
    ndr->data_size = data_size;
187
2.02k
  }
188
2.02k
  if (ndr_flags & NDR_BUFFERS) {
189
76
  }
190
2.02k
  return NDR_ERR_SUCCESS;
191
2.16k
}
192
193
_PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
194
            ndr_flags_type ndr_flags,
195
            const struct dns_res_rec *r)
196
1.31M
{
197
1.31M
  libndr_flags _flags_save_STRUCT = ndr->flags;
198
1.31M
  uint32_t _saved_offset1, _saved_offset2;
199
1.31M
  uint16_t length;
200
1.31M
  ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
201
1.31M
           LIBNDR_FLAG_NOALIGN);
202
1.31M
  if (ndr_flags & NDR_SCALARS) {
203
668k
    libndr_flags _flags_save_name = ndr->flags;
204
205
668k
    NDR_CHECK(ndr_push_align(ndr, 4));
206
207
668k
    switch (r->rr_type) {
208
6.22k
    case DNS_QTYPE_TKEY:
209
6.87k
    case DNS_QTYPE_TSIG:
210
6.87k
      ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_COMPRESSION);
211
6.87k
      break;
212
661k
    default:
213
661k
      break;
214
668k
    }
215
668k
    NDR_CHECK(ndr_push_dns_string(ndr, NDR_SCALARS, r->name));
216
668k
    ndr->flags = _flags_save_name;
217
218
668k
    NDR_CHECK(ndr_push_dns_qtype(ndr, NDR_SCALARS, r->rr_type));
219
668k
    NDR_CHECK(ndr_push_dns_qclass(ndr, NDR_SCALARS, r->rr_class));
220
668k
    NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
221
668k
    _saved_offset1 = ndr->offset;
222
668k
    NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
223
668k
    if (r->length > 0) {
224
15.2k
      uint32_t _saved_offset3;
225
226
15.2k
      NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata,
227
15.2k
                  r->rr_type));
228
15.2k
      _saved_offset3 = ndr->offset;
229
15.2k
      NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS,
230
15.2k
                 &r->rdata));
231
15.1k
      if ((ndr->offset != _saved_offset3) &&
232
10.2k
          (r->unexpected.length > 0)) {
233
        /*
234
         * ndr_push_dns_rdata pushed a known
235
         * record, but we have something
236
         * unexpected. That's invalid.
237
         */
238
38
        return ndr_push_error(ndr,
239
38
                  NDR_ERR_LENGTH,
240
38
                  "Invalid...Unexpected " \
241
38
                  "blob length is too " \
242
38
                  "large");
243
38
      }
244
15.1k
    }
245
667k
    if (r->unexpected.length > UINT16_MAX) {
246
0
      return ndr_push_error(ndr, NDR_ERR_LENGTH,
247
0
                "Unexpected blob length "\
248
0
                "is too large");
249
0
    }
250
251
667k
    NDR_CHECK(ndr_push_bytes(ndr, r->unexpected.data,
252
667k
           r->unexpected.length));
253
667k
    NDR_CHECK(ndr_push_trailer_align(ndr, 4));
254
667k
    length = ndr->offset - (_saved_offset1 + 2);
255
667k
    _saved_offset2 = ndr->offset;
256
667k
    ndr->offset = _saved_offset1;
257
667k
    NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, length));
258
667k
    ndr->offset = _saved_offset2;
259
667k
  }
260
1.31M
  if (ndr_flags & NDR_BUFFERS) {
261
650k
    NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_BUFFERS,
262
650k
               &r->rdata));
263
650k
  }
264
1.31M
  ndr->flags = _flags_save_STRUCT;
265
1.31M
  return NDR_ERR_SUCCESS;
266
1.31M
}
267
268
_PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr,
269
            ndr_flags_type ndr_flags,
270
            struct dns_res_rec *r)
271
3.01M
{
272
3.01M
  libndr_flags _flags_save_STRUCT = ndr->flags;
273
3.01M
  uint32_t _saved_offset1;
274
3.01M
  uint32_t pad, length;
275
276
3.01M
  ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
277
3.01M
           LIBNDR_FLAG_NOALIGN);
278
3.01M
  if (ndr_flags & NDR_SCALARS) {
279
2.31M
    NDR_CHECK(ndr_pull_align(ndr, 4));
280
2.31M
    NDR_CHECK(ndr_pull_dns_string(ndr, NDR_SCALARS, &r->name));
281
2.31M
    NDR_CHECK(ndr_pull_dns_qtype(ndr, NDR_SCALARS, &r->rr_type));
282
2.31M
    NDR_CHECK(ndr_pull_dns_qclass(ndr, NDR_SCALARS, &r->rr_class));
283
2.31M
    NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl));
284
2.31M
    NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
285
2.31M
    _saved_offset1 = ndr->offset;
286
2.31M
    if (r->length > 0) {
287
1.31M
      NDR_CHECK(ndr_token_store(ndr, &ndr->array_size_list,
288
1.31M
              &r->rdata,
289
1.31M
              r->length));
290
1.31M
      NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata,
291
1.31M
                  r->rr_type));
292
1.31M
      NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS,
293
1.31M
                 &r->rdata));
294
1.31M
    } else {
295
1.00M
      ZERO_STRUCT(r->rdata);
296
1.00M
    }
297
2.31M
    length = ndr->offset - _saved_offset1;
298
2.31M
    if (length > r->length) {
299
37
      return ndr_pull_error(ndr, NDR_ERR_LENGTH, "TODO");
300
37
    }
301
302
2.31M
    r->unexpected = data_blob_null;
303
2.31M
    pad = r->length - length;
304
2.31M
    if (pad > 0) {
305
23.7k
      NDR_PULL_NEED_BYTES(ndr, pad);
306
23.6k
      r->unexpected = data_blob_talloc(ndr->current_mem_ctx,
307
23.6k
               ndr->data +
308
23.6k
               ndr->offset,
309
23.6k
               pad);
310
23.6k
      if (r->unexpected.data == NULL) {
311
0
        return ndr_pull_error(ndr,
312
0
                  NDR_ERR_ALLOC,
313
0
                  "Failed to allocate a " \
314
0
                  "data blob");
315
0
      }
316
23.6k
      ndr->offset += pad;
317
23.6k
    }
318
319
320
2.31M
    NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
321
2.31M
  }
322
3.01M
  if (ndr_flags & NDR_BUFFERS) {
323
700k
    NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_BUFFERS, &r->rdata));
324
700k
  }
325
3.01M
  ndr->flags = _flags_save_STRUCT;
326
3.01M
  return NDR_ERR_SUCCESS;
327
3.01M
}