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);
440 /* Add a DNS record */
441 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
442 struct ldb_context *samdb,
443 struct dnsserver_zone *z,
445 struct DNS_RPC_RECORD *add_record)
447 const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
448 struct ldb_result *res;
449 struct dnsp_DnssrvRpcRecord *rec = NULL;
450 struct ldb_message_element *el;
452 enum ndr_err_code ndr_err;
456 bool was_tombstoned = false;
457 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
459 werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
460 if (!W_ERROR_IS_OK(werr)) {
464 /* Set the correct rank for the record. */
465 if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
466 if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
467 rec->rank = DNS_RANK_NS_GLUE;
469 rec->rank |= DNS_RANK_ZONE;
471 } else if (strcmp(z->name, ".") == 0) {
472 rec->rank |= DNS_RANK_ROOT_HINT;
475 serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
480 rec->dwSerial = serial;
481 rec->dwTimeStamp = 0;
483 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
484 "(&(objectClass=dnsNode)(name=%s))",
486 if (ret != LDB_SUCCESS) {
487 return WERR_INTERNAL_DB_ERROR;
490 if (res->count == 0) {
491 dn = dnsserver_name_to_dn(mem_ctx, z, name);
492 W_ERROR_HAVE_NO_MEMORY(dn);
494 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
497 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
499 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
500 if (ret != LDB_SUCCESS) {
501 return WERR_NOT_ENOUGH_MEMORY;
505 was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
506 "dNSTombstoned", false);
507 if (was_tombstoned) {
511 for (i=0; i<el->num_values; i++) {
512 struct dnsp_DnssrvRpcRecord rec2;
514 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
515 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
516 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
517 return WERR_GEN_FAILURE;
520 if (dns_record_match(rec, &rec2)) {
524 if (i < el->num_values) {
525 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
527 if (i == el->num_values) {
528 /* adding a new value */
529 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
530 W_ERROR_HAVE_NO_MEMORY(el->values);
534 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
535 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
536 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
537 return WERR_GEN_FAILURE;
540 el->flags = LDB_FLAG_MOD_REPLACE;
542 el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
544 el->flags = LDB_FLAG_MOD_DELETE;
547 ret = ldb_modify(samdb, res->msgs[0]);
548 if (ret != LDB_SUCCESS) {
549 return WERR_INTERNAL_DB_ERROR;
556 /* Update a DNS record */
557 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
558 struct ldb_context *samdb,
559 struct dnsserver_zone *z,
561 struct DNS_RPC_RECORD *add_record,
562 struct DNS_RPC_RECORD *del_record)
564 const char * const attrs[] = { "dnsRecord", NULL };
565 struct ldb_result *res;
566 struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
567 struct ldb_message_element *el;
568 enum ndr_err_code ndr_err;
572 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
574 werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
575 if (!W_ERROR_IS_OK(werr)) {
579 werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
580 if (!W_ERROR_IS_OK(werr)) {
584 arec->dwTimeStamp = 0;
586 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
587 "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
589 if (ret != LDB_SUCCESS) {
590 return WERR_INTERNAL_DB_ERROR;
593 if (res->count == 0) {
594 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
597 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
598 if (el == NULL || el->num_values == 0) {
599 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
602 for (i=0; i<el->num_values; i++) {
603 struct dnsp_DnssrvRpcRecord rec2;
605 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
606 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
607 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
608 return WERR_GEN_FAILURE;
611 if (dns_record_match(arec, &rec2)) {
615 if (i < el->num_values) {
616 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
620 for (i=0; i<el->num_values; i++) {
621 struct dnsp_DnssrvRpcRecord rec2;
623 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
624 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
625 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
626 return WERR_GEN_FAILURE;
629 if (dns_record_match(drec, &rec2)) {
633 if (i == el->num_values) {
634 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
637 /* If updating SOA record, use specified serial, otherwise increment */
638 if (arec->wType != DNS_TYPE_SOA) {
639 serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
643 arec->dwSerial = serial;
646 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
647 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
648 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
649 return WERR_GEN_FAILURE;
652 el->flags = LDB_FLAG_MOD_REPLACE;
653 ret = ldb_modify(samdb, res->msgs[0]);
654 if (ret != LDB_SUCCESS) {
655 return WERR_INTERNAL_DB_ERROR;
662 /* Delete a DNS record */
663 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
664 struct ldb_context *samdb,
665 struct dnsserver_zone *z,
667 struct DNS_RPC_RECORD *del_record)
669 const char * const attrs[] = { "dnsRecord", NULL };
670 struct ldb_result *res;
671 struct dnsp_DnssrvRpcRecord *rec = NULL;
672 struct ldb_message_element *el;
673 enum ndr_err_code ndr_err;
678 serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
683 werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
684 if (!W_ERROR_IS_OK(werr)) {
688 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
689 "(&(objectClass=dnsNode)(name=%s))",
690 ldb_binary_encode_string(mem_ctx, name));
691 if (ret != LDB_SUCCESS) {
692 return WERR_INTERNAL_DB_ERROR;
695 if (res->count == 0) {
696 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
698 if (res->count > 1) {
699 return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
702 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
703 if (el == NULL || el->num_values == 0) {
704 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
707 for (i=0; i<el->num_values; i++) {
708 struct dnsp_DnssrvRpcRecord rec2;
710 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
711 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
712 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
713 return WERR_GEN_FAILURE;
716 if (dns_record_match(rec, &rec2)) {
720 if (i == el->num_values) {
721 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
723 if (i < el->num_values-1) {
724 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
728 if (el->num_values == 0) {
729 ret = ldb_delete(samdb, res->msgs[0]->dn);
731 el->flags = LDB_FLAG_MOD_REPLACE;
732 ret = ldb_modify(samdb, res->msgs[0]);
734 if (ret != LDB_SUCCESS) {
735 return WERR_INTERNAL_DB_ERROR;
742 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
743 struct ldb_message *msg,
744 struct dnsp_DnsProperty *prop)
746 DATA_BLOB *prop_blob;
747 enum ndr_err_code ndr_err;
750 prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
751 if (prop_blob == NULL) return false;
753 ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
754 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
755 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
758 ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
759 if (ret != LDB_SUCCESS) {
765 WERROR dnsserver_db_do_reset_dword(struct ldb_context *samdb,
766 struct dnsserver_zone *z,
767 struct DNS_RPC_NAME_AND_PARAM *n_p)
769 struct ldb_message_element *element = NULL;
770 struct dnsp_DnsProperty *prop = NULL;
771 enum ndr_err_code err;
772 TALLOC_CTX *tmp_ctx = NULL;
773 const char * const attrs[] = {"dNSProperty", NULL};
774 struct ldb_result *res = NULL;
777 if (strcasecmp(n_p->pszNodeName, "Aging") == 0) {
778 z->zoneinfo->fAging = n_p->dwParam;
779 prop_id = DSPROPERTY_ZONE_AGING_STATE;
780 } else if (strcasecmp(n_p->pszNodeName, "RefreshInterval") == 0) {
781 z->zoneinfo->dwRefreshInterval = n_p->dwParam;
782 prop_id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
783 } else if (strcasecmp(n_p->pszNodeName, "NoRefreshInterval") == 0) {
784 z->zoneinfo->dwNoRefreshInterval = n_p->dwParam;
785 prop_id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
786 } else if (strcasecmp(n_p->pszNodeName, "AllowUpdate") == 0) {
787 z->zoneinfo->fAllowUpdate = n_p->dwParam;
788 prop_id = DSPROPERTY_ZONE_ALLOW_UPDATE;
790 return WERR_UNKNOWN_PROPERTY;
793 tmp_ctx = talloc_new(NULL);
794 if (tmp_ctx == NULL) {
795 return WERR_NOT_ENOUGH_MEMORY;
798 ret = ldb_search(samdb, tmp_ctx, &res, z->zone_dn, LDB_SCOPE_BASE,
799 attrs, "(objectClass=dnsZone)");
800 if (ret != LDB_SUCCESS) {
801 DBG_ERR("dnsserver: no zone: %s\n",
802 ldb_dn_get_linearized(z->zone_dn));
803 TALLOC_FREE(tmp_ctx);
804 return WERR_INTERNAL_DB_ERROR;
807 if (res->count != 1) {
808 DBG_ERR("dnsserver: duplicate zone: %s\n",
809 ldb_dn_get_linearized(z->zone_dn));
810 TALLOC_FREE(tmp_ctx);
811 return WERR_GEN_FAILURE;
814 element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
815 if (element == NULL) {
816 DBG_ERR("dnsserver: zone %s has no properties.\n",
817 ldb_dn_get_linearized(z->zone_dn));
818 TALLOC_FREE(tmp_ctx);
819 return WERR_INTERNAL_DB_ERROR;
822 for (i = 0; i < element->num_values; i++) {
823 prop = talloc_zero(element, struct dnsp_DnsProperty);
825 TALLOC_FREE(tmp_ctx);
826 return WERR_NOT_ENOUGH_MEMORY;
828 err = ndr_pull_struct_blob(
829 &(element->values[i]),
832 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
833 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
835 * If we can't pull it then try again parsing
836 * it again. A Windows server in the domain
837 * will permit the addition of an invalidly
838 * formed property with a 0 length and cause a
841 struct dnsp_DnsProperty_short
843 = talloc_zero(element,
844 struct dnsp_DnsProperty_short);
845 if (short_property == NULL) {
846 TALLOC_FREE(tmp_ctx);
847 return WERR_NOT_ENOUGH_MEMORY;
849 err = ndr_pull_struct_blob_all(
850 &(element->values[i]),
853 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty_short);
854 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
856 * Unknown invalid data should be
857 * ignored and logged to match Windows
860 DBG_NOTICE("dnsserver: couldn't PULL "
861 "dnsProperty value#%d in "
862 "zone %s while trying to "
865 ldb_dn_get_linearized(z->zone_dn),
871 * Initialise the parts of the property not
872 * overwritten by value() in the IDL for
875 *prop = (struct dnsp_DnsProperty){
876 .namelength = short_property->namelength,
877 .id = short_property->id,
878 .name = short_property->name
879 /* .data will be filled in below */
883 if (prop->id == prop_id) {
885 case DSPROPERTY_ZONE_AGING_STATE:
886 prop->data.aging_enabled = n_p->dwParam;
888 case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
889 prop->data.norefresh_hours = n_p->dwParam;
891 case DSPROPERTY_ZONE_REFRESH_INTERVAL:
892 prop->data.refresh_hours = n_p->dwParam;
894 case DSPROPERTY_ZONE_ALLOW_UPDATE:
895 prop->data.allow_update_flag = n_p->dwParam;
899 err = ndr_push_struct_blob(
900 &(element->values[i]),
903 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
904 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
905 DBG_ERR("dnsserver: couldn't PUSH dns prop id "
908 ldb_dn_get_linearized(z->zone_dn));
909 TALLOC_FREE(tmp_ctx);
910 return WERR_INTERNAL_DB_ERROR;
915 element->flags = LDB_FLAG_MOD_REPLACE;
916 ret = ldb_modify(samdb, res->msgs[0]);
917 if (ret != LDB_SUCCESS) {
918 TALLOC_FREE(tmp_ctx);
919 DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
922 ldb_errstring(samdb));
923 return WERR_INTERNAL_DB_ERROR;
925 TALLOC_FREE(tmp_ctx);
930 /* Create dnsZone record to database and set security descriptor */
931 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
932 struct ldb_context *samdb,
933 struct ldb_dn *zone_dn,
934 struct dnsserver_zone *z)
936 const char * const attrs[] = { "objectSID", NULL };
937 struct ldb_message *msg;
938 struct ldb_result *res;
939 struct ldb_message_element *el;
940 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";
942 struct dom_sid dnsadmins_sid;
943 const struct dom_sid *domain_sid;
944 struct security_descriptor *secdesc;
945 struct dnsp_DnsProperty *prop;
946 DATA_BLOB *sd_encoded;
947 enum ndr_err_code ndr_err;
950 /* Get DnsAdmins SID */
951 ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
952 LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
953 if (ret != LDB_SUCCESS || res->count != 1) {
954 return WERR_INTERNAL_DB_ERROR;
957 el = ldb_msg_find_element(res->msgs[0], "objectSID");
958 if (el == NULL || el->num_values != 1) {
959 return WERR_INTERNAL_DB_ERROR;
962 ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
963 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
964 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
965 return WERR_INTERNAL_DB_ERROR;
968 /* create security descriptor with DnsAdmins GUID in sddl template */
969 sddl = talloc_asprintf(tmp_ctx, sddl_template,
970 dom_sid_string(tmp_ctx, &dnsadmins_sid));
972 return WERR_NOT_ENOUGH_MEMORY;
976 domain_sid = samdb_domain_sid(samdb);
977 if (domain_sid == NULL) {
978 return WERR_INTERNAL_DB_ERROR;
981 secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
982 if (secdesc == NULL) {
983 return WERR_GEN_FAILURE;
986 msg = ldb_msg_new(tmp_ctx);
987 W_ERROR_HAVE_NO_MEMORY(msg);
990 ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
991 if (ret != LDB_SUCCESS) {
992 return WERR_NOT_ENOUGH_MEMORY;
995 sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
996 W_ERROR_HAVE_NO_MEMORY(sd_encoded);
998 ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
999 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
1000 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1001 return WERR_GEN_FAILURE;
1004 ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
1005 if (ret != LDB_SUCCESS) {
1006 return WERR_NOT_ENOUGH_MEMORY;
1009 /* dns zone Properties */
1010 prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
1011 W_ERROR_HAVE_NO_MEMORY(prop);
1016 prop->id = DSPROPERTY_ZONE_TYPE;
1017 prop->data.zone_type = z->zoneinfo->dwZoneType;
1018 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1019 return WERR_NOT_ENOUGH_MEMORY;
1023 prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
1024 prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
1025 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1026 return WERR_NOT_ENOUGH_MEMORY;
1030 prop->id = DSPROPERTY_ZONE_SECURE_TIME;
1031 prop->data.zone_secure_time = 0;
1032 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1033 return WERR_NOT_ENOUGH_MEMORY;
1036 /* norefresh interval */
1037 prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
1038 prop->data.norefresh_hours = 168;
1039 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1040 return WERR_NOT_ENOUGH_MEMORY;
1043 /* refresh interval */
1044 prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
1045 prop->data.refresh_hours = 168;
1046 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1047 return WERR_NOT_ENOUGH_MEMORY;
1051 prop->id = DSPROPERTY_ZONE_AGING_STATE;
1052 prop->data.aging_enabled = z->zoneinfo->fAging;
1053 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1054 return WERR_NOT_ENOUGH_MEMORY;
1057 /* aging enabled time */
1058 prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
1059 prop->data.next_scavenging_cycle_hours = 0;
1060 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1061 return WERR_NOT_ENOUGH_MEMORY;
1066 ret = ldb_add(samdb, msg);
1067 if (ret != LDB_SUCCESS) {
1068 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
1069 z->name, ldb_errstring(samdb)));
1071 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1072 return WERR_ACCESS_DENIED;
1075 return WERR_INTERNAL_DB_ERROR;
1082 /* Create new dnsZone record and @ record (SOA + NS) */
1083 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
1084 struct dnsserver_partition *partitions,
1085 struct dnsserver_zone *zone,
1086 struct loadparm_context *lp_ctx)
1088 struct dnsserver_partition *p;
1089 bool in_forest = false;
1092 TALLOC_CTX *tmp_ctx;
1093 struct dnsp_DnssrvRpcRecord *dns_rec;
1094 struct dnsp_soa soa;
1095 char *tmpstr, *server_fqdn, *soa_email;
1096 struct ldb_val name_val = data_blob_string_const(zone->name);
1098 /* We only support primary zones for now */
1099 if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
1100 return WERR_CALL_NOT_IMPLEMENTED;
1103 /* Get the correct partition */
1104 if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
1107 for (p = partitions; p; p = p->next) {
1108 if (in_forest == p->is_forest) {
1113 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
1116 tmp_ctx = talloc_new(NULL);
1117 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1119 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
1120 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
1122 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
1123 talloc_free(tmp_ctx);
1124 return WERR_NOT_ENOUGH_MEMORY;
1127 if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
1128 talloc_free(tmp_ctx);
1129 return WERR_NOT_ENOUGH_MEMORY;
1132 /* Add dnsZone record */
1133 status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
1134 if (!W_ERROR_IS_OK(status)) {
1135 talloc_free(tmp_ctx);
1139 if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
1140 talloc_free(tmp_ctx);
1141 return WERR_NOT_ENOUGH_MEMORY;
1144 dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
1145 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
1147 tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
1148 lpcfg_netbios_name(lp_ctx),
1149 lpcfg_realm(lp_ctx));
1150 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
1151 server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
1152 W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
1153 talloc_free(tmpstr);
1155 tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
1156 lpcfg_realm(lp_ctx));
1157 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
1158 soa_email = strlower_talloc(tmp_ctx, tmpstr);
1159 W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
1160 talloc_free(tmpstr);
1162 /* SOA Record - values same as defined in provision/sambadns.py */
1168 soa.mname = server_fqdn;
1169 soa.rname = soa_email;
1171 dns_rec[0].wType = DNS_TYPE_SOA;
1172 dns_rec[0].rank = DNS_RANK_ZONE;
1173 dns_rec[0].dwSerial = soa.serial;
1174 dns_rec[0].dwTtlSeconds = 3600;
1175 dns_rec[0].dwTimeStamp = 0;
1176 dns_rec[0].data.soa = soa;
1179 dns_rec[1].wType = DNS_TYPE_NS;
1180 dns_rec[1].rank = DNS_RANK_ZONE;
1181 dns_rec[1].dwSerial = soa.serial;
1182 dns_rec[1].dwTtlSeconds = 3600;
1183 dns_rec[1].dwTimeStamp = 0;
1184 dns_rec[1].data.ns = server_fqdn;
1187 status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
1189 talloc_free(tmp_ctx);
1194 /* Delete dnsZone record and all DNS records in the zone */
1195 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
1196 struct dnsserver_zone *zone)
1200 ret = ldb_transaction_start(samdb);
1201 if (ret != LDB_SUCCESS) {
1202 return WERR_INTERNAL_DB_ERROR;
1205 ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
1206 if (ret != LDB_SUCCESS) {
1207 ldb_transaction_cancel(samdb);
1209 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1210 return WERR_ACCESS_DENIED;
1212 return WERR_INTERNAL_DB_ERROR;
1215 ret = ldb_transaction_commit(samdb);
1216 if (ret != LDB_SUCCESS) {
1217 return WERR_INTERNAL_DB_ERROR;