ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / rpc_server / dnsserver / dnsdb.c
blobdc32169dcccd9532bed0d59f7d917ed0a18c1d4b
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 #undef strcasecmp
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;
41 partitions = NULL;
43 /* Domain partition */
44 p = talloc_zero(mem_ctx, struct dnsserver_partition);
45 if (p == NULL) {
46 goto failed;
49 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
50 if (p->partition_dn == NULL) {
51 goto failed;
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;
56 p->is_forest = false;
58 DLIST_ADD_END(partitions, p);
60 /* Forest Partition */
61 p = talloc_zero(mem_ctx, struct dnsserver_partition);
62 if (p == NULL) {
63 goto failed;
66 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
67 if (p->partition_dn == NULL) {
68 goto failed;
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;
73 p->is_forest = true;
75 DLIST_ADD_END(partitions, p);
77 return partitions;
79 failed:
80 return NULL;
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)
90 TALLOC_CTX *tmp_ctx;
91 const char * const attrs[] = {"name", "dNSProperty", NULL};
92 struct ldb_dn *dn;
93 struct ldb_result *res;
94 struct dnsserver_zone *zones, *z;
95 int i, j, ret;
97 tmp_ctx = talloc_new(mem_ctx);
98 if (tmp_ctx == NULL) {
99 return NULL;
102 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
103 if (dn == NULL) {
104 goto failed;
106 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
107 goto failed;
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)));
115 goto failed;
118 zones = NULL;
119 for(i=0; i<res->count; i++) {
120 char *name;
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);
125 if (z == NULL) {
126 goto failed;
129 z->partition = p;
130 name = talloc_strdup(z,
131 ldb_msg_find_attr_as_string(res->msgs[i],
132 "name", NULL));
133 if (strcmp(name, "..TrustAnchors") == 0) {
134 talloc_free(z);
135 continue;
137 if (strcmp(name, "RootDNSServers") == 0) {
138 talloc_free(name);
139 z->name = talloc_strdup(z, ".");
140 } else {
141 z->name = name;
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");
149 if(element != NULL){
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]),
156 mem_ctx,
157 &props[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
167 * length.
169 * We can safely fill in an
170 * extra empty property here
171 * because
172 * dns_zoneinfo_load_zone_property()
173 * just ignores
174 * DSPROPERTY_ZONE_EMPTY
176 ZERO_STRUCT(props[j]);
177 props[j].id = DSPROPERTY_ZONE_EMPTY;
178 continue;
181 z->tmp_props = props;
182 z->num_props = element->num_values;
185 return zones;
187 failed:
188 talloc_free(tmp_ctx);
189 return NULL;
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;
202 struct ldb_dn *dn;
203 struct dnsserver_partition_info *partinfo;
204 int i, ret, instance_type;
205 TALLOC_CTX *tmp_ctx;
207 tmp_ctx = talloc_new(mem_ctx);
208 if (tmp_ctx == NULL) {
209 return NULL;
212 partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
213 if (partinfo == NULL) {
214 talloc_free(tmp_ctx);
215 return NULL;
218 /* Search for the active replica and state */
219 ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
220 attrs, NULL);
221 if (ret != LDB_SUCCESS || res->count != 1) {
222 goto failed;
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;
233 } else {
234 partinfo->dwState = DNS_DP_OKAY;
237 el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
238 if (el == NULL) {
239 partinfo->dwReplicaCount = 0;
240 partinfo->ReplicaArray = NULL;
241 } else {
242 partinfo->dwReplicaCount = el->num_values;
243 partinfo->ReplicaArray = talloc_zero_array(partinfo,
244 struct DNS_RPC_DP_REPLICA *,
245 el->num_values);
246 if (partinfo->ReplicaArray == NULL) {
247 goto failed;
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) {
253 goto failed;
255 partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
256 partinfo,
257 (const char *)el->values[i].data);
258 if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
259 goto failed;
263 talloc_free(res);
265 /* Search for cross-reference object */
266 dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
267 if (dn == NULL) {
268 goto failed;
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) {
274 goto failed;
276 partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
277 if (partinfo->pszCrDn == NULL) {
278 goto failed;
280 talloc_free(res);
282 talloc_free(tmp_ctx);
283 return partinfo;
285 failed:
286 talloc_free(tmp_ctx);
287 talloc_free(partinfo);
288 return NULL;
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,
296 WERROR *werr)
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) {
310 return -1;
313 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
314 if (el == NULL) {
315 return -1;
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)) {
322 continue;
325 if (rec.wType == DNS_TYPE_SOA) {
326 serial = rec.data.soa.serial + 1;
327 rec.dwSerial = serial;
328 rec.dwTimeStamp = 0;
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;
335 return -1;
337 break;
341 if (serial != -1) {
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;
348 return -1;
352 *werr = WERR_OK;
354 return serial;
358 /* Add DNS record to the database */
359 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
360 struct ldb_context *samdb,
361 struct ldb_dn *dn,
362 int num_rec,
363 struct dnsp_DnssrvRpcRecord *rec)
365 struct ldb_message *msg;
366 struct ldb_val v;
367 int ret;
368 enum ndr_err_code ndr_err;
369 int i;
371 msg = ldb_msg_new(mem_ctx);
372 W_ERROR_HAVE_NO_MEMORY(msg);
374 msg->dn = dn;
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;
400 return WERR_OK;
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,
408 const char *name)
410 const char * const attrs[] = { "name", NULL };
411 struct ldb_result *res;
412 struct ldb_dn *dn;
413 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
414 struct ldb_val name_val = data_blob_string_const(name);
415 int ret;
417 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
418 "(&(objectClass=dnsNode)(name=%s))",
419 encoded_name);
420 if (ret != LDB_SUCCESS) {
421 return WERR_INTERNAL_DB_ERROR;
424 if (res->count > 0) {
425 talloc_free(res);
426 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
429 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
430 W_ERROR_HAVE_NO_MEMORY(dn);
432 if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
433 return WERR_NOT_ENOUGH_MEMORY;
436 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
439 static void set_record_rank(struct dnsserver_zone *z,
440 const char *name,
441 struct dnsp_DnssrvRpcRecord *rec)
443 if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
444 if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
445 rec->rank = DNS_RANK_NS_GLUE;
446 } else {
447 rec->rank = DNS_RANK_ZONE;
449 } else if (strcmp(z->name, ".") == 0) {
450 rec->rank = DNS_RANK_ROOT_HINT;
455 /* Add a DNS record */
456 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
457 struct ldb_context *samdb,
458 struct dnsserver_zone *z,
459 const char *name,
460 struct DNS_RPC_RECORD *add_record)
462 const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
463 struct ldb_result *res;
464 struct dnsp_DnssrvRpcRecord *rec = NULL;
465 struct ldb_message_element *el;
466 struct ldb_dn *dn;
467 enum ndr_err_code ndr_err;
468 int ret, i;
469 int serial;
470 WERROR werr;
471 bool was_tombstoned = false;
472 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
474 werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
475 if (!W_ERROR_IS_OK(werr)) {
476 return werr;
479 /* Set the correct rank for the record. */
480 set_record_rank(z, name, rec);
482 serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
483 if (serial < 0) {
484 return werr;
487 rec->dwSerial = serial;
488 rec->dwTimeStamp = 0;
490 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
491 "(&(objectClass=dnsNode)(name=%s))",
492 encoded_name);
493 if (ret != LDB_SUCCESS) {
494 return WERR_INTERNAL_DB_ERROR;
497 if (res->count == 0) {
498 dn = dnsserver_name_to_dn(mem_ctx, z, name);
499 W_ERROR_HAVE_NO_MEMORY(dn);
501 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
504 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
505 if (el == NULL) {
506 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
507 if (ret != LDB_SUCCESS) {
508 return WERR_NOT_ENOUGH_MEMORY;
512 was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
513 "dNSTombstoned", false);
514 if (was_tombstoned) {
515 el->num_values = 0;
518 for (i=0; i<el->num_values; i++) {
519 struct dnsp_DnssrvRpcRecord rec2;
521 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
522 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
523 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
524 return WERR_GEN_FAILURE;
527 if (dns_record_match(rec, &rec2)) {
528 break;
531 if (i < el->num_values) {
532 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
534 if (i == el->num_values) {
535 /* adding a new value */
536 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
537 W_ERROR_HAVE_NO_MEMORY(el->values);
538 el->num_values++;
541 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
542 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
543 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
544 return WERR_GEN_FAILURE;
547 el->flags = LDB_FLAG_MOD_REPLACE;
549 el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
550 if (el != NULL) {
551 el->flags = LDB_FLAG_MOD_DELETE;
554 ret = ldb_modify(samdb, res->msgs[0]);
555 if (ret != LDB_SUCCESS) {
556 return WERR_INTERNAL_DB_ERROR;
559 return WERR_OK;
563 /* Update a DNS record */
564 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
565 struct ldb_context *samdb,
566 struct dnsserver_zone *z,
567 const char *name,
568 struct DNS_RPC_RECORD *add_record,
569 struct DNS_RPC_RECORD *del_record)
571 const char * const attrs[] = { "dnsRecord", NULL };
572 struct ldb_result *res;
573 struct dnsp_DnssrvRpcRecord rec2;
574 struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
575 struct ldb_message_element *el;
576 enum ndr_err_code ndr_err;
577 int ret, i;
578 int serial;
579 WERROR werr;
580 bool updating_ttl = false;
581 char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
583 werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
584 if (!W_ERROR_IS_OK(werr)) {
585 return werr;
588 werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
589 if (!W_ERROR_IS_OK(werr)) {
590 return werr;
593 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
594 "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
595 encoded_name);
596 if (ret != LDB_SUCCESS) {
597 return WERR_INTERNAL_DB_ERROR;
600 if (res->count == 0) {
601 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
604 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
605 if (el == NULL || el->num_values == 0) {
606 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
609 for (i=0; i<el->num_values; i++) {
610 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
611 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
612 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
613 return WERR_GEN_FAILURE;
616 if (dns_record_match(arec, &rec2)) {
617 break;
620 if (i < el->num_values) {
622 * The record already exists, which is an error UNLESS we are
623 * doing an in-place update.
625 * Therefore we need to see if drec also matches, in which
626 * case it's OK, though we can only update dwTtlSeconds and
627 * reset the timestamp to zero.
629 updating_ttl = dns_record_match(drec, &rec2);
630 if (! updating_ttl) {
631 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
633 /* In this case the next loop is redundant */
636 for (i=0; i<el->num_values; i++) {
637 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
638 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
639 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
640 return WERR_GEN_FAILURE;
643 if (dns_record_match(drec, &rec2)) {
645 * we are replacing this one with arec, which is done
646 * by pushing arec into el->values[i] below, after the
647 * various manipulations.
649 break;
652 if (i == el->num_values) {
653 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
657 * If we're updating a SOA record, use the specified serial.
659 * Otherwise, if we are updating ttl in place (i.e., not changing
660 * .wType and .data on a record), we should increment the existing
661 * serial, and save to the SOA.
663 * Outside of those two cases, we look for the zone's SOA record and
664 * use its serial.
666 if (arec->wType != DNS_TYPE_SOA) {
667 if (updating_ttl) {
669 * In this case, we keep some of the old values.
671 arec->dwSerial = rec2.dwSerial;
672 arec->dwReserved = rec2.dwReserved;
674 * TODO: if the old TTL and the new TTL are
675 * different, the serial number is incremented.
677 } else {
678 arec->dwReserved = 0;
679 serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
680 if (serial < 0) {
681 return werr;
683 arec->dwSerial = serial;
687 /* Set the correct rank for the record. */
688 set_record_rank(z, name, arec);
690 * Successful RPC updates *always* zero timestamp and flags and set
691 * version.
693 arec->dwTimeStamp = 0;
694 arec->version = 5;
695 arec->flags = 0;
697 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
698 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
699 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
700 return WERR_GEN_FAILURE;
703 el->flags = LDB_FLAG_MOD_REPLACE;
704 ret = ldb_modify(samdb, res->msgs[0]);
705 if (ret != LDB_SUCCESS) {
706 return WERR_INTERNAL_DB_ERROR;
709 return WERR_OK;
713 /* Delete a DNS record */
714 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
715 struct ldb_context *samdb,
716 struct dnsserver_zone *z,
717 const char *name,
718 struct DNS_RPC_RECORD *del_record)
720 const char * const attrs[] = { "dnsRecord", NULL };
721 struct ldb_result *res;
722 struct dnsp_DnssrvRpcRecord *rec = NULL;
723 struct ldb_message_element *el;
724 enum ndr_err_code ndr_err;
725 int ret, i;
726 int serial;
727 WERROR werr;
729 serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
730 if (serial < 0) {
731 return werr;
734 werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
735 if (!W_ERROR_IS_OK(werr)) {
736 return werr;
739 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
740 "(&(objectClass=dnsNode)(name=%s))",
741 ldb_binary_encode_string(mem_ctx, name));
742 if (ret != LDB_SUCCESS) {
743 return WERR_INTERNAL_DB_ERROR;
746 if (res->count == 0) {
747 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
749 if (res->count > 1) {
750 return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
753 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
754 if (el == NULL || el->num_values == 0) {
755 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
758 for (i=0; i<el->num_values; i++) {
759 struct dnsp_DnssrvRpcRecord rec2;
761 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
762 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
763 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
764 return WERR_GEN_FAILURE;
767 if (dns_record_match(rec, &rec2)) {
768 break;
771 if (i == el->num_values) {
772 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
774 if (i < el->num_values-1) {
775 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
777 el->num_values--;
779 if (el->num_values == 0) {
780 ret = ldb_delete(samdb, res->msgs[0]->dn);
781 } else {
782 el->flags = LDB_FLAG_MOD_REPLACE;
783 ret = ldb_modify(samdb, res->msgs[0]);
785 if (ret != LDB_SUCCESS) {
786 return WERR_INTERNAL_DB_ERROR;
789 return WERR_OK;
793 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
794 struct ldb_message *msg,
795 struct dnsp_DnsProperty *prop)
797 DATA_BLOB *prop_blob;
798 enum ndr_err_code ndr_err;
799 int ret;
801 prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
802 if (prop_blob == NULL) return false;
804 ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
805 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
806 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
807 return false;
809 ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
810 if (ret != LDB_SUCCESS) {
811 return false;
813 return true;
816 WERROR dnsserver_db_do_reset_dword(struct ldb_context *samdb,
817 struct dnsserver_zone *z,
818 struct DNS_RPC_NAME_AND_PARAM *n_p)
820 struct ldb_message_element *element = NULL;
821 struct dnsp_DnsProperty *prop = NULL;
822 enum ndr_err_code err;
823 TALLOC_CTX *tmp_ctx = NULL;
824 const char * const attrs[] = {"dNSProperty", NULL};
825 struct ldb_result *res = NULL;
826 int i, ret, prop_id;
828 if (strcasecmp(n_p->pszNodeName, "Aging") == 0) {
829 z->zoneinfo->fAging = n_p->dwParam;
830 prop_id = DSPROPERTY_ZONE_AGING_STATE;
831 } else if (strcasecmp(n_p->pszNodeName, "RefreshInterval") == 0) {
832 z->zoneinfo->dwRefreshInterval = n_p->dwParam;
833 prop_id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
834 } else if (strcasecmp(n_p->pszNodeName, "NoRefreshInterval") == 0) {
835 z->zoneinfo->dwNoRefreshInterval = n_p->dwParam;
836 prop_id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
837 } else if (strcasecmp(n_p->pszNodeName, "AllowUpdate") == 0) {
838 z->zoneinfo->fAllowUpdate = n_p->dwParam;
839 prop_id = DSPROPERTY_ZONE_ALLOW_UPDATE;
840 } else {
841 return WERR_UNKNOWN_PROPERTY;
844 tmp_ctx = talloc_new(NULL);
845 if (tmp_ctx == NULL) {
846 return WERR_NOT_ENOUGH_MEMORY;
849 ret = ldb_search(samdb, tmp_ctx, &res, z->zone_dn, LDB_SCOPE_BASE,
850 attrs, "(objectClass=dnsZone)");
851 if (ret != LDB_SUCCESS) {
852 DBG_ERR("dnsserver: no zone: %s\n",
853 ldb_dn_get_linearized(z->zone_dn));
854 TALLOC_FREE(tmp_ctx);
855 return WERR_INTERNAL_DB_ERROR;
858 if (res->count != 1) {
859 DBG_ERR("dnsserver: duplicate zone: %s\n",
860 ldb_dn_get_linearized(z->zone_dn));
861 TALLOC_FREE(tmp_ctx);
862 return WERR_GEN_FAILURE;
865 element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
866 if (element == NULL) {
867 DBG_ERR("dnsserver: zone %s has no properties.\n",
868 ldb_dn_get_linearized(z->zone_dn));
869 TALLOC_FREE(tmp_ctx);
870 return WERR_INTERNAL_DB_ERROR;
873 for (i = 0; i < element->num_values; i++) {
874 prop = talloc_zero(element, struct dnsp_DnsProperty);
875 if (prop == NULL) {
876 TALLOC_FREE(tmp_ctx);
877 return WERR_NOT_ENOUGH_MEMORY;
879 err = ndr_pull_struct_blob(
880 &(element->values[i]),
881 tmp_ctx,
882 prop,
883 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
884 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
886 * If we can't pull it then try again parsing
887 * it again. A Windows server in the domain
888 * will permit the addition of an invalidly
889 * formed property with a 0 length and cause a
890 * failure here
892 struct dnsp_DnsProperty_short
893 *short_property
894 = talloc_zero(element,
895 struct dnsp_DnsProperty_short);
896 if (short_property == NULL) {
897 TALLOC_FREE(tmp_ctx);
898 return WERR_NOT_ENOUGH_MEMORY;
900 err = ndr_pull_struct_blob_all(
901 &(element->values[i]),
902 tmp_ctx,
903 short_property,
904 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty_short);
905 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
907 * Unknown invalid data should be
908 * ignored and logged to match Windows
909 * behaviour
911 DBG_NOTICE("dnsserver: couldn't PULL "
912 "dnsProperty value#%d in "
913 "zone %s while trying to "
914 "reset id %d\n",
916 ldb_dn_get_linearized(z->zone_dn),
917 prop_id);
918 continue;
922 * Initialise the parts of the property not
923 * overwritten by value() in the IDL for
924 * re-push
926 *prop = (struct dnsp_DnsProperty){
927 .namelength = short_property->namelength,
928 .id = short_property->id,
929 .name = short_property->name
930 /* .data will be filled in below */
934 if (prop->id == prop_id) {
935 switch (prop_id) {
936 case DSPROPERTY_ZONE_AGING_STATE:
937 prop->data.aging_enabled = n_p->dwParam;
938 break;
939 case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
940 prop->data.norefresh_hours = n_p->dwParam;
941 break;
942 case DSPROPERTY_ZONE_REFRESH_INTERVAL:
943 prop->data.refresh_hours = n_p->dwParam;
944 break;
945 case DSPROPERTY_ZONE_ALLOW_UPDATE:
946 prop->data.allow_update_flag = n_p->dwParam;
947 break;
950 err = ndr_push_struct_blob(
951 &(element->values[i]),
952 tmp_ctx,
953 prop,
954 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
955 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
956 DBG_ERR("dnsserver: couldn't PUSH dns prop id "
957 "%d in zone %s\n",
958 prop->id,
959 ldb_dn_get_linearized(z->zone_dn));
960 TALLOC_FREE(tmp_ctx);
961 return WERR_INTERNAL_DB_ERROR;
966 element->flags = LDB_FLAG_MOD_REPLACE;
967 ret = ldb_modify(samdb, res->msgs[0]);
968 if (ret != LDB_SUCCESS) {
969 TALLOC_FREE(tmp_ctx);
970 DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
971 z->name,
972 n_p->pszNodeName,
973 ldb_errstring(samdb));
974 return WERR_INTERNAL_DB_ERROR;
976 TALLOC_FREE(tmp_ctx);
978 return WERR_OK;
981 /* Create dnsZone record to database and set security descriptor */
982 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
983 struct ldb_context *samdb,
984 struct ldb_dn *zone_dn,
985 struct dnsserver_zone *z)
987 const char * const attrs[] = { "objectSID", NULL };
988 struct ldb_message *msg;
989 struct ldb_result *res;
990 struct ldb_message_element *el;
991 const char sddl_template[] = "D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;CC;;;AU)(A;;RPLCLORC;;;WD)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)(A;CIID;LC;;;RU)(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)S:AI";
992 char *sddl;
993 struct dom_sid dnsadmins_sid;
994 const struct dom_sid *domain_sid;
995 struct security_descriptor *secdesc;
996 struct dnsp_DnsProperty *prop;
997 DATA_BLOB *sd_encoded;
998 enum ndr_err_code ndr_err;
999 int ret;
1001 /* Get DnsAdmins SID */
1002 ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
1003 LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
1004 if (ret != LDB_SUCCESS || res->count != 1) {
1005 return WERR_INTERNAL_DB_ERROR;
1008 el = ldb_msg_find_element(res->msgs[0], "objectSID");
1009 if (el == NULL || el->num_values != 1) {
1010 return WERR_INTERNAL_DB_ERROR;
1013 ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
1014 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1015 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1016 return WERR_INTERNAL_DB_ERROR;
1019 /* create security descriptor with DnsAdmins GUID in sddl template */
1020 sddl = talloc_asprintf(tmp_ctx, sddl_template,
1021 dom_sid_string(tmp_ctx, &dnsadmins_sid));
1022 if (sddl == NULL) {
1023 return WERR_NOT_ENOUGH_MEMORY;
1025 talloc_free(res);
1027 domain_sid = samdb_domain_sid(samdb);
1028 if (domain_sid == NULL) {
1029 return WERR_INTERNAL_DB_ERROR;
1032 secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
1033 if (secdesc == NULL) {
1034 return WERR_GEN_FAILURE;
1037 msg = ldb_msg_new(tmp_ctx);
1038 W_ERROR_HAVE_NO_MEMORY(msg);
1040 msg->dn = zone_dn;
1041 ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
1042 if (ret != LDB_SUCCESS) {
1043 return WERR_NOT_ENOUGH_MEMORY;
1046 sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
1047 W_ERROR_HAVE_NO_MEMORY(sd_encoded);
1049 ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
1050 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
1051 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1052 return WERR_GEN_FAILURE;
1055 ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
1056 if (ret != LDB_SUCCESS) {
1057 return WERR_NOT_ENOUGH_MEMORY;
1060 /* dns zone Properties */
1061 prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
1062 W_ERROR_HAVE_NO_MEMORY(prop);
1064 prop->version = 1;
1066 /* zone type */
1067 prop->id = DSPROPERTY_ZONE_TYPE;
1068 prop->data.zone_type = z->zoneinfo->dwZoneType;
1069 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1070 return WERR_NOT_ENOUGH_MEMORY;
1073 /* allow update */
1074 prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
1075 prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
1076 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1077 return WERR_NOT_ENOUGH_MEMORY;
1080 /* secure time */
1081 prop->id = DSPROPERTY_ZONE_SECURE_TIME;
1082 prop->data.zone_secure_time = 0;
1083 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1084 return WERR_NOT_ENOUGH_MEMORY;
1087 /* norefresh interval */
1088 prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
1089 prop->data.norefresh_hours = 168;
1090 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1091 return WERR_NOT_ENOUGH_MEMORY;
1094 /* refresh interval */
1095 prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
1096 prop->data.refresh_hours = 168;
1097 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1098 return WERR_NOT_ENOUGH_MEMORY;
1101 /* aging state */
1102 prop->id = DSPROPERTY_ZONE_AGING_STATE;
1103 prop->data.aging_enabled = z->zoneinfo->fAging;
1104 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1105 return WERR_NOT_ENOUGH_MEMORY;
1108 /* aging enabled time */
1109 prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
1110 prop->data.next_scavenging_cycle_hours = 0;
1111 if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1112 return WERR_NOT_ENOUGH_MEMORY;
1115 talloc_free(prop);
1117 ret = ldb_add(samdb, msg);
1118 if (ret != LDB_SUCCESS) {
1119 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
1120 z->name, ldb_errstring(samdb)));
1122 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1123 return WERR_ACCESS_DENIED;
1126 return WERR_INTERNAL_DB_ERROR;
1129 return WERR_OK;
1133 /* Create new dnsZone record and @ record (SOA + NS) */
1134 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
1135 struct dnsserver_partition *partitions,
1136 struct dnsserver_zone *zone,
1137 struct loadparm_context *lp_ctx)
1139 struct dnsserver_partition *p;
1140 bool in_forest = false;
1141 WERROR status;
1142 struct ldb_dn *dn;
1143 TALLOC_CTX *tmp_ctx;
1144 struct dnsp_DnssrvRpcRecord *dns_rec;
1145 struct dnsp_soa soa;
1146 char *soa_email = NULL;
1147 const char *dnsdomain = NULL;
1148 struct ldb_val name_val = data_blob_string_const(zone->name);
1150 /* We only support primary zones for now */
1151 if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
1152 return WERR_CALL_NOT_IMPLEMENTED;
1155 /* Get the correct partition */
1156 if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
1157 in_forest = true;
1159 for (p = partitions; p; p = p->next) {
1160 if (in_forest == p->is_forest) {
1161 break;
1164 if (p == NULL) {
1165 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
1168 tmp_ctx = talloc_new(NULL);
1169 W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1171 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
1172 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
1174 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
1175 talloc_free(tmp_ctx);
1176 return WERR_NOT_ENOUGH_MEMORY;
1179 if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
1180 talloc_free(tmp_ctx);
1181 return WERR_NOT_ENOUGH_MEMORY;
1184 /* Add dnsZone record */
1185 status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
1186 if (!W_ERROR_IS_OK(status)) {
1187 talloc_free(tmp_ctx);
1188 return status;
1191 if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
1192 talloc_free(tmp_ctx);
1193 return WERR_NOT_ENOUGH_MEMORY;
1196 dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
1197 W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
1199 dnsdomain = lpcfg_dnsdomain(lp_ctx);
1200 if (dnsdomain == NULL) {
1201 talloc_free(tmp_ctx);
1202 return WERR_NOT_ENOUGH_MEMORY;
1204 soa_email = talloc_asprintf(tmp_ctx, "hostmaster.%s", dnsdomain);
1205 if (soa_email == NULL) {
1206 talloc_free(tmp_ctx);
1207 return WERR_NOT_ENOUGH_MEMORY;
1210 /* SOA Record - values same as defined in provision/sambadns.py */
1211 soa.serial = 1;
1212 soa.refresh = 900;
1213 soa.retry = 600;
1214 soa.expire = 86400;
1215 soa.minimum = 3600;
1216 soa.mname = dnsdomain;
1217 soa.rname = soa_email;
1219 dns_rec[0].wType = DNS_TYPE_SOA;
1220 dns_rec[0].rank = DNS_RANK_ZONE;
1221 dns_rec[0].dwSerial = soa.serial;
1222 dns_rec[0].dwTtlSeconds = 3600;
1223 dns_rec[0].dwTimeStamp = 0;
1224 dns_rec[0].data.soa = soa;
1226 /* NS Record */
1227 dns_rec[1].wType = DNS_TYPE_NS;
1228 dns_rec[1].rank = DNS_RANK_ZONE;
1229 dns_rec[1].dwSerial = soa.serial;
1230 dns_rec[1].dwTtlSeconds = 3600;
1231 dns_rec[1].dwTimeStamp = 0;
1232 dns_rec[1].data.ns = dnsdomain;
1234 /* Add @ Record */
1235 status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
1237 talloc_free(tmp_ctx);
1238 return status;
1242 /* Delete dnsZone record and all DNS records in the zone */
1243 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
1244 struct dnsserver_zone *zone)
1246 int ret;
1248 ret = ldb_transaction_start(samdb);
1249 if (ret != LDB_SUCCESS) {
1250 return WERR_INTERNAL_DB_ERROR;
1253 ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
1254 if (ret != LDB_SUCCESS) {
1255 ldb_transaction_cancel(samdb);
1257 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1258 return WERR_ACCESS_DENIED;
1260 return WERR_INTERNAL_DB_ERROR;
1263 ret = ldb_transaction_commit(samdb);
1264 if (ret != LDB_SUCCESS) {
1265 return WERR_INTERNAL_DB_ERROR;
1268 return WERR_OK;