Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : DNS Server
5 :
6 : Copyright (C) Amitay Isaacs 2011
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "dnsserver.h"
24 : #include "dns_server/dnsserver_common.h"
25 : #include "lib/replace/system/network.h"
26 : #include "librpc/gen_ndr/ndr_dnsp.h"
27 : #include "librpc/gen_ndr/ndr_dnsserver.h"
28 :
29 : #undef strcasecmp
30 :
31 12 : struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
32 : {
33 0 : struct IP4_ARRAY *ret;
34 :
35 12 : if (!ip4) {
36 12 : return NULL;
37 : }
38 :
39 0 : ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
40 0 : if (!ret) {
41 0 : return ret;
42 : }
43 :
44 0 : ret->AddrCount = ip4->AddrCount;
45 0 : if (ip4->AddrCount > 0) {
46 0 : ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
47 0 : if (ret->AddrArray) {
48 0 : memcpy(ret->AddrArray, ip4->AddrArray,
49 0 : sizeof(unsigned int) * ip4->AddrCount);
50 : } else {
51 0 : talloc_free(ret);
52 0 : return NULL;
53 : }
54 : }
55 0 : return ret;
56 : }
57 :
58 :
59 93 : struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
60 : struct IP4_ARRAY *ip4)
61 : {
62 0 : struct DNS_ADDR_ARRAY *ret;
63 0 : int i;
64 :
65 93 : if (!ip4) {
66 93 : return NULL;
67 : }
68 :
69 0 : ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
70 0 : if (!ret) {
71 0 : return ret;
72 : }
73 :
74 0 : ret->MaxCount = ip4->AddrCount;
75 0 : ret->AddrCount = ip4->AddrCount;
76 0 : ret->Family = AF_INET;
77 0 : if (ip4->AddrCount > 0) {
78 0 : ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
79 0 : if (ret->AddrArray) {
80 0 : for (i=0; i<ip4->AddrCount; i++) {
81 0 : ret->AddrArray[i].MaxSa[0] = 0x02;
82 0 : ret->AddrArray[i].MaxSa[3] = 53;
83 0 : memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
84 : sizeof(unsigned int));
85 0 : ret->AddrArray[i].DnsAddrUserDword[0] = 6;
86 : }
87 :
88 : } else {
89 0 : talloc_free(ret);
90 0 : return NULL;
91 : }
92 : }
93 0 : return ret;
94 : }
95 :
96 16 : struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
97 : struct DNS_ADDR_ARRAY *ip)
98 : {
99 0 : struct IP4_ARRAY *ret;
100 0 : size_t i, count, curr;
101 :
102 16 : if (ip == NULL) {
103 0 : return NULL;
104 : }
105 : /* We must only return IPv4 addresses.
106 : The passed DNS_ADDR_ARRAY may contain:
107 : - only ipv4 addresses
108 : - only ipv6 addresses
109 : - a mixture of both
110 : - an empty array
111 : */
112 16 : ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
113 16 : if (!ret) {
114 0 : return ret;
115 : }
116 16 : if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
117 0 : ret->AddrCount = 0;
118 0 : return ret;
119 : }
120 : /* Now only ipv4 addresses or a mixture are left */
121 16 : count = 0;
122 48 : for (i = 0; i < ip->AddrCount; i++) {
123 32 : if (ip->AddrArray[i].MaxSa[0] == 0x02) {
124 : /* Is ipv4 */
125 16 : count++;
126 : }
127 : }
128 16 : if (count == 0) {
129 : /* should not happen */
130 0 : ret->AddrCount = 0;
131 0 : return ret;
132 : }
133 16 : ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
134 16 : if (ret->AddrArray) {
135 16 : curr = 0;
136 48 : for (i = 0; i < ip->AddrCount; i++) {
137 32 : if (ip->AddrArray[i].MaxSa[0] == 0x02) {
138 : /* Is ipv4 */
139 16 : memcpy(&ret->AddrArray[curr],
140 16 : &ip->AddrArray[i].MaxSa[4],
141 : sizeof(uint32_t));
142 16 : curr++;
143 : }
144 : }
145 : } else {
146 0 : talloc_free(ret);
147 0 : return NULL;
148 : }
149 16 : ret->AddrCount = curr;
150 16 : return ret;
151 : }
152 :
153 0 : struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
154 : struct DNS_ADDR_ARRAY *addr)
155 : {
156 0 : struct DNS_ADDR_ARRAY *ret;
157 :
158 0 : if (!addr) {
159 0 : return NULL;
160 : }
161 :
162 0 : ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
163 0 : if (!ret) {
164 0 : return ret;
165 : }
166 :
167 0 : ret->MaxCount = addr->MaxCount;
168 0 : ret->AddrCount = addr->AddrCount;
169 0 : ret->Family = addr->Family;
170 0 : if (addr->AddrCount > 0) {
171 0 : ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
172 0 : if (ret->AddrArray) {
173 0 : memcpy(ret->AddrArray, addr->AddrArray,
174 0 : sizeof(struct DNS_ADDR) * addr->AddrCount);
175 : } else {
176 0 : talloc_free(ret);
177 0 : return NULL;
178 : }
179 : }
180 0 : return ret;
181 : }
182 :
183 :
184 1798 : int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
185 : {
186 1798 : char *str = NULL, *ptr, **list;
187 1798 : int count = 0;
188 :
189 1798 : if (name == NULL) {
190 0 : return 0;
191 : }
192 :
193 1798 : str = talloc_strdup(tmp_ctx, name);
194 1798 : if (!str) {
195 0 : goto failed;
196 : }
197 :
198 1798 : list = talloc_zero_array(tmp_ctx, char *, 0);
199 1798 : if (!list) {
200 0 : goto failed;
201 : }
202 :
203 1798 : ptr = strtok(str, ".");
204 5653 : while (ptr != NULL) {
205 3855 : count++;
206 3855 : list = talloc_realloc(tmp_ctx, list, char *, count);
207 3855 : if (!list) {
208 0 : goto failed;
209 : }
210 3855 : list[count-1] = talloc_strdup(tmp_ctx, ptr);
211 3855 : if (list[count-1] == NULL) {
212 0 : goto failed;
213 : }
214 3855 : ptr = strtok(NULL, ".");
215 : }
216 :
217 1798 : talloc_free(str);
218 :
219 1798 : *components = list;
220 1798 : return count;
221 :
222 0 : failed:
223 0 : TALLOC_FREE(str);
224 0 : return -1;
225 : }
226 :
227 :
228 5236 : char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
229 : {
230 0 : char **nlist, **zlist;
231 0 : char *prefix;
232 0 : int ncount, zcount, i, match;
233 :
234 : /*
235 : * If node_name is "@", return the zone_name
236 : * If node_name is ".", return NULL
237 : * If there is no '.' in node_name, return the node_name as is.
238 : *
239 : * If node_name does not have zone_name in it, return the node_name as is.
240 : *
241 : * If node_name has additional components as compared to zone_name
242 : * return only the additional components as a prefix.
243 : *
244 : */
245 5236 : if (strcmp(node_name, "@") == 0) {
246 6 : prefix = talloc_strdup(tmp_ctx, zone_name);
247 5230 : } else if (strcmp(node_name, ".") == 0) {
248 0 : prefix = NULL;
249 5230 : } else if (strchr(node_name, '.') == NULL) {
250 4901 : prefix = talloc_strdup(tmp_ctx, node_name);
251 : } else {
252 329 : zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
253 329 : ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
254 329 : if (zcount < 0 || ncount < 0) {
255 0 : return NULL;
256 : }
257 :
258 329 : if (ncount < zcount) {
259 39 : prefix = talloc_strdup(tmp_ctx, node_name);
260 : } else {
261 290 : match = 0;
262 1057 : for (i=1; i<=zcount; i++) {
263 844 : if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
264 77 : break;
265 : }
266 767 : match++;
267 : }
268 :
269 290 : if (match == ncount) {
270 0 : prefix = talloc_strdup(tmp_ctx, zone_name);
271 : } else {
272 290 : prefix = talloc_strdup(tmp_ctx, nlist[0]);
273 290 : if (prefix != NULL) {
274 667 : for (i=1; i<ncount-match; i++) {
275 377 : prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
276 377 : if (prefix == NULL) {
277 0 : break;
278 : }
279 : }
280 : }
281 : }
282 : }
283 :
284 329 : talloc_free(zlist);
285 329 : talloc_free(nlist);
286 : }
287 :
288 5236 : return prefix;
289 : }
290 :
291 :
292 1512 : void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
293 : struct DNS_RPC_RECORD *dns)
294 : {
295 0 : int i, len;
296 :
297 1512 : ZERO_STRUCTP(dns);
298 :
299 1512 : dns->wDataLength = dnsp->wDataLength;
300 1512 : dns->wType = dnsp->wType;
301 1512 : dns->dwFlags = dnsp->rank;
302 1512 : dns->dwSerial = dnsp->dwSerial;
303 1512 : dns->dwTtlSeconds = dnsp->dwTtlSeconds;
304 1512 : dns->dwTimeStamp = dnsp->dwTimeStamp;
305 :
306 1512 : switch (dnsp->wType) {
307 :
308 0 : case DNS_TYPE_TOMBSTONE:
309 0 : dns->data.EntombedTime = dnsp->data.EntombedTime;
310 0 : break;
311 :
312 229 : case DNS_TYPE_A:
313 229 : dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
314 229 : break;
315 :
316 214 : case DNS_TYPE_NS:
317 214 : len = strlen(dnsp->data.ns);
318 214 : if (dnsp->data.ns[len-1] == '.') {
319 0 : dns->data.name.len = len;
320 0 : dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
321 : } else {
322 214 : dns->data.name.len = len+1;
323 214 : dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
324 : }
325 214 : break;
326 :
327 115 : case DNS_TYPE_CNAME:
328 115 : len = strlen(dnsp->data.cname);
329 115 : if (dnsp->data.cname[len-1] == '.') {
330 0 : dns->data.name.len = len;
331 0 : dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
332 : } else {
333 115 : dns->data.name.len = len+1;
334 115 : dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
335 : }
336 115 : break;
337 :
338 0 : case DNS_TYPE_SOA:
339 0 : dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
340 0 : dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
341 0 : dns->data.soa.dwRetry = dnsp->data.soa.retry;
342 0 : dns->data.soa.dwExpire = dnsp->data.soa.expire;
343 0 : dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
344 :
345 0 : len = strlen(dnsp->data.soa.mname);
346 0 : if (dnsp->data.soa.mname[len-1] == '.') {
347 0 : dns->data.soa.NamePrimaryServer.len = len;
348 0 : dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
349 : } else {
350 0 : dns->data.soa.NamePrimaryServer.len = len+1;
351 0 : dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
352 : }
353 :
354 0 : len = strlen(dnsp->data.soa.rname);
355 0 : if (dnsp->data.soa.rname[len-1] == '.') {
356 0 : dns->data.soa.ZoneAdministratorEmail.len = len;
357 0 : dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
358 : } else {
359 0 : dns->data.soa.ZoneAdministratorEmail.len = len+1;
360 0 : dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
361 : }
362 0 : break;
363 :
364 184 : case DNS_TYPE_PTR:
365 184 : dns->data.ptr.len = strlen(dnsp->data.ptr);
366 184 : dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
367 184 : break;
368 :
369 160 : case DNS_TYPE_MX:
370 160 : dns->data.mx.wPreference = dnsp->data.mx.wPriority;
371 160 : len = strlen(dnsp->data.mx.nameTarget);
372 160 : if (dnsp->data.mx.nameTarget[len-1] == '.') {
373 0 : dns->data.mx.nameExchange.len = len;
374 0 : dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
375 : } else {
376 160 : dns->data.mx.nameExchange.len = len+1;
377 160 : dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
378 : }
379 160 : break;
380 :
381 126 : case DNS_TYPE_TXT:
382 126 : dns->data.txt.count = dnsp->data.txt.count;
383 126 : dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
384 267 : for (i=0; i<dnsp->data.txt.count; i++) {
385 141 : dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
386 141 : dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
387 : }
388 126 : break;
389 :
390 241 : case DNS_TYPE_AAAA:
391 241 : dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
392 241 : break;
393 :
394 243 : case DNS_TYPE_SRV:
395 243 : dns->data.srv.wPriority = dnsp->data.srv.wPriority;
396 243 : dns->data.srv.wWeight = dnsp->data.srv.wWeight;
397 243 : dns->data.srv.wPort = dnsp->data.srv.wPort;
398 243 : len = strlen(dnsp->data.srv.nameTarget);
399 243 : if (dnsp->data.srv.nameTarget[len-1] == '.') {
400 0 : dns->data.srv.nameTarget.len = len;
401 0 : dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
402 : } else {
403 243 : dns->data.srv.nameTarget.len = len+1;
404 243 : dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
405 : }
406 243 : break;
407 :
408 0 : default:
409 0 : memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_RECORD_DATA));
410 0 : DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d\n", dnsp->wType));
411 : }
412 :
413 1512 : }
414 :
415 4109 : WERROR dns_to_dnsp_convert(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns,
416 : struct dnsp_DnssrvRpcRecord **out_dnsp, bool check_name)
417 : {
418 0 : WERROR res;
419 0 : int i, len;
420 0 : const char *name;
421 4109 : char *talloc_res = NULL;
422 4109 : struct dnsp_DnssrvRpcRecord *dnsp = NULL;
423 :
424 4109 : dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
425 4109 : if (dnsp == NULL) {
426 0 : return WERR_NOT_ENOUGH_MEMORY;
427 : }
428 :
429 4109 : dnsp->wDataLength = dns->wDataLength;
430 4109 : dnsp->wType = dns->wType;
431 4109 : dnsp->version = 5;
432 4109 : dnsp->rank = dns->dwFlags & 0x000000FF;
433 4109 : dnsp->dwSerial = dns->dwSerial;
434 4109 : dnsp->dwTtlSeconds = dns->dwTtlSeconds;
435 4109 : dnsp->dwTimeStamp = dns->dwTimeStamp;
436 :
437 4109 : switch (dns->wType) {
438 :
439 0 : case DNS_TYPE_TOMBSTONE:
440 0 : dnsp->data.EntombedTime = dns->data.EntombedTime;
441 0 : break;
442 :
443 653 : case DNS_TYPE_A:
444 653 : talloc_res = talloc_strdup(mem_ctx, dns->data.ipv4);
445 653 : if (talloc_res == NULL) {
446 0 : goto fail_nomemory;
447 : }
448 653 : dnsp->data.ipv4 = talloc_res;
449 653 : break;
450 :
451 473 : case DNS_TYPE_NS:
452 473 : name = dns->data.name.str;
453 473 : len = dns->data.name.len;
454 :
455 473 : if (check_name) {
456 266 : res = dns_name_check(mem_ctx, len, name);
457 266 : if (!W_ERROR_IS_OK(res)) {
458 40 : return res;
459 : }
460 : }
461 :
462 433 : if (len > 0 && name[len-1] == '.') {
463 48 : talloc_res = talloc_strndup(mem_ctx, name, len-1);
464 48 : if (talloc_res == NULL) {
465 0 : goto fail_nomemory;
466 : }
467 48 : dnsp->data.ns = talloc_res;
468 : } else {
469 385 : talloc_res = talloc_strdup(mem_ctx, name);
470 385 : if (talloc_res == NULL) {
471 0 : goto fail_nomemory;
472 : }
473 385 : dnsp->data.ns = talloc_res;
474 : }
475 :
476 433 : break;
477 :
478 431 : case DNS_TYPE_CNAME:
479 431 : name = dns->data.name.str;
480 431 : len = dns->data.name.len;
481 :
482 431 : if (check_name) {
483 261 : res = dns_name_check(mem_ctx, len, name);
484 261 : if (!W_ERROR_IS_OK(res)) {
485 40 : return res;
486 : }
487 : }
488 :
489 391 : if (len > 0 && name[len-1] == '.') {
490 42 : talloc_res = talloc_strndup(mem_ctx, name, len-1);
491 42 : if (talloc_res == NULL) {
492 0 : goto fail_nomemory;
493 : }
494 42 : dnsp->data.cname = talloc_res;
495 : } else {
496 349 : talloc_res = talloc_strdup(mem_ctx, name);
497 349 : if (talloc_res == NULL) {
498 0 : goto fail_nomemory;
499 : }
500 349 : dnsp->data.cname = talloc_res;
501 : }
502 :
503 391 : break;
504 :
505 0 : case DNS_TYPE_SOA:
506 0 : dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
507 0 : dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
508 0 : dnsp->data.soa.retry = dns->data.soa.dwRetry;
509 0 : dnsp->data.soa.expire = dns->data.soa.dwExpire;
510 0 : dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
511 :
512 0 : name = dns->data.soa.NamePrimaryServer.str;
513 0 : len = dns->data.soa.NamePrimaryServer.len;
514 :
515 0 : if (check_name) {
516 0 : res = dns_name_check(mem_ctx, len, name);
517 0 : if (!W_ERROR_IS_OK(res)) {
518 0 : return res;
519 : }
520 : }
521 :
522 0 : if (len > 0 && name[len-1] == '.') {
523 0 : talloc_res = talloc_strndup(mem_ctx, name, len-1);
524 0 : if (talloc_res == NULL) {
525 0 : goto fail_nomemory;
526 : }
527 0 : dnsp->data.soa.mname = talloc_res;
528 : } else {
529 0 : talloc_res = talloc_strdup(mem_ctx, name);
530 0 : if (talloc_res == NULL) {
531 0 : goto fail_nomemory;
532 : }
533 0 : dnsp->data.soa.mname = talloc_res;
534 : }
535 :
536 0 : name = dns->data.soa.ZoneAdministratorEmail.str;
537 0 : len = dns->data.soa.ZoneAdministratorEmail.len;
538 :
539 0 : res = dns_name_check(mem_ctx, len, name);
540 0 : if (!W_ERROR_IS_OK(res)) {
541 0 : return res;
542 : }
543 :
544 0 : if (len > 0 && name[len-1] == '.') {
545 0 : talloc_res = talloc_strndup(mem_ctx, name, len-1);
546 0 : if (talloc_res == NULL) {
547 0 : goto fail_nomemory;
548 : }
549 0 : dnsp->data.soa.rname = talloc_res;
550 : } else {
551 0 : talloc_res = talloc_strdup(mem_ctx, name);
552 0 : if (talloc_res == NULL) {
553 0 : goto fail_nomemory;
554 : }
555 0 : dnsp->data.soa.rname = talloc_res;
556 : }
557 :
558 0 : break;
559 :
560 467 : case DNS_TYPE_PTR:
561 467 : name = dns->data.ptr.str;
562 467 : len = dns->data.ptr.len;
563 :
564 467 : if (check_name) {
565 262 : res = dns_name_check(mem_ctx, len, name);
566 262 : if (!W_ERROR_IS_OK(res)) {
567 40 : return res;
568 : }
569 : }
570 :
571 427 : talloc_res = talloc_strdup(mem_ctx, name);
572 427 : if (talloc_res == NULL) {
573 0 : goto fail_nomemory;
574 : }
575 427 : dnsp->data.ptr = talloc_res;
576 :
577 427 : break;
578 :
579 427 : case DNS_TYPE_MX:
580 427 : dnsp->data.mx.wPriority = dns->data.mx.wPreference;
581 :
582 427 : name = dns->data.mx.nameExchange.str;
583 427 : len = dns->data.mx.nameExchange.len;
584 :
585 427 : if (check_name) {
586 237 : res = dns_name_check(mem_ctx, len, name);
587 237 : if (!W_ERROR_IS_OK(res)) {
588 38 : return res;
589 : }
590 : }
591 :
592 389 : if (len > 0 && name[len-1] == '.') {
593 35 : talloc_res = talloc_strndup(mem_ctx, name, len-1);
594 35 : if (talloc_res == NULL) {
595 0 : goto fail_nomemory;
596 : }
597 35 : dnsp->data.mx.nameTarget = talloc_res;
598 : } else {
599 354 : talloc_res = talloc_strdup(mem_ctx, name);
600 354 : if (talloc_res == NULL) {
601 0 : goto fail_nomemory;
602 : }
603 354 : dnsp->data.mx.nameTarget = talloc_res;
604 : }
605 :
606 389 : break;
607 :
608 396 : case DNS_TYPE_TXT:
609 396 : dnsp->data.txt.count = dns->data.txt.count;
610 396 : dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
611 821 : for (i=0; i<dns->data.txt.count; i++) {
612 425 : talloc_res = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
613 425 : if (talloc_res == NULL) {
614 0 : goto fail_nomemory;
615 : }
616 425 : dnsp->data.txt.str[i] = talloc_res;
617 : }
618 396 : break;
619 :
620 688 : case DNS_TYPE_AAAA:
621 688 : dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
622 688 : break;
623 :
624 574 : case DNS_TYPE_SRV:
625 574 : dnsp->data.srv.wPriority = dns->data.srv.wPriority;
626 574 : dnsp->data.srv.wWeight = dns->data.srv.wWeight;
627 574 : dnsp->data.srv.wPort = dns->data.srv.wPort;
628 :
629 574 : name = dns->data.srv.nameTarget.str;
630 574 : len = dns->data.srv.nameTarget.len;
631 :
632 574 : if (check_name) {
633 329 : res = dns_name_check(mem_ctx, len, name);
634 329 : if (!W_ERROR_IS_OK(res)) {
635 38 : return res;
636 : }
637 : }
638 :
639 536 : if (len > 0 && name[len-1] == '.') {
640 48 : talloc_res = talloc_strndup(mem_ctx, name, len-1);
641 48 : if (talloc_res == NULL) {
642 0 : goto fail_nomemory;
643 : }
644 48 : dnsp->data.srv.nameTarget = talloc_res;
645 : } else {
646 488 : talloc_res = talloc_strdup(mem_ctx, name);
647 488 : if (talloc_res == NULL) {
648 0 : goto fail_nomemory;
649 : }
650 488 : dnsp->data.srv.nameTarget = talloc_res;
651 : }
652 :
653 536 : break;
654 :
655 0 : default:
656 0 : memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
657 0 : DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d\n", dns->wType));
658 : }
659 :
660 3913 : *out_dnsp = dnsp;
661 3913 : return WERR_OK;
662 :
663 0 : fail_nomemory:
664 0 : return WERR_NOT_ENOUGH_MEMORY;
665 : }
666 :
667 : /* Initialize tree with given name as the root */
668 1077 : static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
669 : {
670 0 : struct dns_tree *tree;
671 :
672 1077 : tree = talloc_zero(mem_ctx, struct dns_tree);
673 1077 : if (tree == NULL) {
674 0 : return NULL;
675 : }
676 :
677 1077 : tree->name = talloc_strdup(tree, name);
678 1077 : if (tree->name == NULL) {
679 0 : talloc_free(tree);
680 0 : return NULL;
681 : }
682 :
683 1077 : tree->data = data;
684 :
685 1077 : return tree;
686 : }
687 :
688 :
689 : /* Add a child one level below */
690 70 : static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
691 : {
692 0 : struct dns_tree *node;
693 :
694 70 : node = talloc_zero(tree, struct dns_tree);
695 70 : if (node == NULL) {
696 0 : return NULL;
697 : }
698 :
699 70 : node->name = talloc_strdup(tree, name);
700 70 : if (node->name == NULL) {
701 0 : talloc_free(node);
702 0 : return NULL;
703 : }
704 70 : node->level = tree->level + 1;
705 70 : node->num_children = 0;
706 70 : node->children = NULL;
707 70 : node->data = data;
708 :
709 70 : if (tree->num_children == 0) {
710 19 : tree->children = talloc_zero(tree, struct dns_tree *);
711 : } else {
712 51 : tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
713 : tree->num_children+1);
714 : }
715 70 : if (tree->children == NULL) {
716 0 : talloc_free(node);
717 0 : return NULL;
718 : }
719 70 : tree->children[tree->num_children] = node;
720 70 : tree->num_children++;
721 :
722 70 : return node;
723 : }
724 :
725 : /* Find a node that matches the name components */
726 63 : static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
727 : {
728 0 : struct dns_tree *node, *next;
729 0 : int i, j, start;
730 :
731 63 : *match_count = -1;
732 :
733 63 : if (strcmp(tree->name, "@") == 0) {
734 33 : start = 0;
735 : } else {
736 30 : if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
737 0 : return NULL;
738 : }
739 30 : start = 1;
740 30 : *match_count = 0;
741 : }
742 :
743 63 : node = tree;
744 93 : for (i=start; i<ncount; i++) {
745 93 : if (node->num_children == 0) {
746 12 : break;
747 : }
748 81 : next = NULL;
749 216 : for (j=0; j<node->num_children; j++) {
750 165 : if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
751 30 : next = node->children[j];
752 30 : *match_count = i;
753 30 : break;
754 : }
755 : }
756 81 : if (next == NULL) {
757 51 : break;
758 : } else {
759 30 : node = next;
760 : }
761 : }
762 :
763 63 : return node;
764 : }
765 :
766 : /* Build a 2-level tree for resulting dns names */
767 1077 : struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
768 : {
769 0 : struct dns_tree *root, *base, *tree, *node;
770 0 : const char *ptr;
771 0 : int rootcount, ncount;
772 0 : char **nlist;
773 0 : int i, level, match_count;
774 :
775 1077 : rootcount = dns_split_name_components(mem_ctx, name, &nlist);
776 1077 : if (rootcount <= 0) {
777 0 : return NULL;
778 : }
779 :
780 1077 : root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
781 1077 : if (root == NULL) {
782 0 : talloc_free(nlist);
783 0 : return NULL;
784 : }
785 :
786 1077 : tree = root;
787 1084 : for (i=rootcount-2; i>=0; i--) {
788 7 : tree = dns_tree_add(tree, nlist[i], NULL);
789 7 : if (tree == NULL) {
790 0 : goto failed;
791 : }
792 : }
793 :
794 1077 : base = tree;
795 :
796 : /* Add all names in the result in a tree */
797 2211 : for (i=0; i<res->count; i++) {
798 1134 : ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
799 1134 : if (ptr == NULL) {
800 0 : DBG_ERR("dnsserver: dns record has no name (%s)\n",
801 : ldb_dn_get_linearized(res->msgs[i]->dn));
802 0 : goto failed;
803 : }
804 :
805 : /*
806 : * This might be the sub-domain in the zone being
807 : * requested, or @ for the root of the zone
808 : */
809 1134 : if (strcasecmp(ptr, name) == 0) {
810 1071 : base->data = res->msgs[i];
811 1071 : continue;
812 : }
813 :
814 63 : ncount = dns_split_name_components(root, ptr, &nlist);
815 63 : if (ncount < 0) {
816 0 : goto failed;
817 : }
818 :
819 : /* Find matching node */
820 63 : tree = dns_tree_find(root, ncount, nlist, &match_count);
821 63 : if (tree == NULL) {
822 0 : goto failed;
823 : }
824 :
825 : /* If the node is on leaf, then add record data */
826 63 : if (match_count+1 == ncount) {
827 0 : tree->data = res->msgs[i];
828 : }
829 :
830 : /* Add missing name components */
831 126 : for (level=match_count+1; level<ncount; level++) {
832 63 : if (tree->level == rootcount+1) {
833 0 : break;
834 : }
835 63 : if (level == ncount-1) {
836 63 : node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
837 : } else {
838 0 : node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
839 : }
840 63 : if (node == NULL) {
841 0 : goto failed;
842 : }
843 63 : tree = node;
844 : }
845 :
846 63 : talloc_free(nlist);
847 : }
848 :
849 : /* Mark the base record, so it can be found easily */
850 1077 : base->level = -1;
851 :
852 1077 : return root;
853 :
854 0 : failed:
855 0 : talloc_free(nlist);
856 0 : talloc_free(root);
857 0 : return NULL;
858 : }
859 :
860 :
861 732 : static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
862 : {
863 0 : int i;
864 732 : char **ptr = *add_names;
865 732 : int count = *add_count;
866 :
867 1100 : for (i=0; i<count; i++) {
868 422 : if (strcasecmp(ptr[i], name) == 0) {
869 54 : return;
870 : }
871 : }
872 :
873 678 : ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
874 678 : if (ptr == NULL) {
875 0 : return;
876 : }
877 :
878 678 : ptr[count] = talloc_strdup(mem_ctx, name);
879 678 : if (ptr[count] == NULL) {
880 0 : talloc_free(ptr);
881 0 : return;
882 : }
883 :
884 678 : *add_names = ptr;
885 678 : *add_count = count+1;
886 : }
887 :
888 :
889 1512 : static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
890 : {
891 1512 : if (add_names == NULL) {
892 39 : return;
893 : }
894 :
895 1473 : switch (rec->wType) {
896 :
897 214 : case DNS_TYPE_NS:
898 214 : _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
899 214 : break;
900 :
901 115 : case DNS_TYPE_CNAME:
902 115 : _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
903 115 : break;
904 :
905 0 : case DNS_TYPE_SOA:
906 0 : _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
907 0 : break;
908 :
909 160 : case DNS_TYPE_MX:
910 160 : _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
911 160 : break;
912 :
913 243 : case DNS_TYPE_SRV:
914 243 : _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
915 243 : break;
916 :
917 741 : default:
918 741 : break;
919 : }
920 : }
921 :
922 :
923 1182 : WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
924 : struct dnsserver_zone *z,
925 : enum dns_record_type record_type,
926 : unsigned int select_flag,
927 : const char *branch_name,
928 : struct ldb_message *msg,
929 : int num_children,
930 : struct DNS_RPC_RECORDS_ARRAY *recs,
931 : char ***add_names,
932 : int *add_count)
933 : {
934 0 : struct ldb_message_element *el;
935 0 : const char *ptr;
936 0 : int i, j;
937 0 : bool found;
938 :
939 1182 : if (recs->count == 0) {
940 1080 : recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
941 : } else {
942 102 : recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
943 : }
944 1182 : if (recs->rec == NULL) {
945 0 : return WERR_NOT_ENOUGH_MEMORY;
946 : }
947 1182 : i = recs->count;
948 1182 : recs->rec[i].wLength = 0;
949 1182 : recs->rec[i].wRecordCount = 0;
950 1182 : recs->rec[i].dwChildCount = num_children;
951 1182 : recs->rec[i].dwFlags = 0;
952 :
953 : /* The base records returned with empty name */
954 : /* Children records returned with names */
955 1182 : if (branch_name == NULL) {
956 1080 : recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
957 1080 : recs->rec[i].dnsNodeName.len = 0;
958 : } else {
959 102 : recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
960 102 : recs->rec[i].dnsNodeName.len = strlen(branch_name);
961 : }
962 1182 : recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
963 1182 : recs->count++;
964 :
965 : /* Allow empty records */
966 1182 : if (msg == NULL) {
967 6 : return WERR_OK;
968 : }
969 :
970 : /* Do not return RR records, if the node has children */
971 1176 : if (branch_name != NULL && num_children > 0) {
972 0 : return WERR_OK;
973 : }
974 :
975 1176 : ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
976 1176 : if (ptr == NULL) {
977 0 : DBG_ERR("dnsserver: dns record has no name (%s)\n",
978 : ldb_dn_get_linearized(msg->dn));
979 0 : return WERR_INTERNAL_DB_ERROR;
980 : }
981 :
982 1176 : el = ldb_msg_find_element(msg, "dnsRecord");
983 1176 : if (el == NULL || el->values == 0) {
984 0 : return WERR_OK;
985 : }
986 :
987 : /* Add RR records */
988 3204 : for (j=0; j<el->num_values; j++) {
989 0 : struct dnsp_DnssrvRpcRecord dnsp_rec;
990 0 : struct DNS_RPC_RECORD *dns_rec;
991 0 : enum ndr_err_code ndr_err;
992 :
993 2028 : ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
994 : (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
995 2028 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
996 0 : DEBUG(0, ("dnsserver: Unable to parse dns record (%s)\n", ldb_dn_get_linearized(msg->dn)));
997 0 : return WERR_INTERNAL_DB_ERROR;
998 : }
999 :
1000 : /* Match the records based on search criteria */
1001 2028 : if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
1002 1516 : found = false;
1003 :
1004 1516 : if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
1005 1438 : if (dnsp_rec.rank == DNS_RANK_ZONE) {
1006 1259 : found = true;
1007 179 : } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
1008 : /*
1009 : * If branch_name is NULL, we're
1010 : * explicitly asked to also return
1011 : * DNS_RANK_NS_GLUE records
1012 : */
1013 175 : if (branch_name == NULL) {
1014 175 : found = true;
1015 : }
1016 : }
1017 : }
1018 1516 : if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
1019 0 : if (dnsp_rec.rank == DNS_RANK_ZONE) {
1020 0 : found = true;
1021 : }
1022 : }
1023 1516 : if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
1024 0 : if (dnsp_rec.rank == DNS_RANK_GLUE) {
1025 0 : found = true;
1026 : }
1027 : }
1028 1516 : if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
1029 78 : if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
1030 78 : found = true;
1031 : }
1032 : }
1033 :
1034 1516 : if (found) {
1035 1512 : recs->rec[i].records = talloc_realloc(recs,
1036 : recs->rec[i].records,
1037 : struct DNS_RPC_RECORD,
1038 : recs->rec[i].wRecordCount+1);
1039 1512 : if (recs->rec[i].records == NULL) {
1040 0 : return WERR_NOT_ENOUGH_MEMORY;
1041 : }
1042 :
1043 1512 : dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
1044 1512 : dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
1045 :
1046 : /* Fix record flags */
1047 1512 : if (strcmp(ptr, "@") == 0) {
1048 42 : dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1049 :
1050 42 : if (dnsp_rec.rank == DNS_RANK_ZONE) {
1051 3 : dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
1052 : }
1053 : }
1054 :
1055 1512 : if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
1056 175 : dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1057 : }
1058 :
1059 1512 : recs->rec[i].wRecordCount++;
1060 :
1061 1512 : dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
1062 : }
1063 : }
1064 : }
1065 :
1066 1176 : return WERR_OK;
1067 : }
1068 :
1069 :
1070 192 : int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const *m2,
1071 : const char *search_name)
1072 : {
1073 0 : const char *name1, *name2;
1074 0 : const char *ptr1, *ptr2;
1075 :
1076 192 : name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
1077 192 : name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
1078 192 : if (name1 == NULL || name2 == NULL) {
1079 0 : return 0;
1080 : }
1081 :
1082 : /* Compare the last components of names.
1083 : * If search_name is not NULL, compare the second last components of names */
1084 192 : ptr1 = strrchr(name1, '.');
1085 192 : if (ptr1 == NULL) {
1086 114 : ptr1 = name1;
1087 : } else {
1088 78 : if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
1089 0 : ptr1--;
1090 0 : while (ptr1 != name1) {
1091 0 : ptr1--;
1092 0 : if (*ptr1 == '.') {
1093 0 : break;
1094 : }
1095 : }
1096 : }
1097 78 : if (*ptr1 == '.') {
1098 78 : ptr1 = &ptr1[1];
1099 : }
1100 : }
1101 :
1102 192 : ptr2 = strrchr(name2, '.');
1103 192 : if (ptr2 == NULL) {
1104 114 : ptr2 = name2;
1105 : } else {
1106 78 : if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
1107 0 : ptr2--;
1108 0 : while (ptr2 != name2) {
1109 0 : ptr2--;
1110 0 : if (*ptr2 == '.') {
1111 0 : break;
1112 : }
1113 : }
1114 : }
1115 78 : if (*ptr2 == '.') {
1116 78 : ptr2 = &ptr2[1];
1117 : }
1118 : }
1119 :
1120 192 : return strcasecmp(ptr1, ptr2);
1121 : }
|