selftest: smb2.durable-open.delete_on_close1 is not flapping any more
[Samba/gebeck_regimport.git] / source4 / rpc_server / dnsserver / dnsdb.c
blob9bf5ecf5ac5c285070352dc32ce14f6c9b5a6045
1 /*
2 Unix SMB/CIFS implementation.
4 DNS Server
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/>.
22 #include "includes.h"
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;
39 partitions = NULL;
41 /* Domain partition */
42 p = talloc_zero(mem_ctx, struct dnsserver_partition);
43 if (p == NULL) {
44 goto failed;
47 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
48 if (p->partition_dn == NULL) {
49 goto failed;
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;
54 p->is_forest = false;
56 DLIST_ADD_END(partitions, p, NULL);
58 /* Forest Partition */
59 p = talloc_zero(mem_ctx, struct dnsserver_partition);
60 if (p == NULL) {
61 goto failed;
64 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
65 if (p->partition_dn == NULL) {
66 goto failed;
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;
71 p->is_forest = true;
73 DLIST_ADD_END(partitions, p, NULL);
75 return partitions;
77 failed:
78 return 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)
88 TALLOC_CTX *tmp_ctx;
89 const char * const attrs[] = {"name", NULL};
90 struct ldb_dn *dn;
91 struct ldb_result *res;
92 struct dnsserver_zone *zones, *z;
93 int i, ret;
95 tmp_ctx = talloc_new(mem_ctx);
96 if (tmp_ctx == NULL) {
97 return NULL;
100 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
101 if (dn == NULL) {
102 goto failed;
104 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
105 goto failed;
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)));
113 goto failed;
116 zones = NULL;
117 for(i=0; i<res->count; i++) {
118 char *name;
119 z = talloc_zero(mem_ctx, struct dnsserver_zone);
120 if (z == NULL) {
121 goto failed;
124 z->partition = p;
125 name = talloc_strdup(z,
126 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
127 if (strcmp(name, "RootDNSServers") == 0) {
128 talloc_free(name);
129 z->name = talloc_strdup(z, ".");
130 } else {
131 z->name = name;
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));
139 return zones;
141 failed:
142 talloc_free(tmp_ctx);
143 return NULL;
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;
156 struct ldb_dn *dn;
157 struct dnsserver_partition_info *partinfo;
158 int i, ret, instance_type;
159 TALLOC_CTX *tmp_ctx;
161 tmp_ctx = talloc_new(mem_ctx);
162 if (tmp_ctx == NULL) {
163 return NULL;
166 partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
167 if (partinfo == NULL) {
168 talloc_free(tmp_ctx);
169 return NULL;
172 /* Search for the active replica and state */
173 ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
174 attrs, NULL);
175 if (ret != LDB_SUCCESS || res->count != 1) {
176 goto failed;
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;
187 } else {
188 partinfo->dwState = DNS_DP_OKAY;
191 el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
192 if (el == NULL) {
193 partinfo->dwReplicaCount = 0;
194 partinfo->ReplicaArray = NULL;
195 } else {
196 partinfo->dwReplicaCount = el->num_values;
197 partinfo->ReplicaArray = talloc_zero_array(partinfo,
198 struct DNS_RPC_DP_REPLICA *,
199 el->num_values);
200 if (partinfo->ReplicaArray == NULL) {
201 goto failed;
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) {
207 goto failed;
209 partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
210 partinfo,
211 (const char *)el->values[i].data);
212 if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
213 goto failed;
217 talloc_free(res);
219 /* Search for cross-reference object */
220 dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
221 if (dn == NULL) {
222 goto failed;
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) {
228 goto failed;
230 partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
231 if (partinfo->pszCrDn == NULL) {
232 goto failed;
234 talloc_free(res);
236 talloc_free(tmp_ctx);
237 return partinfo;
239 failed:
240 talloc_free(tmp_ctx);
241 talloc_free(partinfo);
242 return NULL;
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;
257 NTTIME t;
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) {
266 return -1;
269 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
270 if (el == NULL) {
271 return -1;
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)) {
278 continue;
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)) {
290 return -1;
292 break;
296 if (serial != -1) {
297 el->flags = LDB_FLAG_MOD_REPLACE;
298 ret = ldb_modify(samdb, res->msgs[0]);
299 if (ret != LDB_SUCCESS) {
300 return -1;
304 return serial;
308 /* Add DNS record to the database */
309 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
310 struct ldb_context *samdb,
311 struct ldb_dn *dn,
312 int num_rec,
313 struct dnsp_DnssrvRpcRecord *rec)
315 struct ldb_message *msg;
316 struct ldb_val v;
317 int ret;
318 enum ndr_err_code ndr_err;
319 int i;
321 msg = ldb_msg_new(mem_ctx);
322 W_ERROR_HAVE_NO_MEMORY(msg);
324 msg->dn = dn;
325 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
326 if (ret != LDB_SUCCESS) {
327 return WERR_NOMEM;
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) {
340 return WERR_NOMEM;
345 ret = ldb_add(samdb, msg);
346 if (ret != LDB_SUCCESS) {
347 return WERR_INTERNAL_DB_ERROR;
350 return WERR_OK;
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,
358 const char *name)
360 const char * const attrs[] = { "name", NULL };
361 struct ldb_result *res;
362 struct ldb_dn *dn;
363 int ret;
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) {
372 talloc_free(res);
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)) {
380 return WERR_NOMEM;
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,
391 const char *name,
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;
398 struct ldb_dn *dn;
399 enum ndr_err_code ndr_err;
400 NTTIME t;
401 int ret, i;
402 int serial;
404 rec = dns_to_dnsp_copy(mem_ctx, add_record);
405 W_ERROR_HAVE_NO_MEMORY(rec);
407 /* Set the correct rank for the record.
408 * FIXME: add logic to check for glue records */
409 if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
410 rec->rank |= DNS_RANK_ZONE;
411 } else if (strcmp(z->name, ".") == 0) {
412 rec->rank |= DNS_RANK_ROOT_HINT;
415 serial = dnsserver_update_soa(mem_ctx, samdb, z);
416 if (serial < 0) {
417 return WERR_INTERNAL_DB_ERROR;
420 unix_to_nt_time(&t, time(NULL));
421 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
422 t /= 3600; /* convert to hours */
424 rec->dwSerial = serial;
425 rec->dwTimeStamp = t;
427 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
428 "(&(objectClass=dnsNode)(name=%s))", name);
429 if (ret != LDB_SUCCESS) {
430 return WERR_INTERNAL_DB_ERROR;
433 if (res->count == 0) {
434 dn = dnsserver_name_to_dn(mem_ctx, z, name);
435 W_ERROR_HAVE_NO_MEMORY(dn);
437 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
440 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
441 if (el == NULL) {
442 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
443 if (ret != LDB_SUCCESS) {
444 return WERR_NOMEM;
448 for (i=0; i<el->num_values; i++) {
449 struct dnsp_DnssrvRpcRecord rec2;
451 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
452 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
453 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
454 return WERR_GENERAL_FAILURE;
457 if (dns_record_match(rec, &rec2)) {
458 break;
461 if (i < el->num_values) {
462 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
464 if (i == el->num_values) {
465 /* adding a new value */
466 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
467 W_ERROR_HAVE_NO_MEMORY(el->values);
468 el->num_values++;
471 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
472 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
473 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
474 return WERR_GENERAL_FAILURE;
477 el->flags = LDB_FLAG_MOD_REPLACE;
478 ret = ldb_modify(samdb, res->msgs[0]);
479 if (ret != LDB_SUCCESS) {
480 return WERR_INTERNAL_DB_ERROR;
483 return WERR_OK;
487 /* Update a DNS record */
488 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
489 struct ldb_context *samdb,
490 struct dnsserver_zone *z,
491 const char *name,
492 struct DNS_RPC_RECORD *add_record,
493 struct DNS_RPC_RECORD *del_record)
495 const char * const attrs[] = { "dnsRecord", NULL };
496 struct ldb_result *res;
497 struct dnsp_DnssrvRpcRecord *arec, *drec;
498 struct ldb_message_element *el;
499 enum ndr_err_code ndr_err;
500 NTTIME t;
501 int ret, i;
502 int serial;
504 serial = dnsserver_update_soa(mem_ctx, samdb, z);
505 if (serial < 0) {
506 return WERR_INTERNAL_DB_ERROR;
509 arec = dns_to_dnsp_copy(mem_ctx, add_record);
510 W_ERROR_HAVE_NO_MEMORY(arec);
512 drec = dns_to_dnsp_copy(mem_ctx, del_record);
513 W_ERROR_HAVE_NO_MEMORY(drec);
515 unix_to_nt_time(&t, time(NULL));
516 t /= 10*1000*1000;
518 arec->dwSerial = serial;
519 arec->dwTimeStamp = t;
521 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
522 "(&(objectClass=dnsNode)(name=%s))", name);
523 if (ret != LDB_SUCCESS) {
524 return WERR_INTERNAL_DB_ERROR;
527 if (res->count == 0) {
528 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
531 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
532 if (el == NULL || el->num_values == 0) {
533 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
536 for (i=0; i<el->num_values; i++) {
537 struct dnsp_DnssrvRpcRecord rec2;
539 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
540 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
541 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
542 return WERR_GENERAL_FAILURE;
545 if (dns_record_match(arec, &rec2)) {
546 break;
549 if (i < el->num_values) {
550 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
554 for (i=0; i<el->num_values; i++) {
555 struct dnsp_DnssrvRpcRecord rec2;
557 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
558 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
559 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
560 return WERR_GENERAL_FAILURE;
563 if (dns_record_match(drec, &rec2)) {
564 break;
567 if (i == el->num_values) {
568 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
571 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
572 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
573 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
574 return WERR_GENERAL_FAILURE;
577 el->flags = LDB_FLAG_MOD_REPLACE;
578 ret = ldb_modify(samdb, res->msgs[0]);
579 if (ret != LDB_SUCCESS) {
580 return WERR_INTERNAL_DB_ERROR;
583 return WERR_OK;
587 /* Delete a DNS record */
588 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
589 struct ldb_context *samdb,
590 struct dnsserver_zone *z,
591 const char *name,
592 struct DNS_RPC_RECORD *del_record)
594 const char * const attrs[] = { "dnsRecord", NULL };
595 struct ldb_result *res;
596 struct dnsp_DnssrvRpcRecord *rec;
597 struct ldb_message_element *el;
598 enum ndr_err_code ndr_err;
599 int ret, i;
600 int serial;
602 serial = dnsserver_update_soa(mem_ctx, samdb, z);
603 if (serial < 0) {
604 return WERR_INTERNAL_DB_ERROR;
607 rec = dns_to_dnsp_copy(mem_ctx, del_record);
608 W_ERROR_HAVE_NO_MEMORY(rec);
610 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
611 "(&(objectClass=dnsNode)(name=%s))", name);
612 if (ret != LDB_SUCCESS) {
613 return WERR_INTERNAL_DB_ERROR;
616 if (res->count == 0) {
617 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
620 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
621 if (el == NULL || el->num_values == 0) {
622 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
625 for (i=0; i<el->num_values; i++) {
626 struct dnsp_DnssrvRpcRecord rec2;
628 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
629 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
630 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
631 return WERR_GENERAL_FAILURE;
634 if (dns_record_match(rec, &rec2)) {
635 break;
638 if (i == el->num_values) {
639 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
641 if (i < el->num_values-1) {
642 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
644 el->num_values--;
646 if (el->num_values == 0) {
647 ret = ldb_delete(samdb, res->msgs[0]->dn);
648 } else {
649 el->flags = LDB_FLAG_MOD_REPLACE;
650 ret = ldb_modify(samdb, res->msgs[0]);
652 if (ret != LDB_SUCCESS) {
653 return WERR_INTERNAL_DB_ERROR;
656 return WERR_OK;
660 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
661 struct ldb_message *msg,
662 struct dnsp_DnsProperty *prop)
664 DATA_BLOB *prop_blob;
665 enum ndr_err_code ndr_err;
666 int ret;
668 prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
669 if (prop_blob == NULL) return false;
671 ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
672 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
673 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
674 return false;
676 ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
677 if (ret != LDB_SUCCESS) {
678 return false;
680 return true;
684 /* Create dnsZone record to database and set security descriptor */
685 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
686 struct ldb_context *samdb,
687 struct ldb_dn *zone_dn,
688 struct dnsserver_zone *z)
690 const char * const attrs[] = { "objectSID", NULL };
691 struct ldb_message *msg;
692 struct ldb_result *res;
693 struct ldb_message_element *el;
694 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";
695 char *sddl;
696 struct dom_sid dnsadmins_sid;
697 const struct dom_sid *domain_sid;
698 struct security_descriptor *secdesc;
699 struct dnsp_DnsProperty *prop;
700 DATA_BLOB *sd_encoded;
701 enum ndr_err_code ndr_err;
702 int ret;
704 /* Get DnsAdmins SID */
705 ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
706 LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
707 if (ret != LDB_SUCCESS || res->count != 1) {
708 return WERR_INTERNAL_DB_ERROR;
711 el = ldb_msg_find_element(res->msgs[0], "objectSID");
712 if (el == NULL || el->num_values != 1) {
713 return WERR_INTERNAL_DB_ERROR;
716 ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
717 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
718 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
719 return WERR_INTERNAL_DB_ERROR;
722 /* create security descriptor with DnsAdmins GUID in sddl template */
723 sddl = talloc_asprintf(tmp_ctx, sddl_template,
724 dom_sid_string(tmp_ctx, &dnsadmins_sid));
725 if (sddl == NULL) {
726 return WERR_NOMEM;
728 talloc_free(res);
730 domain_sid = samdb_domain_sid(samdb);
731 if (domain_sid == NULL) {
732 return WERR_INTERNAL_DB_ERROR;
735 secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
736 if (secdesc == NULL) {
737 return WERR_GENERAL_FAILURE;
740 msg = ldb_msg_new(tmp_ctx);
741 W_ERROR_HAVE_NO_MEMORY(msg);
743 msg->dn = zone_dn;
744 ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
745 if (ret != LDB_SUCCESS) {
746 return WERR_NOMEM;
749 sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
750 W_ERROR_HAVE_NO_MEMORY(sd_encoded);
752 ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
753 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
754 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
755 return WERR_GENERAL_FAILURE;
758 ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
759 if (ret != LDB_SUCCESS) {
760 return WERR_NOMEM;
763 /* dns zone Properties */
764 prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
765 W_ERROR_HAVE_NO_MEMORY(prop);
767 prop->version = 1;
769 /* zone type */
770 prop->id = DSPROPERTY_ZONE_TYPE;
771 prop->data.zone_type = z->zoneinfo->dwZoneType;
772 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
773 return WERR_NOMEM;
776 /* allow update */
777 prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
778 prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
779 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
780 return WERR_NOMEM;
783 /* secure time */
784 prop->id = DSPROPERTY_ZONE_SECURE_TIME;
785 prop->data.zone_secure_time = 0;
786 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
787 return WERR_NOMEM;
790 /* norefresh interval */
791 prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
792 prop->data.norefresh_hours = 168;
793 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
794 return WERR_NOMEM;
797 /* refresh interval */
798 prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
799 prop->data.refresh_hours = 168;
800 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
801 return WERR_NOMEM;
804 /* aging state */
805 prop->id = DSPROPERTY_ZONE_AGING_STATE;
806 prop->data.aging_enabled = z->zoneinfo->fAging;
807 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
808 return WERR_NOMEM;
811 /* aging enabled time */
812 prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
813 prop->data.next_scavenging_cycle_hours = 0;
814 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
815 return WERR_NOMEM;
818 talloc_free(prop);
820 ret = ldb_add(samdb, msg);
821 if (ret != LDB_SUCCESS) {
822 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
823 z->name, ldb_errstring(samdb)));
824 return WERR_INTERNAL_DB_ERROR;
827 return WERR_OK;
831 /* Create new dnsZone record and @ record (SOA + NS) */
832 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
833 struct dnsserver_partition *partitions,
834 struct dnsserver_zone *zone,
835 struct loadparm_context *lp_ctx)
837 struct dnsserver_partition *p;
838 bool in_forest = false;
839 WERROR status;
840 struct ldb_dn *dn;
841 TALLOC_CTX *tmp_ctx;
842 struct dnsp_DnssrvRpcRecord *dns_rec;
843 struct dnsp_soa soa;
844 char *tmpstr, *server_fqdn, *soa_email;
845 NTTIME t;
847 /* We only support primary zones for now */
848 if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
849 return WERR_CALL_NOT_IMPLEMENTED;
852 /* Get the correct partition */
853 if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
854 in_forest = true;
856 for (p = partitions; p; p = p->next) {
857 if (in_forest == p->is_forest) {
858 break;
861 if (p == NULL) {
862 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
865 tmp_ctx = talloc_new(NULL);
866 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
868 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
869 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
871 if(!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS", zone->name)) {
872 talloc_free(tmp_ctx);
873 return WERR_NOMEM;
876 /* Add dnsZone record */
877 status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
878 if (!W_ERROR_IS_OK(status)) {
879 talloc_free(tmp_ctx);
880 return status;
883 if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
884 talloc_free(tmp_ctx);
885 return WERR_NOMEM;
888 dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
889 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
891 tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
892 lpcfg_netbios_name(lp_ctx),
893 lpcfg_realm(lp_ctx));
894 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
895 server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
896 W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
897 talloc_free(tmpstr);
899 tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
900 lpcfg_realm(lp_ctx));
901 W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
902 soa_email = strlower_talloc(tmp_ctx, tmpstr);
903 W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
904 talloc_free(tmpstr);
906 unix_to_nt_time(&t, time(NULL));
907 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
908 t /= 3600; /* convert to hours */
910 /* SOA Record - values same as defined in provision/sambadns.py */
911 soa.serial = 1;
912 soa.refresh = 900;
913 soa.retry = 600;
914 soa.expire = 86400;
915 soa.minimum = 3600;
916 soa.mname = server_fqdn;
917 soa.rname = soa_email;
919 dns_rec[0].wType = DNS_TYPE_SOA;
920 dns_rec[0].rank = DNS_RANK_ZONE;
921 dns_rec[0].dwSerial = soa.serial;
922 dns_rec[0].dwTtlSeconds = 3600;
923 dns_rec[0].dwTimeStamp = (uint32_t)t;
924 dns_rec[0].data.soa = soa;
926 /* NS Record */
927 dns_rec[1].wType = DNS_TYPE_NS;
928 dns_rec[1].rank = DNS_RANK_ZONE;
929 dns_rec[1].dwSerial = soa.serial;
930 dns_rec[1].dwTimeStamp = (uint32_t)t;
931 dns_rec[1].data.ns = server_fqdn;
933 /* Add @ Record */
934 status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
936 talloc_free(tmp_ctx);
937 return status;
941 /* Delete dnsZone record and all DNS records in the zone */
942 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
943 struct dnsserver_zone *zone)
945 int ret;
947 ret = ldb_transaction_start(samdb);
948 if (ret != LDB_SUCCESS) {
949 return WERR_INTERNAL_DB_ERROR;
952 ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
953 if (ret != LDB_SUCCESS) {
954 ldb_transaction_cancel(samdb);
955 return WERR_INTERNAL_DB_ERROR;
958 ret = ldb_transaction_commit(samdb);
959 if (ret != LDB_SUCCESS) {
960 return WERR_INTERNAL_DB_ERROR;
963 return WERR_OK;