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
, ".");
227 char *dns_split_node_name(TALLOC_CTX
*tmp_ctx
, const char *node_name
, const char *zone_name
)
229 char **nlist
, **zlist
;
231 int ncount
, zcount
, i
, match
;
234 * If node_name is "@", return the zone_name
235 * If node_name is ".", return NULL
236 * If there is no '.' in node_name, return the node_name as is.
238 * If node_name does not have zone_name in it, return the node_name as is.
240 * If node_name has additional components as compared to zone_name
241 * return only the additional components as a prefix.
244 if (strcmp(node_name
, "@") == 0) {
245 prefix
= talloc_strdup(tmp_ctx
, zone_name
);
246 } else if (strcmp(node_name
, ".") == 0) {
248 } else if (strchr(node_name
, '.') == NULL
) {
249 prefix
= talloc_strdup(tmp_ctx
, node_name
);
251 zcount
= dns_split_name_components(tmp_ctx
, zone_name
, &zlist
);
252 ncount
= dns_split_name_components(tmp_ctx
, node_name
, &nlist
);
253 if (zcount
< 0 || ncount
< 0) {
257 if (ncount
< zcount
) {
258 prefix
= talloc_strdup(tmp_ctx
, node_name
);
261 for (i
=1; i
<=zcount
; i
++) {
262 if (strcasecmp(nlist
[ncount
-i
], zlist
[zcount
-i
]) != 0) {
268 if (match
== ncount
) {
269 prefix
= talloc_strdup(tmp_ctx
, zone_name
);
271 prefix
= talloc_strdup(tmp_ctx
, nlist
[0]);
272 if (prefix
!= NULL
) {
273 for (i
=1; i
<ncount
-match
; i
++) {
274 prefix
= talloc_asprintf_append(prefix
, ".%s", nlist
[i
]);
275 if (prefix
== NULL
) {
291 void dnsp_to_dns_copy(TALLOC_CTX
*mem_ctx
, struct dnsp_DnssrvRpcRecord
*dnsp
,
292 struct DNS_RPC_RECORD
*dns
)
298 dns
->wDataLength
= dnsp
->wDataLength
;
299 dns
->wType
= dnsp
->wType
;
300 dns
->dwFlags
= dnsp
->rank
;
301 dns
->dwSerial
= dnsp
->dwSerial
;
302 dns
->dwTtlSeconds
= dnsp
->dwTtlSeconds
;
303 dns
->dwTimeStamp
= dnsp
->dwTimeStamp
;
305 switch (dnsp
->wType
) {
307 case DNS_TYPE_TOMBSTONE
:
308 dns
->data
.timestamp
= dnsp
->data
.timestamp
;
312 dns
->data
.ipv4
= talloc_strdup(mem_ctx
, dnsp
->data
.ipv4
);
316 len
= strlen(dnsp
->data
.ns
);
317 if (dnsp
->data
.ns
[len
-1] == '.') {
318 dns
->data
.name
.len
= len
;
319 dns
->data
.name
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.ns
);
321 dns
->data
.name
.len
= len
+1;
322 dns
->data
.name
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.ns
);
327 len
= strlen(dnsp
->data
.cname
);
328 if (dnsp
->data
.cname
[len
-1] == '.') {
329 dns
->data
.name
.len
= len
;
330 dns
->data
.name
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.cname
);
332 dns
->data
.name
.len
= len
+1;
333 dns
->data
.name
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.cname
);
338 dns
->data
.soa
.dwSerialNo
= dnsp
->data
.soa
.serial
;
339 dns
->data
.soa
.dwRefresh
= dnsp
->data
.soa
.refresh
;
340 dns
->data
.soa
.dwRetry
= dnsp
->data
.soa
.retry
;
341 dns
->data
.soa
.dwExpire
= dnsp
->data
.soa
.expire
;
342 dns
->data
.soa
.dwMinimumTtl
= dnsp
->data
.soa
.minimum
;
344 len
= strlen(dnsp
->data
.soa
.mname
);
345 if (dnsp
->data
.soa
.mname
[len
-1] == '.') {
346 dns
->data
.soa
.NamePrimaryServer
.len
= len
;
347 dns
->data
.soa
.NamePrimaryServer
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.soa
.mname
);
349 dns
->data
.soa
.NamePrimaryServer
.len
= len
+1;
350 dns
->data
.soa
.NamePrimaryServer
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.soa
.mname
);
353 len
= strlen(dnsp
->data
.soa
.rname
);
354 if (dnsp
->data
.soa
.rname
[len
-1] == '.') {
355 dns
->data
.soa
.ZoneAdministratorEmail
.len
= len
;
356 dns
->data
.soa
.ZoneAdministratorEmail
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.soa
.rname
);
358 dns
->data
.soa
.ZoneAdministratorEmail
.len
= len
+1;
359 dns
->data
.soa
.ZoneAdministratorEmail
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.soa
.rname
);
364 dns
->data
.ptr
.len
= strlen(dnsp
->data
.ptr
);
365 dns
->data
.ptr
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.ptr
);
369 dns
->data
.mx
.wPreference
= dnsp
->data
.mx
.wPriority
;
370 len
= strlen(dnsp
->data
.mx
.nameTarget
);
371 if (dnsp
->data
.mx
.nameTarget
[len
-1] == '.') {
372 dns
->data
.mx
.nameExchange
.len
= len
;
373 dns
->data
.mx
.nameExchange
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.mx
.nameTarget
);
375 dns
->data
.mx
.nameExchange
.len
= len
+1;
376 dns
->data
.mx
.nameExchange
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.mx
.nameTarget
);
381 dns
->data
.txt
.count
= dnsp
->data
.txt
.count
;
382 dns
->data
.txt
.str
= talloc_array(mem_ctx
, struct DNS_RPC_NAME
, dnsp
->data
.txt
.count
);
383 for (i
=0; i
<dnsp
->data
.txt
.count
; i
++) {
384 dns
->data
.txt
.str
[i
].str
= talloc_strdup(mem_ctx
, dnsp
->data
.txt
.str
[i
]);
385 dns
->data
.txt
.str
[i
].len
= strlen(dnsp
->data
.txt
.str
[i
]);
390 dns
->data
.ipv6
= talloc_strdup(mem_ctx
, dnsp
->data
.ipv6
);
394 dns
->data
.srv
.wPriority
= dnsp
->data
.srv
.wPriority
;
395 dns
->data
.srv
.wWeight
= dnsp
->data
.srv
.wWeight
;
396 dns
->data
.srv
.wPort
= dnsp
->data
.srv
.wPort
;
397 len
= strlen(dnsp
->data
.srv
.nameTarget
);
398 if (dnsp
->data
.srv
.nameTarget
[len
-1] == '.') {
399 dns
->data
.srv
.nameTarget
.len
= len
;
400 dns
->data
.srv
.nameTarget
.str
= talloc_strdup(mem_ctx
, dnsp
->data
.srv
.nameTarget
);
402 dns
->data
.srv
.nameTarget
.len
= len
+1;
403 dns
->data
.srv
.nameTarget
.str
= talloc_asprintf(mem_ctx
, "%s.", dnsp
->data
.srv
.nameTarget
);
408 memcpy(&dns
->data
, &dnsp
->data
, sizeof(union DNS_RPC_DATA
));
409 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp
->wType
));
414 WERROR
dns_to_dnsp_convert(TALLOC_CTX
*mem_ctx
, struct DNS_RPC_RECORD
*dns
,
415 struct dnsp_DnssrvRpcRecord
**out_dnsp
, bool check_name
)
420 char *talloc_res
= NULL
;
421 struct dnsp_DnssrvRpcRecord
*dnsp
= NULL
;
423 dnsp
= talloc_zero(mem_ctx
, struct dnsp_DnssrvRpcRecord
);
425 return WERR_NOT_ENOUGH_MEMORY
;
428 dnsp
->wDataLength
= dns
->wDataLength
;
429 dnsp
->wType
= dns
->wType
;
431 dnsp
->rank
= dns
->dwFlags
& 0x000000FF;
432 dnsp
->dwSerial
= dns
->dwSerial
;
433 dnsp
->dwTtlSeconds
= dns
->dwTtlSeconds
;
434 dnsp
->dwTimeStamp
= dns
->dwTimeStamp
;
436 switch (dns
->wType
) {
438 case DNS_TYPE_TOMBSTONE
:
439 dnsp
->data
.timestamp
= dns
->data
.timestamp
;
443 talloc_res
= talloc_strdup(mem_ctx
, dns
->data
.ipv4
);
444 if (talloc_res
== NULL
) {
447 dnsp
->data
.ipv4
= talloc_res
;
451 name
= dns
->data
.name
.str
;
452 len
= dns
->data
.name
.len
;
455 res
= dns_name_check(mem_ctx
, len
, name
);
456 if (!W_ERROR_IS_OK(res
)) {
461 if (len
> 0 && name
[len
-1] == '.') {
462 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
463 if (talloc_res
== NULL
) {
466 dnsp
->data
.ns
= talloc_res
;
468 talloc_res
= talloc_strdup(mem_ctx
, name
);
469 if (talloc_res
== NULL
) {
472 dnsp
->data
.ns
= talloc_res
;
478 name
= dns
->data
.name
.str
;
479 len
= dns
->data
.name
.len
;
482 res
= dns_name_check(mem_ctx
, len
, name
);
483 if (!W_ERROR_IS_OK(res
)) {
488 if (len
> 0 && name
[len
-1] == '.') {
489 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
490 if (talloc_res
== NULL
) {
493 dnsp
->data
.cname
= talloc_res
;
495 talloc_res
= talloc_strdup(mem_ctx
, name
);
496 if (talloc_res
== NULL
) {
499 dnsp
->data
.cname
= talloc_res
;
505 dnsp
->data
.soa
.serial
= dns
->data
.soa
.dwSerialNo
;
506 dnsp
->data
.soa
.refresh
= dns
->data
.soa
.dwRefresh
;
507 dnsp
->data
.soa
.retry
= dns
->data
.soa
.dwRetry
;
508 dnsp
->data
.soa
.expire
= dns
->data
.soa
.dwExpire
;
509 dnsp
->data
.soa
.minimum
= dns
->data
.soa
.dwMinimumTtl
;
511 name
= dns
->data
.soa
.NamePrimaryServer
.str
;
512 len
= dns
->data
.soa
.NamePrimaryServer
.len
;
515 res
= dns_name_check(mem_ctx
, len
, name
);
516 if (!W_ERROR_IS_OK(res
)) {
521 if (len
> 0 && name
[len
-1] == '.') {
522 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
523 if (talloc_res
== NULL
) {
526 dnsp
->data
.soa
.mname
= talloc_res
;
528 talloc_res
= talloc_strdup(mem_ctx
, name
);
529 if (talloc_res
== NULL
) {
532 dnsp
->data
.soa
.mname
= talloc_res
;
535 name
= dns
->data
.soa
.ZoneAdministratorEmail
.str
;
536 len
= dns
->data
.soa
.ZoneAdministratorEmail
.len
;
538 res
= dns_name_check(mem_ctx
, len
, name
);
539 if (!W_ERROR_IS_OK(res
)) {
543 if (len
> 0 && name
[len
-1] == '.') {
544 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
545 if (talloc_res
== NULL
) {
548 dnsp
->data
.soa
.rname
= talloc_res
;
550 talloc_res
= talloc_strdup(mem_ctx
, name
);
551 if (talloc_res
== NULL
) {
554 dnsp
->data
.soa
.rname
= talloc_res
;
560 name
= dns
->data
.ptr
.str
;
561 len
= dns
->data
.ptr
.len
;
564 res
= dns_name_check(mem_ctx
, len
, name
);
565 if (!W_ERROR_IS_OK(res
)) {
570 talloc_res
= talloc_strdup(mem_ctx
, name
);
571 if (talloc_res
== NULL
) {
574 dnsp
->data
.ptr
= talloc_res
;
579 dnsp
->data
.mx
.wPriority
= dns
->data
.mx
.wPreference
;
581 name
= dns
->data
.mx
.nameExchange
.str
;
582 len
= dns
->data
.mx
.nameExchange
.len
;
585 res
= dns_name_check(mem_ctx
, len
, name
);
586 if (!W_ERROR_IS_OK(res
)) {
591 if (len
> 0 && name
[len
-1] == '.') {
592 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
593 if (talloc_res
== NULL
) {
596 dnsp
->data
.mx
.nameTarget
= talloc_res
;
598 talloc_res
= talloc_strdup(mem_ctx
, name
);
599 if (talloc_res
== NULL
) {
602 dnsp
->data
.mx
.nameTarget
= talloc_res
;
608 dnsp
->data
.txt
.count
= dns
->data
.txt
.count
;
609 dnsp
->data
.txt
.str
= talloc_array(mem_ctx
, const char *, dns
->data
.txt
.count
);
610 for (i
=0; i
<dns
->data
.txt
.count
; i
++) {
611 talloc_res
= talloc_strdup(mem_ctx
, dns
->data
.txt
.str
[i
].str
);
612 if (talloc_res
== NULL
) {
615 dnsp
->data
.txt
.str
[i
] = talloc_res
;
620 dnsp
->data
.ipv6
= talloc_strdup(mem_ctx
, dns
->data
.ipv6
);
624 dnsp
->data
.srv
.wPriority
= dns
->data
.srv
.wPriority
;
625 dnsp
->data
.srv
.wWeight
= dns
->data
.srv
.wWeight
;
626 dnsp
->data
.srv
.wPort
= dns
->data
.srv
.wPort
;
628 name
= dns
->data
.srv
.nameTarget
.str
;
629 len
= dns
->data
.srv
.nameTarget
.len
;
632 res
= dns_name_check(mem_ctx
, len
, name
);
633 if (!W_ERROR_IS_OK(res
)) {
638 if (len
> 0 && name
[len
-1] == '.') {
639 talloc_res
= talloc_strndup(mem_ctx
, name
, len
-1);
640 if (talloc_res
== NULL
) {
643 dnsp
->data
.srv
.nameTarget
= talloc_res
;
645 talloc_res
= talloc_strdup(mem_ctx
, name
);
646 if (talloc_res
== NULL
) {
649 dnsp
->data
.srv
.nameTarget
= talloc_res
;
655 memcpy(&dnsp
->data
, &dns
->data
, sizeof(union dnsRecordData
));
656 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns
->wType
));
663 return WERR_NOT_ENOUGH_MEMORY
;
666 /* Intialize tree with given name as the root */
667 static struct dns_tree
*dns_tree_init(TALLOC_CTX
*mem_ctx
, const char *name
, void *data
)
669 struct dns_tree
*tree
;
671 tree
= talloc_zero(mem_ctx
, struct dns_tree
);
676 tree
->name
= talloc_strdup(tree
, name
);
677 if (tree
->name
== NULL
) {
688 /* Add a child one level below */
689 static struct dns_tree
*dns_tree_add(struct dns_tree
*tree
, const char *name
, void *data
)
691 struct dns_tree
*node
;
693 node
= talloc_zero(tree
, struct dns_tree
);
698 node
->name
= talloc_strdup(tree
, name
);
699 if (node
->name
== NULL
) {
703 node
->level
= tree
->level
+ 1;
704 node
->num_children
= 0;
705 node
->children
= NULL
;
708 if (tree
->num_children
== 0) {
709 tree
->children
= talloc_zero(tree
, struct dns_tree
*);
711 tree
->children
= talloc_realloc(tree
, tree
->children
, struct dns_tree
*,
712 tree
->num_children
+1);
714 if (tree
->children
== NULL
) {
718 tree
->children
[tree
->num_children
] = node
;
719 tree
->num_children
++;
724 /* Find a node that matches the name components */
725 static struct dns_tree
*dns_tree_find(struct dns_tree
*tree
, int ncount
, char **nlist
, int *match_count
)
727 struct dns_tree
*node
, *next
;
732 if (strcmp(tree
->name
, "@") == 0) {
735 if (strcasecmp(tree
->name
, nlist
[ncount
-1]) != 0) {
743 for (i
=start
; i
<ncount
; i
++) {
744 if (node
->num_children
== 0) {
748 for (j
=0; j
<node
->num_children
; j
++) {
749 if (strcasecmp(nlist
[(ncount
-1)-i
], node
->children
[j
]->name
) == 0) {
750 next
= node
->children
[j
];
765 /* Build a 2-level tree for resulting dns names */
766 struct dns_tree
*dns_build_tree(TALLOC_CTX
*mem_ctx
, const char *name
, struct ldb_result
*res
)
768 struct dns_tree
*root
, *base
, *tree
, *node
;
770 int rootcount
, ncount
;
772 int i
, level
, match_count
;
774 rootcount
= dns_split_name_components(mem_ctx
, name
, &nlist
);
775 if (rootcount
<= 0) {
779 root
= dns_tree_init(mem_ctx
, nlist
[rootcount
-1], NULL
);
785 for (i
=rootcount
-2; i
>=0; i
--) {
786 tree
= dns_tree_add(tree
, nlist
[i
], NULL
);
794 /* Add all names in the result in a tree */
795 for (i
=0; i
<res
->count
; i
++) {
796 ptr
= ldb_msg_find_attr_as_string(res
->msgs
[i
], "name", NULL
);
798 DBG_ERR("dnsserver: dns record has no name (%s)",
799 ldb_dn_get_linearized(res
->msgs
[i
]->dn
));
803 if (strcmp(ptr
, "@") == 0) {
804 base
->data
= res
->msgs
[i
];
806 } else if (strcasecmp(ptr
, name
) == 0) {
807 base
->data
= res
->msgs
[i
];
811 ncount
= dns_split_name_components(root
, ptr
, &nlist
);
816 /* Find matching node */
817 tree
= dns_tree_find(root
, ncount
, nlist
, &match_count
);
822 /* If the node is on leaf, then add record data */
823 if (match_count
+1 == ncount
) {
824 tree
->data
= res
->msgs
[i
];
827 /* Add missing name components */
828 for (level
=match_count
+1; level
<ncount
; level
++) {
829 if (tree
->level
== rootcount
+1) {
832 if (level
== ncount
-1) {
833 node
= dns_tree_add(tree
, nlist
[(ncount
-1)-level
], res
->msgs
[i
]);
835 node
= dns_tree_add(tree
, nlist
[(ncount
-1)-level
], NULL
);
846 /* Mark the base record, so it can be found easily */
857 static void _dns_add_name(TALLOC_CTX
*mem_ctx
, const char *name
, char ***add_names
, int *add_count
)
860 char **ptr
= *add_names
;
861 int count
= *add_count
;
863 for (i
=0; i
<count
; i
++) {
864 if (strcasecmp(ptr
[i
], name
) == 0) {
869 ptr
= talloc_realloc(mem_ctx
, ptr
, char *, count
+1);
874 ptr
[count
] = talloc_strdup(mem_ctx
, name
);
875 if (ptr
[count
] == NULL
) {
881 *add_count
= count
+1;
885 static void dns_find_additional_names(TALLOC_CTX
*mem_ctx
, struct dnsp_DnssrvRpcRecord
*rec
, char ***add_names
, int *add_count
)
887 if (add_names
== NULL
) {
891 switch (rec
->wType
) {
894 _dns_add_name(mem_ctx
, rec
->data
.ns
, add_names
, add_count
);
898 _dns_add_name(mem_ctx
, rec
->data
.cname
, add_names
, add_count
);
902 _dns_add_name(mem_ctx
, rec
->data
.soa
.mname
, add_names
, add_count
);
906 _dns_add_name(mem_ctx
, rec
->data
.mx
.nameTarget
, add_names
, add_count
);
910 _dns_add_name(mem_ctx
, rec
->data
.srv
.nameTarget
, add_names
, add_count
);
919 WERROR
dns_fill_records_array(TALLOC_CTX
*mem_ctx
,
920 struct dnsserver_zone
*z
,
921 enum dns_record_type record_type
,
922 unsigned int select_flag
,
923 const char *branch_name
,
924 struct ldb_message
*msg
,
926 struct DNS_RPC_RECORDS_ARRAY
*recs
,
930 struct ldb_message_element
*el
;
935 if (recs
->count
== 0) {
936 recs
->rec
= talloc_zero(recs
, struct DNS_RPC_RECORDS
);
938 recs
->rec
= talloc_realloc(recs
, recs
->rec
, struct DNS_RPC_RECORDS
, recs
->count
+1);
940 if (recs
->rec
== NULL
) {
941 return WERR_NOT_ENOUGH_MEMORY
;
944 recs
->rec
[i
].wLength
= 0;
945 recs
->rec
[i
].wRecordCount
= 0;
946 recs
->rec
[i
].dwChildCount
= num_children
;
947 recs
->rec
[i
].dwFlags
= 0;
949 /* The base records returned with empty name */
950 /* Children records returned with names */
951 if (branch_name
== NULL
) {
952 recs
->rec
[i
].dnsNodeName
.str
= talloc_strdup(recs
, "");
953 recs
->rec
[i
].dnsNodeName
.len
= 0;
955 recs
->rec
[i
].dnsNodeName
.str
= talloc_strdup(recs
, branch_name
);
956 recs
->rec
[i
].dnsNodeName
.len
= strlen(branch_name
);
958 recs
->rec
[i
].records
= talloc_zero_array(recs
, struct DNS_RPC_RECORD
, 0);
961 /* Allow empty records */
966 /* Do not return RR records, if the node has children */
967 if (branch_name
!= NULL
&& num_children
> 0) {
971 ptr
= ldb_msg_find_attr_as_string(msg
, "name", NULL
);
973 DBG_ERR("dnsserver: dns record has no name (%s)",
974 ldb_dn_get_linearized(msg
->dn
));
975 return WERR_INTERNAL_DB_ERROR
;
978 el
= ldb_msg_find_element(msg
, "dnsRecord");
979 if (el
== NULL
|| el
->values
== 0) {
984 for (j
=0; j
<el
->num_values
; j
++) {
985 struct dnsp_DnssrvRpcRecord dnsp_rec
;
986 struct DNS_RPC_RECORD
*dns_rec
;
987 enum ndr_err_code ndr_err
;
989 ndr_err
= ndr_pull_struct_blob(&el
->values
[j
], mem_ctx
, &dnsp_rec
,
990 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
991 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
992 DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg
->dn
)));
993 return WERR_INTERNAL_DB_ERROR
;
996 /* Match the records based on search criteria */
997 if (record_type
== DNS_TYPE_ALL
|| dnsp_rec
.wType
== record_type
) {
1000 if (select_flag
& DNS_RPC_VIEW_AUTHORITY_DATA
) {
1001 if (dnsp_rec
.rank
== DNS_RANK_ZONE
) {
1003 } else if (dnsp_rec
.rank
== DNS_RANK_NS_GLUE
) {
1005 * If branch_name is NULL, we're
1006 * explicitly asked to also return
1007 * DNS_RANK_NS_GLUE records
1009 if (branch_name
== NULL
) {
1014 if (select_flag
& DNS_RPC_VIEW_CACHE_DATA
) {
1015 if (dnsp_rec
.rank
== DNS_RANK_ZONE
) {
1019 if (select_flag
& DNS_RPC_VIEW_GLUE_DATA
) {
1020 if (dnsp_rec
.rank
== DNS_RANK_GLUE
) {
1024 if (select_flag
& DNS_RPC_VIEW_ROOT_HINT_DATA
) {
1025 if (dnsp_rec
.rank
== DNS_RANK_ROOT_HINT
) {
1031 recs
->rec
[i
].records
= talloc_realloc(recs
,
1032 recs
->rec
[i
].records
,
1033 struct DNS_RPC_RECORD
,
1034 recs
->rec
[i
].wRecordCount
+1);
1035 if (recs
->rec
[i
].records
== NULL
) {
1036 return WERR_NOT_ENOUGH_MEMORY
;
1039 dns_rec
= &recs
->rec
[i
].records
[recs
->rec
[i
].wRecordCount
];
1040 dnsp_to_dns_copy(recs
, &dnsp_rec
, dns_rec
);
1042 /* Fix record flags */
1043 if (strcmp(ptr
, "@") == 0) {
1044 dns_rec
->dwFlags
|= DNS_RPC_FLAG_ZONE_ROOT
;
1046 if (dnsp_rec
.rank
== DNS_RANK_ZONE
) {
1047 dns_rec
->dwFlags
|= DNS_RPC_FLAG_AUTH_ZONE_ROOT
;
1051 if (dns_rec
->dwFlags
== DNS_RANK_NS_GLUE
) {
1052 dns_rec
->dwFlags
|= DNS_RPC_FLAG_ZONE_ROOT
;
1055 recs
->rec
[i
].wRecordCount
++;
1057 dns_find_additional_names(mem_ctx
, &dnsp_rec
, add_names
, add_count
);
1066 int dns_name_compare(const struct ldb_message
**m1
, const struct ldb_message
**m2
,
1069 const char *name1
, *name2
;
1070 const char *ptr1
, *ptr2
;
1072 name1
= ldb_msg_find_attr_as_string(*m1
, "name", NULL
);
1073 name2
= ldb_msg_find_attr_as_string(*m2
, "name", NULL
);
1074 if (name1
== NULL
|| name2
== NULL
) {
1078 /* '@' record and the search_name record gets preference */
1079 if (name1
[0] == '@') {
1082 if (search_name
&& strcasecmp(name1
, search_name
) == 0) {
1086 if (name2
[0] == '@') {
1089 if (search_name
&& strcasecmp(name2
, search_name
) == 0) {
1093 /* Compare the last components of names.
1094 * If search_name is not NULL, compare the second last components of names */
1095 ptr1
= strrchr(name1
, '.');
1099 if (search_name
&& strcasecmp(ptr1
+1, search_name
) == 0) {
1101 while (ptr1
!= name1
) {
1113 ptr2
= strrchr(name2
, '.');
1117 if (search_name
&& strcasecmp(ptr2
+1, search_name
) == 0) {
1119 while (ptr2
!= name2
) {
1131 return strcasecmp(ptr1
, ptr2
);
1134 bool dns_record_match(struct dnsp_DnssrvRpcRecord
*rec1
, struct dnsp_DnssrvRpcRecord
*rec2
)
1139 if (rec1
->wType
!= rec2
->wType
) {
1143 switch(rec1
->wType
) {
1144 case DNS_TYPE_TOMBSTONE
:
1148 return strcmp(rec1
->data
.ipv4
, rec2
->data
.ipv4
) == 0;
1151 return dns_name_equal(rec1
->data
.ns
, rec2
->data
.ns
);
1153 case DNS_TYPE_CNAME
:
1154 return dns_name_equal(rec1
->data
.cname
, rec2
->data
.cname
);
1157 return dns_name_equal(rec1
->data
.soa
.mname
, rec2
->data
.soa
.mname
) &&
1158 dns_name_equal(rec1
->data
.soa
.rname
, rec2
->data
.soa
.rname
) &&
1159 rec1
->data
.soa
.serial
== rec2
->data
.soa
.serial
&&
1160 rec1
->data
.soa
.refresh
== rec2
->data
.soa
.refresh
&&
1161 rec1
->data
.soa
.retry
== rec2
->data
.soa
.retry
&&
1162 rec1
->data
.soa
.expire
== rec2
->data
.soa
.expire
&&
1163 rec1
->data
.soa
.minimum
== rec2
->data
.soa
.minimum
;
1166 return dns_name_equal(rec1
->data
.ptr
, rec2
->data
.ptr
);
1169 return rec1
->data
.mx
.wPriority
== rec2
->data
.mx
.wPriority
&&
1170 dns_name_equal(rec1
->data
.mx
.nameTarget
, rec2
->data
.mx
.nameTarget
);
1173 if (rec1
->data
.txt
.count
!= rec2
->data
.txt
.count
) {
1177 for (i
=0; i
<rec1
->data
.txt
.count
; i
++) {
1178 status
= status
&& (strcmp(rec1
->data
.txt
.str
[i
],
1179 rec2
->data
.txt
.str
[i
]) == 0);
1184 return strcmp(rec1
->data
.ipv6
, rec2
->data
.ipv6
) == 0;
1187 return rec1
->data
.srv
.wPriority
== rec2
->data
.srv
.wPriority
&&
1188 rec1
->data
.srv
.wWeight
== rec2
->data
.srv
.wWeight
&&
1189 rec1
->data
.srv
.wPort
== rec2
->data
.srv
.wPort
&&
1190 dns_name_equal(rec1
->data
.srv
.nameTarget
, rec2
->data
.srv
.nameTarget
);
1193 DEBUG(0, ("dnsserver: unhandled record type %u", rec1
->wType
));