s4-ldap: added DSDB_CONTROL_NO_GLOBAL_CATALOG to ldap encoding list
[nivanova/samba-autobuild/.git] / librpc / ndr / ndr_dns.c
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 "system/locale.h"
34 #include "lib/util/util_net.h"
35
36 /* don't allow an unlimited number of name components */
37 #define MAX_COMPONENTS 128
38
39 /**
40   print a dns string
41 */
42 _PUBLIC_ void ndr_print_dns_string(struct ndr_print *ndr,
43                                    const char *name,
44                                    const char *s)
45 {
46         ndr_print_string(ndr, name, s);
47 }
48
49 /*
50   pull one component of a dns_string
51 */
52 static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr,
53                                             uint8_t **component,
54                                             uint32_t *offset,
55                                             uint32_t *max_offset)
56 {
57         uint8_t len;
58         unsigned int loops = 0;
59         while (loops < 5) {
60                 if (*offset >= ndr->data_size) {
61                         return ndr_pull_error(ndr, NDR_ERR_STRING,
62                                         "BAD DNS NAME component, bad offset");
63                 }
64                 len = ndr->data[*offset];
65                 if (len == 0) {
66                         *offset += 1;
67                         *max_offset = MAX(*max_offset, *offset);
68                         *component = NULL;
69                         return NDR_ERR_SUCCESS;
70                 }
71                 if ((len & 0xC0) == 0xC0) {
72                         /* its a label pointer */
73                         if (1 + *offset >= ndr->data_size) {
74                                 return ndr_pull_error(ndr, NDR_ERR_STRING,
75                                                 "BAD DNS NAME component, " \
76                                                 "bad label offset");
77                         }
78                         *max_offset = MAX(*max_offset, *offset + 2);
79                         *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
80                         *max_offset = MAX(*max_offset, *offset);
81                         loops++;
82                         continue;
83                 }
84                 if ((len & 0xC0) != 0) {
85                         /* its a reserved length field */
86                         return ndr_pull_error(ndr, NDR_ERR_STRING,
87                                               "BAD DNS NAME component, " \
88                                               "reserved lenght field: 0x%02x",
89                                               (len &0xC));
90                 }
91                 if (*offset + len + 2 > ndr->data_size) {
92                         return ndr_pull_error(ndr, NDR_ERR_STRING,
93                                               "BAD DNS NAME component, "\
94                                               "length too long");
95                 }
96                 *component = (uint8_t*)talloc_strndup(ndr,
97                                 (const char *)&ndr->data[1 + *offset], len);
98                 NDR_ERR_HAVE_NO_MEMORY(*component);
99                 *offset += len + 1;
100                 *max_offset = MAX(*max_offset, *offset);
101                 return NDR_ERR_SUCCESS;
102         }
103
104         /* too many pointers */
105         return ndr_pull_error(ndr, NDR_ERR_STRING,
106                               "BAD DNS NAME component, too many pointers");
107 }
108
109 /**
110   pull a dns_string from the wire
111 */
112 _PUBLIC_ enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr,
113                                                int ndr_flags,
114                                                const char **s)
115 {
116         uint32_t offset = ndr->offset;
117         uint32_t max_offset = offset;
118         unsigned num_components;
119         char *name;
120
121         if (!(ndr_flags & NDR_SCALARS)) {
122                 return NDR_ERR_SUCCESS;
123         }
124
125         name = talloc_strdup(ndr->current_mem_ctx, "");
126
127         /* break up name into a list of components */
128         for (num_components=0; num_components<MAX_COMPONENTS;
129              num_components++) {
130                 uint8_t *component = NULL;
131                 NDR_CHECK(ndr_pull_component(ndr, &component, &offset,
132                                              &max_offset));
133                 if (component == NULL) break;
134                 if (num_components > 0) {
135                         name = talloc_asprintf_append_buffer(name, ".%s",
136                                                              component);
137                 } else {
138                         name = talloc_asprintf_append_buffer(name, "%s",
139                                                              component);
140                 }
141                 NDR_ERR_HAVE_NO_MEMORY(name);
142         }
143         if (num_components == MAX_COMPONENTS) {
144                 return ndr_pull_error(ndr, NDR_ERR_STRING,
145                                       "BAD DNS NAME too many components");
146         }
147
148         (*s) = name;
149         ndr->offset = max_offset;
150
151         return NDR_ERR_SUCCESS;
152 }
153
154 /**
155   push a dns string to the wire
156 */
157 _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
158                                                int ndr_flags,
159                                                const char *s)
160 {
161         if (!(ndr_flags & NDR_SCALARS)) {
162                 return NDR_ERR_SUCCESS;
163         }
164
165         while (s && *s) {
166                 enum ndr_err_code ndr_err;
167                 char *compname;
168                 size_t complen;
169                 uint32_t offset;
170
171                 /* see if we have pushed the remaing string allready,
172                  * if so we use a label pointer to this string
173                  */
174                 ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s,
175                                                     &offset,
176                                                     (comparison_fn_t)strcmp,
177                                                     false);
178                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
179                         uint8_t b[2];
180
181                         if (offset > 0x3FFF) {
182                                 return ndr_push_error(ndr, NDR_ERR_STRING,
183                                                       "offset for dns string " \
184                                                       "label pointer " \
185                                                       "%u[%08X] > 0x00003FFF",
186                                                       offset, offset);
187                         }
188
189                         b[0] = 0xC0 | (offset>>8);
190                         b[1] = (offset & 0xFF);
191
192                         return ndr_push_bytes(ndr, b, 2);
193                 }
194
195                 complen = strcspn(s, ".");
196
197                 /* we need to make sure the length fits into 6 bytes */
198                 if (complen > 0x3F) {
199                         return ndr_push_error(ndr, NDR_ERR_STRING,
200                                               "component length %u[%08X] > " \
201                                               "0x0000003F",
202                                               (unsigned)complen,
203                                               (unsigned)complen);
204                 }
205
206                 compname = talloc_asprintf(ndr, "%c%*.*s",
207                                                 (unsigned char)complen,
208                                                 (unsigned char)complen,
209                                                 (unsigned char)complen, s);
210                 NDR_ERR_HAVE_NO_MEMORY(compname);
211
212                 /* remember the current componemt + the rest of the string
213                  * so it can be reused later
214                  */
215                 NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s,
216                                           ndr->offset));
217
218                 /* push just this component into the blob */
219                 NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname,
220                                          complen+1));
221                 talloc_free(compname);
222
223                 s += complen;
224                 if (*s == '.') s++;
225         }
226
227         /* if we reach the end of the string and have pushed the last component
228          * without using a label pointer, we need to terminate the string
229          */
230         return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
231 }
232
233 _PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
234                                                 int ndr_flags,
235                                                 const struct dns_res_rec *r)
236 {
237         uint32_t _flags_save_STRUCT = ndr->flags;
238         uint32_t _saved_offset1, _saved_offset2;
239         uint16_t length;
240         ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
241                                    LIBNDR_FLAG_NOALIGN);
242         if (ndr_flags & NDR_SCALARS) {
243                 NDR_CHECK(ndr_push_align(ndr, 4));
244                 NDR_CHECK(ndr_push_dns_string(ndr, NDR_SCALARS, r->name));
245                 NDR_CHECK(ndr_push_dns_qtype(ndr, NDR_SCALARS, r->rr_type));
246                 NDR_CHECK(ndr_push_dns_qclass(ndr, NDR_SCALARS, r->rr_class));
247                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
248                 _saved_offset1 = ndr->offset;
249                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
250                 if (r->length > 0) {
251                         NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata,
252                                                             r->rr_type));
253                         NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS,
254                                                      &r->rdata));
255                         if (r->unexpected.length > 0) {
256                                 return ndr_push_error(ndr,
257                                                       NDR_ERR_LENGTH,
258                                                       "Invalid...Unexpected " \
259                                                       "blob lenght is too " \
260                                                       "large");
261                         }
262                 }
263                 if (r->unexpected.length > UINT16_MAX) {
264                         return ndr_push_error(ndr, NDR_ERR_LENGTH,
265                                               "Unexpected blob lenght "\
266                                               "is too large");
267                 }
268
269                 NDR_CHECK(ndr_push_bytes(ndr, r->unexpected.data,
270                                          r->unexpected.length));
271                 NDR_CHECK(ndr_push_trailer_align(ndr, 4));
272                 length = ndr->offset - (_saved_offset1 + 2);
273                 _saved_offset2 = ndr->offset;
274                 ndr->offset = _saved_offset1;
275                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, length));
276                 ndr->offset = _saved_offset2;
277         }
278         if (ndr_flags & NDR_BUFFERS) {
279                 NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_BUFFERS,
280                                              &r->rdata));
281         }
282         ndr->flags = _flags_save_STRUCT;
283         return NDR_ERR_SUCCESS;
284 }
285
286 _PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr,
287                                                 int ndr_flags,
288                                                 struct dns_res_rec *r)
289 {
290         uint32_t _flags_save_STRUCT = ndr->flags;
291         uint32_t _saved_offset1;
292         uint32_t pad, length;
293
294         ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
295                                    LIBNDR_FLAG_NOALIGN);
296         if (ndr_flags & NDR_SCALARS) {
297                 NDR_CHECK(ndr_pull_align(ndr, 4));
298                 NDR_CHECK(ndr_pull_dns_string(ndr, NDR_SCALARS, &r->name));
299                 NDR_CHECK(ndr_pull_dns_qtype(ndr, NDR_SCALARS, &r->rr_type));
300                 NDR_CHECK(ndr_pull_dns_qclass(ndr, NDR_SCALARS, &r->rr_class));
301                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl));
302                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
303                 _saved_offset1 = ndr->offset;
304                 if (r->length > 0) {
305                         NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata,
306                                                             r->rr_type));
307                         NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS,
308                                                      &r->rdata));
309                 } else {
310                         ZERO_STRUCT(r->rdata);
311                 }
312                 length = ndr->offset - _saved_offset1;
313                 if (length > r->length) {
314                         return ndr_pull_error(ndr, NDR_ERR_LENGTH, "TODO");
315                 }
316
317                 r->unexpected = data_blob_null;
318                 pad = r->length - length;
319                 if (pad > 0) {
320                         NDR_PULL_NEED_BYTES(ndr, pad);
321                         r->unexpected = data_blob_talloc(ndr->current_mem_ctx,
322                                                          ndr->data +
323                                                          ndr->offset,
324                                                          pad);
325                         if (r->unexpected.data == NULL) {
326                                 return ndr_pull_error(ndr,
327                                                       NDR_ERR_ALLOC,
328                                                       "Failed to allocate a " \
329                                                       "data blob");
330                         }
331                         ndr->offset += pad;
332                 }
333
334
335                 NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
336         }
337         if (ndr_flags & NDR_BUFFERS) {
338                 NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_BUFFERS, &r->rdata));
339         }
340         ndr->flags = _flags_save_STRUCT;
341         return NDR_ERR_SUCCESS;
342 }