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, NULL);
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, NULL);
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", 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 z = talloc_zero(mem_ctx, struct dnsserver_zone);
125 name = talloc_strdup(z,
126 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
127 if (strcmp(name, "RootDNSServers") == 0) {
129 z->name = talloc_strdup(z, ".");
133 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
135 DLIST_ADD_END(zones, z, NULL);
136 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
142 talloc_free(tmp_ctx);
147 /* Find DNS partition information */
148 struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
149 struct ldb_context *samdb,
150 struct dnsserver_partition *p)
152 const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
153 const char * const attrs_none[] = { NULL };
154 struct ldb_result *res;
155 struct ldb_message_element *el;
157 struct dnsserver_partition_info *partinfo;
158 int i, ret, instance_type;
161 tmp_ctx = talloc_new(mem_ctx);
162 if (tmp_ctx == NULL) {
166 partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
167 if (partinfo == NULL) {
168 talloc_free(tmp_ctx);
172 /* Search for the active replica and state */
173 ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
175 if (ret != LDB_SUCCESS || res->count != 1) {
179 /* Set the state of the partition */
180 instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
181 if (instance_type == -1) {
182 partinfo->dwState = DNS_DP_STATE_UNKNOWN;
183 } else if (instance_type & INSTANCE_TYPE_NC_COMING) {
184 partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
185 } else if (instance_type & INSTANCE_TYPE_NC_GOING) {
186 partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
188 partinfo->dwState = DNS_DP_OKAY;
191 el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
193 partinfo->dwReplicaCount = 0;
194 partinfo->ReplicaArray = NULL;
196 partinfo->dwReplicaCount = el->num_values;
197 partinfo->ReplicaArray = talloc_zero_array(partinfo,
198 struct DNS_RPC_DP_REPLICA *,
200 if (partinfo->ReplicaArray == NULL) {
203 for (i=0; i<el->num_values; i++) {
204 partinfo->ReplicaArray[i] = talloc_zero(partinfo,
205 struct DNS_RPC_DP_REPLICA);
206 if (partinfo->ReplicaArray[i] == NULL) {
209 partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
211 (const char *)el->values[i].data);
212 if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
219 /* Search for cross-reference object */
220 dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
225 ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
226 "(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
227 if (ret != LDB_SUCCESS || res->count != 1) {
230 partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
231 if (partinfo->pszCrDn == NULL) {
236 talloc_free(tmp_ctx);
240 talloc_free(tmp_ctx);
241 talloc_free(partinfo);
246 /* Increment serial number and update timestamp */
247 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
248 struct ldb_context *samdb,
249 struct dnsserver_zone *z)
251 const char * const attrs[] = { "dnsRecord", NULL };
252 struct ldb_result *res;
253 struct dnsp_DnssrvRpcRecord rec;
254 struct ldb_message_element *el;
255 enum ndr_err_code ndr_err;
256 int ret, i, serial = -1;
259 unix_to_nt_time(&t, time(NULL));
260 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
261 t /= 3600; /* convert to hours */
263 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
264 "(&(objectClass=dnsNode)(name=@))");
265 if (ret != LDB_SUCCESS || res->count == 0) {
269 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
274 for (i=0; i<el->num_values; i++) {
275 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
276 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
281 if (rec.wType == DNS_TYPE_SOA) {
282 serial = rec.data.soa.serial + 1;
283 rec.dwSerial = serial;
284 rec.dwTimeStamp = (uint32_t)t;
285 rec.data.soa.serial = serial;
287 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
288 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
289 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
297 el->flags = LDB_FLAG_MOD_REPLACE;
298 ret = ldb_modify(samdb, res->msgs[0]);
299 if (ret != LDB_SUCCESS) {
308 /* Add DNS record to the database */
309 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
310 struct ldb_context *samdb,
313 struct dnsp_DnssrvRpcRecord *rec)
315 struct ldb_message *msg;
318 enum ndr_err_code ndr_err;
321 msg = ldb_msg_new(mem_ctx);
322 W_ERROR_HAVE_NO_MEMORY(msg);
325 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
326 if (ret != LDB_SUCCESS) {
330 if (num_rec > 0 && rec) {
331 for (i=0; i<num_rec; i++) {
332 ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
333 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
335 return WERR_GENERAL_FAILURE;
338 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
339 if (ret != LDB_SUCCESS) {
345 ret = ldb_add(samdb, msg);
346 if (ret != LDB_SUCCESS) {
347 return WERR_INTERNAL_DB_ERROR;
354 /* Add dnsNode record to the database with DNS record */
355 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
356 struct ldb_context *samdb,
357 struct dnsserver_zone *z,
360 const char * const attrs[] = { "name", NULL };
361 struct ldb_result *res;
365 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
366 "(&(objectClass=dnsNode)(name=%s))", name);
367 if (ret != LDB_SUCCESS) {
368 return WERR_INTERNAL_DB_ERROR;
371 if (res->count > 0) {
373 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
376 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
377 W_ERROR_HAVE_NO_MEMORY(dn);
379 if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
383 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
387 /* Add a DNS record */
388 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
389 struct ldb_context *samdb,
390 struct dnsserver_zone *z,
392 struct DNS_RPC_RECORD *add_record)
394 const char * const attrs[] = { "dnsRecord", NULL };
395 struct ldb_result *res;
396 struct dnsp_DnssrvRpcRecord *rec;
397 struct ldb_message_element *el;
399 enum ndr_err_code ndr_err;
404 rec = dns_to_dnsp_copy(mem_ctx, add_record);
405 W_ERROR_HAVE_NO_MEMORY(rec);
407 serial = dnsserver_update_soa(mem_ctx, samdb, z);
409 return WERR_INTERNAL_DB_ERROR;
412 unix_to_nt_time(&t, time(NULL));
413 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
414 t /= 3600; /* convert to hours */
416 rec->dwSerial = serial;
417 rec->dwTimeStamp = t;
419 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
420 "(&(objectClass=dnsNode)(name=%s))", name);
421 if (ret != LDB_SUCCESS) {
422 return WERR_INTERNAL_DB_ERROR;
425 if (res->count == 0) {
426 dn = dnsserver_name_to_dn(mem_ctx, z, name);
427 W_ERROR_HAVE_NO_MEMORY(dn);
429 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
432 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
434 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
435 if (ret != LDB_SUCCESS) {
440 for (i=0; i<el->num_values; i++) {
441 struct dnsp_DnssrvRpcRecord rec2;
443 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
444 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
445 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
446 return WERR_GENERAL_FAILURE;
449 if (dns_record_match(rec, &rec2)) {
453 if (i < el->num_values) {
454 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
456 if (i == el->num_values) {
457 /* adding a new value */
458 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
459 W_ERROR_HAVE_NO_MEMORY(el->values);
463 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
464 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
466 return WERR_GENERAL_FAILURE;
469 el->flags = LDB_FLAG_MOD_REPLACE;
470 ret = ldb_modify(samdb, res->msgs[0]);
471 if (ret != LDB_SUCCESS) {
472 return WERR_INTERNAL_DB_ERROR;
479 /* Update a DNS record */
480 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
481 struct ldb_context *samdb,
482 struct dnsserver_zone *z,
484 struct DNS_RPC_RECORD *add_record,
485 struct DNS_RPC_RECORD *del_record)
487 const char * const attrs[] = { "dnsRecord", NULL };
488 struct ldb_result *res;
489 struct dnsp_DnssrvRpcRecord *arec, *drec;
490 struct ldb_message_element *el;
491 enum ndr_err_code ndr_err;
496 serial = dnsserver_update_soa(mem_ctx, samdb, z);
498 return WERR_INTERNAL_DB_ERROR;
501 arec = dns_to_dnsp_copy(mem_ctx, add_record);
502 W_ERROR_HAVE_NO_MEMORY(arec);
504 drec = dns_to_dnsp_copy(mem_ctx, del_record);
505 W_ERROR_HAVE_NO_MEMORY(drec);
507 unix_to_nt_time(&t, time(NULL));
510 arec->dwSerial = serial;
511 arec->dwTimeStamp = t;
513 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
514 "(&(objectClass=dnsNode)(name=%s))", name);
515 if (ret != LDB_SUCCESS) {
516 return WERR_INTERNAL_DB_ERROR;
519 if (res->count == 0) {
520 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
523 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
524 if (el == NULL || el->num_values == 0) {
525 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
528 for (i=0; i<el->num_values; i++) {
529 struct dnsp_DnssrvRpcRecord rec2;
531 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
532 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
533 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
534 return WERR_GENERAL_FAILURE;
537 if (dns_record_match(arec, &rec2)) {
541 if (i < el->num_values) {
542 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
546 for (i=0; i<el->num_values; i++) {
547 struct dnsp_DnssrvRpcRecord rec2;
549 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
550 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
551 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
552 return WERR_GENERAL_FAILURE;
555 if (dns_record_match(drec, &rec2)) {
559 if (i == el->num_values) {
560 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
563 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
564 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
565 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
566 return WERR_GENERAL_FAILURE;
569 el->flags = LDB_FLAG_MOD_REPLACE;
570 ret = ldb_modify(samdb, res->msgs[0]);
571 if (ret != LDB_SUCCESS) {
572 return WERR_INTERNAL_DB_ERROR;
579 /* Delete a DNS record */
580 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
581 struct ldb_context *samdb,
582 struct dnsserver_zone *z,
584 struct DNS_RPC_RECORD *del_record)
586 const char * const attrs[] = { "dnsRecord", NULL };
587 struct ldb_result *res;
588 struct dnsp_DnssrvRpcRecord *rec;
589 struct ldb_message_element *el;
590 enum ndr_err_code ndr_err;
594 serial = dnsserver_update_soa(mem_ctx, samdb, z);
596 return WERR_INTERNAL_DB_ERROR;
599 rec = dns_to_dnsp_copy(mem_ctx, del_record);
600 W_ERROR_HAVE_NO_MEMORY(rec);
602 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
603 "(&(objectClass=dnsNode)(name=%s))", name);
604 if (ret != LDB_SUCCESS) {
605 return WERR_INTERNAL_DB_ERROR;
608 if (res->count == 0) {
609 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
612 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
613 if (el == NULL || el->num_values == 0) {
614 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
617 for (i=0; i<el->num_values; i++) {
618 struct dnsp_DnssrvRpcRecord rec2;
620 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
621 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
622 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
623 return WERR_GENERAL_FAILURE;
626 if (dns_record_match(rec, &rec2)) {
630 if (i == el->num_values) {
631 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
633 if (i < el->num_values-1) {
634 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
638 if (el->num_values == 0) {
639 ret = ldb_delete(samdb, res->msgs[0]->dn);
641 el->flags = LDB_FLAG_MOD_REPLACE;
642 ret = ldb_modify(samdb, res->msgs[0]);
644 if (ret != LDB_SUCCESS) {
645 return WERR_INTERNAL_DB_ERROR;
652 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
653 struct ldb_message *msg,
654 struct dnsp_DnsProperty *prop)
656 DATA_BLOB *prop_blob;
657 enum ndr_err_code ndr_err;
660 prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
661 if (prop_blob == NULL) return false;
663 ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
664 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
665 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
668 ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
669 if (ret != LDB_SUCCESS) {
676 /* Create dnsZone record to database and set security descriptor */
677 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
678 struct ldb_context *samdb,
679 struct ldb_dn *zone_dn,
680 struct dnsserver_zone *z)
682 const char * const attrs[] = { "objectSID", NULL };
683 struct ldb_message *msg;
684 struct ldb_result *res;
685 struct ldb_message_element *el;
686 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";
688 struct dom_sid dnsadmins_sid;
689 const struct dom_sid *domain_sid;
690 struct security_descriptor *secdesc;
691 struct dnsp_DnsProperty *prop;
692 DATA_BLOB *sd_encoded;
693 enum ndr_err_code ndr_err;
696 /* Get DnsAdmins SID */
697 ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
698 LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
699 if (ret != LDB_SUCCESS || res->count != 1) {
700 return WERR_INTERNAL_DB_ERROR;
703 el = ldb_msg_find_element(res->msgs[0], "objectSID");
704 if (el == NULL || el->num_values != 1) {
705 return WERR_INTERNAL_DB_ERROR;
708 ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
709 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
710 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
711 return WERR_INTERNAL_DB_ERROR;
714 /* create security descriptor with DnsAdmins GUID in sddl template */
715 sddl = talloc_asprintf(tmp_ctx, sddl_template,
716 dom_sid_string(tmp_ctx, &dnsadmins_sid));
722 domain_sid = samdb_domain_sid(samdb);
723 if (domain_sid == NULL) {
724 return WERR_INTERNAL_DB_ERROR;
727 secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
728 if (secdesc == NULL) {
729 return WERR_GENERAL_FAILURE;
732 msg = ldb_msg_new(tmp_ctx);
733 W_ERROR_HAVE_NO_MEMORY(msg);
736 ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
737 if (ret != LDB_SUCCESS) {
741 sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
742 W_ERROR_HAVE_NO_MEMORY(sd_encoded);
744 ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
745 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
746 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
747 return WERR_GENERAL_FAILURE;
750 ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
751 if (ret != LDB_SUCCESS) {
755 /* dns zone Properties */
756 prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
757 W_ERROR_HAVE_NO_MEMORY(prop);
762 prop->id = DSPROPERTY_ZONE_TYPE;
763 prop->data.zone_type = z->zoneinfo->dwZoneType;
764 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
769 prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
770 prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
771 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
776 prop->id = DSPROPERTY_ZONE_SECURE_TIME;
777 prop->data.zone_secure_time = 0;
778 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
782 /* norefresh interval */
783 prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
784 prop->data.norefresh_hours = 168;
785 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
789 /* refresh interval */
790 prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
791 prop->data.refresh_hours = 168;
792 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
797 prop->id = DSPROPERTY_ZONE_AGING_STATE;
798 prop->data.aging_enabled = z->zoneinfo->fAging;
799 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
803 /* aging enabled time */
804 prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
805 prop->data.next_scavenging_cycle_hours = 0;
806 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
812 ret = ldb_add(samdb, msg);
813 if (ret != LDB_SUCCESS) {
814 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
815 z->name, ldb_errstring(samdb)));
816 return WERR_INTERNAL_DB_ERROR;
823 /* Create new dnsZone record and @ record (SOA + NS) */
824 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
825 struct dnsserver_partition *partitions,
826 struct dnsserver_zone *zone,
827 struct loadparm_context *lp_ctx)
829 struct dnsserver_partition *p;
830 bool in_forest = false;
834 struct dnsp_DnssrvRpcRecord *dns_rec;
836 char *tmpstr, *server_fqdn, *soa_email;
839 /* We only support primary zones for now */
840 if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
841 return WERR_CALL_NOT_IMPLEMENTED;
844 /* Get the correct partition */
845 if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
848 for (p = partitions; p; p = p->next) {
849 if (in_forest == p->is_forest) {
854 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
857 tmp_ctx = talloc_new(NULL);
858 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
860 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
861 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
863 if(!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS", zone->name)) {
864 talloc_free(tmp_ctx);
868 /* Add dnsZone record */
869 status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
870 if (!W_ERROR_IS_OK(status)) {
871 talloc_free(tmp_ctx);
875 if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
876 talloc_free(tmp_ctx);
880 dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
881 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
883 tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
884 lpcfg_netbios_name(lp_ctx),
885 lpcfg_realm(lp_ctx));
886 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
887 server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
888 W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
891 tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
892 lpcfg_realm(lp_ctx));
893 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
894 soa_email = strlower_talloc(tmp_ctx, tmpstr);
895 W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
898 unix_to_nt_time(&t, time(NULL));
899 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
900 t /= 3600; /* convert to hours */
902 /* SOA Record - values same as defined in provision/sambadns.py */
908 soa.mname = server_fqdn;
909 soa.rname = soa_email;
911 dns_rec[0].wType = DNS_TYPE_SOA;
912 dns_rec[0].rank = DNS_RANK_ZONE;
913 dns_rec[0].dwSerial = soa.serial;
914 dns_rec[0].dwTtlSeconds = 3600;
915 dns_rec[0].dwTimeStamp = (uint32_t)t;
916 dns_rec[0].data.soa = soa;
919 dns_rec[1].wType = DNS_TYPE_NS;
920 dns_rec[1].rank = DNS_RANK_ZONE;
921 dns_rec[1].dwSerial = soa.serial;
922 dns_rec[1].dwTimeStamp = (uint32_t)t;
923 dns_rec[1].data.ns = server_fqdn;
926 status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
928 talloc_free(tmp_ctx);
933 /* Delete dnsZone record and all DNS records in the zone */
934 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
935 struct dnsserver_zone *zone)
939 ret = ldb_transaction_start(samdb);
940 if (ret != LDB_SUCCESS) {
941 return WERR_INTERNAL_DB_ERROR;
944 ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
945 if (ret != LDB_SUCCESS) {
946 ldb_transaction_cancel(samdb);
947 return WERR_INTERNAL_DB_ERROR;
950 ret = ldb_transaction_commit(samdb);
951 if (ret != LDB_SUCCESS) {
952 return WERR_INTERNAL_DB_ERROR;