2 Unix SMB/CIFS implementation.
6 Copyright (C) 2010 Kai Blin
7 Copyright (C) 2014 Stefan Metzmacher
8 Copyright (C) 2015 Andrew Bartlett
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "libcli/util/ntstatus.h"
26 #include "libcli/util/werror.h"
27 #include "librpc/ndr/libndr.h"
28 #include "librpc/gen_ndr/ndr_dns.h"
29 #include "librpc/gen_ndr/ndr_dnsp.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "dsdb/common/util.h"
33 #include "dns_server/dnsserver_common.h"
34 #include "rpc_server/dnsserver/dnsserver.h"
35 #include "lib/util/dlinklist.h"
38 #define DBGC_CLASS DBGC_DNS
40 uint8_t werr_to_dns_err(WERROR werr
)
42 if (W_ERROR_EQUAL(WERR_OK
, werr
)) {
44 } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR
), werr
)) {
45 return DNS_RCODE_FORMERR
;
46 } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE
), werr
)) {
47 return DNS_RCODE_SERVFAIL
;
48 } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR
), werr
)) {
49 return DNS_RCODE_NXDOMAIN
;
50 } else if (W_ERROR_EQUAL(WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
, werr
)) {
51 return DNS_RCODE_NXDOMAIN
;
52 } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED
), werr
)) {
53 return DNS_RCODE_NOTIMP
;
54 } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED
), werr
)) {
55 return DNS_RCODE_REFUSED
;
56 } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN
), werr
)) {
57 return DNS_RCODE_YXDOMAIN
;
58 } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET
), werr
)) {
59 return DNS_RCODE_YXRRSET
;
60 } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET
), werr
)) {
61 return DNS_RCODE_NXRRSET
;
62 } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH
), werr
)) {
63 return DNS_RCODE_NOTAUTH
;
64 } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE
), werr
)) {
65 return DNS_RCODE_NOTZONE
;
66 } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY
), werr
)) {
67 return DNS_RCODE_BADKEY
;
69 DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr
)));
70 return DNS_RCODE_SERVFAIL
;
73 WERROR
dns_common_extract(struct ldb_context
*samdb
,
74 const struct ldb_message_element
*el
,
76 struct dnsp_DnssrvRpcRecord
**records
,
77 uint16_t *num_records
)
80 struct dnsp_DnssrvRpcRecord
*recs
;
85 recs
= talloc_zero_array(mem_ctx
, struct dnsp_DnssrvRpcRecord
,
88 return WERR_NOT_ENOUGH_MEMORY
;
90 for (ri
= 0; ri
< el
->num_values
; ri
++) {
93 const char *dnsHostName
= NULL
;
94 struct ldb_val
*v
= &el
->values
[ri
];
95 enum ndr_err_code ndr_err
;
96 ndr_err
= ndr_pull_struct_blob(v
, recs
, &recs
[ri
],
97 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
98 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
100 DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n"));
101 return DNS_ERR(SERVER_FAILURE
);
105 * In AD, except on an RODC (where we should list a random RWDC,
106 * we should over-stamp the MNAME with our own hostname
108 if (recs
[ri
].wType
!= DNS_TYPE_SOA
) {
112 ret
= samdb_rodc(samdb
, &am_rodc
);
113 if (ret
!= LDB_SUCCESS
) {
114 DEBUG(0, ("Failed to confirm we are not an RODC: %s\n",
115 ldb_errstring(samdb
)));
116 return DNS_ERR(SERVER_FAILURE
);
123 ret
= samdb_dns_host_name(samdb
, &dnsHostName
);
124 if (ret
!= LDB_SUCCESS
|| dnsHostName
== NULL
) {
125 DEBUG(0, ("Failed to get dnsHostName from rootDSE"));
126 return DNS_ERR(SERVER_FAILURE
);
129 recs
[ri
].data
.soa
.mname
= talloc_strdup(recs
, dnsHostName
);
133 *num_records
= el
->num_values
;
138 * Lookup a DNS record, performing an exact match.
139 * i.e. DNS wild card records are not considered.
141 WERROR
dns_common_lookup(struct ldb_context
*samdb
,
144 struct dnsp_DnssrvRpcRecord
**records
,
145 uint16_t *num_records
,
148 const struct timeval start
= timeval_current();
149 static const char * const attrs
[] = {
155 WERROR werr
= WERR_OK
;
156 struct ldb_message
*msg
= NULL
;
157 struct ldb_message_element
*el
;
162 if (tombstoned
!= NULL
) {
164 ret
= dsdb_search_one(samdb
, mem_ctx
, &msg
, dn
,
165 LDB_SCOPE_BASE
, attrs
, 0,
166 "(objectClass=dnsNode)");
168 ret
= dsdb_search_one(samdb
, mem_ctx
, &msg
, dn
,
169 LDB_SCOPE_BASE
, attrs
, 0,
170 "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
172 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
173 werr
= WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
;
176 if (ret
!= LDB_SUCCESS
) {
177 /* TODO: we need to check if there's a glue record we need to
178 * create a referral to */
179 werr
= DNS_ERR(NAME_ERROR
);
183 if (tombstoned
!= NULL
) {
184 *tombstoned
= ldb_msg_find_attr_as_bool(msg
,
185 "dNSTombstoned", false);
188 el
= ldb_msg_find_element(msg
, "dnsRecord");
192 * records produced by older Samba releases
193 * keep dnsNode objects without dnsRecord and
194 * without setting dNSTombstoned=TRUE.
196 * We just pretend they're tombstones.
198 if (tombstoned
!= NULL
) {
199 struct dnsp_DnssrvRpcRecord
*recs
;
200 recs
= talloc_array(mem_ctx
,
201 struct dnsp_DnssrvRpcRecord
,
204 werr
= WERR_NOT_ENOUGH_MEMORY
;
207 recs
[0] = (struct dnsp_DnssrvRpcRecord
) {
208 .wType
= DNS_TYPE_TOMBSTONE
,
210 * A value of timestamp != 0
211 * indicated that the object was already
212 * a tombstone, this will be used
213 * in dns_common_replace()
225 * Because we are not looking for a tombstone
226 * in this codepath, we just pretend it does
229 werr
= WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
;
234 werr
= dns_common_extract(samdb
, el
, mem_ctx
, records
, num_records
);
236 if (!W_ERROR_IS_OK(werr
)) {
242 DNS_COMMON_LOG_OPERATION(
246 dn
== NULL
? NULL
: ldb_dn_get_linearized(dn
),
252 * Build an ldb_parse_tree node for an equality check
254 * Note: name is assumed to have been validated by dns_name_check
255 * so will be zero terminated and of a reasonable size.
257 static struct ldb_parse_tree
*build_equality_operation(
259 bool add_asterix
, /* prepend an '*' to the name */
260 const uint8_t *name
, /* the value being matched */
261 const char *attr
, /* the attribute to check name against */
262 size_t size
) /* length of name */
265 struct ldb_parse_tree
*el
= NULL
; /* Equality node being built */
266 struct ldb_val
*value
= NULL
; /* Value the attr will be compared
268 size_t length
= 0; /* calculated length of the value
269 including option '*' prefix and
270 '\0' string terminator */
272 el
= talloc(mem_ctx
, struct ldb_parse_tree
);
274 DBG_ERR("Unable to allocate ldb_parse_tree\n");
278 el
->operation
= LDB_OP_EQUALITY
;
279 el
->u
.equality
.attr
= talloc_strdup(mem_ctx
, attr
);
280 value
= &el
->u
.equality
.value
;
281 length
= (add_asterix
) ? size
+ 2 : size
+ 1;
282 value
->data
= talloc_zero_array(el
, uint8_t, length
);
284 DBG_ERR("Unable to allocate value->data\n");
289 value
->length
= length
;
291 value
->data
[0] = '*';
292 memcpy(&value
->data
[1], name
, size
);
294 memcpy(value
->data
, name
, size
);
300 * Determine the number of levels in name
301 * essentially the number of '.'s in the name + 1
303 * name is assumed to have been validated by dns_name_check
305 static unsigned int number_of_labels(const struct ldb_val
*name
) {
307 unsigned int labels
= 1;
308 for (x
= 0; x
< name
->length
; x
++) {
309 if (name
->data
[x
] == '.') {
316 * Build a query that matches the target name, and any possible
317 * DNS wild card entries
319 * Builds a parse tree equivalent to the example query.
321 * x.y.z -> (|(name=x.y.z)(name=\2a.y.z)(name=\2a.z)(name=\2a))
323 * The attribute 'name' is used as this is what the LDB index is on
324 * (the RDN, being 'dc' in this use case, does not have an index in
327 * Returns NULL if unable to build the query.
329 * The first component of the DN is assumed to be the name being looked up
330 * and also that it has been validated by dns_name_check
333 #define BASE "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE))(|(a=b)(c=d)))"
334 static struct ldb_parse_tree
*build_wildcard_query(
338 const struct ldb_val
*name
= NULL
; /* The DNS name being
340 const char *attr
= "name"; /* The attribute name */
341 struct ldb_parse_tree
*query
= NULL
; /* The constructed query
343 struct ldb_parse_tree
*wildcard_query
= NULL
; /* The parse tree for the
346 int labels
= 0; /* The number of labels in the name */
348 name
= ldb_dn_get_rdn_val(dn
);
350 DBG_ERR("Unable to get domain name value\n");
353 labels
= number_of_labels(name
);
355 query
= ldb_parse_tree(mem_ctx
, BASE
);
357 DBG_ERR("Unable to parse query %s\n", BASE
);
362 * The 3rd element of BASE is a place holder which is replaced with
363 * the actual wild card query
365 wildcard_query
= query
->u
.list
.elements
[2];
366 TALLOC_FREE(wildcard_query
->u
.list
.elements
);
368 wildcard_query
->u
.list
.num_elements
= labels
+ 1;
369 wildcard_query
->u
.list
.elements
= talloc_array(
371 struct ldb_parse_tree
*,
374 * Build the wild card query
377 int x
= 0; /* current character in the name */
378 int l
= 0; /* current equality operator index in elements */
379 struct ldb_parse_tree
*el
= NULL
; /* Equality operator being
381 bool add_asterix
= true; /* prepend an '*' to the value */
382 for (l
= 0, x
= 0; l
< labels
&& x
< name
->length
; l
++) {
383 unsigned int size
= name
->length
- x
;
384 add_asterix
= (name
->data
[x
] == '.');
385 el
= build_equality_operation(
392 return NULL
; /* Reason will have been logged */
394 wildcard_query
->u
.list
.elements
[l
] = el
;
396 /* skip to the start of the next label */
398 for (;x
< name
->length
&& name
->data
[x
] != '.'; x
++);
401 /* Add the base level "*" only query */
402 el
= build_equality_operation(mem_ctx
, true, NULL
, attr
, 0);
405 return NULL
; /* Reason will have been logged */
407 wildcard_query
->u
.list
.elements
[l
] = el
;
413 * Scan the list of records matching a dns wildcard query and return the
416 * The best match is either an exact name match, or the longest wild card
419 * i.e. name = a.b.c candidates *.b.c, *.c, - *.b.c would be selected
420 * name = a.b.c candidates a.b.c, *.b.c, *.c - a.b.c would be selected
422 static struct ldb_message
*get_best_match(struct ldb_dn
*dn
,
423 struct ldb_result
*result
)
425 int matched
= 0; /* Index of the current best match in result */
426 size_t length
= 0; /* The length of the current candidate */
427 const struct ldb_val
*target
= NULL
; /* value we're looking for */
428 const struct ldb_val
*candidate
= NULL
; /* current candidate value */
431 target
= ldb_dn_get_rdn_val(dn
);
432 for(x
= 0; x
< result
->count
; x
++) {
433 candidate
= ldb_dn_get_rdn_val(result
->msgs
[x
]->dn
);
434 if (strncasecmp((char *) target
->data
,
435 (char *) candidate
->data
,
436 target
->length
) == 0) {
437 /* Exact match stop searching and return */
438 return result
->msgs
[x
];
440 if (candidate
->length
> length
) {
442 length
= candidate
->length
;
445 return result
->msgs
[matched
];
449 * Look up a DNS entry, if an exact match does not exist, return the
450 * closest matching DNS wildcard entry if available
452 * Returns: LDB_ERR_NO_SUCH_OBJECT If no matching record exists
453 * LDB_ERR_OPERATIONS_ERROR If the query fails
454 * LDB_SUCCESS If a matching record was retrieved
457 static int dns_wildcard_lookup(struct ldb_context
*samdb
,
460 struct ldb_message
**msg
)
462 static const char * const attrs
[] = {
467 struct ldb_dn
*parent
= NULL
; /* The parent dn */
468 struct ldb_result
*result
= NULL
; /* Results of the search */
469 int ret
; /* Return code */
470 struct ldb_parse_tree
*query
= NULL
; /* The query to run */
471 struct ldb_request
*request
= NULL
; /* LDB request for the query op */
472 struct ldb_message
*match
= NULL
; /* the best matching DNS record */
473 TALLOC_CTX
*frame
= talloc_stackframe();
475 parent
= ldb_dn_get_parent(frame
, dn
);
476 if (parent
== NULL
) {
477 DBG_ERR("Unable to extract parent from dn\n");
479 return LDB_ERR_OPERATIONS_ERROR
;
482 query
= build_wildcard_query(frame
, dn
);
485 return LDB_ERR_OPERATIONS_ERROR
;
488 result
= talloc_zero(mem_ctx
, struct ldb_result
);
489 if (result
== NULL
) {
491 DBG_ERR("Unable to allocate ldb_result\n");
492 return LDB_ERR_OPERATIONS_ERROR
;
495 ret
= ldb_build_search_req_ex(&request
,
504 ldb_search_default_callback
,
506 if (ret
!= LDB_SUCCESS
) {
508 DBG_ERR("ldb_build_search_req_ex returned %d\n", ret
);
512 ret
= ldb_request(samdb
, request
);
513 if (ret
!= LDB_SUCCESS
) {
518 ret
= ldb_wait(request
->handle
, LDB_WAIT_ALL
);
519 if (ret
!= LDB_SUCCESS
) {
524 if (result
->count
== 0) {
526 return LDB_ERR_NO_SUCH_OBJECT
;
529 match
= get_best_match(dn
, result
);
532 return LDB_ERR_OPERATIONS_ERROR
;
535 *msg
= talloc_move(mem_ctx
, &match
);
541 * Lookup a DNS record, will match DNS wild card records if an exact match
544 WERROR
dns_common_wildcard_lookup(struct ldb_context
*samdb
,
547 struct dnsp_DnssrvRpcRecord
**records
,
548 uint16_t *num_records
)
550 const struct timeval start
= timeval_current();
552 WERROR werr
= WERR_OK
;
553 struct ldb_message
*msg
= NULL
;
554 struct ldb_message_element
*el
= NULL
;
555 const struct ldb_val
*name
= NULL
;
560 name
= ldb_dn_get_rdn_val(dn
);
562 werr
= DNS_ERR(NAME_ERROR
);
566 /* Don't look for a wildcard for @ */
567 if (name
->length
== 1 && name
->data
[0] == '@') {
568 werr
= dns_common_lookup(samdb
,
577 werr
= dns_name_check(
579 strlen((const char*)name
->data
),
580 (const char*) name
->data
);
581 if (!W_ERROR_IS_OK(werr
)) {
586 * Do a point search first, then fall back to a wildcard
587 * lookup if it does not exist
589 werr
= dns_common_lookup(samdb
,
595 if (!W_ERROR_EQUAL(werr
, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
)) {
599 ret
= dns_wildcard_lookup(samdb
, mem_ctx
, dn
, &msg
);
600 if (ret
== LDB_ERR_OPERATIONS_ERROR
) {
601 werr
= DNS_ERR(SERVER_FAILURE
);
604 if (ret
!= LDB_SUCCESS
) {
605 werr
= DNS_ERR(NAME_ERROR
);
609 el
= ldb_msg_find_element(msg
, "dnsRecord");
611 werr
= WERR_DNS_ERROR_NAME_DOES_NOT_EXIST
;
615 werr
= dns_common_extract(samdb
, el
, mem_ctx
, records
, num_records
);
617 if (!W_ERROR_IS_OK(werr
)) {
623 DNS_COMMON_LOG_OPERATION(
627 dn
== NULL
? NULL
: ldb_dn_get_linearized(dn
),
632 static int rec_cmp(const struct dnsp_DnssrvRpcRecord
*r1
,
633 const struct dnsp_DnssrvRpcRecord
*r2
)
635 if (r1
->wType
!= r2
->wType
) {
637 * The records are sorted with higher types first
639 return r2
->wType
- r1
->wType
;
643 * Then we need to sort from the oldest to newest timestamp
645 return r1
->dwTimeStamp
- r2
->dwTimeStamp
;
649 * Check for valid DNS names. These are names which:
651 * - do not start with a dot
652 * - do not have any empty labels
653 * - have no more than 127 labels
654 * - are no longer than 253 characters
655 * - none of the labels exceed 63 characters
657 WERROR
dns_name_check(TALLOC_CTX
*mem_ctx
, size_t len
, const char *name
)
660 unsigned int labels
= 0;
661 unsigned int label_len
= 0;
664 return WERR_DS_INVALID_DN_SYNTAX
;
667 if (len
> 1 && name
[0] == '.') {
668 return WERR_DS_INVALID_DN_SYNTAX
;
671 if ((len
- 1) > DNS_MAX_DOMAIN_LENGTH
) {
672 return WERR_DS_INVALID_DN_SYNTAX
;
675 for (i
= 0; i
< len
- 1; i
++) {
676 if (name
[i
] == '.' && name
[i
+1] == '.') {
677 return WERR_DS_INVALID_DN_SYNTAX
;
679 if (name
[i
] == '.') {
681 if (labels
> DNS_MAX_LABELS
) {
682 return WERR_DS_INVALID_DN_SYNTAX
;
687 if (label_len
> DNS_MAX_LABEL_LENGTH
) {
688 return WERR_DS_INVALID_DN_SYNTAX
;
696 static WERROR
check_name_list(TALLOC_CTX
*mem_ctx
, uint16_t rec_count
,
697 struct dnsp_DnssrvRpcRecord
*records
)
702 struct dnsp_DnssrvRpcRecord record
;
705 for (i
= 0; i
< rec_count
; i
++) {
708 switch (record
.wType
) {
711 len
= strlen(record
.data
.ns
);
712 werr
= dns_name_check(mem_ctx
, len
, record
.data
.ns
);
715 len
= strlen(record
.data
.cname
);
716 werr
= dns_name_check(mem_ctx
, len
, record
.data
.cname
);
719 len
= strlen(record
.data
.soa
.mname
);
720 werr
= dns_name_check(mem_ctx
, len
, record
.data
.soa
.mname
);
721 if (!W_ERROR_IS_OK(werr
)) {
724 len
= strlen(record
.data
.soa
.rname
);
725 werr
= dns_name_check(mem_ctx
, len
, record
.data
.soa
.rname
);
728 len
= strlen(record
.data
.ptr
);
729 werr
= dns_name_check(mem_ctx
, len
, record
.data
.ptr
);
732 len
= strlen(record
.data
.mx
.nameTarget
);
733 werr
= dns_name_check(mem_ctx
, len
, record
.data
.mx
.nameTarget
);
736 len
= strlen(record
.data
.srv
.nameTarget
);
737 werr
= dns_name_check(mem_ctx
, len
,
738 record
.data
.srv
.nameTarget
);
741 * In the default case, the record doesn't have a DN, so it
748 if (!W_ERROR_IS_OK(werr
)) {
756 bool dns_name_is_static(struct dnsp_DnssrvRpcRecord
*records
,
760 for (i
= 0; i
< rec_count
; i
++) {
761 if (records
[i
].wType
== DNS_TYPE_TOMBSTONE
) {
765 if (records
[i
].wType
== DNS_TYPE_SOA
||
766 records
[i
].dwTimeStamp
== 0) {
774 * Helper function to copy a dnsp_ip4_array struct to an IP4_ARRAY struct.
775 * The new structure and it's data are allocated on the supplied talloc context
777 static struct IP4_ARRAY
*copy_ip4_array(TALLOC_CTX
*ctx
,
779 struct dnsp_ip4_array array
)
782 struct IP4_ARRAY
*ip4_array
= NULL
;
785 ip4_array
= talloc_zero(ctx
, struct IP4_ARRAY
);
786 if (ip4_array
== NULL
) {
787 DBG_ERR("Out of memory copying property [%s]\n", name
);
791 ip4_array
->AddrCount
= array
.addrCount
;
792 if (ip4_array
->AddrCount
== 0) {
796 ip4_array
->AddrArray
=
797 talloc_array(ip4_array
, uint32_t, ip4_array
->AddrCount
);
798 if (ip4_array
->AddrArray
== NULL
) {
799 TALLOC_FREE(ip4_array
);
800 DBG_ERR("Out of memory copying property [%s] values\n", name
);
804 for (i
= 0; i
< ip4_array
->AddrCount
; i
++) {
805 ip4_array
->AddrArray
[i
] = array
.addrArray
[i
];
811 bool dns_zoneinfo_load_zone_property(struct dnsserver_zoneinfo
*zoneinfo
,
812 struct dnsp_DnsProperty
*prop
)
815 case DSPROPERTY_ZONE_TYPE
:
816 zoneinfo
->dwZoneType
= prop
->data
.zone_type
;
818 case DSPROPERTY_ZONE_ALLOW_UPDATE
:
819 zoneinfo
->fAllowUpdate
= prop
->data
.allow_update_flag
;
821 case DSPROPERTY_ZONE_NOREFRESH_INTERVAL
:
822 zoneinfo
->dwNoRefreshInterval
= prop
->data
.norefresh_hours
;
824 case DSPROPERTY_ZONE_REFRESH_INTERVAL
:
825 zoneinfo
->dwRefreshInterval
= prop
->data
.refresh_hours
;
827 case DSPROPERTY_ZONE_AGING_STATE
:
828 zoneinfo
->fAging
= prop
->data
.aging_enabled
;
830 case DSPROPERTY_ZONE_SCAVENGING_SERVERS
:
831 zoneinfo
->aipScavengeServers
= copy_ip4_array(
832 zoneinfo
, "ZONE_SCAVENGING_SERVERS", prop
->data
.servers
);
833 if (zoneinfo
->aipScavengeServers
== NULL
) {
837 case DSPROPERTY_ZONE_AGING_ENABLED_TIME
:
838 zoneinfo
->dwAvailForScavengeTime
=
839 prop
->data
.next_scavenging_cycle_hours
;
841 case DSPROPERTY_ZONE_MASTER_SERVERS
:
842 zoneinfo
->aipLocalMasters
= copy_ip4_array(
843 zoneinfo
, "ZONE_MASTER_SERVERS", prop
->data
.master_servers
);
844 if (zoneinfo
->aipLocalMasters
== NULL
) {
848 case DSPROPERTY_ZONE_EMPTY
:
849 case DSPROPERTY_ZONE_SECURE_TIME
:
850 case DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME
:
851 case DSPROPERTY_ZONE_AUTO_NS_SERVERS
:
852 case DSPROPERTY_ZONE_DCPROMO_CONVERT
:
853 case DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA
:
854 case DSPROPERTY_ZONE_MASTER_SERVERS_DA
:
855 case DSPROPERTY_ZONE_NS_SERVERS_DA
:
856 case DSPROPERTY_ZONE_NODE_DBFLAGS
:
861 WERROR
dns_get_zone_properties(struct ldb_context
*samdb
,
863 struct ldb_dn
*zone_dn
,
864 struct dnsserver_zoneinfo
*zoneinfo
)
868 struct dnsp_DnsProperty
*prop
= NULL
;
869 struct ldb_message_element
*element
= NULL
;
870 const char *const attrs
[] = {"dNSProperty", NULL
};
871 struct ldb_result
*res
= NULL
;
872 enum ndr_err_code err
;
874 ret
= ldb_search(samdb
,
880 "(objectClass=dnsZone)");
881 if (ret
!= LDB_SUCCESS
) {
882 DBG_ERR("dnsserver: Failed to find DNS zone: %s\n",
883 ldb_dn_get_linearized(zone_dn
));
884 return DNS_ERR(SERVER_FAILURE
);
887 element
= ldb_msg_find_element(res
->msgs
[0], "dNSProperty");
888 if (element
== NULL
) {
889 return DNS_ERR(NOTZONE
);
892 for (i
= 0; i
< element
->num_values
; i
++) {
894 prop
= talloc_zero(mem_ctx
, struct dnsp_DnsProperty
);
896 return WERR_NOT_ENOUGH_MEMORY
;
898 err
= ndr_pull_struct_blob(
899 &(element
->values
[i
]),
902 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnsProperty
);
903 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
905 * If we can't pull it, then there is no valid
906 * data to load into the zone, so ignore this
907 * as Micosoft does. Windows can load an
908 * invalid property with a zero length into
909 * the dnsProperty attribute.
915 dns_zoneinfo_load_zone_property(zoneinfo
, prop
);
916 if (!valid_property
) {
917 return DNS_ERR(SERVER_FAILURE
);
924 WERROR
dns_common_replace(struct ldb_context
*samdb
,
929 struct dnsp_DnssrvRpcRecord
*records
,
932 const struct timeval start
= timeval_current();
933 struct ldb_message_element
*el
;
937 struct ldb_message
*msg
= NULL
;
938 bool was_tombstoned
= false;
939 bool become_tombstoned
= false;
940 struct ldb_dn
*zone_dn
= NULL
;
941 struct dnsserver_zoneinfo
*zoneinfo
= NULL
;
944 msg
= ldb_msg_new(mem_ctx
);
945 W_ERROR_HAVE_NO_MEMORY(msg
);
949 zone_dn
= ldb_dn_copy(mem_ctx
, dn
);
950 if (zone_dn
== NULL
) {
951 werr
= WERR_NOT_ENOUGH_MEMORY
;
954 if (!ldb_dn_remove_child_components(zone_dn
, 1)) {
955 werr
= DNS_ERR(SERVER_FAILURE
);
958 zoneinfo
= talloc(mem_ctx
, struct dnsserver_zoneinfo
);
959 if (zoneinfo
== NULL
) {
960 werr
= WERR_NOT_ENOUGH_MEMORY
;
963 werr
= dns_get_zone_properties(samdb
, mem_ctx
, zone_dn
, zoneinfo
);
964 if (W_ERROR_EQUAL(DNS_ERR(NOTZONE
), werr
)) {
966 * We only got zoneinfo for aging so if we didn't find any
967 * properties then just disable aging and keep going.
969 zoneinfo
->fAging
= 0;
970 } else if (!W_ERROR_IS_OK(werr
)) {
974 werr
= check_name_list(mem_ctx
, rec_count
, records
);
975 if (!W_ERROR_IS_OK(werr
)) {
979 ret
= ldb_msg_add_empty(msg
, "dnsRecord", LDB_FLAG_MOD_REPLACE
, &el
);
980 if (ret
!= LDB_SUCCESS
) {
981 werr
= DNS_ERR(SERVER_FAILURE
);
986 * we have at least one value,
987 * which might be used for the tombstone marker
989 el
->values
= talloc_zero_array(el
, struct ldb_val
, MAX(1, rec_count
));
991 if (el
->values
== NULL
) {
992 werr
= WERR_NOT_ENOUGH_MEMORY
;
997 * We store a sorted list with the high wType values first
998 * that's what windows does. It also simplifies the
999 * filtering of DNS_TYPE_TOMBSTONE records
1001 TYPESAFE_QSORT(records
, rec_count
, rec_cmp
);
1004 for (i
= 0; i
< rec_count
; i
++) {
1005 struct ldb_val
*v
= &el
->values
[el
->num_values
];
1006 enum ndr_err_code ndr_err
;
1008 if (records
[i
].wType
== DNS_TYPE_TOMBSTONE
) {
1009 if (records
[i
].data
.timestamp
!= 0) {
1010 was_tombstoned
= true;
1015 if (zoneinfo
->fAging
== 1 && records
[i
].dwTimeStamp
!= 0) {
1016 unix_to_nt_time(&t
, time(NULL
));
1017 t
/= 10 * 1000 * 1000;
1019 if (t
- records
[i
].dwTimeStamp
>
1020 zoneinfo
->dwNoRefreshInterval
) {
1021 records
[i
].dwTimeStamp
= t
;
1025 records
[i
].dwSerial
= serial
;
1026 ndr_err
= ndr_push_struct_blob(v
, el
->values
, &records
[i
],
1027 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnssrvRpcRecord
);
1028 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1029 DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
1030 werr
= DNS_ERR(SERVER_FAILURE
);
1037 if (el
->num_values
== 0) {
1042 ret
= ldb_msg_add_string(msg
, "objectClass", "dnsNode");
1043 if (ret
!= LDB_SUCCESS
) {
1044 werr
= DNS_ERR(SERVER_FAILURE
);
1048 ret
= ldb_add(samdb
, msg
);
1049 if (ret
!= LDB_SUCCESS
) {
1050 werr
= DNS_ERR(SERVER_FAILURE
);
1058 if (el
->num_values
== 0) {
1059 struct dnsp_DnssrvRpcRecord tbs
;
1060 struct ldb_val
*v
= &el
->values
[el
->num_values
];
1061 enum ndr_err_code ndr_err
;
1064 if (was_tombstoned
) {
1066 * This is already a tombstoned object.
1067 * Just leave it instead of updating the time stamp.
1073 tv
= timeval_current();
1074 tbs
= (struct dnsp_DnssrvRpcRecord
) {
1075 .wType
= DNS_TYPE_TOMBSTONE
,
1077 .data
.timestamp
= timeval_to_nttime(&tv
),
1080 ndr_err
= ndr_push_struct_blob(v
, el
->values
, &tbs
,
1081 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnssrvRpcRecord
);
1082 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1083 DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n"));
1084 werr
= DNS_ERR(SERVER_FAILURE
);
1089 become_tombstoned
= true;
1092 if (was_tombstoned
|| become_tombstoned
) {
1093 ret
= ldb_msg_add_empty(msg
, "dNSTombstoned",
1094 LDB_FLAG_MOD_REPLACE
, NULL
);
1095 if (ret
!= LDB_SUCCESS
) {
1096 werr
= DNS_ERR(SERVER_FAILURE
);
1100 ret
= ldb_msg_add_fmt(msg
, "dNSTombstoned", "%s",
1101 become_tombstoned
? "TRUE" : "FALSE");
1102 if (ret
!= LDB_SUCCESS
) {
1103 werr
= DNS_ERR(SERVER_FAILURE
);
1108 ret
= ldb_modify(samdb
, msg
);
1109 if (ret
!= LDB_SUCCESS
) {
1110 NTSTATUS nt
= dsdb_ldb_err_to_ntstatus(ret
);
1111 werr
= ntstatus_to_werror(nt
);
1117 DNS_COMMON_LOG_OPERATION(
1121 dn
== NULL
? NULL
: ldb_dn_get_linearized(dn
),
1126 bool dns_name_match(const char *zone
, const char *name
, size_t *host_part_len
)
1128 size_t zl
= strlen(zone
);
1129 size_t nl
= strlen(name
);
1131 static const size_t fixup
= 'a' - 'A';
1137 for (zi
= zl
, ni
= nl
; zi
>= 0; zi
--, ni
--) {
1141 /* convert to lower case */
1142 if (zc
>= 'A' && zc
<= 'Z') {
1145 if (nc
>= 'A' && nc
<= 'Z') {
1155 if (name
[ni
] != '.') {
1162 *host_part_len
= ni
+1;
1167 WERROR
dns_common_name2dn(struct ldb_context
*samdb
,
1168 struct dns_server_zone
*zones
,
1169 TALLOC_CTX
*mem_ctx
,
1171 struct ldb_dn
**_dn
)
1173 struct ldb_dn
*base
;
1175 const struct dns_server_zone
*z
;
1176 size_t host_part_len
= 0;
1177 struct ldb_val host_part
;
1180 const char *casefold
= NULL
;
1183 return DNS_ERR(FORMAT_ERROR
);
1186 if (strcmp(name
, "") == 0) {
1187 base
= ldb_get_default_basedn(samdb
);
1188 dn
= ldb_dn_copy(mem_ctx
, base
);
1189 ok
= ldb_dn_add_child_fmt(dn
,
1190 "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System");
1193 return WERR_NOT_ENOUGH_MEMORY
;
1200 /* Check non-empty names */
1201 werr
= dns_name_check(mem_ctx
, strlen(name
), name
);
1202 if (!W_ERROR_IS_OK(werr
)) {
1206 for (z
= zones
; z
!= NULL
; z
= z
->next
) {
1209 match
= dns_name_match(z
->name
, name
, &host_part_len
);
1216 return DNS_ERR(NAME_ERROR
);
1219 if (host_part_len
== 0) {
1220 dn
= ldb_dn_copy(mem_ctx
, z
->dn
);
1221 ok
= ldb_dn_add_child_fmt(dn
, "DC=@");
1224 return WERR_NOT_ENOUGH_MEMORY
;
1230 dn
= ldb_dn_copy(mem_ctx
, z
->dn
);
1233 return WERR_NOT_ENOUGH_MEMORY
;
1236 host_part
= data_blob_const(name
, host_part_len
);
1238 ok
= ldb_dn_add_child_val(dn
, "DC", host_part
);
1242 return WERR_NOT_ENOUGH_MEMORY
;
1246 * Check the new DN here for validity, so as to catch errors
1249 ok
= ldb_dn_validate(dn
);
1252 return DNS_ERR(NAME_ERROR
);
1256 * The value from this check is saved in the DN, and doing
1257 * this here allows an easy return here.
1259 casefold
= ldb_dn_get_casefold(dn
);
1260 if (casefold
== NULL
) {
1262 return DNS_ERR(NAME_ERROR
);
1269 static int dns_common_sort_zones(struct ldb_message
**m1
, struct ldb_message
**m2
)
1271 const char *n1
, *n2
;
1274 n1
= ldb_msg_find_attr_as_string(*m1
, "name", NULL
);
1275 n2
= ldb_msg_find_attr_as_string(*m2
, "name", NULL
);
1276 if (n1
== NULL
|| n2
== NULL
) {
1279 } else if (n2
!= NULL
) {
1288 /* If the string lengths are not equal just sort by length */
1290 /* If m1 is the larger zone name, return it first */
1294 /*TODO: We need to compare DNs here, we want the DomainDNSZones first */
1298 NTSTATUS
dns_common_zones(struct ldb_context
*samdb
,
1299 TALLOC_CTX
*mem_ctx
,
1300 struct ldb_dn
*base_dn
,
1301 struct dns_server_zone
**zones_ret
)
1303 const struct timeval start
= timeval_current();
1305 static const char * const attrs
[] = { "name", NULL
};
1306 struct ldb_result
*res
;
1308 struct dns_server_zone
*new_list
= NULL
;
1309 TALLOC_CTX
*frame
= talloc_stackframe();
1310 NTSTATUS result
= NT_STATUS_OK
;
1313 /* This search will work against windows */
1314 ret
= dsdb_search(samdb
, frame
, &res
,
1315 base_dn
, LDB_SCOPE_SUBTREE
,
1316 attrs
, 0, "(objectClass=dnsZone)");
1318 /* TODO: this search does not work against windows */
1319 ret
= dsdb_search(samdb
, frame
, &res
, NULL
,
1322 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
,
1323 "(objectClass=dnsZone)");
1325 if (ret
!= LDB_SUCCESS
) {
1327 result
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
1331 TYPESAFE_QSORT(res
->msgs
, res
->count
, dns_common_sort_zones
);
1333 for (i
=0; i
< res
->count
; i
++) {
1334 struct dns_server_zone
*z
;
1336 z
= talloc_zero(mem_ctx
, struct dns_server_zone
);
1339 result
= NT_STATUS_NO_MEMORY
;
1343 z
->name
= ldb_msg_find_attr_as_string(res
->msgs
[i
], "name", NULL
);
1344 talloc_steal(z
, z
->name
);
1345 z
->dn
= talloc_move(z
, &res
->msgs
[i
]->dn
);
1347 * Ignore the RootDNSServers zone and zones that we don't support yet
1348 * RootDNSServers should never be returned (Windows DNS server don't)
1349 * ..TrustAnchors should never be returned as is, (Windows returns
1350 * TrustAnchors) and for the moment we don't support DNSSEC so we'd better
1351 * not return this zone.
1353 if ((strcmp(z
->name
, "RootDNSServers") == 0) ||
1354 (strcmp(z
->name
, "..TrustAnchors") == 0))
1356 DEBUG(10, ("Ignoring zone %s\n", z
->name
));
1360 DLIST_ADD_END(new_list
, z
);
1363 *zones_ret
= new_list
;
1365 result
= NT_STATUS_OK
;
1367 DNS_COMMON_LOG_OPERATION(
1371 base_dn
== NULL
? NULL
: ldb_dn_get_linearized(base_dn
),
1377 see if two DNS names are the same
1379 bool dns_name_equal(const char *name1
, const char *name2
)
1381 size_t len1
= strlen(name1
);
1382 size_t len2
= strlen(name2
);
1384 if (len1
> 0 && name1
[len1
- 1] == '.') {
1387 if (len2
> 0 && name2
[len2
- 1] == '.') {
1393 return strncasecmp(name1
, name2
, len1
) == 0;