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"
32 /* There are only 2 fixed partitions for DNS */
33 struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
34 struct dnsserver_serverinfo *serverinfo,
35 struct ldb_context *samdb)
37 struct dnsserver_partition *partitions, *p;
41 /* Domain partition */
42 p = talloc_zero(mem_ctx, struct dnsserver_partition);
47 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
48 if (p->partition_dn == NULL) {
52 p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
53 p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_DOMAIN_DEFAULT | DNS_DP_ENLISTED;
56 DLIST_ADD_END(partitions, p);
58 /* Forest Partition */
59 p = talloc_zero(mem_ctx, struct dnsserver_partition);
64 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
65 if (p->partition_dn == NULL) {
69 p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
70 p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED;
73 DLIST_ADD_END(partitions, p);
83 /* Search for all dnsZone records */
84 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
85 struct ldb_context *samdb,
86 struct dnsserver_partition *p)
89 const char * const attrs[] = {"name", "dNSProperty", NULL};
91 struct ldb_result *res;
92 struct dnsserver_zone *zones, *z;
95 tmp_ctx = talloc_new(mem_ctx);
96 if (tmp_ctx == NULL) {
100 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
104 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
108 ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
109 attrs, "(objectClass=dnsZone)");
110 if (ret != LDB_SUCCESS) {
111 DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
112 ldb_dn_get_linearized(dn)));
117 for(i=0; i<res->count; i++) {
119 struct ldb_message_element *element = NULL;
120 struct dnsp_DnsProperty *props = NULL;
121 enum ndr_err_code err;
122 z = talloc_zero(mem_ctx, struct dnsserver_zone);
128 name = talloc_strdup(z,
129 ldb_msg_find_attr_as_string(res->msgs[i],
131 if (strcmp(name, "..TrustAnchors") == 0) {
135 if (strcmp(name, "RootDNSServers") == 0) {
137 z->name = talloc_strdup(z, ".");
141 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
143 DLIST_ADD_END(zones, z);
144 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
146 element = ldb_msg_find_element(res->msgs[i], "dNSProperty");
148 props = talloc_zero_array(tmp_ctx,
149 struct dnsp_DnsProperty,
150 element->num_values);
151 for (j = 0; j < element->num_values; j++ ) {
152 err = ndr_pull_struct_blob(
153 &(element->values[j]),
156 (ndr_pull_flags_fn_t)
157 ndr_pull_dnsp_DnsProperty);
158 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
162 z->tmp_props = props;
163 z->num_props = element->num_values;
169 talloc_free(tmp_ctx);
174 /* Find DNS partition information */
175 struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
176 struct ldb_context *samdb,
177 struct dnsserver_partition *p)
179 const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
180 const char * const attrs_none[] = { NULL };
181 struct ldb_result *res;
182 struct ldb_message_element *el;
184 struct dnsserver_partition_info *partinfo;
185 int i, ret, instance_type;
188 tmp_ctx = talloc_new(mem_ctx);
189 if (tmp_ctx == NULL) {
193 partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
194 if (partinfo == NULL) {
195 talloc_free(tmp_ctx);
199 /* Search for the active replica and state */
200 ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
202 if (ret != LDB_SUCCESS || res->count != 1) {
206 /* Set the state of the partition */
207 instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
208 if (instance_type == -1) {
209 partinfo->dwState = DNS_DP_STATE_UNKNOWN;
210 } else if (instance_type & INSTANCE_TYPE_NC_COMING) {
211 partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
212 } else if (instance_type & INSTANCE_TYPE_NC_GOING) {
213 partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
215 partinfo->dwState = DNS_DP_OKAY;
218 el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
220 partinfo->dwReplicaCount = 0;
221 partinfo->ReplicaArray = NULL;
223 partinfo->dwReplicaCount = el->num_values;
224 partinfo->ReplicaArray = talloc_zero_array(partinfo,
225 struct DNS_RPC_DP_REPLICA *,
227 if (partinfo->ReplicaArray == NULL) {
230 for (i=0; i<el->num_values; i++) {
231 partinfo->ReplicaArray[i] = talloc_zero(partinfo,
232 struct DNS_RPC_DP_REPLICA);
233 if (partinfo->ReplicaArray[i] == NULL) {
236 partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
238 (const char *)el->values[i].data);
239 if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
246 /* Search for cross-reference object */
247 dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
252 ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
253 "(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
254 if (ret != LDB_SUCCESS || res->count != 1) {
257 partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
258 if (partinfo->pszCrDn == NULL) {
263 talloc_free(tmp_ctx);
267 talloc_free(tmp_ctx);
268 talloc_free(partinfo);
273 /* Increment serial number and update timestamp */
274 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
275 struct ldb_context *samdb,
276 struct dnsserver_zone *z)
278 const char * const attrs[] = { "dnsRecord", NULL };
279 struct ldb_result *res;
280 struct dnsp_DnssrvRpcRecord rec;
281 struct ldb_message_element *el;
282 enum ndr_err_code ndr_err;
283 int ret, i, serial = -1;
285 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
286 "(&(objectClass=dnsNode)(name=@))");
287 if (ret != LDB_SUCCESS || res->count == 0) {
291 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
296 for (i=0; i<el->num_values; i++) {
297 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
298 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
299 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
303 if (rec.wType == DNS_TYPE_SOA) {
304 serial = rec.data.soa.serial + 1;
305 rec.dwSerial = serial;
307 rec.data.soa.serial = serial;
309 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
310 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
311 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
319 el->flags = LDB_FLAG_MOD_REPLACE;
320 ret = ldb_modify(samdb, res->msgs[0]);
321 if (ret != LDB_SUCCESS) {
330 /* Add DNS record to the database */
331 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
332 struct ldb_context *samdb,
335 struct dnsp_DnssrvRpcRecord *rec)
337 struct ldb_message *msg;
340 enum ndr_err_code ndr_err;
343 msg = ldb_msg_new(mem_ctx);
344 W_ERROR_HAVE_NO_MEMORY(msg);
347 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
348 if (ret != LDB_SUCCESS) {
349 return WERR_NOT_ENOUGH_MEMORY;
352 if (num_rec > 0 && rec) {
353 for (i=0; i<num_rec; i++) {
354 ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
355 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
356 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
357 return WERR_GEN_FAILURE;
360 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
361 if (ret != LDB_SUCCESS) {
362 return WERR_NOT_ENOUGH_MEMORY;
367 ret = ldb_add(samdb, msg);
368 if (ret != LDB_SUCCESS) {
369 return WERR_INTERNAL_DB_ERROR;
376 /* Add dnsNode record to the database with DNS record */
377 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
378 struct ldb_context *samdb,
379 struct dnsserver_zone *z,
382 const char * const attrs[] = { "name", NULL };
383 struct ldb_result *res;
385 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
386 struct ldb_val name_val = data_blob_string_const(name);
389 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
390 "(&(objectClass=dnsNode)(name=%s))",
392 if (ret != LDB_SUCCESS) {
393 return WERR_INTERNAL_DB_ERROR;
396 if (res->count > 0) {
398 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
401 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
402 W_ERROR_HAVE_NO_MEMORY(dn);
404 if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
405 return WERR_NOT_ENOUGH_MEMORY;
408 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
412 /* Add a DNS record */
413 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
414 struct ldb_context *samdb,
415 struct dnsserver_zone *z,
417 struct DNS_RPC_RECORD *add_record)
419 const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
420 struct ldb_result *res;
421 struct dnsp_DnssrvRpcRecord *rec = NULL;
422 struct ldb_message_element *el;
424 enum ndr_err_code ndr_err;
428 bool was_tombstoned = false;
429 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
431 werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
432 if (!W_ERROR_IS_OK(werr)) {
436 /* Set the correct rank for the record. */
437 if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
438 if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
439 rec->rank = DNS_RANK_NS_GLUE;
441 rec->rank |= DNS_RANK_ZONE;
443 } else if (strcmp(z->name, ".") == 0) {
444 rec->rank |= DNS_RANK_ROOT_HINT;
447 serial = dnsserver_update_soa(mem_ctx, samdb, z);
449 return WERR_INTERNAL_DB_ERROR;
452 rec->dwSerial = serial;
453 rec->dwTimeStamp = 0;
455 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
456 "(&(objectClass=dnsNode)(name=%s))",
458 if (ret != LDB_SUCCESS) {
459 return WERR_INTERNAL_DB_ERROR;
462 if (res->count == 0) {
463 dn = dnsserver_name_to_dn(mem_ctx, z, name);
464 W_ERROR_HAVE_NO_MEMORY(dn);
466 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
469 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
471 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
472 if (ret != LDB_SUCCESS) {
473 return WERR_NOT_ENOUGH_MEMORY;
477 was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
478 "dNSTombstoned", false);
479 if (was_tombstoned) {
483 for (i=0; i<el->num_values; i++) {
484 struct dnsp_DnssrvRpcRecord rec2;
486 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
487 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
488 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
489 return WERR_GEN_FAILURE;
492 if (dns_record_match(rec, &rec2)) {
496 if (i < el->num_values) {
497 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
499 if (i == el->num_values) {
500 /* adding a new value */
501 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
502 W_ERROR_HAVE_NO_MEMORY(el->values);
506 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
507 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
508 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
509 return WERR_GEN_FAILURE;
512 el->flags = LDB_FLAG_MOD_REPLACE;
514 el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
516 el->flags = LDB_FLAG_MOD_DELETE;
519 ret = ldb_modify(samdb, res->msgs[0]);
520 if (ret != LDB_SUCCESS) {
521 return WERR_INTERNAL_DB_ERROR;
528 /* Update a DNS record */
529 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
530 struct ldb_context *samdb,
531 struct dnsserver_zone *z,
533 struct DNS_RPC_RECORD *add_record,
534 struct DNS_RPC_RECORD *del_record)
536 const char * const attrs[] = { "dnsRecord", NULL };
537 struct ldb_result *res;
538 struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
539 struct ldb_message_element *el;
540 enum ndr_err_code ndr_err;
544 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
546 werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
547 if (!W_ERROR_IS_OK(werr)) {
551 werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
552 if (!W_ERROR_IS_OK(werr)) {
556 arec->dwTimeStamp = 0;
558 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
559 "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
561 if (ret != LDB_SUCCESS) {
562 return WERR_INTERNAL_DB_ERROR;
565 if (res->count == 0) {
566 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
569 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
570 if (el == NULL || el->num_values == 0) {
571 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
574 for (i=0; i<el->num_values; i++) {
575 struct dnsp_DnssrvRpcRecord rec2;
577 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
578 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
579 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
580 return WERR_GEN_FAILURE;
583 if (dns_record_match(arec, &rec2)) {
587 if (i < el->num_values) {
588 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
592 for (i=0; i<el->num_values; i++) {
593 struct dnsp_DnssrvRpcRecord rec2;
595 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
596 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
597 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
598 return WERR_GEN_FAILURE;
601 if (dns_record_match(drec, &rec2)) {
605 if (i == el->num_values) {
606 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
609 /* If updating SOA record, use specified serial, otherwise increment */
610 if (arec->wType != DNS_TYPE_SOA) {
611 serial = dnsserver_update_soa(mem_ctx, samdb, z);
613 return WERR_INTERNAL_DB_ERROR;
615 arec->dwSerial = serial;
618 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
619 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
620 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
621 return WERR_GEN_FAILURE;
624 el->flags = LDB_FLAG_MOD_REPLACE;
625 ret = ldb_modify(samdb, res->msgs[0]);
626 if (ret != LDB_SUCCESS) {
627 return WERR_INTERNAL_DB_ERROR;
634 /* Delete a DNS record */
635 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
636 struct ldb_context *samdb,
637 struct dnsserver_zone *z,
639 struct DNS_RPC_RECORD *del_record)
641 const char * const attrs[] = { "dnsRecord", NULL };
642 struct ldb_result *res;
643 struct dnsp_DnssrvRpcRecord *rec = NULL;
644 struct ldb_message_element *el;
645 enum ndr_err_code ndr_err;
650 serial = dnsserver_update_soa(mem_ctx, samdb, z);
652 return WERR_INTERNAL_DB_ERROR;
655 werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
656 if (!W_ERROR_IS_OK(werr)) {
660 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
661 "(&(objectClass=dnsNode)(name=%s))",
662 ldb_binary_encode_string(mem_ctx, name));
663 if (ret != LDB_SUCCESS) {
664 return WERR_INTERNAL_DB_ERROR;
667 if (res->count == 0) {
668 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
670 if (res->count > 1) {
671 return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
674 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
675 if (el == NULL || el->num_values == 0) {
676 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
679 for (i=0; i<el->num_values; i++) {
680 struct dnsp_DnssrvRpcRecord rec2;
682 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
683 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
684 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
685 return WERR_GEN_FAILURE;
688 if (dns_record_match(rec, &rec2)) {
692 if (i == el->num_values) {
693 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
695 if (i < el->num_values-1) {
696 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
700 if (el->num_values == 0) {
701 ret = ldb_delete(samdb, res->msgs[0]->dn);
703 el->flags = LDB_FLAG_MOD_REPLACE;
704 ret = ldb_modify(samdb, res->msgs[0]);
706 if (ret != LDB_SUCCESS) {
707 return WERR_INTERNAL_DB_ERROR;
714 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
715 struct ldb_message *msg,
716 struct dnsp_DnsProperty *prop)
718 DATA_BLOB *prop_blob;
719 enum ndr_err_code ndr_err;
722 prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
723 if (prop_blob == NULL) return false;
725 ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
726 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
727 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
730 ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
731 if (ret != LDB_SUCCESS) {
737 WERROR dnsserver_db_do_reset_dword(struct ldb_context *samdb,
738 struct dnsserver_zone *z,
739 struct DNS_RPC_NAME_AND_PARAM *n_p)
741 struct ldb_message_element *element = NULL;
742 struct dnsp_DnsProperty *prop = NULL;
743 enum ndr_err_code err;
744 TALLOC_CTX *tmp_ctx = NULL;
745 const char * const attrs[] = {"dNSProperty", NULL};
746 struct ldb_result *res = NULL;
749 if (strcasecmp(n_p->pszNodeName, "Aging") == 0) {
750 z->zoneinfo->fAging = n_p->dwParam;
751 prop_id = DSPROPERTY_ZONE_AGING_STATE;
752 } else if (strcasecmp(n_p->pszNodeName, "RefreshInterval") == 0) {
753 z->zoneinfo->dwRefreshInterval = n_p->dwParam;
754 prop_id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
755 } else if (strcasecmp(n_p->pszNodeName, "NoRefreshInterval") == 0) {
756 z->zoneinfo->dwNoRefreshInterval = n_p->dwParam;
757 prop_id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
758 } else if (strcasecmp(n_p->pszNodeName, "AllowUpdate") == 0) {
759 z->zoneinfo->fAllowUpdate = n_p->dwParam;
760 prop_id = DSPROPERTY_ZONE_ALLOW_UPDATE;
762 return WERR_UNKNOWN_PROPERTY;
765 tmp_ctx = talloc_new(NULL);
766 if (tmp_ctx == NULL) {
767 return WERR_NOT_ENOUGH_MEMORY;
770 ret = ldb_search(samdb, tmp_ctx, &res, z->zone_dn, LDB_SCOPE_BASE,
771 attrs, "(objectClass=dnsZone)");
772 if (ret != LDB_SUCCESS) {
773 DBG_ERR("dnsserver: no zone: %s\n",
774 ldb_dn_get_linearized(z->zone_dn));
775 TALLOC_FREE(tmp_ctx);
776 return WERR_INTERNAL_DB_ERROR;
779 if (res->count != 1) {
780 DBG_ERR("dnsserver: duplicate zone: %s\n",
781 ldb_dn_get_linearized(z->zone_dn));
782 TALLOC_FREE(tmp_ctx);
783 return WERR_GEN_FAILURE;
786 element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
787 if (element == NULL) {
788 DBG_ERR("dnsserver: zone %s has no properties.\n",
789 ldb_dn_get_linearized(z->zone_dn));
790 TALLOC_FREE(tmp_ctx);
791 return WERR_INTERNAL_DB_ERROR;
794 for (i = 0; i < element->num_values; i++) {
795 prop = talloc_zero(element, struct dnsp_DnsProperty);
797 TALLOC_FREE(tmp_ctx);
798 return WERR_NOT_ENOUGH_MEMORY;
800 err = ndr_pull_struct_blob(
801 &(element->values[i]),
804 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
805 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
806 DBG_ERR("dnsserver: couldn't PULL dns property id "
809 ldb_dn_get_linearized(z->zone_dn));
810 TALLOC_FREE(tmp_ctx);
811 return WERR_INTERNAL_DB_ERROR;
814 if (prop->id == prop_id) {
816 case DSPROPERTY_ZONE_AGING_STATE:
817 prop->data.aging_enabled = n_p->dwParam;
819 case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
820 prop->data.norefresh_hours = n_p->dwParam;
822 case DSPROPERTY_ZONE_REFRESH_INTERVAL:
823 prop->data.refresh_hours = n_p->dwParam;
825 case DSPROPERTY_ZONE_ALLOW_UPDATE:
826 prop->data.allow_update_flag = n_p->dwParam;
830 err = ndr_push_struct_blob(
831 &(element->values[i]),
834 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
835 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
836 DBG_ERR("dnsserver: couldn't PUSH dns prop id "
839 ldb_dn_get_linearized(z->zone_dn));
840 TALLOC_FREE(tmp_ctx);
841 return WERR_INTERNAL_DB_ERROR;
846 element->flags = LDB_FLAG_MOD_REPLACE;
847 ret = ldb_modify(samdb, res->msgs[0]);
848 if (ret != LDB_SUCCESS) {
849 TALLOC_FREE(tmp_ctx);
850 DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
853 ldb_errstring(samdb));
854 return WERR_INTERNAL_DB_ERROR;
856 TALLOC_FREE(tmp_ctx);
861 /* Create dnsZone record to database and set security descriptor */
862 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
863 struct ldb_context *samdb,
864 struct ldb_dn *zone_dn,
865 struct dnsserver_zone *z)
867 const char * const attrs[] = { "objectSID", NULL };
868 struct ldb_message *msg;
869 struct ldb_result *res;
870 struct ldb_message_element *el;
871 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";
873 struct dom_sid dnsadmins_sid;
874 const struct dom_sid *domain_sid;
875 struct security_descriptor *secdesc;
876 struct dnsp_DnsProperty *prop;
877 DATA_BLOB *sd_encoded;
878 enum ndr_err_code ndr_err;
881 /* Get DnsAdmins SID */
882 ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
883 LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
884 if (ret != LDB_SUCCESS || res->count != 1) {
885 return WERR_INTERNAL_DB_ERROR;
888 el = ldb_msg_find_element(res->msgs[0], "objectSID");
889 if (el == NULL || el->num_values != 1) {
890 return WERR_INTERNAL_DB_ERROR;
893 ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
894 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
895 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
896 return WERR_INTERNAL_DB_ERROR;
899 /* create security descriptor with DnsAdmins GUID in sddl template */
900 sddl = talloc_asprintf(tmp_ctx, sddl_template,
901 dom_sid_string(tmp_ctx, &dnsadmins_sid));
903 return WERR_NOT_ENOUGH_MEMORY;
907 domain_sid = samdb_domain_sid(samdb);
908 if (domain_sid == NULL) {
909 return WERR_INTERNAL_DB_ERROR;
912 secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
913 if (secdesc == NULL) {
914 return WERR_GEN_FAILURE;
917 msg = ldb_msg_new(tmp_ctx);
918 W_ERROR_HAVE_NO_MEMORY(msg);
921 ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
922 if (ret != LDB_SUCCESS) {
923 return WERR_NOT_ENOUGH_MEMORY;
926 sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
927 W_ERROR_HAVE_NO_MEMORY(sd_encoded);
929 ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
930 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
931 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
932 return WERR_GEN_FAILURE;
935 ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
936 if (ret != LDB_SUCCESS) {
937 return WERR_NOT_ENOUGH_MEMORY;
940 /* dns zone Properties */
941 prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
942 W_ERROR_HAVE_NO_MEMORY(prop);
947 prop->id = DSPROPERTY_ZONE_TYPE;
948 prop->data.zone_type = z->zoneinfo->dwZoneType;
949 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
950 return WERR_NOT_ENOUGH_MEMORY;
954 prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
955 prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
956 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
957 return WERR_NOT_ENOUGH_MEMORY;
961 prop->id = DSPROPERTY_ZONE_SECURE_TIME;
962 prop->data.zone_secure_time = 0;
963 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
964 return WERR_NOT_ENOUGH_MEMORY;
967 /* norefresh interval */
968 prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
969 prop->data.norefresh_hours = 168;
970 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
971 return WERR_NOT_ENOUGH_MEMORY;
974 /* refresh interval */
975 prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
976 prop->data.refresh_hours = 168;
977 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
978 return WERR_NOT_ENOUGH_MEMORY;
982 prop->id = DSPROPERTY_ZONE_AGING_STATE;
983 prop->data.aging_enabled = z->zoneinfo->fAging;
984 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
985 return WERR_NOT_ENOUGH_MEMORY;
988 /* aging enabled time */
989 prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
990 prop->data.next_scavenging_cycle_hours = 0;
991 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
992 return WERR_NOT_ENOUGH_MEMORY;
997 ret = ldb_add(samdb, msg);
998 if (ret != LDB_SUCCESS) {
999 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
1000 z->name, ldb_errstring(samdb)));
1001 return WERR_INTERNAL_DB_ERROR;
1008 /* Create new dnsZone record and @ record (SOA + NS) */
1009 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
1010 struct dnsserver_partition *partitions,
1011 struct dnsserver_zone *zone,
1012 struct loadparm_context *lp_ctx)
1014 struct dnsserver_partition *p;
1015 bool in_forest = false;
1018 TALLOC_CTX *tmp_ctx;
1019 struct dnsp_DnssrvRpcRecord *dns_rec;
1020 struct dnsp_soa soa;
1021 char *tmpstr, *server_fqdn, *soa_email;
1022 struct ldb_val name_val = data_blob_string_const(zone->name);
1024 /* We only support primary zones for now */
1025 if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
1026 return WERR_CALL_NOT_IMPLEMENTED;
1029 /* Get the correct partition */
1030 if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
1033 for (p = partitions; p; p = p->next) {
1034 if (in_forest == p->is_forest) {
1039 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
1042 tmp_ctx = talloc_new(NULL);
1043 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1045 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
1046 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
1048 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
1049 talloc_free(tmp_ctx);
1050 return WERR_NOT_ENOUGH_MEMORY;
1053 if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
1054 talloc_free(tmp_ctx);
1055 return WERR_NOT_ENOUGH_MEMORY;
1058 /* Add dnsZone record */
1059 status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
1060 if (!W_ERROR_IS_OK(status)) {
1061 talloc_free(tmp_ctx);
1065 if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
1066 talloc_free(tmp_ctx);
1067 return WERR_NOT_ENOUGH_MEMORY;
1070 dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
1071 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
1073 tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
1074 lpcfg_netbios_name(lp_ctx),
1075 lpcfg_realm(lp_ctx));
1076 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
1077 server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
1078 W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
1079 talloc_free(tmpstr);
1081 tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
1082 lpcfg_realm(lp_ctx));
1083 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
1084 soa_email = strlower_talloc(tmp_ctx, tmpstr);
1085 W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
1086 talloc_free(tmpstr);
1088 /* SOA Record - values same as defined in provision/sambadns.py */
1094 soa.mname = server_fqdn;
1095 soa.rname = soa_email;
1097 dns_rec[0].wType = DNS_TYPE_SOA;
1098 dns_rec[0].rank = DNS_RANK_ZONE;
1099 dns_rec[0].dwSerial = soa.serial;
1100 dns_rec[0].dwTtlSeconds = 3600;
1101 dns_rec[0].dwTimeStamp = 0;
1102 dns_rec[0].data.soa = soa;
1105 dns_rec[1].wType = DNS_TYPE_NS;
1106 dns_rec[1].rank = DNS_RANK_ZONE;
1107 dns_rec[1].dwSerial = soa.serial;
1108 dns_rec[1].dwTtlSeconds = 3600;
1109 dns_rec[1].dwTimeStamp = 0;
1110 dns_rec[1].data.ns = server_fqdn;
1113 status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
1115 talloc_free(tmp_ctx);
1120 /* Delete dnsZone record and all DNS records in the zone */
1121 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
1122 struct dnsserver_zone *zone)
1126 ret = ldb_transaction_start(samdb);
1127 if (ret != LDB_SUCCESS) {
1128 return WERR_INTERNAL_DB_ERROR;
1131 ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
1132 if (ret != LDB_SUCCESS) {
1133 ldb_transaction_cancel(samdb);
1134 return WERR_INTERNAL_DB_ERROR;
1137 ret = ldb_transaction_commit(samdb);
1138 if (ret != LDB_SUCCESS) {
1139 return WERR_INTERNAL_DB_ERROR;