s4:provision: set the correct nTSecurityDescriptor on CN=Builtin,... (bug #9481)
[Samba/gebeck_regimport.git] / source4 / rpc_server / dnsserver / dnsdata.c
blob3dc7dccf288a73e72ef0f228e4efdfcd780a5363
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 "lib/replace/system/network.h"
25 #include "librpc/gen_ndr/ndr_dnsp.h"
26 #include "librpc/gen_ndr/ndr_dnsserver.h"
29 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
31 struct IP4_ARRAY *ret;
33 if (!ip4) {
34 return NULL;
37 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
38 if (!ret) {
39 return ret;
42 ret->AddrCount = ip4->AddrCount;
43 if (ip4->AddrCount > 0) {
44 ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
45 if (ret->AddrArray) {
46 memcpy(ret->AddrArray, ip4->AddrArray,
47 sizeof(unsigned int) * ip4->AddrCount);
48 } else {
49 talloc_free(ret);
50 return NULL;
53 return ret;
57 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
58 struct IP4_ARRAY *ip4)
60 struct DNS_ADDR_ARRAY *ret;
61 int i;
63 if (!ip4) {
64 return NULL;
67 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
68 if (!ret) {
69 return ret;
72 ret->MaxCount = ip4->AddrCount;
73 ret->AddrCount = ip4->AddrCount;
74 ret->Family = AF_INET;
75 if (ip4->AddrCount > 0) {
76 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
77 if (ret->AddrArray) {
78 for (i=0; i<ip4->AddrCount; i++) {
79 ret->AddrArray[i].MaxSa[0] = 0x02;
80 ret->AddrArray[i].MaxSa[3] = 53;
81 memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
82 sizeof(unsigned int));
83 ret->AddrArray[i].DnsAddrUserDword[0] = 6;
86 } else {
87 talloc_free(ret);
88 return NULL;
91 return ret;
95 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
96 struct DNS_ADDR_ARRAY *addr)
98 struct DNS_ADDR_ARRAY *ret;
100 if (!addr) {
101 return NULL;
104 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
105 if (!ret) {
106 return ret;
109 ret->MaxCount = addr->MaxCount;
110 ret->AddrCount = addr->AddrCount;
111 ret->Family = addr->Family;
112 if (addr->AddrCount > 0) {
113 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
114 if (ret->AddrArray) {
115 memcpy(ret->AddrArray, addr->AddrArray,
116 sizeof(struct DNS_ADDR) * addr->AddrCount);
117 } else {
118 talloc_free(ret);
119 return NULL;
122 return ret;
126 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
128 char *str = NULL, *ptr, **list;
129 int count = 0;
131 if (name == NULL) {
132 return 0;
135 str = talloc_strdup(tmp_ctx, name);
136 if (!str) {
137 goto failed;
140 list = talloc_zero_array(tmp_ctx, char *, 0);
141 if (!list) {
142 goto failed;
145 ptr = strtok(str, ".");
146 while (ptr != NULL) {
147 count++;
148 list = talloc_realloc(tmp_ctx, list, char *, count);
149 if (!list) {
150 goto failed;
152 list[count-1] = talloc_strdup(tmp_ctx, ptr);
153 if (list[count-1] == NULL) {
154 goto failed;
156 ptr = strtok(NULL, ".");
159 talloc_free(str);
161 *components = list;
162 return count;
164 failed:
165 if (str) {
166 talloc_free(str);
168 return -1;
172 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
174 char **nlist, **zlist;
175 char *prefix;
176 int ncount, zcount, i, match;
179 * If node_name is "@", return the zone_name
180 * If node_name is ".", return NULL
181 * If there is no '.' in node_name, return the node_name as is.
183 * If node_name does not have zone_name in it, return the node_name as is.
185 * If node_name has additional components as compared to zone_name
186 * return only the additional components as a prefix.
189 if (strcmp(node_name, "@") == 0) {
190 prefix = talloc_strdup(tmp_ctx, zone_name);
191 } else if (strcmp(node_name, ".") == 0) {
192 prefix = NULL;
193 } else if (strchr(node_name, '.') == NULL) {
194 prefix = talloc_strdup(tmp_ctx, node_name);
195 } else {
196 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
197 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
198 if (zcount < 0 || ncount < 0) {
199 return NULL;
202 if (ncount < zcount) {
203 prefix = talloc_strdup(tmp_ctx, node_name);
204 } else {
205 match = 0;
206 for (i=1; i<=zcount; i++) {
207 if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
208 break;
210 match++;
213 if (match == ncount) {
214 prefix = talloc_strdup(tmp_ctx, zone_name);
215 } else {
216 prefix = talloc_strdup(tmp_ctx, nlist[0]);
217 if (prefix != NULL) {
218 for (i=1; i<ncount-match; i++) {
219 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
220 if (prefix == NULL) {
221 break;
228 talloc_free(zlist);
229 talloc_free(nlist);
232 return prefix;
236 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
237 struct DNS_RPC_RECORD *dns)
239 int i, len;
241 ZERO_STRUCTP(dns);
243 dns->wDataLength = dnsp->wDataLength;
244 dns->wType = dnsp->wType;
245 dns->dwFlags = dnsp->rank;
246 dns->dwSerial = dnsp->dwSerial;
247 dns->dwTtlSeconds = dnsp->dwTtlSeconds;
248 dns->dwTimeStamp = dnsp->dwTimeStamp;
250 switch (dnsp->wType) {
252 case DNS_TYPE_TOMBSTONE:
253 dns->data.timestamp = dnsp->data.timestamp;
254 break;
256 case DNS_TYPE_A:
257 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
258 break;
260 case DNS_TYPE_NS:
261 len = strlen(dnsp->data.ns);
262 if (dnsp->data.ns[len-1] == '.') {
263 dns->data.name.len = len;
264 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
265 } else {
266 dns->data.name.len = len+1;
267 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
269 break;
271 case DNS_TYPE_CNAME:
272 len = strlen(dnsp->data.cname);
273 if (dnsp->data.cname[len-1] == '.') {
274 dns->data.name.len = len;
275 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
276 } else {
277 dns->data.name.len = len+1;
278 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
280 break;
282 case DNS_TYPE_SOA:
283 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
284 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
285 dns->data.soa.dwRetry = dnsp->data.soa.retry;
286 dns->data.soa.dwExpire = dnsp->data.soa.expire;
287 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
289 len = strlen(dnsp->data.soa.mname);
290 if (dnsp->data.soa.mname[len-1] == '.') {
291 dns->data.soa.NamePrimaryServer.len = len;
292 dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
293 } else {
294 dns->data.soa.NamePrimaryServer.len = len+1;
295 dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
298 len = strlen(dnsp->data.soa.rname);
299 if (dnsp->data.soa.rname[len-1] == '.') {
300 dns->data.soa.ZoneAdministratorEmail.len = len;
301 dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
302 } else {
303 dns->data.soa.ZoneAdministratorEmail.len = len+1;
304 dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
306 break;
308 case DNS_TYPE_PTR:
309 dns->data.ptr.len = strlen(dnsp->data.ptr);
310 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
311 break;
313 case DNS_TYPE_MX:
314 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
315 len = strlen(dnsp->data.mx.nameTarget);
316 if (dnsp->data.mx.nameTarget[len-1] == '.') {
317 dns->data.mx.nameExchange.len = len;
318 dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
319 } else {
320 dns->data.mx.nameExchange.len = len+1;
321 dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
323 break;
325 case DNS_TYPE_TXT:
326 dns->data.txt.count = dnsp->data.txt.count;
327 dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
328 for (i=0; i<dnsp->data.txt.count; i++) {
329 dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
330 dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
332 break;
334 case DNS_TYPE_AAAA:
335 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
336 break;
338 case DNS_TYPE_SRV:
339 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
340 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
341 dns->data.srv.wPort = dnsp->data.srv.wPort;
342 len = strlen(dnsp->data.srv.nameTarget);
343 if (dnsp->data.srv.nameTarget[len-1] == '.') {
344 dns->data.srv.nameTarget.len = len;
345 dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
346 } else {
347 dns->data.srv.nameTarget.len = len+1;
348 dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
350 break;
352 default:
353 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
354 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
360 struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
362 int i, len;
363 struct dnsp_DnssrvRpcRecord *dnsp;
365 dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
366 if (dnsp == NULL) {
367 return NULL;
370 dnsp->wDataLength = dns->wDataLength;
371 dnsp->wType = dns->wType;
372 dnsp->version = 5;
373 dnsp->rank = dns->dwFlags & 0x000000FF;
374 dnsp->dwSerial = dns->dwSerial;
375 dnsp->dwTtlSeconds = dns->dwTtlSeconds;
376 dnsp->dwTimeStamp = dns->dwTimeStamp;
378 switch (dns->wType) {
380 case DNS_TYPE_TOMBSTONE:
381 dnsp->data.timestamp = dns->data.timestamp;
382 break;
384 case DNS_TYPE_A:
385 dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4);
386 break;
388 case DNS_TYPE_NS:
389 len = dns->data.name.len;
390 if (dns->data.name.str[len-1] == '.') {
391 dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
392 } else {
393 dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str);
395 break;
397 case DNS_TYPE_CNAME:
398 len = dns->data.name.len;
399 if (dns->data.name.str[len-1] == '.') {
400 dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
401 } else {
402 dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str);
404 break;
406 case DNS_TYPE_SOA:
407 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
408 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
409 dnsp->data.soa.retry = dns->data.soa.dwRetry;
410 dnsp->data.soa.expire = dns->data.soa.dwExpire;
411 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
413 len = dns->data.soa.NamePrimaryServer.len;
414 if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
415 dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
416 } else {
417 dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
420 len = dns->data.soa.ZoneAdministratorEmail.len;
421 if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') {
422 dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1);
423 } else {
424 dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str);
426 break;
428 case DNS_TYPE_PTR:
429 dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str);
430 break;
432 case DNS_TYPE_MX:
433 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
434 len = dns->data.mx.nameExchange.len;
435 if (dns->data.mx.nameExchange.str[len-1] == '.') {
436 dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1);
437 } else {
438 dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str);
440 break;
442 case DNS_TYPE_TXT:
443 dnsp->data.txt.count = dns->data.txt.count;
444 dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
445 for (i=0; i<dns->data.txt.count; i++) {
446 dnsp->data.txt.str[i] = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
448 break;
450 case DNS_TYPE_AAAA:
451 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
452 break;
454 case DNS_TYPE_SRV:
455 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
456 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
457 dnsp->data.srv.wPort = dns->data.srv.wPort;
459 len = dns->data.srv.nameTarget.len;
460 if (dns->data.srv.nameTarget.str[len-1] == '.') {
461 dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1);
462 } else {
463 dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str);
465 break;
467 default:
468 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
469 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
473 return dnsp;
477 /* Intialize tree with given name as the root */
478 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
480 struct dns_tree *tree;
482 tree = talloc_zero(mem_ctx, struct dns_tree);
483 if (tree == NULL) {
484 return NULL;
487 tree->name = talloc_strdup(tree, name);
488 if (tree->name == NULL) {
489 talloc_free(tree);
490 return NULL;
493 tree->data = data;
495 return tree;
499 /* Add a child one level below */
500 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
502 struct dns_tree *node;
504 node = talloc_zero(tree, struct dns_tree);
505 if (node == NULL) {
506 return NULL;
509 node->name = talloc_strdup(tree, name);
510 if (node->name == NULL) {
511 talloc_free(node);
512 return NULL;
514 node->level = tree->level + 1;
515 node->num_children = 0;
516 node->children = NULL;
517 node->data = data;
519 if (tree->num_children == 0) {
520 tree->children = talloc_zero(tree, struct dns_tree *);
521 } else {
522 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
523 tree->num_children+1);
525 if (tree->children == NULL) {
526 talloc_free(node);
527 return NULL;
529 tree->children[tree->num_children] = node;
530 tree->num_children++;
532 return node;
535 /* Find a node that matches the name components */
536 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
538 struct dns_tree *node, *next;
539 int i, j, start;
541 *match_count = -1;
543 if (strcmp(tree->name, "@") == 0) {
544 start = 0;
545 } else {
546 if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
547 return NULL;
549 start = 1;
550 *match_count = 0;
553 node = tree;
554 for (i=start; i<ncount; i++) {
555 if (node->num_children == 0) {
556 break;
558 next = NULL;
559 for (j=0; j<node->num_children; j++) {
560 if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
561 next = node->children[j];
562 *match_count = i;
563 break;
566 if (next == NULL) {
567 break;
568 } else {
569 node = next;
573 return node;
576 /* Build a 2-level tree for resulting dns names */
577 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
579 struct dns_tree *root, *base, *tree, *node;
580 const char *ptr;
581 int rootcount, ncount;
582 char **nlist;
583 int i, level, match_count;
585 rootcount = dns_split_name_components(mem_ctx, name, &nlist);
586 if (rootcount <= 0) {
587 return NULL;
590 root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
591 if (root == NULL) {
592 return NULL;
595 tree = root;
596 for (i=rootcount-2; i>=0; i--) {
597 tree = dns_tree_add(tree, nlist[i], NULL);
598 if (tree == NULL) {
599 goto failed;
603 base = tree;
605 /* Add all names in the result in a tree */
606 for (i=0; i<res->count; i++) {
607 ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
609 if (strcmp(ptr, "@") == 0) {
610 base->data = res->msgs[i];
611 continue;
612 } else if (strcasecmp(ptr, name) == 0) {
613 base->data = res->msgs[i];
614 continue;
617 ncount = dns_split_name_components(root, ptr, &nlist);
618 if (ncount < 0) {
619 goto failed;
622 /* Find matching node */
623 tree = dns_tree_find(root, ncount, nlist, &match_count);
624 if (tree == NULL) {
625 goto failed;
628 /* If the node is on leaf, then add record data */
629 if (match_count+1 == ncount) {
630 tree->data = res->msgs[i];
633 /* Add missing name components */
634 for (level=match_count+1; level<ncount; level++) {
635 if (tree->level == rootcount+1) {
636 break;
638 if (level == ncount-1) {
639 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
640 } else {
641 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
643 if (node == NULL) {
644 goto failed;
646 tree = node;
649 talloc_free(nlist);
652 /* Mark the base record, so it can be found easily */
653 base->level = -1;
655 return root;
657 failed:
658 talloc_free(root);
659 return NULL;
663 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
665 int i;
666 char **ptr = *add_names;
667 int count = *add_count;
669 for (i=0; i<count; i++) {
670 if (strcasecmp(ptr[i], name) == 0) {
671 return;
675 ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
676 if (ptr == NULL) {
677 return;
680 ptr[count] = talloc_strdup(mem_ctx, name);
681 if (ptr[count] == NULL) {
682 return;
685 *add_names = ptr;
686 *add_count = count+1;
690 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
692 if (add_names == NULL) {
693 return;
696 switch (rec->wType) {
698 case DNS_TYPE_NS:
699 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
700 break;
702 case DNS_TYPE_CNAME:
703 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
704 break;
706 case DNS_TYPE_SOA:
707 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
708 break;
710 case DNS_TYPE_MX:
711 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
712 break;
714 case DNS_TYPE_SRV:
715 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
716 break;
718 default:
719 break;
724 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
725 struct dnsserver_zone *z,
726 enum dns_record_type record_type,
727 unsigned int select_flag,
728 const char *branch_name,
729 struct ldb_message *msg,
730 int num_children,
731 struct DNS_RPC_RECORDS_ARRAY *recs,
732 char ***add_names,
733 int *add_count)
735 struct ldb_message_element *el;
736 const char *ptr;
737 int i, j;
738 bool found;
740 if (recs->count == 0) {
741 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
742 } else {
743 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
745 if (recs->rec == NULL) {
746 return WERR_NOMEM;
748 i = recs->count;
749 recs->rec[i].wLength = 0;
750 recs->rec[i].wRecordCount = 0;
751 recs->rec[i].dwChildCount = num_children;
753 /* The base records returned with empty name */
754 /* Children records returned with names */
755 if (branch_name == NULL) {
756 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
757 recs->rec[i].dnsNodeName.len = 0;
758 } else {
759 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
760 recs->rec[i].dnsNodeName.len = strlen(branch_name);
762 recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
763 recs->count++;
765 /* Allow empty records */
766 if (msg == NULL) {
767 return WERR_OK;
770 /* Do not return RR records, if the node has children */
771 if (branch_name != NULL && num_children > 0) {
772 return WERR_OK;
775 ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
776 el = ldb_msg_find_element(msg, "dnsRecord");
777 if (el == NULL || el->values == 0) {
778 return WERR_OK;
781 /* Add RR records */
782 for (j=0; j<el->num_values; j++) {
783 struct dnsp_DnssrvRpcRecord dnsp_rec;
784 struct DNS_RPC_RECORD *dns_rec;
785 enum ndr_err_code ndr_err;
787 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
788 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
789 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
790 DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
791 return WERR_INTERNAL_DB_ERROR;
794 /* Match the records based on search criteria */
795 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
796 found = false;
798 if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
799 if (dnsp_rec.rank == DNS_RANK_ZONE) {
800 found = true;
803 if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
804 if (dnsp_rec.rank == DNS_RANK_ZONE) {
805 found = true;
808 if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
809 if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
810 found = true;
813 if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
814 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
815 found = true;
819 if (found) {
820 recs->rec[i].records = talloc_realloc(recs,
821 recs->rec[i].records,
822 struct DNS_RPC_RECORD,
823 recs->rec[i].wRecordCount+1);
824 if (recs->rec[i].records == NULL) {
825 return WERR_NOMEM;
828 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
829 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
831 /* Fix record flags */
832 if (strcmp(ptr, "@") == 0) {
833 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
835 if (dnsp_rec.rank == DNS_RANK_ZONE) {
836 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
840 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
841 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
844 recs->rec[i].wRecordCount++;
846 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
851 return WERR_OK;
855 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
856 char *search_name)
858 const char *name1, *name2;
859 const char *ptr1, *ptr2;
861 name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
862 name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
863 if (name1 == NULL || name2 == NULL) {
864 return 0;
867 /* '@' record and the search_name record gets preference */
868 if (name1[0] == '@') {
869 return -1;
871 if (search_name && strcasecmp(name1, search_name) == 0) {
872 return -1;
875 if (name2[0] == '@') {
876 return 1;
878 if (search_name && strcasecmp(name2, search_name) == 0) {
879 return 1;
882 /* Compare the last components of names.
883 * If search_name is not NULL, compare the second last components of names */
884 ptr1 = strrchr(name1, '.');
885 if (ptr1 == NULL) {
886 ptr1 = name1;
887 } else {
888 if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
889 ptr1--;
890 while (ptr1 != name1) {
891 ptr1--;
892 if (*ptr1 == '.') {
893 break;
897 if (*ptr1 == '.') {
898 ptr1 = &ptr1[1];
902 ptr2 = strrchr(name2, '.');
903 if (ptr2 == NULL) {
904 ptr2 = name2;
905 } else {
906 if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
907 ptr2--;
908 while (ptr2 != name2) {
909 ptr2--;
910 if (*ptr2 == '.') {
911 break;
915 if (*ptr2 == '.') {
916 ptr2 = &ptr2[1];
920 return strcasecmp(ptr1, ptr2);
924 bool dns_name_equal(const char *name1, const char *name2)
926 size_t len1 = strlen(name1);
927 size_t len2 = strlen(name2);
929 if (name1[len1-1] == '.') len1--;
930 if (name2[len2-1] == '.') len2--;
931 if (len1 != len2) {
932 return false;
934 return strncasecmp(name1, name2, len1) == 0;
938 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
940 bool status;
941 int i;
943 if (rec1->wType != rec2->wType) {
944 return false;
947 switch(rec1->wType) {
948 case DNS_TYPE_TOMBSTONE:
949 return true;
951 case DNS_TYPE_A:
952 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
954 case DNS_TYPE_NS:
955 return dns_name_equal(rec1->data.ns, rec2->data.ns);
957 case DNS_TYPE_CNAME:
958 return dns_name_equal(rec1->data.cname, rec2->data.cname);
960 case DNS_TYPE_SOA:
961 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) == 0 &&
962 dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) == 0 &&
963 rec1->data.soa.serial == rec2->data.soa.serial &&
964 rec1->data.soa.refresh == rec2->data.soa.refresh &&
965 rec1->data.soa.retry == rec2->data.soa.retry &&
966 rec1->data.soa.expire == rec2->data.soa.expire &&
967 rec1->data.soa.minimum == rec2->data.soa.minimum;
969 case DNS_TYPE_PTR:
970 return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
972 case DNS_TYPE_MX:
973 return rec1->data.mx.wPriority == rec2->data.srv.wPriority &&
974 dns_name_equal(rec1->data.mx.nameTarget, rec2->data.srv.nameTarget);
976 case DNS_TYPE_TXT:
977 if (rec1->data.txt.count != rec2->data.txt.count) {
978 return false;
980 status = true;
981 for (i=0; i<rec1->data.txt.count; i++) {
982 status = status && (strcmp(rec1->data.txt.str[i],
983 rec2->data.txt.str[i]) == 0);
985 return status;
987 case DNS_TYPE_AAAA:
988 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
990 case DNS_TYPE_SRV:
991 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
992 rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
993 rec1->data.srv.wPort == rec2->data.srv.wPort &&
994 dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
996 default:
997 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
998 break;
1001 return false;