s4:rpc_server: Fix size types in dcerpc dnsserver
[Samba.git] / source4 / rpc_server / dnsserver / dnsdata.c
blob8080fa480b284329a06cb5cc3b7edce105ff2274
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"
30 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
32 struct IP4_ARRAY *ret;
34 if (!ip4) {
35 return NULL;
38 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
39 if (!ret) {
40 return ret;
43 ret->AddrCount = ip4->AddrCount;
44 if (ip4->AddrCount > 0) {
45 ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
46 if (ret->AddrArray) {
47 memcpy(ret->AddrArray, ip4->AddrArray,
48 sizeof(unsigned int) * ip4->AddrCount);
49 } else {
50 talloc_free(ret);
51 return NULL;
54 return ret;
58 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
59 struct IP4_ARRAY *ip4)
61 struct DNS_ADDR_ARRAY *ret;
62 int i;
64 if (!ip4) {
65 return NULL;
68 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
69 if (!ret) {
70 return ret;
73 ret->MaxCount = ip4->AddrCount;
74 ret->AddrCount = ip4->AddrCount;
75 ret->Family = AF_INET;
76 if (ip4->AddrCount > 0) {
77 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
78 if (ret->AddrArray) {
79 for (i=0; i<ip4->AddrCount; i++) {
80 ret->AddrArray[i].MaxSa[0] = 0x02;
81 ret->AddrArray[i].MaxSa[3] = 53;
82 memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
83 sizeof(unsigned int));
84 ret->AddrArray[i].DnsAddrUserDword[0] = 6;
87 } else {
88 talloc_free(ret);
89 return NULL;
92 return ret;
95 struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
96 struct DNS_ADDR_ARRAY *ip)
98 struct IP4_ARRAY *ret;
99 size_t i, count, curr;
101 if (ip == NULL) {
102 return NULL;
104 /* We must only return IPv4 addresses.
105 The passed DNS_ADDR_ARRAY may contain:
106 - only ipv4 addresses
107 - only ipv6 addresses
108 - a mixture of both
109 - an empty array
111 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
112 if (!ret) {
113 return ret;
115 if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
116 ret->AddrCount = 0;
117 return ret;
119 /* Now only ipv4 addresses or a mixture are left */
120 count = 0;
121 for (i = 0; i < ip->AddrCount; i++) {
122 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
123 /* Is ipv4 */
124 count++;
127 if (count == 0) {
128 /* should not happen */
129 ret->AddrCount = 0;
130 return ret;
132 ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
133 if (ret->AddrArray) {
134 curr = 0;
135 for (i = 0; i < ip->AddrCount; i++) {
136 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
137 /* Is ipv4 */
138 memcpy(&ret->AddrArray[curr],
139 &ip->AddrArray[i].MaxSa[4],
140 sizeof(uint32_t));
141 curr++;
144 } else {
145 talloc_free(ret);
146 return NULL;
148 ret->AddrCount = curr;
149 return ret;
152 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
153 struct DNS_ADDR_ARRAY *addr)
155 struct DNS_ADDR_ARRAY *ret;
157 if (!addr) {
158 return NULL;
161 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
162 if (!ret) {
163 return ret;
166 ret->MaxCount = addr->MaxCount;
167 ret->AddrCount = addr->AddrCount;
168 ret->Family = addr->Family;
169 if (addr->AddrCount > 0) {
170 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
171 if (ret->AddrArray) {
172 memcpy(ret->AddrArray, addr->AddrArray,
173 sizeof(struct DNS_ADDR) * addr->AddrCount);
174 } else {
175 talloc_free(ret);
176 return NULL;
179 return ret;
183 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
185 char *str = NULL, *ptr, **list;
186 int count = 0;
188 if (name == NULL) {
189 return 0;
192 str = talloc_strdup(tmp_ctx, name);
193 if (!str) {
194 goto failed;
197 list = talloc_zero_array(tmp_ctx, char *, 0);
198 if (!list) {
199 goto failed;
202 ptr = strtok(str, ".");
203 while (ptr != NULL) {
204 count++;
205 list = talloc_realloc(tmp_ctx, list, char *, count);
206 if (!list) {
207 goto failed;
209 list[count-1] = talloc_strdup(tmp_ctx, ptr);
210 if (list[count-1] == NULL) {
211 goto failed;
213 ptr = strtok(NULL, ".");
216 talloc_free(str);
218 *components = list;
219 return count;
221 failed:
222 if (str) {
223 talloc_free(str);
225 return -1;
229 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
231 char **nlist, **zlist;
232 char *prefix;
233 int ncount, zcount, i, match;
236 * If node_name is "@", return the zone_name
237 * If node_name is ".", return NULL
238 * If there is no '.' in node_name, return the node_name as is.
240 * If node_name does not have zone_name in it, return the node_name as is.
242 * If node_name has additional components as compared to zone_name
243 * return only the additional components as a prefix.
246 if (strcmp(node_name, "@") == 0) {
247 prefix = talloc_strdup(tmp_ctx, zone_name);
248 } else if (strcmp(node_name, ".") == 0) {
249 prefix = NULL;
250 } else if (strchr(node_name, '.') == NULL) {
251 prefix = talloc_strdup(tmp_ctx, node_name);
252 } else {
253 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
254 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
255 if (zcount < 0 || ncount < 0) {
256 return NULL;
259 if (ncount < zcount) {
260 prefix = talloc_strdup(tmp_ctx, node_name);
261 } else {
262 match = 0;
263 for (i=1; i<=zcount; i++) {
264 if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
265 break;
267 match++;
270 if (match == ncount) {
271 prefix = talloc_strdup(tmp_ctx, zone_name);
272 } else {
273 prefix = talloc_strdup(tmp_ctx, nlist[0]);
274 if (prefix != NULL) {
275 for (i=1; i<ncount-match; i++) {
276 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
277 if (prefix == NULL) {
278 break;
285 talloc_free(zlist);
286 talloc_free(nlist);
289 return prefix;
293 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
294 struct DNS_RPC_RECORD *dns)
296 int i, len;
298 ZERO_STRUCTP(dns);
300 dns->wDataLength = dnsp->wDataLength;
301 dns->wType = dnsp->wType;
302 dns->dwFlags = dnsp->rank;
303 dns->dwSerial = dnsp->dwSerial;
304 dns->dwTtlSeconds = dnsp->dwTtlSeconds;
305 dns->dwTimeStamp = dnsp->dwTimeStamp;
307 switch (dnsp->wType) {
309 case DNS_TYPE_TOMBSTONE:
310 dns->data.timestamp = dnsp->data.timestamp;
311 break;
313 case DNS_TYPE_A:
314 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
315 break;
317 case DNS_TYPE_NS:
318 len = strlen(dnsp->data.ns);
319 if (dnsp->data.ns[len-1] == '.') {
320 dns->data.name.len = len;
321 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
322 } else {
323 dns->data.name.len = len+1;
324 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
326 break;
328 case DNS_TYPE_CNAME:
329 len = strlen(dnsp->data.cname);
330 if (dnsp->data.cname[len-1] == '.') {
331 dns->data.name.len = len;
332 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
333 } else {
334 dns->data.name.len = len+1;
335 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
337 break;
339 case DNS_TYPE_SOA:
340 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
341 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
342 dns->data.soa.dwRetry = dnsp->data.soa.retry;
343 dns->data.soa.dwExpire = dnsp->data.soa.expire;
344 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
346 len = strlen(dnsp->data.soa.mname);
347 if (dnsp->data.soa.mname[len-1] == '.') {
348 dns->data.soa.NamePrimaryServer.len = len;
349 dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
350 } else {
351 dns->data.soa.NamePrimaryServer.len = len+1;
352 dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
355 len = strlen(dnsp->data.soa.rname);
356 if (dnsp->data.soa.rname[len-1] == '.') {
357 dns->data.soa.ZoneAdministratorEmail.len = len;
358 dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
359 } else {
360 dns->data.soa.ZoneAdministratorEmail.len = len+1;
361 dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
363 break;
365 case DNS_TYPE_PTR:
366 dns->data.ptr.len = strlen(dnsp->data.ptr);
367 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
368 break;
370 case DNS_TYPE_MX:
371 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
372 len = strlen(dnsp->data.mx.nameTarget);
373 if (dnsp->data.mx.nameTarget[len-1] == '.') {
374 dns->data.mx.nameExchange.len = len;
375 dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
376 } else {
377 dns->data.mx.nameExchange.len = len+1;
378 dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
380 break;
382 case DNS_TYPE_TXT:
383 dns->data.txt.count = dnsp->data.txt.count;
384 dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
385 for (i=0; i<dnsp->data.txt.count; i++) {
386 dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
387 dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
389 break;
391 case DNS_TYPE_AAAA:
392 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
393 break;
395 case DNS_TYPE_SRV:
396 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
397 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
398 dns->data.srv.wPort = dnsp->data.srv.wPort;
399 len = strlen(dnsp->data.srv.nameTarget);
400 if (dnsp->data.srv.nameTarget[len-1] == '.') {
401 dns->data.srv.nameTarget.len = len;
402 dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
403 } else {
404 dns->data.srv.nameTarget.len = len+1;
405 dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
407 break;
409 default:
410 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
411 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
416 WERROR dns_to_dnsp_convert(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns,
417 struct dnsp_DnssrvRpcRecord **out_dnsp, bool check_name)
419 WERROR res;
420 int i, len;
421 const char *name;
422 char *talloc_res = NULL;
423 struct dnsp_DnssrvRpcRecord *dnsp = NULL;
425 dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
426 if (dnsp == NULL) {
427 return WERR_NOT_ENOUGH_MEMORY;
430 dnsp->wDataLength = dns->wDataLength;
431 dnsp->wType = dns->wType;
432 dnsp->version = 5;
433 dnsp->rank = dns->dwFlags & 0x000000FF;
434 dnsp->dwSerial = dns->dwSerial;
435 dnsp->dwTtlSeconds = dns->dwTtlSeconds;
436 dnsp->dwTimeStamp = dns->dwTimeStamp;
438 switch (dns->wType) {
440 case DNS_TYPE_TOMBSTONE:
441 dnsp->data.timestamp = dns->data.timestamp;
442 break;
444 case DNS_TYPE_A:
445 talloc_res = talloc_strdup(mem_ctx, dns->data.ipv4);
446 if (talloc_res == NULL) {
447 goto fail_nomemory;
449 dnsp->data.ipv4 = talloc_res;
450 break;
452 case DNS_TYPE_NS:
453 name = dns->data.name.str;
454 len = dns->data.name.len;
456 if (check_name) {
457 res = dns_name_check(mem_ctx, len, name);
458 if (!W_ERROR_IS_OK(res)) {
459 return res;
463 if (len > 0 && name[len-1] == '.') {
464 talloc_res = talloc_strndup(mem_ctx, name, len-1);
465 if (talloc_res == NULL) {
466 goto fail_nomemory;
468 dnsp->data.ns = talloc_res;
469 } else {
470 talloc_res = talloc_strdup(mem_ctx, name);
471 if (talloc_res == NULL) {
472 goto fail_nomemory;
474 dnsp->data.ns = talloc_res;
477 break;
479 case DNS_TYPE_CNAME:
480 name = dns->data.name.str;
481 len = dns->data.name.len;
483 if (check_name) {
484 res = dns_name_check(mem_ctx, len, name);
485 if (!W_ERROR_IS_OK(res)) {
486 return res;
490 if (len > 0 && name[len-1] == '.') {
491 talloc_res = talloc_strndup(mem_ctx, name, len-1);
492 if (talloc_res == NULL) {
493 goto fail_nomemory;
495 dnsp->data.cname = talloc_res;
496 } else {
497 talloc_res = talloc_strdup(mem_ctx, name);
498 if (talloc_res == NULL) {
499 goto fail_nomemory;
501 dnsp->data.cname = talloc_res;
504 break;
506 case DNS_TYPE_SOA:
507 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
508 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
509 dnsp->data.soa.retry = dns->data.soa.dwRetry;
510 dnsp->data.soa.expire = dns->data.soa.dwExpire;
511 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
513 name = dns->data.soa.NamePrimaryServer.str;
514 len = dns->data.soa.NamePrimaryServer.len;
516 if (check_name) {
517 res = dns_name_check(mem_ctx, len, name);
518 if (!W_ERROR_IS_OK(res)) {
519 return res;
523 if (len > 0 && name[len-1] == '.') {
524 talloc_res = talloc_strndup(mem_ctx, name, len-1);
525 if (talloc_res == NULL) {
526 goto fail_nomemory;
528 dnsp->data.soa.mname = talloc_res;
529 } else {
530 talloc_res = talloc_strdup(mem_ctx, name);
531 if (talloc_res == NULL) {
532 goto fail_nomemory;
534 dnsp->data.soa.mname = talloc_res;
537 name = dns->data.soa.ZoneAdministratorEmail.str;
538 len = dns->data.soa.ZoneAdministratorEmail.len;
540 res = dns_name_check(mem_ctx, len, name);
541 if (!W_ERROR_IS_OK(res)) {
542 return res;
545 if (len > 0 && name[len-1] == '.') {
546 talloc_res = talloc_strndup(mem_ctx, name, len-1);
547 if (talloc_res == NULL) {
548 goto fail_nomemory;
550 dnsp->data.soa.rname = talloc_res;
551 } else {
552 talloc_res = talloc_strdup(mem_ctx, name);
553 if (talloc_res == NULL) {
554 goto fail_nomemory;
556 dnsp->data.soa.rname = talloc_res;
559 break;
561 case DNS_TYPE_PTR:
562 name = dns->data.ptr.str;
563 len = dns->data.ptr.len;
565 if (check_name) {
566 res = dns_name_check(mem_ctx, len, name);
567 if (!W_ERROR_IS_OK(res)) {
568 return res;
572 talloc_res = talloc_strdup(mem_ctx, name);
573 if (talloc_res == NULL) {
574 goto fail_nomemory;
576 dnsp->data.ptr = talloc_res;
578 break;
580 case DNS_TYPE_MX:
581 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
583 name = dns->data.mx.nameExchange.str;
584 len = dns->data.mx.nameExchange.len;
586 if (check_name) {
587 res = dns_name_check(mem_ctx, len, name);
588 if (!W_ERROR_IS_OK(res)) {
589 return res;
593 if (len > 0 && name[len-1] == '.') {
594 talloc_res = talloc_strndup(mem_ctx, name, len-1);
595 if (talloc_res == NULL) {
596 goto fail_nomemory;
598 dnsp->data.mx.nameTarget = talloc_res;
599 } else {
600 talloc_res = talloc_strdup(mem_ctx, name);
601 if (talloc_res == NULL) {
602 goto fail_nomemory;
604 dnsp->data.mx.nameTarget = talloc_res;
607 break;
609 case DNS_TYPE_TXT:
610 dnsp->data.txt.count = dns->data.txt.count;
611 dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
612 for (i=0; i<dns->data.txt.count; i++) {
613 talloc_res = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
614 if (talloc_res == NULL) {
615 goto fail_nomemory;
617 dnsp->data.txt.str[i] = talloc_res;
619 break;
621 case DNS_TYPE_AAAA:
622 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
623 break;
625 case DNS_TYPE_SRV:
626 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
627 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
628 dnsp->data.srv.wPort = dns->data.srv.wPort;
630 name = dns->data.srv.nameTarget.str;
631 len = dns->data.srv.nameTarget.len;
633 if (check_name) {
634 res = dns_name_check(mem_ctx, len, name);
635 if (!W_ERROR_IS_OK(res)) {
636 return res;
640 if (len > 0 && name[len-1] == '.') {
641 talloc_res = talloc_strndup(mem_ctx, name, len-1);
642 if (talloc_res == NULL) {
643 goto fail_nomemory;
645 dnsp->data.srv.nameTarget = talloc_res;
646 } else {
647 talloc_res = talloc_strdup(mem_ctx, name);
648 if (talloc_res == NULL) {
649 goto fail_nomemory;
651 dnsp->data.srv.nameTarget = talloc_res;
654 break;
656 default:
657 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
658 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
661 *out_dnsp = dnsp;
662 return WERR_OK;
664 fail_nomemory:
665 return WERR_NOT_ENOUGH_MEMORY;
668 /* Intialize tree with given name as the root */
669 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
671 struct dns_tree *tree;
673 tree = talloc_zero(mem_ctx, struct dns_tree);
674 if (tree == NULL) {
675 return NULL;
678 tree->name = talloc_strdup(tree, name);
679 if (tree->name == NULL) {
680 talloc_free(tree);
681 return NULL;
684 tree->data = data;
686 return tree;
690 /* Add a child one level below */
691 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
693 struct dns_tree *node;
695 node = talloc_zero(tree, struct dns_tree);
696 if (node == NULL) {
697 return NULL;
700 node->name = talloc_strdup(tree, name);
701 if (node->name == NULL) {
702 talloc_free(node);
703 return NULL;
705 node->level = tree->level + 1;
706 node->num_children = 0;
707 node->children = NULL;
708 node->data = data;
710 if (tree->num_children == 0) {
711 tree->children = talloc_zero(tree, struct dns_tree *);
712 } else {
713 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
714 tree->num_children+1);
716 if (tree->children == NULL) {
717 talloc_free(node);
718 return NULL;
720 tree->children[tree->num_children] = node;
721 tree->num_children++;
723 return node;
726 /* Find a node that matches the name components */
727 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
729 struct dns_tree *node, *next;
730 int i, j, start;
732 *match_count = -1;
734 if (strcmp(tree->name, "@") == 0) {
735 start = 0;
736 } else {
737 if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
738 return NULL;
740 start = 1;
741 *match_count = 0;
744 node = tree;
745 for (i=start; i<ncount; i++) {
746 if (node->num_children == 0) {
747 break;
749 next = NULL;
750 for (j=0; j<node->num_children; j++) {
751 if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
752 next = node->children[j];
753 *match_count = i;
754 break;
757 if (next == NULL) {
758 break;
759 } else {
760 node = next;
764 return node;
767 /* Build a 2-level tree for resulting dns names */
768 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
770 struct dns_tree *root, *base, *tree, *node;
771 const char *ptr;
772 int rootcount, ncount;
773 char **nlist;
774 int i, level, match_count;
776 rootcount = dns_split_name_components(mem_ctx, name, &nlist);
777 if (rootcount <= 0) {
778 return NULL;
781 root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
782 if (root == NULL) {
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);
800 if (strcmp(ptr, "@") == 0) {
801 base->data = res->msgs[i];
802 continue;
803 } else if (strcasecmp(ptr, name) == 0) {
804 base->data = res->msgs[i];
805 continue;
808 ncount = dns_split_name_components(root, ptr, &nlist);
809 if (ncount < 0) {
810 goto failed;
813 /* Find matching node */
814 tree = dns_tree_find(root, ncount, nlist, &match_count);
815 if (tree == NULL) {
816 goto failed;
819 /* If the node is on leaf, then add record data */
820 if (match_count+1 == ncount) {
821 tree->data = res->msgs[i];
824 /* Add missing name components */
825 for (level=match_count+1; level<ncount; level++) {
826 if (tree->level == rootcount+1) {
827 break;
829 if (level == ncount-1) {
830 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
831 } else {
832 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
834 if (node == NULL) {
835 goto failed;
837 tree = node;
840 talloc_free(nlist);
843 /* Mark the base record, so it can be found easily */
844 base->level = -1;
846 return root;
848 failed:
849 talloc_free(root);
850 return NULL;
854 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
856 int i;
857 char **ptr = *add_names;
858 int count = *add_count;
860 for (i=0; i<count; i++) {
861 if (strcasecmp(ptr[i], name) == 0) {
862 return;
866 ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
867 if (ptr == NULL) {
868 return;
871 ptr[count] = talloc_strdup(mem_ctx, name);
872 if (ptr[count] == NULL) {
873 return;
876 *add_names = ptr;
877 *add_count = count+1;
881 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
883 if (add_names == NULL) {
884 return;
887 switch (rec->wType) {
889 case DNS_TYPE_NS:
890 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
891 break;
893 case DNS_TYPE_CNAME:
894 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
895 break;
897 case DNS_TYPE_SOA:
898 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
899 break;
901 case DNS_TYPE_MX:
902 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
903 break;
905 case DNS_TYPE_SRV:
906 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
907 break;
909 default:
910 break;
915 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
916 struct dnsserver_zone *z,
917 enum dns_record_type record_type,
918 unsigned int select_flag,
919 const char *branch_name,
920 struct ldb_message *msg,
921 int num_children,
922 struct DNS_RPC_RECORDS_ARRAY *recs,
923 char ***add_names,
924 int *add_count)
926 struct ldb_message_element *el;
927 const char *ptr;
928 int i, j;
929 bool found;
931 if (recs->count == 0) {
932 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
933 } else {
934 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
936 if (recs->rec == NULL) {
937 return WERR_NOT_ENOUGH_MEMORY;
939 i = recs->count;
940 recs->rec[i].wLength = 0;
941 recs->rec[i].wRecordCount = 0;
942 recs->rec[i].dwChildCount = num_children;
943 recs->rec[i].dwFlags = 0;
945 /* The base records returned with empty name */
946 /* Children records returned with names */
947 if (branch_name == NULL) {
948 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
949 recs->rec[i].dnsNodeName.len = 0;
950 } else {
951 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
952 recs->rec[i].dnsNodeName.len = strlen(branch_name);
954 recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
955 recs->count++;
957 /* Allow empty records */
958 if (msg == NULL) {
959 return WERR_OK;
962 /* Do not return RR records, if the node has children */
963 if (branch_name != NULL && num_children > 0) {
964 return WERR_OK;
967 ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
968 el = ldb_msg_find_element(msg, "dnsRecord");
969 if (el == NULL || el->values == 0) {
970 return WERR_OK;
973 /* Add RR records */
974 for (j=0; j<el->num_values; j++) {
975 struct dnsp_DnssrvRpcRecord dnsp_rec;
976 struct DNS_RPC_RECORD *dns_rec;
977 enum ndr_err_code ndr_err;
979 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
980 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
981 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
982 DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
983 return WERR_INTERNAL_DB_ERROR;
986 /* Match the records based on search criteria */
987 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
988 found = false;
990 if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
991 if (dnsp_rec.rank == DNS_RANK_ZONE) {
992 found = true;
993 } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
995 * If branch_name is NULL, we're
996 * explicitly asked to also return
997 * DNS_RANK_NS_GLUE records
999 if (branch_name == NULL) {
1000 found = true;
1004 if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
1005 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1006 found = true;
1009 if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
1010 if (dnsp_rec.rank == DNS_RANK_GLUE) {
1011 found = true;
1014 if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
1015 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
1016 found = true;
1020 if (found) {
1021 recs->rec[i].records = talloc_realloc(recs,
1022 recs->rec[i].records,
1023 struct DNS_RPC_RECORD,
1024 recs->rec[i].wRecordCount+1);
1025 if (recs->rec[i].records == NULL) {
1026 return WERR_NOT_ENOUGH_MEMORY;
1029 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
1030 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
1032 /* Fix record flags */
1033 if (strcmp(ptr, "@") == 0) {
1034 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1036 if (dnsp_rec.rank == DNS_RANK_ZONE) {
1037 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
1041 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
1042 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
1045 recs->rec[i].wRecordCount++;
1047 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
1052 return WERR_OK;
1056 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
1057 char *search_name)
1059 const char *name1, *name2;
1060 const char *ptr1, *ptr2;
1062 name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
1063 name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
1064 if (name1 == NULL || name2 == NULL) {
1065 return 0;
1068 /* '@' record and the search_name record gets preference */
1069 if (name1[0] == '@') {
1070 return -1;
1072 if (search_name && strcasecmp(name1, search_name) == 0) {
1073 return -1;
1076 if (name2[0] == '@') {
1077 return 1;
1079 if (search_name && strcasecmp(name2, search_name) == 0) {
1080 return 1;
1083 /* Compare the last components of names.
1084 * If search_name is not NULL, compare the second last components of names */
1085 ptr1 = strrchr(name1, '.');
1086 if (ptr1 == NULL) {
1087 ptr1 = name1;
1088 } else {
1089 if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
1090 ptr1--;
1091 while (ptr1 != name1) {
1092 ptr1--;
1093 if (*ptr1 == '.') {
1094 break;
1098 if (*ptr1 == '.') {
1099 ptr1 = &ptr1[1];
1103 ptr2 = strrchr(name2, '.');
1104 if (ptr2 == NULL) {
1105 ptr2 = name2;
1106 } else {
1107 if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
1108 ptr2--;
1109 while (ptr2 != name2) {
1110 ptr2--;
1111 if (*ptr2 == '.') {
1112 break;
1116 if (*ptr2 == '.') {
1117 ptr2 = &ptr2[1];
1121 return strcasecmp(ptr1, ptr2);
1125 bool dns_name_equal(const char *name1, const char *name2)
1127 size_t len1 = strlen(name1);
1128 size_t len2 = strlen(name2);
1130 if (len1 > 0 && name1[len1-1] == '.') len1--;
1131 if (len2 > 0 && name2[len2-1] == '.') len2--;
1132 if (len1 != len2) {
1133 return false;
1135 return strncasecmp(name1, name2, len1) == 0;
1139 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
1141 bool status;
1142 int i;
1144 if (rec1->wType != rec2->wType) {
1145 return false;
1148 switch(rec1->wType) {
1149 case DNS_TYPE_TOMBSTONE:
1150 return true;
1152 case DNS_TYPE_A:
1153 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
1155 case DNS_TYPE_NS:
1156 return dns_name_equal(rec1->data.ns, rec2->data.ns);
1158 case DNS_TYPE_CNAME:
1159 return dns_name_equal(rec1->data.cname, rec2->data.cname);
1161 case DNS_TYPE_SOA:
1162 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) &&
1163 dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) &&
1164 rec1->data.soa.serial == rec2->data.soa.serial &&
1165 rec1->data.soa.refresh == rec2->data.soa.refresh &&
1166 rec1->data.soa.retry == rec2->data.soa.retry &&
1167 rec1->data.soa.expire == rec2->data.soa.expire &&
1168 rec1->data.soa.minimum == rec2->data.soa.minimum;
1170 case DNS_TYPE_PTR:
1171 return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
1173 case DNS_TYPE_MX:
1174 return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
1175 dns_name_equal(rec1->data.mx.nameTarget, rec2->data.mx.nameTarget);
1177 case DNS_TYPE_TXT:
1178 if (rec1->data.txt.count != rec2->data.txt.count) {
1179 return false;
1181 status = true;
1182 for (i=0; i<rec1->data.txt.count; i++) {
1183 status = status && (strcmp(rec1->data.txt.str[i],
1184 rec2->data.txt.str[i]) == 0);
1186 return status;
1188 case DNS_TYPE_AAAA:
1189 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
1191 case DNS_TYPE_SRV:
1192 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
1193 rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
1194 rec1->data.srv.wPort == rec2->data.srv.wPort &&
1195 dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
1197 default:
1198 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
1199 break;
1202 return false;