2 Unix SMB/CIFS implementation.
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/>.
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
;
38 ret
= talloc_zero(mem_ctx
, struct IP4_ARRAY
);
43 ret
->AddrCount
= ip4
->AddrCount
;
44 if (ip4
->AddrCount
> 0) {
45 ret
->AddrArray
= talloc_zero_array(mem_ctx
, unsigned int, ip4
->AddrCount
);
47 memcpy(ret
->AddrArray
, ip4
->AddrArray
,
48 sizeof(unsigned int) * ip4
->AddrCount
);
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
;
68 ret
= talloc_zero(mem_ctx
, struct DNS_ADDR_ARRAY
);
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
);
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;
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
;
104 /* We must only return IPv4 addresses.
105 The passed DNS_ADDR_ARRAY may contain:
106 - only ipv4 addresses
107 - only ipv6 addresses
111 ret
= talloc_zero(mem_ctx
, struct IP4_ARRAY
);
115 if (ip
->AddrCount
== 0 || ip
->Family
== AF_INET6
) {
119 /* Now only ipv4 addresses or a mixture are left */
121 for (i
= 0; i
< ip
->AddrCount
; i
++) {
122 if (ip
->AddrArray
[i
].MaxSa
[0] == 0x02) {
128 /* should not happen */
132 ret
->AddrArray
= talloc_zero_array(mem_ctx
, uint32_t, count
);
133 if (ret
->AddrArray
) {
135 for (i
= 0; i
< ip
->AddrCount
; i
++) {
136 if (ip
->AddrArray
[i
].MaxSa
[0] == 0x02) {
138 memcpy(&ret
->AddrArray
[curr
],
139 &ip
->AddrArray
[i
].MaxSa
[4],
148 ret
->AddrCount
= curr
;
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
;
161 ret
= talloc_zero(mem_ctx
, struct DNS_ADDR_ARRAY
);
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
);
183 int dns_split_name_components(TALLOC_CTX
*tmp_ctx
, const char *name
, char ***components
)
185 char *str
= NULL
, *ptr
, **list
;
192 str
= talloc_strdup(tmp_ctx
, name
);
197 list
= talloc_zero_array(tmp_ctx
, char *, 0);
202 ptr
= strtok(str
, ".");
203 while (ptr
!= NULL
) {
205 list
= talloc_realloc(tmp_ctx
, list
, char *, count
);
209 list
[count
-1] = talloc_strdup(tmp_ctx
, ptr
);
210 if (list
[count
-1] == NULL
) {
213 ptr
= strtok(NULL
, ".");
229 char *dns_split_node_name(TALLOC_CTX
*tmp_ctx
, const char *node_name
, const char *zone_name
)
231 char **nlist
, **zlist
;
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) {
250 } else if (strchr(node_name
, '.') == NULL
) {
251 prefix
= talloc_strdup(tmp_ctx
, node_name
);
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) {
259 if (ncount
< zcount
) {
260 prefix
= talloc_strdup(tmp_ctx
, node_name
);
263 for (i
=1; i
<=zcount
; i
++) {
264 if (strcasecmp(nlist
[ncount
-i
], zlist
[zcount
-i
]) != 0) {
270 if (match
== ncount
) {
271 prefix
= talloc_strdup(tmp_ctx
, zone_name
);
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
) {
293 void dnsp_to_dns_copy(TALLOC_CTX
*mem_ctx
, struct dnsp_DnssrvRpcRecord
*dnsp
,
294 struct DNS_RPC_RECORD
*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
;
314 dns
->data
.ipv4
= talloc_strdup(mem_ctx
, dnsp
->data
.ipv4
);
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
);
323 dns
->data
.name
.len
= len
+1;
324 dns
->data
.name
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.ns
);
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
);
334 dns
->data
.name
.len
= len
+1;
335 dns
->data
.name
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.cname
);
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
);
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
);
360 dns
->data
.soa
.ZoneAdministratorEmail
.len
= len
+1;
361 dns
->data
.soa
.ZoneAdministratorEmail
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.soa
.rname
);
366 dns
->data
.ptr
.len
= strlen(dnsp
->data
.ptr
);
367 dns
->data
.ptr
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.ptr
);
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
);
377 dns
->data
.mx
.nameExchange
.len
= len
+1;
378 dns
->data
.mx
.nameExchange
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.mx
.nameTarget
);
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
]);
392 dns
->data
.ipv6
= talloc_strdup(mem_ctx
, dnsp
->data
.ipv6
);
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
);
404 dns
->data
.srv
.nameTarget
.len
= len
+1;
405 dns
->data
.srv
.nameTarget
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.srv
.nameTarget
);
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
)
422 char *talloc_res
= NULL
;
423 struct dnsp_DnssrvRpcRecord
*dnsp
= NULL
;
425 dnsp
= talloc_zero(mem_ctx
, struct dnsp_DnssrvRpcRecord
);
427 return WERR_NOT_ENOUGH_MEMORY
;
430 dnsp
->wDataLength
= dns
->wDataLength
;
431 dnsp
->wType
= dns
->wType
;
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
;
445 talloc_res
= talloc_strdup(mem_ctx
, dns
->data
.ipv4
);
446 if (talloc_res
== NULL
) {
449 dnsp
->data
.ipv4
= talloc_res
;
453 name
= dns
->data
.name
.str
;
454 len
= dns
->data
.name
.len
;
457 res
= dns_name_check(mem_ctx
, len
, name
);
458 if (!W_ERROR_IS_OK(res
)) {
463 if (len
> 0 && name
[len
-1] == '.') {
464 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
465 if (talloc_res
== NULL
) {
468 dnsp
->data
.ns
= talloc_res
;
470 talloc_res
= talloc_strdup(mem_ctx
, name
);
471 if (talloc_res
== NULL
) {
474 dnsp
->data
.ns
= talloc_res
;
480 name
= dns
->data
.name
.str
;
481 len
= dns
->data
.name
.len
;
484 res
= dns_name_check(mem_ctx
, len
, name
);
485 if (!W_ERROR_IS_OK(res
)) {
490 if (len
> 0 && name
[len
-1] == '.') {
491 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
492 if (talloc_res
== NULL
) {
495 dnsp
->data
.cname
= talloc_res
;
497 talloc_res
= talloc_strdup(mem_ctx
, name
);
498 if (talloc_res
== NULL
) {
501 dnsp
->data
.cname
= talloc_res
;
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
;
517 res
= dns_name_check(mem_ctx
, len
, name
);
518 if (!W_ERROR_IS_OK(res
)) {
523 if (len
> 0 && name
[len
-1] == '.') {
524 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
525 if (talloc_res
== NULL
) {
528 dnsp
->data
.soa
.mname
= talloc_res
;
530 talloc_res
= talloc_strdup(mem_ctx
, name
);
531 if (talloc_res
== NULL
) {
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
)) {
545 if (len
> 0 && name
[len
-1] == '.') {
546 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
547 if (talloc_res
== NULL
) {
550 dnsp
->data
.soa
.rname
= talloc_res
;
552 talloc_res
= talloc_strdup(mem_ctx
, name
);
553 if (talloc_res
== NULL
) {
556 dnsp
->data
.soa
.rname
= talloc_res
;
562 name
= dns
->data
.ptr
.str
;
563 len
= dns
->data
.ptr
.len
;
566 res
= dns_name_check(mem_ctx
, len
, name
);
567 if (!W_ERROR_IS_OK(res
)) {
572 talloc_res
= talloc_strdup(mem_ctx
, name
);
573 if (talloc_res
== NULL
) {
576 dnsp
->data
.ptr
= talloc_res
;
581 dnsp
->data
.mx
.wPriority
= dns
->data
.mx
.wPreference
;
583 name
= dns
->data
.mx
.nameExchange
.str
;
584 len
= dns
->data
.mx
.nameExchange
.len
;
587 res
= dns_name_check(mem_ctx
, len
, name
);
588 if (!W_ERROR_IS_OK(res
)) {
593 if (len
> 0 && name
[len
-1] == '.') {
594 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
595 if (talloc_res
== NULL
) {
598 dnsp
->data
.mx
.nameTarget
= talloc_res
;
600 talloc_res
= talloc_strdup(mem_ctx
, name
);
601 if (talloc_res
== NULL
) {
604 dnsp
->data
.mx
.nameTarget
= talloc_res
;
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
) {
617 dnsp
->data
.txt
.str
[i
] = talloc_res
;
622 dnsp
->data
.ipv6
= talloc_strdup(mem_ctx
, dns
->data
.ipv6
);
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
;
634 res
= dns_name_check(mem_ctx
, len
, name
);
635 if (!W_ERROR_IS_OK(res
)) {
640 if (len
> 0 && name
[len
-1] == '.') {
641 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
642 if (talloc_res
== NULL
) {
645 dnsp
->data
.srv
.nameTarget
= talloc_res
;
647 talloc_res
= talloc_strdup(mem_ctx
, name
);
648 if (talloc_res
== NULL
) {
651 dnsp
->data
.srv
.nameTarget
= talloc_res
;
657 memcpy(&dnsp
->data
, &dns
->data
, sizeof(union dnsRecordData
));
658 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns
->wType
));
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
);
678 tree
->name
= talloc_strdup(tree
, name
);
679 if (tree
->name
== NULL
) {
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
);
700 node
->name
= talloc_strdup(tree
, name
);
701 if (node
->name
== NULL
) {
705 node
->level
= tree
->level
+ 1;
706 node
->num_children
= 0;
707 node
->children
= NULL
;
710 if (tree
->num_children
== 0) {
711 tree
->children
= talloc_zero(tree
, struct dns_tree
*);
713 tree
->children
= talloc_realloc(tree
, tree
->children
, struct dns_tree
*,
714 tree
->num_children
+1);
716 if (tree
->children
== NULL
) {
720 tree
->children
[tree
->num_children
] = node
;
721 tree
->num_children
++;
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
;
734 if (strcmp(tree
->name
, "@") == 0) {
737 if (strcasecmp(tree
->name
, nlist
[ncount
-1]) != 0) {
745 for (i
=start
; i
<ncount
; i
++) {
746 if (node
->num_children
== 0) {
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
];
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
;
772 int rootcount
, ncount
;
774 int i
, level
, match_count
;
776 rootcount
= dns_split_name_components(mem_ctx
, name
, &nlist
);
777 if (rootcount
<= 0) {
781 root
= dns_tree_init(mem_ctx
, nlist
[rootcount
-1], NULL
);
787 for (i
=rootcount
-2; i
>=0; i
--) {
788 tree
= dns_tree_add(tree
, nlist
[i
], NULL
);
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
];
803 } else if (strcasecmp(ptr
, name
) == 0) {
804 base
->data
= res
->msgs
[i
];
808 ncount
= dns_split_name_components(root
, ptr
, &nlist
);
813 /* Find matching node */
814 tree
= dns_tree_find(root
, ncount
, nlist
, &match_count
);
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) {
829 if (level
== ncount
-1) {
830 node
= dns_tree_add(tree
, nlist
[(ncount
-1)-level
], res
->msgs
[i
]);
832 node
= dns_tree_add(tree
, nlist
[(ncount
-1)-level
], NULL
);
843 /* Mark the base record, so it can be found easily */
854 static void _dns_add_name(TALLOC_CTX
*mem_ctx
, const char *name
, char ***add_names
, int *add_count
)
857 char **ptr
= *add_names
;
858 int count
= *add_count
;
860 for (i
=0; i
<count
; i
++) {
861 if (strcasecmp(ptr
[i
], name
) == 0) {
866 ptr
= talloc_realloc(mem_ctx
, ptr
, char *, count
+1);
871 ptr
[count
] = talloc_strdup(mem_ctx
, name
);
872 if (ptr
[count
] == NULL
) {
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
) {
887 switch (rec
->wType
) {
890 _dns_add_name(mem_ctx
, rec
->data
.ns
, add_names
, add_count
);
894 _dns_add_name(mem_ctx
, rec
->data
.cname
, add_names
, add_count
);
898 _dns_add_name(mem_ctx
, rec
->data
.soa
.mname
, add_names
, add_count
);
902 _dns_add_name(mem_ctx
, rec
->data
.mx
.nameTarget
, add_names
, add_count
);
906 _dns_add_name(mem_ctx
, rec
->data
.srv
.nameTarget
, add_names
, add_count
);
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
,
922 struct DNS_RPC_RECORDS_ARRAY
*recs
,
926 struct ldb_message_element
*el
;
931 if (recs
->count
== 0) {
932 recs
->rec
= talloc_zero(recs
, struct DNS_RPC_RECORDS
);
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
;
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;
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);
957 /* Allow empty records */
962 /* Do not return RR records, if the node has children */
963 if (branch_name
!= NULL
&& num_children
> 0) {
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) {
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
) {
990 if (select_flag
& DNS_RPC_VIEW_AUTHORITY_DATA
) {
991 if (dnsp_rec
.rank
== DNS_RANK_ZONE
) {
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
) {
1004 if (select_flag
& DNS_RPC_VIEW_CACHE_DATA
) {
1005 if (dnsp_rec
.rank
== DNS_RANK_ZONE
) {
1009 if (select_flag
& DNS_RPC_VIEW_GLUE_DATA
) {
1010 if (dnsp_rec
.rank
== DNS_RANK_GLUE
) {
1014 if (select_flag
& DNS_RPC_VIEW_ROOT_HINT_DATA
) {
1015 if (dnsp_rec
.rank
== DNS_RANK_ROOT_HINT
) {
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
);
1056 int dns_name_compare(const struct ldb_message
**m1
, const struct ldb_message
**m2
,
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
) {
1068 /* '@' record and the search_name record gets preference */
1069 if (name1
[0] == '@') {
1072 if (search_name
&& strcasecmp(name1
, search_name
) == 0) {
1076 if (name2
[0] == '@') {
1079 if (search_name
&& strcasecmp(name2
, search_name
) == 0) {
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
, '.');
1089 if (search_name
&& strcasecmp(ptr1
+1, search_name
) == 0) {
1091 while (ptr1
!= name1
) {
1103 ptr2
= strrchr(name2
, '.');
1107 if (search_name
&& strcasecmp(ptr2
+1, search_name
) == 0) {
1109 while (ptr2
!= name2
) {
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
--;
1135 return strncasecmp(name1
, name2
, len1
) == 0;
1139 bool dns_record_match(struct dnsp_DnssrvRpcRecord
*rec1
, struct dnsp_DnssrvRpcRecord
*rec2
)
1144 if (rec1
->wType
!= rec2
->wType
) {
1148 switch(rec1
->wType
) {
1149 case DNS_TYPE_TOMBSTONE
:
1153 return strcmp(rec1
->data
.ipv4
, rec2
->data
.ipv4
) == 0;
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
);
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
;
1171 return dns_name_equal(rec1
->data
.ptr
, rec2
->data
.ptr
);
1174 return rec1
->data
.mx
.wPriority
== rec2
->data
.mx
.wPriority
&&
1175 dns_name_equal(rec1
->data
.mx
.nameTarget
, rec2
->data
.mx
.nameTarget
);
1178 if (rec1
->data
.txt
.count
!= rec2
->data
.txt
.count
) {
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);
1189 return strcmp(rec1
->data
.ipv6
, rec2
->data
.ipv6
) == 0;
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
);
1198 DEBUG(0, ("dnsserver: unhandled record type %u", rec1
->wType
));