s4:rpcsrv:dnsserver: make dns_name_compare transitive with NULLs
[Samba.git] / source4 / rpc_server / dnsserver / dnsdata.c
blob6ffca196861d881ec03c2be505dde26758064173
1 /*
2 Unix SMB/CIFS implementation.
4 DNS Server
6 Copyright (C) Amitay Isaacs 2011
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.
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.
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/>.
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"
29 #undef strcasecmp
31 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
33 struct IP4_ARRAY *ret;
35 if (!ip4) {
36 return NULL;
39 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
40 if (!ret) {
41 return ret;
44 ret->AddrCount = ip4->AddrCount;
45 if (ip4->AddrCount > 0) {
46 ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
47 if (ret->AddrArray) {
48 memcpy(ret->AddrArray, ip4->AddrArray,
49 sizeof(unsigned int) * ip4->AddrCount);
50 } else {
51 talloc_free(ret);
52 return NULL;
55 return ret;
59 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
60 struct IP4_ARRAY *ip4)
62 struct DNS_ADDR_ARRAY *ret;
63 int i;
65 if (!ip4) {
66 return NULL;
69 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
70 if (!ret) {
71 return ret;
74 ret->MaxCount = ip4->AddrCount;
75 ret->AddrCount = ip4->AddrCount;
76 ret->Family = AF_INET;
77 if (ip4->AddrCount > 0) {
78 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
79 if (ret->AddrArray) {
80 for (i=0; i<ip4->AddrCount; i++) {
81 ret->AddrArray[i].MaxSa[0] = 0x02;
82 ret->AddrArray[i].MaxSa[3] = 53;
83 memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
84 sizeof(unsigned int));
85 ret->AddrArray[i].DnsAddrUserDword[0] = 6;
88 } else {
89 talloc_free(ret);
90 return NULL;
93 return ret;
96 struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
97 struct DNS_ADDR_ARRAY *ip)
99 struct IP4_ARRAY *ret;
100 size_t i, count, curr;
102 if (ip == NULL) {
103 return NULL;
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
112 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
113 if (!ret) {
114 return ret;
116 if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
117 ret->AddrCount = 0;
118 return ret;
120 /* Now only ipv4 addresses or a mixture are left */
121 count = 0;
122 for (i = 0; i < ip->AddrCount; i++) {
123 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
124 /* Is ipv4 */
125 count++;
128 if (count == 0) {
129 /* should not happen */
130 ret->AddrCount = 0;
131 return ret;
133 ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
134 if (ret->AddrArray) {
135 curr = 0;
136 for (i = 0; i < ip->AddrCount; i++) {
137 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
138 /* Is ipv4 */
139 memcpy(&ret->AddrArray[curr],
140 &ip->AddrArray[i].MaxSa[4],
141 sizeof(uint32_t));
142 curr++;
145 } else {
146 talloc_free(ret);
147 return NULL;
149 ret->AddrCount = curr;
150 return ret;
153 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
154 struct DNS_ADDR_ARRAY *addr)
156 struct DNS_ADDR_ARRAY *ret;
158 if (!addr) {
159 return NULL;
162 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
163 if (!ret) {
164 return ret;
167 ret->MaxCount = addr->MaxCount;
168 ret->AddrCount = addr->AddrCount;
169 ret->Family = addr->Family;
170 if (addr->AddrCount > 0) {
171 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
172 if (ret->AddrArray) {
173 memcpy(ret->AddrArray, addr->AddrArray,
174 sizeof(struct DNS_ADDR) * addr->AddrCount);
175 } else {
176 talloc_free(ret);
177 return NULL;
180 return ret;
184 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
186 char *str = NULL, *ptr, **list;
187 int count = 0;
189 if (name == NULL) {
190 return 0;
193 str = talloc_strdup(tmp_ctx, name);
194 if (!str) {
195 goto failed;
198 list = talloc_zero_array(tmp_ctx, char *, 0);
199 if (!list) {
200 goto failed;
203 ptr = strtok(str, ".");
204 while (ptr != NULL) {
205 count++;
206 list = talloc_realloc(tmp_ctx, list, char *, count);
207 if (!list) {
208 goto failed;
210 list[count-1] = talloc_strdup(tmp_ctx, ptr);
211 if (list[count-1] == NULL) {
212 goto failed;
214 ptr = strtok(NULL, ".");
217 talloc_free(str);
219 *components = list;
220 return count;
222 failed:
223 TALLOC_FREE(str);
224 return -1;
228 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
230 char **nlist, **zlist;
231 char *prefix;
232 int ncount, zcount, i, match;
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.
239 * If node_name does not have zone_name in it, return the node_name as is.
241 * If node_name has additional components as compared to zone_name
242 * return only the additional components as a prefix.
245 if (strcmp(node_name, "@") == 0) {
246 prefix = talloc_strdup(tmp_ctx, zone_name);
247 } else if (strcmp(node_name, ".") == 0) {
248 prefix = NULL;
249 } else if (strchr(node_name, '.') == NULL) {
250 prefix = talloc_strdup(tmp_ctx, node_name);
251 } else {
252 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
253 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
254 if (zcount < 0 || ncount < 0) {
255 return NULL;
258 if (ncount < zcount) {
259 prefix = talloc_strdup(tmp_ctx, node_name);
260 } else {
261 match = 0;
262 for (i=1; i<=zcount; i++) {
263 if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
264 break;
266 match++;
269 if (match == ncount) {
270 prefix = talloc_strdup(tmp_ctx, zone_name);
271 } else {
272 prefix = talloc_strdup(tmp_ctx, nlist[0]);
273 if (prefix != NULL) {
274 for (i=1; i<ncount-match; i++) {
275 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
276 if (prefix == NULL) {
277 break;
284 talloc_free(zlist);
285 talloc_free(nlist);
288 return prefix;
292 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
293 struct DNS_RPC_RECORD *dns)
295 int i, len;
297 ZERO_STRUCTP(dns);
299 dns->wDataLength = dnsp->wDataLength;
300 dns->wType = dnsp->wType;
301 dns->dwFlags = dnsp->rank;
302 dns->dwSerial = dnsp->dwSerial;
303 dns->dwTtlSeconds = dnsp->dwTtlSeconds;
304 dns->dwTimeStamp = dnsp->dwTimeStamp;
306 switch (dnsp->wType) {
308 case DNS_TYPE_TOMBSTONE:
309 dns->data.EntombedTime = dnsp->data.EntombedTime;
310 break;
312 case DNS_TYPE_A:
313 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
314 break;
316 case DNS_TYPE_NS:
317 len = strlen(dnsp->data.ns);
318 if (dnsp->data.ns[len-1] == '.') {
319 dns->data.name.len = len;
320 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
321 } else {
322 dns->data.name.len = len+1;
323 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
325 break;
327 case DNS_TYPE_CNAME:
328 len = strlen(dnsp->data.cname);
329 if (dnsp->data.cname[len-1] == '.') {
330 dns->data.name.len = len;
331 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
332 } else {
333 dns->data.name.len = len+1;
334 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
336 break;
338 case DNS_TYPE_SOA:
339 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
340 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
341 dns->data.soa.dwRetry = dnsp->data.soa.retry;
342 dns->data.soa.dwExpire = dnsp->data.soa.expire;
343 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
345 len = strlen(dnsp->data.soa.mname);
346 if (dnsp->data.soa.mname[len-1] == '.') {
347 dns->data.soa.NamePrimaryServer.len = len;
348 dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
349 } else {
350 dns->data.soa.NamePrimaryServer.len = len+1;
351 dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
354 len = strlen(dnsp->data.soa.rname);
355 if (dnsp->data.soa.rname[len-1] == '.') {
356 dns->data.soa.ZoneAdministratorEmail.len = len;
357 dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
358 } else {
359 dns->data.soa.ZoneAdministratorEmail.len = len+1;
360 dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
362 break;
364 case DNS_TYPE_PTR:
365 dns->data.ptr.len = strlen(dnsp->data.ptr);
366 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
367 break;
369 case DNS_TYPE_MX:
370 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
371 len = strlen(dnsp->data.mx.nameTarget);
372 if (dnsp->data.mx.nameTarget[len-1] == '.') {
373 dns->data.mx.nameExchange.len = len;
374 dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
375 } else {
376 dns->data.mx.nameExchange.len = len+1;
377 dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
379 break;
381 case DNS_TYPE_TXT:
382 dns->data.txt.count = dnsp->data.txt.count;
383 dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
384 for (i=0; i<dnsp->data.txt.count; i++) {
385 dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
386 dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
388 break;
390 case DNS_TYPE_AAAA:
391 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
392 break;
394 case DNS_TYPE_SRV:
395 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
396 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
397 dns->data.srv.wPort = dnsp->data.srv.wPort;
398 len = strlen(dnsp->data.srv.nameTarget);
399 if (dnsp->data.srv.nameTarget[len-1] == '.') {
400 dns->data.srv.nameTarget.len = len;
401 dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
402 } else {
403 dns->data.srv.nameTarget.len = len+1;
404 dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
406 break;
408 default:
409 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_RECORD_DATA));
410 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d\n", dnsp->wType));
415 WERROR dns_to_dnsp_convert(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns,
416 struct dnsp_DnssrvRpcRecord **out_dnsp, bool check_name)
418 WERROR res;
419 int i, len;
420 const char *name;
421 char *talloc_res = NULL;
422 struct dnsp_DnssrvRpcRecord *dnsp = NULL;
424 dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
425 if (dnsp == NULL) {
426 return WERR_NOT_ENOUGH_MEMORY;
429 dnsp->wDataLength = dns->wDataLength;
430 dnsp->wType = dns->wType;
431 dnsp->version = 5;
432 dnsp->rank = dns->dwFlags & 0x000000FF;
433 dnsp->dwSerial = dns->dwSerial;
434 dnsp->dwTtlSeconds = dns->dwTtlSeconds;
435 dnsp->dwTimeStamp = dns->dwTimeStamp;
437 switch (dns->wType) {
439 case DNS_TYPE_TOMBSTONE:
440 dnsp->data.EntombedTime = dns->data.EntombedTime;
441 break;
443 case DNS_TYPE_A:
444 talloc_res = talloc_strdup(mem_ctx, dns->data.ipv4);
445 if (talloc_res == NULL) {
446 goto fail_nomemory;
448 dnsp->data.ipv4 = talloc_res;
449 break;
451 case DNS_TYPE_NS:
452 name = dns->data.name.str;
453 len = dns->data.name.len;
455 if (check_name) {
456 res = dns_name_check(mem_ctx, len, name);
457 if (!W_ERROR_IS_OK(res)) {
458 return res;
462 if (len > 0 && name[len-1] == '.') {
463 talloc_res = talloc_strndup(mem_ctx, name, len-1);
464 if (talloc_res == NULL) {
465 goto fail_nomemory;
467 dnsp->data.ns = talloc_res;
468 } else {
469 talloc_res = talloc_strdup(mem_ctx, name);
470 if (talloc_res == NULL) {
471 goto fail_nomemory;
473 dnsp->data.ns = talloc_res;
476 break;
478 case DNS_TYPE_CNAME:
479 name = dns->data.name.str;
480 len = dns->data.name.len;
482 if (check_name) {
483 res = dns_name_check(mem_ctx, len, name);
484 if (!W_ERROR_IS_OK(res)) {
485 return res;
489 if (len > 0 && name[len-1] == '.') {
490 talloc_res = talloc_strndup(mem_ctx, name, len-1);
491 if (talloc_res == NULL) {
492 goto fail_nomemory;
494 dnsp->data.cname = talloc_res;
495 } else {
496 talloc_res = talloc_strdup(mem_ctx, name);
497 if (talloc_res == NULL) {
498 goto fail_nomemory;
500 dnsp->data.cname = talloc_res;
503 break;
505 case DNS_TYPE_SOA:
506 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
507 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
508 dnsp->data.soa.retry = dns->data.soa.dwRetry;
509 dnsp->data.soa.expire = dns->data.soa.dwExpire;
510 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
512 name = dns->data.soa.NamePrimaryServer.str;
513 len = dns->data.soa.NamePrimaryServer.len;
515 if (check_name) {
516 res = dns_name_check(mem_ctx, len, name);
517 if (!W_ERROR_IS_OK(res)) {
518 return res;
522 if (len > 0 && name[len-1] == '.') {
523 talloc_res = talloc_strndup(mem_ctx, name, len-1);
524 if (talloc_res == NULL) {
525 goto fail_nomemory;
527 dnsp->data.soa.mname = talloc_res;
528 } else {
529 talloc_res = talloc_strdup(mem_ctx, name);
530 if (talloc_res == NULL) {
531 goto fail_nomemory;
533 dnsp->data.soa.mname = talloc_res;
536 name = dns->data.soa.ZoneAdministratorEmail.str;
537 len = dns->data.soa.ZoneAdministratorEmail.len;
539 res = dns_name_check(mem_ctx, len, name);
540 if (!W_ERROR_IS_OK(res)) {
541 return res;
544 if (len > 0 && name[len-1] == '.') {
545 talloc_res = talloc_strndup(mem_ctx, name, len-1);
546 if (talloc_res == NULL) {
547 goto fail_nomemory;
549 dnsp->data.soa.rname = talloc_res;
550 } else {
551 talloc_res = talloc_strdup(mem_ctx, name);
552 if (talloc_res == NULL) {
553 goto fail_nomemory;
555 dnsp->data.soa.rname = talloc_res;
558 break;
560 case DNS_TYPE_PTR:
561 name = dns->data.ptr.str;
562 len = dns->data.ptr.len;
564 if (check_name) {
565 res = dns_name_check(mem_ctx, len, name);
566 if (!W_ERROR_IS_OK(res)) {
567 return res;
571 talloc_res = talloc_strdup(mem_ctx, name);
572 if (talloc_res == NULL) {
573 goto fail_nomemory;
575 dnsp->data.ptr = talloc_res;
577 break;
579 case DNS_TYPE_MX:
580 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
582 name = dns->data.mx.nameExchange.str;
583 len = dns->data.mx.nameExchange.len;
585 if (check_name) {
586 res = dns_name_check(mem_ctx, len, name);
587 if (!W_ERROR_IS_OK(res)) {
588 return res;
592 if (len > 0 && name[len-1] == '.') {
593 talloc_res = talloc_strndup(mem_ctx, name, len-1);
594 if (talloc_res == NULL) {
595 goto fail_nomemory;
597 dnsp->data.mx.nameTarget = talloc_res;
598 } else {
599 talloc_res = talloc_strdup(mem_ctx, name);
600 if (talloc_res == NULL) {
601 goto fail_nomemory;
603 dnsp->data.mx.nameTarget = talloc_res;
606 break;
608 case DNS_TYPE_TXT:
609 dnsp->data.txt.count = dns->data.txt.count;
610 dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
611 for (i=0; i<dns->data.txt.count; i++) {
612 talloc_res = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
613 if (talloc_res == NULL) {
614 goto fail_nomemory;
616 dnsp->data.txt.str[i] = talloc_res;
618 break;
620 case DNS_TYPE_AAAA:
621 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
622 break;
624 case DNS_TYPE_SRV:
625 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
626 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
627 dnsp->data.srv.wPort = dns->data.srv.wPort;
629 name = dns->data.srv.nameTarget.str;
630 len = dns->data.srv.nameTarget.len;
632 if (check_name) {
633 res = dns_name_check(mem_ctx, len, name);
634 if (!W_ERROR_IS_OK(res)) {
635 return res;
639 if (len > 0 && name[len-1] == '.') {
640 talloc_res = talloc_strndup(mem_ctx, name, len-1);
641 if (talloc_res == NULL) {
642 goto fail_nomemory;
644 dnsp->data.srv.nameTarget = talloc_res;
645 } else {
646 talloc_res = talloc_strdup(mem_ctx, name);
647 if (talloc_res == NULL) {
648 goto fail_nomemory;
650 dnsp->data.srv.nameTarget = talloc_res;
653 break;
655 default:
656 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
657 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d\n", dns->wType));
660 *out_dnsp = dnsp;
661 return WERR_OK;
663 fail_nomemory:
664 return WERR_NOT_ENOUGH_MEMORY;
667 /* Initialize tree with given name as the root */
668 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
670 struct dns_tree *tree;
672 tree = talloc_zero(mem_ctx, struct dns_tree);
673 if (tree == NULL) {
674 return NULL;
677 tree->name = talloc_strdup(tree, name);
678 if (tree->name == NULL) {
679 talloc_free(tree);
680 return NULL;
683 tree->data = data;
685 return tree;
689 /* Add a child one level below */
690 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
692 struct dns_tree *node;
694 node = talloc_zero(tree, struct dns_tree);
695 if (node == NULL) {
696 return NULL;
699 node->name = talloc_strdup(tree, name);
700 if (node->name == NULL) {
701 talloc_free(node);
702 return NULL;
704 node->level = tree->level + 1;
705 node->num_children = 0;
706 node->children = NULL;
707 node->data = data;
709 if (tree->num_children == 0) {
710 tree->children = talloc_zero(tree, struct dns_tree *);
711 } else {
712 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
713 tree->num_children+1);
715 if (tree->children == NULL) {
716 talloc_free(node);
717 return NULL;
719 tree->children[tree->num_children] = node;
720 tree->num_children++;
722 return node;
725 /* Find a node that matches the name components */
726 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
728 struct dns_tree *node, *next;
729 int i, j, start;
731 *match_count = -1;
733 if (strcmp(tree->name, "@") == 0) {
734 start = 0;
735 } else {
736 if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
737 return NULL;
739 start = 1;
740 *match_count = 0;
743 node = tree;
744 for (i=start; i<ncount; i++) {
745 if (node->num_children == 0) {
746 break;
748 next = NULL;
749 for (j=0; j<node->num_children; j++) {
750 if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
751 next = node->children[j];
752 *match_count = i;
753 break;
756 if (next == NULL) {
757 break;
758 } else {
759 node = next;
763 return node;
766 /* Build a 2-level tree for resulting dns names */
767 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
769 struct dns_tree *root, *base, *tree, *node;
770 const char *ptr;
771 int rootcount, ncount;
772 char **nlist;
773 int i, level, match_count;
775 rootcount = dns_split_name_components(mem_ctx, name, &nlist);
776 if (rootcount <= 0) {
777 return NULL;
780 root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
781 if (root == NULL) {
782 talloc_free(nlist);
783 return NULL;
786 tree = root;
787 for (i=rootcount-2; i>=0; i--) {
788 tree = dns_tree_add(tree, nlist[i], NULL);
789 if (tree == NULL) {
790 goto failed;
794 base = tree;
796 /* Add all names in the result in a tree */
797 for (i=0; i<res->count; i++) {
798 ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
799 if (ptr == NULL) {
800 DBG_ERR("dnsserver: dns record has no name (%s)\n",
801 ldb_dn_get_linearized(res->msgs[i]->dn));
802 goto failed;
806 * This might be the sub-domain in the zone being
807 * requested, or @ for the root of the zone
809 if (strcasecmp(ptr, name) == 0) {
810 base->data = res->msgs[i];
811 continue;
814 ncount = dns_split_name_components(root, ptr, &nlist);
815 if (ncount < 0) {
816 goto failed;
819 /* Find matching node */
820 tree = dns_tree_find(root, ncount, nlist, &match_count);
821 if (tree == NULL) {
822 goto failed;
825 /* If the node is on leaf, then add record data */
826 if (match_count+1 == ncount) {
827 tree->data = res->msgs[i];
830 /* Add missing name components */
831 for (level=match_count+1; level<ncount; level++) {
832 if (tree->level == rootcount+1) {
833 break;
835 if (level == ncount-1) {
836 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
837 } else {
838 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
840 if (node == NULL) {
841 goto failed;
843 tree = node;
846 talloc_free(nlist);
849 /* Mark the base record, so it can be found easily */
850 base->level = -1;
852 return root;
854 failed:
855 talloc_free(nlist);
856 talloc_free(root);
857 return NULL;
861 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
863 int i;
864 char **ptr = *add_names;
865 int count = *add_count;
867 for (i=0; i<count; i++) {
868 if (strcasecmp(ptr[i], name) == 0) {
869 return;
873 ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
874 if (ptr == NULL) {
875 return;
878 ptr[count] = talloc_strdup(mem_ctx, name);
879 if (ptr[count] == NULL) {
880 talloc_free(ptr);
881 return;
884 *add_names = ptr;
885 *add_count = count+1;
889 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
891 if (add_names == NULL) {
892 return;
895 switch (rec->wType) {
897 case DNS_TYPE_NS:
898 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
899 break;
901 case DNS_TYPE_CNAME:
902 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
903 break;
905 case DNS_TYPE_SOA:
906 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
907 break;
909 case DNS_TYPE_MX:
910 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
911 break;
913 case DNS_TYPE_SRV:
914 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
915 break;
917 default:
918 break;
923 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)
934 struct ldb_message_element *el;
935 const char *ptr;
936 int i, j;
937 bool found;
939 if (recs->count == 0) {
940 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
941 } else {
942 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
944 if (recs->rec == NULL) {
945 return WERR_NOT_ENOUGH_MEMORY;
947 i = recs->count;
948 recs->rec[i].wLength = 0;
949 recs->rec[i].wRecordCount = 0;
950 recs->rec[i].dwChildCount = num_children;
951 recs->rec[i].dwFlags = 0;
953 /* The base records returned with empty name */
954 /* Children records returned with names */
955 if (branch_name == NULL) {
956 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
957 recs->rec[i].dnsNodeName.len = 0;
958 } else {
959 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
960 recs->rec[i].dnsNodeName.len = strlen(branch_name);
962 recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
963 recs->count++;
965 /* Allow empty records */
966 if (msg == NULL) {
967 return WERR_OK;
970 /* Do not return RR records, if the node has children */
971 if (branch_name != NULL && num_children > 0) {
972 return WERR_OK;
975 ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
976 if (ptr == NULL) {
977 DBG_ERR("dnsserver: dns record has no name (%s)\n",
978 ldb_dn_get_linearized(msg->dn));
979 return WERR_INTERNAL_DB_ERROR;
982 el = ldb_msg_find_element(msg, "dnsRecord");
983 if (el == NULL || el->values == 0) {
984 return WERR_OK;
987 /* Add RR records */
988 for (j=0; j<el->num_values; j++) {
989 struct dnsp_DnssrvRpcRecord dnsp_rec;
990 struct DNS_RPC_RECORD *dns_rec;
991 enum ndr_err_code ndr_err;
993 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
994 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
995 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
996 DEBUG(0, ("dnsserver: Unable to parse dns record (%s)\n", ldb_dn_get_linearized(msg->dn)));
997 return WERR_INTERNAL_DB_ERROR;
1000 /* Match the records based on search criteria */
1001 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
1002 found = false;
1004 if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
1005 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1006 found = true;
1007 } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
1009 * If branch_name is NULL, we're
1010 * explicitly asked to also return
1011 * DNS_RANK_NS_GLUE records
1013 if (branch_name == NULL) {
1014 found = true;
1018 if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
1019 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1020 found = true;
1023 if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
1024 if (dnsp_rec.rank == DNS_RANK_GLUE) {
1025 found = true;
1028 if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
1029 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
1030 found = true;
1034 if (found) {
1035 recs->rec[i].records = talloc_realloc(recs,
1036 recs->rec[i].records,
1037 struct DNS_RPC_RECORD,
1038 recs->rec[i].wRecordCount+1);
1039 if (recs->rec[i].records == NULL) {
1040 return WERR_NOT_ENOUGH_MEMORY;
1043 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
1044 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
1046 /* Fix record flags */
1047 if (strcmp(ptr, "@") == 0) {
1048 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1050 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1051 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
1055 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
1056 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1059 recs->rec[i].wRecordCount++;
1061 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
1066 return WERR_OK;
1070 int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const *m2,
1071 const char *search_name)
1073 const char *name1, *name2;
1074 const char *ptr1, *ptr2;
1076 name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
1077 name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
1079 * We sort NULL names to the start of the list, because the only
1080 * caller of this function, dnsserver_enumerate_records() will call
1081 * dns_build_tree() with the sorted list, which will always return an
1082 * error when it hits a NULL, so we might as well make that happen
1083 * quickly.
1085 if (name1 == name2) {
1086 /* this includes the both NULL case */
1087 return 0;
1089 if (name1 == NULL) {
1090 return -1;
1092 if (name2 == NULL) {
1093 return 1;
1096 /* Compare the last components of names.
1097 * If search_name is not NULL, compare the second last components of names */
1098 ptr1 = strrchr(name1, '.');
1099 if (ptr1 == NULL) {
1100 ptr1 = name1;
1101 } else {
1102 if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
1103 ptr1--;
1104 while (ptr1 != name1) {
1105 ptr1--;
1106 if (*ptr1 == '.') {
1107 break;
1111 if (*ptr1 == '.') {
1112 ptr1 = &ptr1[1];
1116 ptr2 = strrchr(name2, '.');
1117 if (ptr2 == NULL) {
1118 ptr2 = name2;
1119 } else {
1120 if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
1121 ptr2--;
1122 while (ptr2 != name2) {
1123 ptr2--;
1124 if (*ptr2 == '.') {
1125 break;
1129 if (*ptr2 == '.') {
1130 ptr2 = &ptr2[1];
1134 return strcasecmp(ptr1, ptr2);