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 "lib/util/dlinklist.h"
25 #include "librpc/gen_ndr/ndr_dnsp.h"
26 #include "librpc/gen_ndr/ndr_security.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "libcli/security/security.h"
30 #include "dsdb/common/util.h"
34 /* There are only 2 fixed partitions for DNS */
35 struct dnsserver_partition
*dnsserver_db_enumerate_partitions(TALLOC_CTX
*mem_ctx
,
36 struct dnsserver_serverinfo
*serverinfo
,
37 struct ldb_context
*samdb
)
39 struct dnsserver_partition
*partitions
, *p
;
43 /* Domain partition */
44 p
= talloc_zero(mem_ctx
, struct dnsserver_partition
);
49 p
->partition_dn
= ldb_dn_new(p
, samdb
, serverinfo
->pszDomainDirectoryPartition
);
50 if (p
->partition_dn
== NULL
) {
54 p
->pszDpFqdn
= samdb_dn_to_dns_domain(p
, p
->partition_dn
);
55 p
->dwDpFlags
= DNS_DP_AUTOCREATED
| DNS_DP_DOMAIN_DEFAULT
| DNS_DP_ENLISTED
;
58 DLIST_ADD_END(partitions
, p
);
60 /* Forest Partition */
61 p
= talloc_zero(mem_ctx
, struct dnsserver_partition
);
66 p
->partition_dn
= ldb_dn_new(p
, samdb
, serverinfo
->pszForestDirectoryPartition
);
67 if (p
->partition_dn
== NULL
) {
71 p
->pszDpFqdn
= samdb_dn_to_dns_domain(p
, p
->partition_dn
);
72 p
->dwDpFlags
= DNS_DP_AUTOCREATED
| DNS_DP_FOREST_DEFAULT
| DNS_DP_ENLISTED
;
75 DLIST_ADD_END(partitions
, p
);
85 /* Search for all dnsZone records */
86 struct dnsserver_zone
*dnsserver_db_enumerate_zones(TALLOC_CTX
*mem_ctx
,
87 struct ldb_context
*samdb
,
88 struct dnsserver_partition
*p
)
91 const char * const attrs
[] = {"name", "dNSProperty", NULL
};
93 struct ldb_result
*res
;
94 struct dnsserver_zone
*zones
, *z
;
97 tmp_ctx
= talloc_new(mem_ctx
);
98 if (tmp_ctx
== NULL
) {
102 dn
= ldb_dn_copy(tmp_ctx
, p
->partition_dn
);
106 if (!ldb_dn_add_child_fmt(dn
, "CN=MicrosoftDNS")) {
110 ret
= ldb_search(samdb
, tmp_ctx
, &res
, dn
, LDB_SCOPE_SUBTREE
,
111 attrs
, "(objectClass=dnsZone)");
112 if (ret
!= LDB_SUCCESS
) {
113 DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
114 ldb_dn_get_linearized(dn
)));
119 for(i
=0; i
<res
->count
; i
++) {
121 struct ldb_message_element
*element
= NULL
;
122 struct dnsp_DnsProperty
*props
= NULL
;
123 enum ndr_err_code err
;
124 z
= talloc_zero(mem_ctx
, struct dnsserver_zone
);
130 name
= talloc_strdup(z
,
131 ldb_msg_find_attr_as_string(res
->msgs
[i
],
133 if (strcmp(name
, "..TrustAnchors") == 0) {
137 if (strcmp(name
, "RootDNSServers") == 0) {
139 z
->name
= talloc_strdup(z
, ".");
143 z
->zone_dn
= talloc_steal(z
, res
->msgs
[i
]->dn
);
145 DLIST_ADD_END(zones
, z
);
146 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z
->name
));
148 element
= ldb_msg_find_element(res
->msgs
[i
], "dNSProperty");
150 props
= talloc_zero_array(tmp_ctx
,
151 struct dnsp_DnsProperty
,
152 element
->num_values
);
153 for (j
= 0; j
< element
->num_values
; j
++ ) {
154 err
= ndr_pull_struct_blob(
155 &(element
->values
[j
]),
158 (ndr_pull_flags_fn_t
)
159 ndr_pull_dnsp_DnsProperty
);
160 if (!NDR_ERR_CODE_IS_SUCCESS(err
)){
162 * Per Microsoft we must
163 * ignore invalid data here
164 * and continue as a Windows
165 * server can put in a
166 * structure with an invalid
169 * We can safely fill in an
170 * extra empty property here
172 * dns_zoneinfo_load_zone_property()
174 * DSPROPERTY_ZONE_EMPTY
176 ZERO_STRUCT(props
[j
]);
177 props
[j
].id
= DSPROPERTY_ZONE_EMPTY
;
181 z
->tmp_props
= props
;
182 z
->num_props
= element
->num_values
;
188 talloc_free(tmp_ctx
);
193 /* Find DNS partition information */
194 struct dnsserver_partition_info
*dnsserver_db_partition_info(TALLOC_CTX
*mem_ctx
,
195 struct ldb_context
*samdb
,
196 struct dnsserver_partition
*p
)
198 const char * const attrs
[] = { "instanceType", "msDs-masteredBy", NULL
};
199 const char * const attrs_none
[] = { NULL
};
200 struct ldb_result
*res
;
201 struct ldb_message_element
*el
;
203 struct dnsserver_partition_info
*partinfo
;
204 int i
, ret
, instance_type
;
207 tmp_ctx
= talloc_new(mem_ctx
);
208 if (tmp_ctx
== NULL
) {
212 partinfo
= talloc_zero(mem_ctx
, struct dnsserver_partition_info
);
213 if (partinfo
== NULL
) {
214 talloc_free(tmp_ctx
);
218 /* Search for the active replica and state */
219 ret
= ldb_search(samdb
, tmp_ctx
, &res
, p
->partition_dn
, LDB_SCOPE_BASE
,
221 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
225 /* Set the state of the partition */
226 instance_type
= ldb_msg_find_attr_as_int(res
->msgs
[0], "instanceType", -1);
227 if (instance_type
== -1) {
228 partinfo
->dwState
= DNS_DP_STATE_UNKNOWN
;
229 } else if (instance_type
& INSTANCE_TYPE_NC_COMING
) {
230 partinfo
->dwState
= DNS_DP_STATE_REPL_INCOMING
;
231 } else if (instance_type
& INSTANCE_TYPE_NC_GOING
) {
232 partinfo
->dwState
= DNS_DP_STATE_REPL_OUTGOING
;
234 partinfo
->dwState
= DNS_DP_OKAY
;
237 el
= ldb_msg_find_element(res
->msgs
[0], "msDs-masteredBy");
239 partinfo
->dwReplicaCount
= 0;
240 partinfo
->ReplicaArray
= NULL
;
242 partinfo
->dwReplicaCount
= el
->num_values
;
243 partinfo
->ReplicaArray
= talloc_zero_array(partinfo
,
244 struct DNS_RPC_DP_REPLICA
*,
246 if (partinfo
->ReplicaArray
== NULL
) {
249 for (i
=0; i
<el
->num_values
; i
++) {
250 partinfo
->ReplicaArray
[i
] = talloc_zero(partinfo
,
251 struct DNS_RPC_DP_REPLICA
);
252 if (partinfo
->ReplicaArray
[i
] == NULL
) {
255 partinfo
->ReplicaArray
[i
]->pszReplicaDn
= talloc_strdup(
257 (const char *)el
->values
[i
].data
);
258 if (partinfo
->ReplicaArray
[i
]->pszReplicaDn
== NULL
) {
265 /* Search for cross-reference object */
266 dn
= ldb_dn_copy(tmp_ctx
, ldb_get_config_basedn(samdb
));
271 ret
= ldb_search(samdb
, tmp_ctx
, &res
, dn
, LDB_SCOPE_DEFAULT
, attrs_none
,
272 "(nCName=%s)", ldb_dn_get_linearized(p
->partition_dn
));
273 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
276 partinfo
->pszCrDn
= talloc_strdup(partinfo
, ldb_dn_get_linearized(res
->msgs
[0]->dn
));
277 if (partinfo
->pszCrDn
== NULL
) {
282 talloc_free(tmp_ctx
);
286 talloc_free(tmp_ctx
);
287 talloc_free(partinfo
);
292 /* Increment serial number and update timestamp */
293 static unsigned int dnsserver_update_soa(TALLOC_CTX
*mem_ctx
,
294 struct ldb_context
*samdb
,
295 struct dnsserver_zone
*z
,
298 const char * const attrs
[] = { "dnsRecord", NULL
};
299 struct ldb_result
*res
;
300 struct dnsp_DnssrvRpcRecord rec
;
301 struct ldb_message_element
*el
;
302 enum ndr_err_code ndr_err
;
303 int ret
, i
, serial
= -1;
305 *werr
= WERR_INTERNAL_DB_ERROR
;
307 ret
= ldb_search(samdb
, mem_ctx
, &res
, z
->zone_dn
, LDB_SCOPE_ONELEVEL
, attrs
,
308 "(&(objectClass=dnsNode)(name=@))");
309 if (ret
!= LDB_SUCCESS
|| res
->count
== 0) {
313 el
= ldb_msg_find_element(res
->msgs
[0], "dnsRecord");
318 for (i
=0; i
<el
->num_values
; i
++) {
319 ndr_err
= ndr_pull_struct_blob(&el
->values
[i
], mem_ctx
, &rec
,
320 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
321 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
325 if (rec
.wType
== DNS_TYPE_SOA
) {
326 serial
= rec
.data
.soa
.serial
+ 1;
327 rec
.dwSerial
= serial
;
329 rec
.data
.soa
.serial
= serial
;
331 ndr_err
= ndr_push_struct_blob(&el
->values
[i
], mem_ctx
, &rec
,
332 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnssrvRpcRecord
);
333 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
334 *werr
= WERR_NOT_ENOUGH_MEMORY
;
342 el
->flags
= LDB_FLAG_MOD_REPLACE
;
343 ret
= ldb_modify(samdb
, res
->msgs
[0]);
344 if (ret
!= LDB_SUCCESS
) {
345 if (ret
== LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
346 *werr
= WERR_ACCESS_DENIED
;
358 /* Add DNS record to the database */
359 static WERROR
dnsserver_db_do_add_rec(TALLOC_CTX
*mem_ctx
,
360 struct ldb_context
*samdb
,
363 struct dnsp_DnssrvRpcRecord
*rec
)
365 struct ldb_message
*msg
;
368 enum ndr_err_code ndr_err
;
371 msg
= ldb_msg_new(mem_ctx
);
372 W_ERROR_HAVE_NO_MEMORY(msg
);
375 ret
= ldb_msg_add_string(msg
, "objectClass", "dnsNode");
376 if (ret
!= LDB_SUCCESS
) {
377 return WERR_NOT_ENOUGH_MEMORY
;
380 if (num_rec
> 0 && rec
) {
381 for (i
=0; i
<num_rec
; i
++) {
382 ndr_err
= ndr_push_struct_blob(&v
, mem_ctx
, &rec
[i
],
383 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnssrvRpcRecord
);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
385 return WERR_GEN_FAILURE
;
388 ret
= ldb_msg_add_value(msg
, "dnsRecord", &v
, NULL
);
389 if (ret
!= LDB_SUCCESS
) {
390 return WERR_NOT_ENOUGH_MEMORY
;
395 ret
= ldb_add(samdb
, msg
);
396 if (ret
!= LDB_SUCCESS
) {
397 return WERR_INTERNAL_DB_ERROR
;
404 /* Add dnsNode record to the database with DNS record */
405 WERROR
dnsserver_db_add_empty_node(TALLOC_CTX
*mem_ctx
,
406 struct ldb_context
*samdb
,
407 struct dnsserver_zone
*z
,
410 const char * const attrs
[] = { "name", NULL
};
411 struct ldb_result
*res
;
413 char *encoded_name
= ldb_binary_encode_string(mem_ctx
, name
);
414 struct ldb_val name_val
= data_blob_string_const(name
);
417 ret
= ldb_search(samdb
, mem_ctx
, &res
, z
->zone_dn
, LDB_SCOPE_BASE
, attrs
,
418 "(&(objectClass=dnsNode)(name=%s))",
420 if (ret
!= LDB_SUCCESS
) {
421 return WERR_INTERNAL_DB_ERROR
;
424 if (res
->count
> 0) {
426 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS
;
429 dn
= ldb_dn_copy(mem_ctx
, z
->zone_dn
);
430 W_ERROR_HAVE_NO_MEMORY(dn
);
432 if (!ldb_dn_add_child_val(dn
, "DC", name_val
)) {
433 return WERR_NOT_ENOUGH_MEMORY
;
436 return dnsserver_db_do_add_rec(mem_ctx
, samdb
, dn
, 0, NULL
);
439 static void set_record_rank(struct dnsserver_zone
*z
,
441 struct dnsp_DnssrvRpcRecord
*rec
)
443 if (z
->zoneinfo
->dwZoneType
== DNS_ZONE_TYPE_PRIMARY
) {
444 if (strcmp(name
, "@") != 0 && rec
->wType
== DNS_TYPE_NS
) {
445 rec
->rank
= DNS_RANK_NS_GLUE
;
447 rec
->rank
= DNS_RANK_ZONE
;
449 } else if (strcmp(z
->name
, ".") == 0) {
450 rec
->rank
= DNS_RANK_ROOT_HINT
;
455 /* Add a DNS record */
456 WERROR
dnsserver_db_add_record(TALLOC_CTX
*mem_ctx
,
457 struct ldb_context
*samdb
,
458 struct dnsserver_zone
*z
,
460 struct DNS_RPC_RECORD
*add_record
)
462 const char * const attrs
[] = { "dnsRecord", "dNSTombstoned", NULL
};
463 struct ldb_result
*res
;
464 struct dnsp_DnssrvRpcRecord
*rec
= NULL
;
465 struct ldb_message_element
*el
;
467 enum ndr_err_code ndr_err
;
471 bool was_tombstoned
= false;
472 char *encoded_name
= ldb_binary_encode_string(mem_ctx
, name
);
474 werr
= dns_to_dnsp_convert(mem_ctx
, add_record
, &rec
, true);
475 if (!W_ERROR_IS_OK(werr
)) {
479 /* Set the correct rank for the record. */
480 set_record_rank(z
, name
, rec
);
482 serial
= dnsserver_update_soa(mem_ctx
, samdb
, z
, &werr
);
487 rec
->dwSerial
= serial
;
488 rec
->dwTimeStamp
= 0;
490 ret
= ldb_search(samdb
, mem_ctx
, &res
, z
->zone_dn
, LDB_SCOPE_ONELEVEL
, attrs
,
491 "(&(objectClass=dnsNode)(name=%s))",
493 if (ret
!= LDB_SUCCESS
) {
494 return WERR_INTERNAL_DB_ERROR
;
497 if (res
->count
== 0) {
498 dn
= dnsserver_name_to_dn(mem_ctx
, z
, name
);
499 W_ERROR_HAVE_NO_MEMORY(dn
);
501 return dnsserver_db_do_add_rec(mem_ctx
, samdb
, dn
, 1, rec
);
504 el
= ldb_msg_find_element(res
->msgs
[0], "dnsRecord");
506 ret
= ldb_msg_add_empty(res
->msgs
[0], "dnsRecord", 0, &el
);
507 if (ret
!= LDB_SUCCESS
) {
508 return WERR_NOT_ENOUGH_MEMORY
;
512 was_tombstoned
= ldb_msg_find_attr_as_bool(res
->msgs
[0],
513 "dNSTombstoned", false);
514 if (was_tombstoned
) {
518 for (i
=0; i
<el
->num_values
; i
++) {
519 struct dnsp_DnssrvRpcRecord rec2
;
521 ndr_err
= ndr_pull_struct_blob(&el
->values
[i
], mem_ctx
, &rec2
,
522 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
523 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
524 return WERR_GEN_FAILURE
;
527 if (dns_record_match(rec
, &rec2
)) {
531 if (i
< el
->num_values
) {
532 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS
;
534 if (i
== el
->num_values
) {
535 /* adding a new value */
536 el
->values
= talloc_realloc(el
, el
->values
, struct ldb_val
, el
->num_values
+1);
537 W_ERROR_HAVE_NO_MEMORY(el
->values
);
541 ndr_err
= ndr_push_struct_blob(&el
->values
[i
], mem_ctx
, rec
,
542 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnssrvRpcRecord
);
543 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
544 return WERR_GEN_FAILURE
;
547 el
->flags
= LDB_FLAG_MOD_REPLACE
;
549 el
= ldb_msg_find_element(res
->msgs
[0], "dNSTombstoned");
551 el
->flags
= LDB_FLAG_MOD_DELETE
;
554 ret
= ldb_modify(samdb
, res
->msgs
[0]);
555 if (ret
!= LDB_SUCCESS
) {
556 return WERR_INTERNAL_DB_ERROR
;
563 /* Update a DNS record */
564 WERROR
dnsserver_db_update_record(TALLOC_CTX
*mem_ctx
,
565 struct ldb_context
*samdb
,
566 struct dnsserver_zone
*z
,
568 struct DNS_RPC_RECORD
*add_record
,
569 struct DNS_RPC_RECORD
*del_record
)
571 const char * const attrs
[] = { "dnsRecord", NULL
};
572 struct ldb_result
*res
;
573 struct dnsp_DnssrvRpcRecord rec2
;
574 struct dnsp_DnssrvRpcRecord
*arec
= NULL
, *drec
= NULL
;
575 struct ldb_message_element
*el
;
576 enum ndr_err_code ndr_err
;
580 bool updating_ttl
= false;
581 char *encoded_name
= ldb_binary_encode_string(mem_ctx
, name
);
583 werr
= dns_to_dnsp_convert(mem_ctx
, add_record
, &arec
, true);
584 if (!W_ERROR_IS_OK(werr
)) {
588 werr
= dns_to_dnsp_convert(mem_ctx
, del_record
, &drec
, true);
589 if (!W_ERROR_IS_OK(werr
)) {
593 ret
= ldb_search(samdb
, mem_ctx
, &res
, z
->zone_dn
, LDB_SCOPE_ONELEVEL
, attrs
,
594 "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
596 if (ret
!= LDB_SUCCESS
) {
597 return WERR_INTERNAL_DB_ERROR
;
600 if (res
->count
== 0) {
601 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST
;
604 el
= ldb_msg_find_element(res
->msgs
[0], "dnsRecord");
605 if (el
== NULL
|| el
->num_values
== 0) {
606 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST
;
609 for (i
=0; i
<el
->num_values
; i
++) {
610 ndr_err
= ndr_pull_struct_blob(&el
->values
[i
], mem_ctx
, &rec2
,
611 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
612 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
613 return WERR_GEN_FAILURE
;
616 if (dns_record_match(arec
, &rec2
)) {
620 if (i
< el
->num_values
) {
622 * The record already exists, which is an error UNLESS we are
623 * doing an in-place update.
625 * Therefore we need to see if drec also matches, in which
626 * case it's OK, though we can only update dwTtlSeconds and
627 * reset the timestamp to zero.
629 updating_ttl
= dns_record_match(drec
, &rec2
);
630 if (! updating_ttl
) {
631 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS
;
633 /* In this case the next loop is redundant */
636 for (i
=0; i
<el
->num_values
; i
++) {
637 ndr_err
= ndr_pull_struct_blob(&el
->values
[i
], mem_ctx
, &rec2
,
638 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
639 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
640 return WERR_GEN_FAILURE
;
643 if (dns_record_match(drec
, &rec2
)) {
645 * we are replacing this one with arec, which is done
646 * by pushing arec into el->values[i] below, after the
647 * various manipulations.
652 if (i
== el
->num_values
) {
653 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST
;
657 * If we're updating a SOA record, use the specified serial.
659 * Otherwise, if we are updating ttl in place (i.e., not changing
660 * .wType and .data on a record), we should increment the existing
661 * serial, and save to the SOA.
663 * Outside of those two cases, we look for the zone's SOA record and
666 if (arec
->wType
!= DNS_TYPE_SOA
) {
669 * In this case, we keep some of the old values.
671 arec
->dwSerial
= rec2
.dwSerial
;
672 arec
->dwReserved
= rec2
.dwReserved
;
674 * TODO: if the old TTL and the new TTL are
675 * different, the serial number is incremented.
678 arec
->dwReserved
= 0;
679 serial
= dnsserver_update_soa(mem_ctx
, samdb
, z
, &werr
);
683 arec
->dwSerial
= serial
;
687 /* Set the correct rank for the record. */
688 set_record_rank(z
, name
, arec
);
690 * Successful RPC updates *always* zero timestamp and flags and set
693 arec
->dwTimeStamp
= 0;
697 ndr_err
= ndr_push_struct_blob(&el
->values
[i
], mem_ctx
, arec
,
698 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnssrvRpcRecord
);
699 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
700 return WERR_GEN_FAILURE
;
703 el
->flags
= LDB_FLAG_MOD_REPLACE
;
704 ret
= ldb_modify(samdb
, res
->msgs
[0]);
705 if (ret
!= LDB_SUCCESS
) {
706 return WERR_INTERNAL_DB_ERROR
;
713 /* Delete a DNS record */
714 WERROR
dnsserver_db_delete_record(TALLOC_CTX
*mem_ctx
,
715 struct ldb_context
*samdb
,
716 struct dnsserver_zone
*z
,
718 struct DNS_RPC_RECORD
*del_record
)
720 const char * const attrs
[] = { "dnsRecord", NULL
};
721 struct ldb_result
*res
;
722 struct dnsp_DnssrvRpcRecord
*rec
= NULL
;
723 struct ldb_message_element
*el
;
724 enum ndr_err_code ndr_err
;
729 serial
= dnsserver_update_soa(mem_ctx
, samdb
, z
, &werr
);
734 werr
= dns_to_dnsp_convert(mem_ctx
, del_record
, &rec
, false);
735 if (!W_ERROR_IS_OK(werr
)) {
739 ret
= ldb_search(samdb
, mem_ctx
, &res
, z
->zone_dn
, LDB_SCOPE_ONELEVEL
, attrs
,
740 "(&(objectClass=dnsNode)(name=%s))",
741 ldb_binary_encode_string(mem_ctx
, name
));
742 if (ret
!= LDB_SUCCESS
) {
743 return WERR_INTERNAL_DB_ERROR
;
746 if (res
->count
== 0) {
747 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST
;
749 if (res
->count
> 1) {
750 return WERR_DNS_ERROR_RCODE_SERVER_FAILURE
;
753 el
= ldb_msg_find_element(res
->msgs
[0], "dnsRecord");
754 if (el
== NULL
|| el
->num_values
== 0) {
755 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST
;
758 for (i
=0; i
<el
->num_values
; i
++) {
759 struct dnsp_DnssrvRpcRecord rec2
;
761 ndr_err
= ndr_pull_struct_blob(&el
->values
[i
], mem_ctx
, &rec2
,
762 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnssrvRpcRecord
);
763 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
764 return WERR_GEN_FAILURE
;
767 if (dns_record_match(rec
, &rec2
)) {
771 if (i
== el
->num_values
) {
772 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST
;
774 if (i
< el
->num_values
-1) {
775 memmove(&el
->values
[i
], &el
->values
[i
+1], sizeof(el
->values
[0])*((el
->num_values
-1)-i
));
779 if (el
->num_values
== 0) {
780 ret
= ldb_delete(samdb
, res
->msgs
[0]->dn
);
782 el
->flags
= LDB_FLAG_MOD_REPLACE
;
783 ret
= ldb_modify(samdb
, res
->msgs
[0]);
785 if (ret
!= LDB_SUCCESS
) {
786 return WERR_INTERNAL_DB_ERROR
;
793 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX
*mem_ctx
,
794 struct ldb_message
*msg
,
795 struct dnsp_DnsProperty
*prop
)
797 DATA_BLOB
*prop_blob
;
798 enum ndr_err_code ndr_err
;
801 prop_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
802 if (prop_blob
== NULL
) return false;
804 ndr_err
= ndr_push_struct_blob(prop_blob
, mem_ctx
, prop
,
805 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnsProperty
);
806 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
809 ret
= ldb_msg_add_steal_value(msg
, "dNSProperty", prop_blob
);
810 if (ret
!= LDB_SUCCESS
) {
816 WERROR
dnsserver_db_do_reset_dword(struct ldb_context
*samdb
,
817 struct dnsserver_zone
*z
,
818 struct DNS_RPC_NAME_AND_PARAM
*n_p
)
820 struct ldb_message_element
*element
= NULL
;
821 struct dnsp_DnsProperty
*prop
= NULL
;
822 enum ndr_err_code err
;
823 TALLOC_CTX
*tmp_ctx
= NULL
;
824 const char * const attrs
[] = {"dNSProperty", NULL
};
825 struct ldb_result
*res
= NULL
;
828 if (strcasecmp(n_p
->pszNodeName
, "Aging") == 0) {
829 z
->zoneinfo
->fAging
= n_p
->dwParam
;
830 prop_id
= DSPROPERTY_ZONE_AGING_STATE
;
831 } else if (strcasecmp(n_p
->pszNodeName
, "RefreshInterval") == 0) {
832 z
->zoneinfo
->dwRefreshInterval
= n_p
->dwParam
;
833 prop_id
= DSPROPERTY_ZONE_REFRESH_INTERVAL
;
834 } else if (strcasecmp(n_p
->pszNodeName
, "NoRefreshInterval") == 0) {
835 z
->zoneinfo
->dwNoRefreshInterval
= n_p
->dwParam
;
836 prop_id
= DSPROPERTY_ZONE_NOREFRESH_INTERVAL
;
837 } else if (strcasecmp(n_p
->pszNodeName
, "AllowUpdate") == 0) {
838 z
->zoneinfo
->fAllowUpdate
= n_p
->dwParam
;
839 prop_id
= DSPROPERTY_ZONE_ALLOW_UPDATE
;
841 return WERR_UNKNOWN_PROPERTY
;
844 tmp_ctx
= talloc_new(NULL
);
845 if (tmp_ctx
== NULL
) {
846 return WERR_NOT_ENOUGH_MEMORY
;
849 ret
= ldb_search(samdb
, tmp_ctx
, &res
, z
->zone_dn
, LDB_SCOPE_BASE
,
850 attrs
, "(objectClass=dnsZone)");
851 if (ret
!= LDB_SUCCESS
) {
852 DBG_ERR("dnsserver: no zone: %s\n",
853 ldb_dn_get_linearized(z
->zone_dn
));
854 TALLOC_FREE(tmp_ctx
);
855 return WERR_INTERNAL_DB_ERROR
;
858 if (res
->count
!= 1) {
859 DBG_ERR("dnsserver: duplicate zone: %s\n",
860 ldb_dn_get_linearized(z
->zone_dn
));
861 TALLOC_FREE(tmp_ctx
);
862 return WERR_GEN_FAILURE
;
865 element
= ldb_msg_find_element(res
->msgs
[0], "dNSProperty");
866 if (element
== NULL
) {
867 DBG_ERR("dnsserver: zone %s has no properties.\n",
868 ldb_dn_get_linearized(z
->zone_dn
));
869 TALLOC_FREE(tmp_ctx
);
870 return WERR_INTERNAL_DB_ERROR
;
873 for (i
= 0; i
< element
->num_values
; i
++) {
874 prop
= talloc_zero(element
, struct dnsp_DnsProperty
);
876 TALLOC_FREE(tmp_ctx
);
877 return WERR_NOT_ENOUGH_MEMORY
;
879 err
= ndr_pull_struct_blob(
880 &(element
->values
[i
]),
883 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnsProperty
);
884 if (!NDR_ERR_CODE_IS_SUCCESS(err
)){
886 * If we can't pull it then try again parsing
887 * it again. A Windows server in the domain
888 * will permit the addition of an invalidly
889 * formed property with a 0 length and cause a
892 struct dnsp_DnsProperty_short
894 = talloc_zero(element
,
895 struct dnsp_DnsProperty_short
);
896 if (short_property
== NULL
) {
897 TALLOC_FREE(tmp_ctx
);
898 return WERR_NOT_ENOUGH_MEMORY
;
900 err
= ndr_pull_struct_blob_all(
901 &(element
->values
[i
]),
904 (ndr_pull_flags_fn_t
)ndr_pull_dnsp_DnsProperty_short
);
905 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
907 * Unknown invalid data should be
908 * ignored and logged to match Windows
911 DBG_NOTICE("dnsserver: couldn't PULL "
912 "dnsProperty value#%d in "
913 "zone %s while trying to "
916 ldb_dn_get_linearized(z
->zone_dn
),
922 * Initialise the parts of the property not
923 * overwritten by value() in the IDL for
926 *prop
= (struct dnsp_DnsProperty
){
927 .namelength
= short_property
->namelength
,
928 .id
= short_property
->id
,
929 .name
= short_property
->name
930 /* .data will be filled in below */
934 if (prop
->id
== prop_id
) {
936 case DSPROPERTY_ZONE_AGING_STATE
:
937 prop
->data
.aging_enabled
= n_p
->dwParam
;
939 case DSPROPERTY_ZONE_NOREFRESH_INTERVAL
:
940 prop
->data
.norefresh_hours
= n_p
->dwParam
;
942 case DSPROPERTY_ZONE_REFRESH_INTERVAL
:
943 prop
->data
.refresh_hours
= n_p
->dwParam
;
945 case DSPROPERTY_ZONE_ALLOW_UPDATE
:
946 prop
->data
.allow_update_flag
= n_p
->dwParam
;
950 err
= ndr_push_struct_blob(
951 &(element
->values
[i
]),
954 (ndr_push_flags_fn_t
)ndr_push_dnsp_DnsProperty
);
955 if (!NDR_ERR_CODE_IS_SUCCESS(err
)){
956 DBG_ERR("dnsserver: couldn't PUSH dns prop id "
959 ldb_dn_get_linearized(z
->zone_dn
));
960 TALLOC_FREE(tmp_ctx
);
961 return WERR_INTERNAL_DB_ERROR
;
966 element
->flags
= LDB_FLAG_MOD_REPLACE
;
967 ret
= ldb_modify(samdb
, res
->msgs
[0]);
968 if (ret
!= LDB_SUCCESS
) {
969 TALLOC_FREE(tmp_ctx
);
970 DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
973 ldb_errstring(samdb
));
974 return WERR_INTERNAL_DB_ERROR
;
976 TALLOC_FREE(tmp_ctx
);
981 /* Create dnsZone record to database and set security descriptor */
982 static WERROR
dnsserver_db_do_create_zone(TALLOC_CTX
*tmp_ctx
,
983 struct ldb_context
*samdb
,
984 struct ldb_dn
*zone_dn
,
985 struct dnsserver_zone
*z
)
987 const char * const attrs
[] = { "objectSID", NULL
};
988 struct ldb_message
*msg
;
989 struct ldb_result
*res
;
990 struct ldb_message_element
*el
;
991 const char sddl_template
[] = "D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;CC;;;AU)(A;;RPLCLORC;;;WD)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)(A;CIID;LC;;;RU)(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)S:AI";
993 struct dom_sid dnsadmins_sid
;
994 const struct dom_sid
*domain_sid
;
995 struct security_descriptor
*secdesc
;
996 struct dnsp_DnsProperty
*prop
;
997 DATA_BLOB
*sd_encoded
;
998 enum ndr_err_code ndr_err
;
1001 /* Get DnsAdmins SID */
1002 ret
= ldb_search(samdb
, tmp_ctx
, &res
, ldb_get_default_basedn(samdb
),
1003 LDB_SCOPE_DEFAULT
, attrs
, "(sAMAccountName=DnsAdmins)");
1004 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
1005 return WERR_INTERNAL_DB_ERROR
;
1008 el
= ldb_msg_find_element(res
->msgs
[0], "objectSID");
1009 if (el
== NULL
|| el
->num_values
!= 1) {
1010 return WERR_INTERNAL_DB_ERROR
;
1013 ndr_err
= ndr_pull_struct_blob(&el
->values
[0], tmp_ctx
, &dnsadmins_sid
,
1014 (ndr_pull_flags_fn_t
)ndr_pull_dom_sid
);
1015 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1016 return WERR_INTERNAL_DB_ERROR
;
1019 /* create security descriptor with DnsAdmins GUID in sddl template */
1020 sddl
= talloc_asprintf(tmp_ctx
, sddl_template
,
1021 dom_sid_string(tmp_ctx
, &dnsadmins_sid
));
1023 return WERR_NOT_ENOUGH_MEMORY
;
1027 domain_sid
= samdb_domain_sid(samdb
);
1028 if (domain_sid
== NULL
) {
1029 return WERR_INTERNAL_DB_ERROR
;
1032 secdesc
= sddl_decode(tmp_ctx
, sddl
, domain_sid
);
1033 if (secdesc
== NULL
) {
1034 return WERR_GEN_FAILURE
;
1037 msg
= ldb_msg_new(tmp_ctx
);
1038 W_ERROR_HAVE_NO_MEMORY(msg
);
1041 ret
= ldb_msg_add_string(msg
, "objectClass", "dnsZone");
1042 if (ret
!= LDB_SUCCESS
) {
1043 return WERR_NOT_ENOUGH_MEMORY
;
1046 sd_encoded
= talloc_zero(tmp_ctx
, DATA_BLOB
);
1047 W_ERROR_HAVE_NO_MEMORY(sd_encoded
);
1049 ndr_err
= ndr_push_struct_blob(sd_encoded
, tmp_ctx
, secdesc
,
1050 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
1051 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1052 return WERR_GEN_FAILURE
;
1055 ret
= ldb_msg_add_steal_value(msg
, "nTSecurityDescriptor", sd_encoded
);
1056 if (ret
!= LDB_SUCCESS
) {
1057 return WERR_NOT_ENOUGH_MEMORY
;
1060 /* dns zone Properties */
1061 prop
= talloc_zero(tmp_ctx
, struct dnsp_DnsProperty
);
1062 W_ERROR_HAVE_NO_MEMORY(prop
);
1067 prop
->id
= DSPROPERTY_ZONE_TYPE
;
1068 prop
->data
.zone_type
= z
->zoneinfo
->dwZoneType
;
1069 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1070 return WERR_NOT_ENOUGH_MEMORY
;
1074 prop
->id
= DSPROPERTY_ZONE_ALLOW_UPDATE
;
1075 prop
->data
.allow_update_flag
= z
->zoneinfo
->fAllowUpdate
;
1076 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1077 return WERR_NOT_ENOUGH_MEMORY
;
1081 prop
->id
= DSPROPERTY_ZONE_SECURE_TIME
;
1082 prop
->data
.zone_secure_time
= 0;
1083 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1084 return WERR_NOT_ENOUGH_MEMORY
;
1087 /* norefresh interval */
1088 prop
->id
= DSPROPERTY_ZONE_NOREFRESH_INTERVAL
;
1089 prop
->data
.norefresh_hours
= 168;
1090 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1091 return WERR_NOT_ENOUGH_MEMORY
;
1094 /* refresh interval */
1095 prop
->id
= DSPROPERTY_ZONE_REFRESH_INTERVAL
;
1096 prop
->data
.refresh_hours
= 168;
1097 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1098 return WERR_NOT_ENOUGH_MEMORY
;
1102 prop
->id
= DSPROPERTY_ZONE_AGING_STATE
;
1103 prop
->data
.aging_enabled
= z
->zoneinfo
->fAging
;
1104 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1105 return WERR_NOT_ENOUGH_MEMORY
;
1108 /* aging enabled time */
1109 prop
->id
= DSPROPERTY_ZONE_AGING_ENABLED_TIME
;
1110 prop
->data
.next_scavenging_cycle_hours
= 0;
1111 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx
, msg
, prop
)) {
1112 return WERR_NOT_ENOUGH_MEMORY
;
1117 ret
= ldb_add(samdb
, msg
);
1118 if (ret
!= LDB_SUCCESS
) {
1119 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
1120 z
->name
, ldb_errstring(samdb
)));
1122 if (ret
== LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
1123 return WERR_ACCESS_DENIED
;
1126 return WERR_INTERNAL_DB_ERROR
;
1133 /* Create new dnsZone record and @ record (SOA + NS) */
1134 WERROR
dnsserver_db_create_zone(struct ldb_context
*samdb
,
1135 struct dnsserver_partition
*partitions
,
1136 struct dnsserver_zone
*zone
,
1137 struct loadparm_context
*lp_ctx
)
1139 struct dnsserver_partition
*p
;
1140 bool in_forest
= false;
1143 TALLOC_CTX
*tmp_ctx
;
1144 struct dnsp_DnssrvRpcRecord
*dns_rec
;
1145 struct dnsp_soa soa
;
1146 char *soa_email
= NULL
;
1147 const char *dnsdomain
= NULL
;
1148 struct ldb_val name_val
= data_blob_string_const(zone
->name
);
1150 /* We only support primary zones for now */
1151 if (zone
->zoneinfo
->dwZoneType
!= DNS_ZONE_TYPE_PRIMARY
) {
1152 return WERR_CALL_NOT_IMPLEMENTED
;
1155 /* Get the correct partition */
1156 if (zone
->partition
->dwDpFlags
& DNS_DP_FOREST_DEFAULT
) {
1159 for (p
= partitions
; p
; p
= p
->next
) {
1160 if (in_forest
== p
->is_forest
) {
1165 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST
;
1168 tmp_ctx
= talloc_new(NULL
);
1169 W_ERROR_HAVE_NO_MEMORY(tmp_ctx
);
1171 dn
= ldb_dn_copy(tmp_ctx
, p
->partition_dn
);
1172 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn
, tmp_ctx
);
1174 if (!ldb_dn_add_child_fmt(dn
, "CN=MicrosoftDNS")) {
1175 talloc_free(tmp_ctx
);
1176 return WERR_NOT_ENOUGH_MEMORY
;
1179 if (!ldb_dn_add_child_val(dn
, "DC", name_val
)) {
1180 talloc_free(tmp_ctx
);
1181 return WERR_NOT_ENOUGH_MEMORY
;
1184 /* Add dnsZone record */
1185 status
= dnsserver_db_do_create_zone(tmp_ctx
, samdb
, dn
, zone
);
1186 if (!W_ERROR_IS_OK(status
)) {
1187 talloc_free(tmp_ctx
);
1191 if (!ldb_dn_add_child_fmt(dn
, "DC=@")) {
1192 talloc_free(tmp_ctx
);
1193 return WERR_NOT_ENOUGH_MEMORY
;
1196 dns_rec
= talloc_zero_array(tmp_ctx
, struct dnsp_DnssrvRpcRecord
, 2);
1197 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec
, tmp_ctx
);
1199 dnsdomain
= lpcfg_dnsdomain(lp_ctx
);
1200 if (dnsdomain
== NULL
) {
1201 talloc_free(tmp_ctx
);
1202 return WERR_NOT_ENOUGH_MEMORY
;
1204 soa_email
= talloc_asprintf(tmp_ctx
, "hostmaster.%s", dnsdomain
);
1205 if (soa_email
== NULL
) {
1206 talloc_free(tmp_ctx
);
1207 return WERR_NOT_ENOUGH_MEMORY
;
1210 /* SOA Record - values same as defined in provision/sambadns.py */
1216 soa
.mname
= dnsdomain
;
1217 soa
.rname
= soa_email
;
1219 dns_rec
[0].wType
= DNS_TYPE_SOA
;
1220 dns_rec
[0].rank
= DNS_RANK_ZONE
;
1221 dns_rec
[0].dwSerial
= soa
.serial
;
1222 dns_rec
[0].dwTtlSeconds
= 3600;
1223 dns_rec
[0].dwTimeStamp
= 0;
1224 dns_rec
[0].data
.soa
= soa
;
1227 dns_rec
[1].wType
= DNS_TYPE_NS
;
1228 dns_rec
[1].rank
= DNS_RANK_ZONE
;
1229 dns_rec
[1].dwSerial
= soa
.serial
;
1230 dns_rec
[1].dwTtlSeconds
= 3600;
1231 dns_rec
[1].dwTimeStamp
= 0;
1232 dns_rec
[1].data
.ns
= dnsdomain
;
1235 status
= dnsserver_db_do_add_rec(tmp_ctx
, samdb
, dn
, 2, dns_rec
);
1237 talloc_free(tmp_ctx
);
1242 /* Delete dnsZone record and all DNS records in the zone */
1243 WERROR
dnsserver_db_delete_zone(struct ldb_context
*samdb
,
1244 struct dnsserver_zone
*zone
)
1248 ret
= ldb_transaction_start(samdb
);
1249 if (ret
!= LDB_SUCCESS
) {
1250 return WERR_INTERNAL_DB_ERROR
;
1253 ret
= dsdb_delete(samdb
, zone
->zone_dn
, DSDB_TREE_DELETE
);
1254 if (ret
!= LDB_SUCCESS
) {
1255 ldb_transaction_cancel(samdb
);
1257 if (ret
== LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
) {
1258 return WERR_ACCESS_DENIED
;
1260 return WERR_INTERNAL_DB_ERROR
;
1263 ret
= ldb_transaction_commit(samdb
);
1264 if (ret
!= LDB_SUCCESS
) {
1265 return WERR_INTERNAL_DB_ERROR
;