1 /*
2    Unix SMB/CIFS implementation.
3 
4    DNS Server
5 
6    Copyright (C) Amitay Isaacs 2011
7 
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.
12 
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.
17 
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/>.
20 */
21 
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"
31 
32 /* There are only 2 fixed partitions for DNS */
dnsserver_db_enumerate_partitions(TALLOC_CTX * mem_ctx,struct dnsserver_serverinfo * serverinfo,struct ldb_context * samdb)33 struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
34 							struct dnsserver_serverinfo *serverinfo,
35 							struct ldb_context *samdb)
36 {
37 	struct dnsserver_partition *partitions, *p;
38 
39 	partitions = NULL;
40 
41 	/* Domain partition */
42 	p = talloc_zero(mem_ctx, struct dnsserver_partition);
43 	if (p == NULL) {
44 		goto failed;
45 	}
46 
47 	p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
48 	if (p->partition_dn == NULL) {
49 		goto failed;
50 	}
51 
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;
55 
56 	DLIST_ADD_END(partitions, p);
57 
58 	/* Forest Partition */
59 	p = talloc_zero(mem_ctx, struct dnsserver_partition);
60 	if (p == NULL) {
61 		goto failed;
62 	}
63 
64 	p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
65 	if (p->partition_dn == NULL) {
66 		goto failed;
67 	}
68 
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;
72 
73 	DLIST_ADD_END(partitions, p);
74 
75 	return partitions;
76 
77 failed:
78 	return NULL;
79 
80 }
81 
82 
83 /* Search for all dnsZone records */
dnsserver_db_enumerate_zones(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_partition * p)84 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
85 						struct ldb_context *samdb,
86 						struct dnsserver_partition *p)
87 {
88 	TALLOC_CTX *tmp_ctx;
89 	const char * const attrs[] = {"name", "dNSProperty", NULL};
90 	struct ldb_dn *dn;
91 	struct ldb_result *res;
92 	struct dnsserver_zone *zones, *z;
93 	int i, j, ret;
94 
95 	tmp_ctx = talloc_new(mem_ctx);
96 	if (tmp_ctx == NULL) {
97 		return NULL;
98 	}
99 
100 	dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
101 	if (dn == NULL) {
102 		goto failed;
103 	}
104 	if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
105 		goto failed;
106 	}
107 
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;
114 	}
115 
116 	zones = NULL;
117 	for(i=0; i<res->count; i++) {
118 		char *name;
119 		struct ldb_message_element *element = NULL;
120 		struct dnsp_DnsProperty *props = NULL;
121 		enum ndr_err_code err;
122 		z = talloc_zero(mem_ctx, struct dnsserver_zone);
123 		if (z == NULL) {
124 			goto failed;
125 		}
126 
127 		z->partition = p;
128 		name = talloc_strdup(z,
129 				ldb_msg_find_attr_as_string(res->msgs[i],
130 							    "name", NULL));
131 		if (strcmp(name, "..TrustAnchors") == 0) {
132 			talloc_free(z);
133 			continue;
134 		}
135 		if (strcmp(name, "RootDNSServers") == 0) {
136 			talloc_free(name);
137 			z->name = talloc_strdup(z, ".");
138 		} else {
139 			z->name = name;
140 		}
141 		z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
142 
143 		DLIST_ADD_END(zones, z);
144 		DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
145 
146 		element = ldb_msg_find_element(res->msgs[i], "dNSProperty");
147 		if(element != NULL){
148 			props = talloc_zero_array(tmp_ctx,
149 						  struct dnsp_DnsProperty,
150 						  element->num_values);
151 			for (j = 0; j < element->num_values; j++ ) {
152 				err = ndr_pull_struct_blob(
153 					&(element->values[j]),
154 					mem_ctx,
155 					&props[j],
156 					(ndr_pull_flags_fn_t)
157 						ndr_pull_dnsp_DnsProperty);
158 				if (!NDR_ERR_CODE_IS_SUCCESS(err)){
159 					/*
160 					 * Per Microsoft we must
161 					 * ignore invalid data here
162 					 * and continue as a Windows
163 					 * server can put in a
164 					 * structure with an invalid
165 					 * length.
166 					 *
167 					 * We can safely fill in an
168 					 * extra empty property here
169 					 * because
170 					 * dns_zoneinfo_load_zone_property()
171 					 * just ignores
172 					 * DSPROPERTY_ZONE_EMPTY
173 					 */
174 					ZERO_STRUCT(props[j]);
175 					props[j].id = DSPROPERTY_ZONE_EMPTY;
176 					continue;
177 				}
178 			}
179 			z->tmp_props = props;
180 			z->num_props = element->num_values;
181 		}
182 	}
183 	return zones;
184 
185 failed:
186 	talloc_free(tmp_ctx);
187 	return NULL;
188 }
189 
190 
191 /* Find DNS partition information */
dnsserver_db_partition_info(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_partition * p)192 struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
193 							struct ldb_context *samdb,
194 							struct dnsserver_partition *p)
195 {
196 	const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
197 	const char * const attrs_none[] = { NULL };
198 	struct ldb_result *res;
199 	struct ldb_message_element *el;
200 	struct ldb_dn *dn;
201 	struct dnsserver_partition_info *partinfo;
202 	int i, ret, instance_type;
203 	TALLOC_CTX *tmp_ctx;
204 
205 	tmp_ctx = talloc_new(mem_ctx);
206 	if (tmp_ctx == NULL) {
207 		return NULL;
208 	}
209 
210 	partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
211 	if (partinfo == NULL) {
212 		talloc_free(tmp_ctx);
213 		return NULL;
214 	}
215 
216 	/* Search for the active replica and state */
217 	ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
218 			attrs, NULL);
219 	if (ret != LDB_SUCCESS || res->count != 1) {
220 		goto failed;
221 	}
222 
223 	/* Set the state of the partition */
224 	instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
225 	if (instance_type == -1) {
226 		partinfo->dwState = DNS_DP_STATE_UNKNOWN;
227 	} else if (instance_type & INSTANCE_TYPE_NC_COMING) {
228 		partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
229 	} else if (instance_type & INSTANCE_TYPE_NC_GOING) {
230 		partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
231 	} else {
232 		partinfo->dwState = DNS_DP_OKAY;
233 	}
234 
235 	el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
236 	if (el == NULL) {
237 		partinfo->dwReplicaCount = 0;
238 		partinfo->ReplicaArray = NULL;
239 	} else {
240 		partinfo->dwReplicaCount = el->num_values;
241 		partinfo->ReplicaArray = talloc_zero_array(partinfo,
242 							   struct DNS_RPC_DP_REPLICA *,
243 							   el->num_values);
244 		if (partinfo->ReplicaArray == NULL) {
245 			goto failed;
246 		}
247 		for (i=0; i<el->num_values; i++) {
248 			partinfo->ReplicaArray[i] = talloc_zero(partinfo,
249 							struct DNS_RPC_DP_REPLICA);
250 			if (partinfo->ReplicaArray[i] == NULL) {
251 				goto failed;
252 			}
253 			partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
254 									partinfo,
255 									(const char *)el->values[i].data);
256 			if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
257 				goto failed;
258 			}
259 		}
260 	}
261 	talloc_free(res);
262 
263 	/* Search for cross-reference object */
264 	dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
265 	if (dn == NULL) {
266 		goto failed;
267 	}
268 
269 	ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
270 			"(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
271 	if (ret != LDB_SUCCESS || res->count != 1) {
272 		goto failed;
273 	}
274 	partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
275 	if (partinfo->pszCrDn == NULL) {
276 		goto failed;
277 	}
278 	talloc_free(res);
279 
280 	talloc_free(tmp_ctx);
281 	return partinfo;
282 
283 failed:
284 	talloc_free(tmp_ctx);
285 	talloc_free(partinfo);
286 	return NULL;
287 }
288 
289 
290 /* Increment serial number and update timestamp */
dnsserver_update_soa(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_zone * z,WERROR * werr)291 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
292 				struct ldb_context *samdb,
293 				struct dnsserver_zone *z,
294 				WERROR *werr)
295 {
296 	const char * const attrs[] = { "dnsRecord", NULL };
297 	struct ldb_result *res;
298 	struct dnsp_DnssrvRpcRecord rec;
299 	struct ldb_message_element *el;
300 	enum ndr_err_code ndr_err;
301 	int ret, i, serial = -1;
302 
303 	*werr = WERR_INTERNAL_DB_ERROR;
304 
305 	ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
306 			"(&(objectClass=dnsNode)(name=@))");
307 	if (ret != LDB_SUCCESS || res->count == 0) {
308 		return -1;
309 	}
310 
311 	el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
312 	if (el == NULL) {
313 		return -1;
314 	}
315 
316 	for (i=0; i<el->num_values; i++) {
317 		ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
318 					(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
319 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
320 			continue;
321 		}
322 
323 		if (rec.wType == DNS_TYPE_SOA) {
324 			serial = rec.data.soa.serial + 1;
325 			rec.dwSerial = serial;
326 			rec.dwTimeStamp = 0;
327 			rec.data.soa.serial = serial;
328 
329 			ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
330 					(ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
331 			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
332 				*werr = WERR_NOT_ENOUGH_MEMORY;
333 				return -1;
334 			}
335 			break;
336 		}
337 	}
338 
339 	if (serial != -1) {
340 		el->flags = LDB_FLAG_MOD_REPLACE;
341 		ret = ldb_modify(samdb, res->msgs[0]);
342 		if (ret != LDB_SUCCESS) {
343 			if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
344 				*werr = WERR_ACCESS_DENIED;
345 			}
346 			return -1;
347 		}
348 	}
349 
350 	*werr = WERR_OK;
351 
352 	return serial;
353 }
354 
355 
356 /* Add DNS record to the database */
dnsserver_db_do_add_rec(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct ldb_dn * dn,int num_rec,struct dnsp_DnssrvRpcRecord * rec)357 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
358 				struct ldb_context *samdb,
359 				struct ldb_dn *dn,
360 				int num_rec,
361 				struct dnsp_DnssrvRpcRecord *rec)
362 {
363 	struct ldb_message *msg;
364 	struct ldb_val v;
365 	int ret;
366 	enum ndr_err_code ndr_err;
367 	int i;
368 
369 	msg = ldb_msg_new(mem_ctx);
370 	W_ERROR_HAVE_NO_MEMORY(msg);
371 
372 	msg->dn = dn;
373 	ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
374 	if (ret != LDB_SUCCESS) {
375 		return WERR_NOT_ENOUGH_MEMORY;
376 	}
377 
378 	if (num_rec > 0 && rec) {
379 		for (i=0; i<num_rec; i++) {
380 			ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
381 					(ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
382 			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
383 				return WERR_GEN_FAILURE;
384 			}
385 
386 			ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
387 			if (ret != LDB_SUCCESS) {
388 				return WERR_NOT_ENOUGH_MEMORY;
389 			}
390 		}
391 	}
392 
393 	ret = ldb_add(samdb, msg);
394 	if (ret != LDB_SUCCESS) {
395 		return WERR_INTERNAL_DB_ERROR;
396 	}
397 
398 	return WERR_OK;
399 }
400 
401 
402 /* Add dnsNode record to the database with DNS record */
dnsserver_db_add_empty_node(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_zone * z,const char * name)403 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
404 					struct ldb_context *samdb,
405 					struct dnsserver_zone *z,
406 					const char *name)
407 {
408 	const char * const attrs[] = { "name", NULL };
409 	struct ldb_result *res;
410 	struct ldb_dn *dn;
411 	char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
412 	struct ldb_val name_val = data_blob_string_const(name);
413 	int ret;
414 
415 	ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
416 			"(&(objectClass=dnsNode)(name=%s))",
417 			 encoded_name);
418 	if (ret != LDB_SUCCESS) {
419 		return WERR_INTERNAL_DB_ERROR;
420 	}
421 
422 	if (res->count > 0) {
423 		talloc_free(res);
424 		return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
425 	}
426 
427 	dn = ldb_dn_copy(mem_ctx, z->zone_dn);
428 	W_ERROR_HAVE_NO_MEMORY(dn);
429 
430 	if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
431 		return WERR_NOT_ENOUGH_MEMORY;
432 	}
433 
434 	return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
435 }
436 
437 
438 /* Add a DNS record */
dnsserver_db_add_record(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_zone * z,const char * name,struct DNS_RPC_RECORD * add_record)439 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
440 					struct ldb_context *samdb,
441 					struct dnsserver_zone *z,
442 					const char *name,
443 					struct DNS_RPC_RECORD *add_record)
444 {
445 	const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
446 	struct ldb_result *res;
447 	struct dnsp_DnssrvRpcRecord *rec = NULL;
448 	struct ldb_message_element *el;
449 	struct ldb_dn *dn;
450 	enum ndr_err_code ndr_err;
451 	int ret, i;
452 	int serial;
453 	WERROR werr;
454 	bool was_tombstoned = false;
455 	char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
456 
457 	werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
458 	if (!W_ERROR_IS_OK(werr)) {
459 		return werr;
460 	}
461 
462 	/* Set the correct rank for the record. */
463 	if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
464 		if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
465 			rec->rank = DNS_RANK_NS_GLUE;
466 		} else {
467 			rec->rank |= DNS_RANK_ZONE;
468 		}
469 	} else if (strcmp(z->name, ".") == 0) {
470 		rec->rank |= DNS_RANK_ROOT_HINT;
471 	}
472 
473 	serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
474 	if (serial < 0) {
475 		return werr;
476 	}
477 
478 	rec->dwSerial = serial;
479 	rec->dwTimeStamp = 0;
480 
481 	ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
482 			"(&(objectClass=dnsNode)(name=%s))",
483 			 encoded_name);
484 	if (ret != LDB_SUCCESS) {
485 		return WERR_INTERNAL_DB_ERROR;
486 	}
487 
488 	if (res->count == 0) {
489 		dn = dnsserver_name_to_dn(mem_ctx, z, name);
490 		W_ERROR_HAVE_NO_MEMORY(dn);
491 
492 		return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
493 	}
494 
495 	el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
496 	if (el == NULL) {
497 		ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
498 		if (ret != LDB_SUCCESS) {
499 			return WERR_NOT_ENOUGH_MEMORY;
500 		}
501 	}
502 
503 	was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
504 						   "dNSTombstoned", false);
505 	if (was_tombstoned) {
506 		el->num_values = 0;
507 	}
508 
509 	for (i=0; i<el->num_values; i++) {
510 		struct dnsp_DnssrvRpcRecord rec2;
511 
512 		ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
513 						(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
514 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
515 			return WERR_GEN_FAILURE;
516 		}
517 
518 		if (dns_record_match(rec, &rec2)) {
519 			break;
520 		}
521 	}
522 	if (i < el->num_values) {
523 		return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
524 	}
525 	if (i == el->num_values) {
526 		/* adding a new value */
527 		el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
528 		W_ERROR_HAVE_NO_MEMORY(el->values);
529 		el->num_values++;
530 	}
531 
532 	ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
533 					(ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
534 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
535 		return WERR_GEN_FAILURE;
536 	}
537 
538 	el->flags = LDB_FLAG_MOD_REPLACE;
539 
540 	el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
541 	if (el != NULL) {
542 		el->flags = LDB_FLAG_MOD_DELETE;
543 	}
544 
545 	ret = ldb_modify(samdb, res->msgs[0]);
546 	if (ret != LDB_SUCCESS) {
547 		return WERR_INTERNAL_DB_ERROR;
548 	}
549 
550 	return WERR_OK;
551 }
552 
553 
554 /* Update a DNS record */
dnsserver_db_update_record(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_zone * z,const char * name,struct DNS_RPC_RECORD * add_record,struct DNS_RPC_RECORD * del_record)555 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
556 					struct ldb_context *samdb,
557 					struct dnsserver_zone *z,
558 					const char *name,
559 					struct DNS_RPC_RECORD *add_record,
560 					struct DNS_RPC_RECORD *del_record)
561 {
562 	const char * const attrs[] = { "dnsRecord", NULL };
563 	struct ldb_result *res;
564 	struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
565 	struct ldb_message_element *el;
566 	enum ndr_err_code ndr_err;
567 	int ret, i;
568 	int serial;
569 	WERROR werr;
570 	char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
571 
572 	werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
573 	if (!W_ERROR_IS_OK(werr)) {
574 		return werr;
575 	}
576 
577 	werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
578 	if (!W_ERROR_IS_OK(werr)) {
579 		return werr;
580 	}
581 
582 	arec->dwTimeStamp = 0;
583 
584 	ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
585 			"(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
586 			 encoded_name);
587 	if (ret != LDB_SUCCESS) {
588 		return WERR_INTERNAL_DB_ERROR;
589 	}
590 
591 	if (res->count == 0) {
592 		return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
593 	}
594 
595 	el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
596 	if (el == NULL || el->num_values == 0) {
597 		return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
598 	}
599 
600 	for (i=0; i<el->num_values; i++) {
601 		struct dnsp_DnssrvRpcRecord rec2;
602 
603 		ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
604 						(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
605 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
606 			return WERR_GEN_FAILURE;
607 		}
608 
609 		if (dns_record_match(arec, &rec2)) {
610 			break;
611 		}
612 	}
613 	if (i < el->num_values) {
614 		return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
615 	}
616 
617 
618 	for (i=0; i<el->num_values; i++) {
619 		struct dnsp_DnssrvRpcRecord rec2;
620 
621 		ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
622 						(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
623 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
624 			return WERR_GEN_FAILURE;
625 		}
626 
627 		if (dns_record_match(drec, &rec2)) {
628 			break;
629 		}
630 	}
631 	if (i == el->num_values) {
632 		return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
633 	}
634 
635 	/* If updating SOA record, use specified serial, otherwise increment */
636 	if (arec->wType != DNS_TYPE_SOA) {
637 		serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
638 		if (serial < 0) {
639 			return werr;
640 		}
641 		arec->dwSerial = serial;
642 	}
643 
644 	ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
645 					(ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
646 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
647 		return WERR_GEN_FAILURE;
648 	}
649 
650 	el->flags = LDB_FLAG_MOD_REPLACE;
651 	ret = ldb_modify(samdb, res->msgs[0]);
652 	if (ret != LDB_SUCCESS) {
653 		return WERR_INTERNAL_DB_ERROR;
654 	}
655 
656 	return WERR_OK;
657 }
658 
659 
660 /* Delete a DNS record */
dnsserver_db_delete_record(TALLOC_CTX * mem_ctx,struct ldb_context * samdb,struct dnsserver_zone * z,const char * name,struct DNS_RPC_RECORD * del_record)661 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
662 					struct ldb_context *samdb,
663 					struct dnsserver_zone *z,
664 					const char *name,
665 					struct DNS_RPC_RECORD *del_record)
666 {
667 	const char * const attrs[] = { "dnsRecord", NULL };
668 	struct ldb_result *res;
669 	struct dnsp_DnssrvRpcRecord *rec = NULL;
670 	struct ldb_message_element *el;
671 	enum ndr_err_code ndr_err;
672 	int ret, i;
673 	int serial;
674 	WERROR werr;
675 
676 	serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
677 	if (serial < 0) {
678 		return werr;
679 	}
680 
681 	werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
682 	if (!W_ERROR_IS_OK(werr)) {
683 		return werr;
684 	}
685 
686 	ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
687 			"(&(objectClass=dnsNode)(name=%s))",
688 			 ldb_binary_encode_string(mem_ctx, name));
689 	if (ret != LDB_SUCCESS) {
690 		return WERR_INTERNAL_DB_ERROR;
691 	}
692 
693 	if (res->count == 0) {
694 		return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
695 	}
696 	if (res->count > 1) {
697 		return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
698 	}
699 
700 	el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
701 	if (el == NULL || el->num_values == 0) {
702 		return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
703 	}
704 
705 	for (i=0; i<el->num_values; i++) {
706 		struct dnsp_DnssrvRpcRecord rec2;
707 
708 		ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
709 						(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
710 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
711 			return WERR_GEN_FAILURE;
712 		}
713 
714 		if (dns_record_match(rec, &rec2)) {
715 			break;
716 		}
717 	}
718 	if (i == el->num_values) {
719 		return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
720 	}
721 	if (i < el->num_values-1) {
722 		memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
723 	}
724 	el->num_values--;
725 
726 	if (el->num_values == 0) {
727 		ret = ldb_delete(samdb, res->msgs[0]->dn);
728 	} else {
729 		el->flags = LDB_FLAG_MOD_REPLACE;
730 		ret = ldb_modify(samdb, res->msgs[0]);
731 	}
732 	if (ret != LDB_SUCCESS) {
733 		return WERR_INTERNAL_DB_ERROR;
734 	}
735 
736 	return WERR_OK;
737 }
738 
739 
dnsserver_db_msg_add_dnsproperty(TALLOC_CTX * mem_ctx,struct ldb_message * msg,struct dnsp_DnsProperty * prop)740 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
741 					     struct ldb_message *msg,
742 					     struct dnsp_DnsProperty *prop)
743 {
744 	DATA_BLOB *prop_blob;
745 	enum ndr_err_code ndr_err;
746 	int ret;
747 
748 	prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
749 	if (prop_blob == NULL) return false;
750 
751 	ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
752 			(ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
753 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
754 		return false;
755 	}
756 	ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
757 	if (ret != LDB_SUCCESS) {
758 		return false;
759 	}
760 	return true;
761 }
762 
dnsserver_db_do_reset_dword(struct ldb_context * samdb,struct dnsserver_zone * z,struct DNS_RPC_NAME_AND_PARAM * n_p)763 WERROR dnsserver_db_do_reset_dword(struct ldb_context *samdb,
764 				   struct dnsserver_zone *z,
765 				   struct DNS_RPC_NAME_AND_PARAM *n_p)
766 {
767 	struct ldb_message_element *element = NULL;
768 	struct dnsp_DnsProperty *prop = NULL;
769 	enum ndr_err_code err;
770 	TALLOC_CTX *tmp_ctx = NULL;
771 	const char * const attrs[] = {"dNSProperty", NULL};
772 	struct ldb_result *res = NULL;
773 	int i, ret, prop_id;
774 
775 	if (strcasecmp(n_p->pszNodeName, "Aging") == 0) {
776 		z->zoneinfo->fAging = n_p->dwParam;
777 		prop_id = DSPROPERTY_ZONE_AGING_STATE;
778 	} else if (strcasecmp(n_p->pszNodeName, "RefreshInterval") == 0) {
779 		z->zoneinfo->dwRefreshInterval = n_p->dwParam;
780 		prop_id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
781 	} else if (strcasecmp(n_p->pszNodeName, "NoRefreshInterval") == 0) {
782 		z->zoneinfo->dwNoRefreshInterval = n_p->dwParam;
783 		prop_id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
784 	} else if (strcasecmp(n_p->pszNodeName, "AllowUpdate") == 0) {
785 		z->zoneinfo->fAllowUpdate = n_p->dwParam;
786 		prop_id = DSPROPERTY_ZONE_ALLOW_UPDATE;
787 	} else {
788 		return WERR_UNKNOWN_PROPERTY;
789 	}
790 
791 	tmp_ctx = talloc_new(NULL);
792 	if (tmp_ctx == NULL) {
793 		return WERR_NOT_ENOUGH_MEMORY;
794 	}
795 
796 	ret = ldb_search(samdb, tmp_ctx, &res, z->zone_dn, LDB_SCOPE_BASE,
797 			 attrs, "(objectClass=dnsZone)");
798 	if (ret != LDB_SUCCESS) {
799 		DBG_ERR("dnsserver: no zone: %s\n",
800 			ldb_dn_get_linearized(z->zone_dn));
801 		TALLOC_FREE(tmp_ctx);
802 		return WERR_INTERNAL_DB_ERROR;
803 	}
804 
805 	if (res->count != 1) {
806 		DBG_ERR("dnsserver: duplicate zone: %s\n",
807 			ldb_dn_get_linearized(z->zone_dn));
808 		TALLOC_FREE(tmp_ctx);
809 		return WERR_GEN_FAILURE;
810 	}
811 
812 	element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
813 	if (element == NULL) {
814 		DBG_ERR("dnsserver: zone %s has no properties.\n",
815 			ldb_dn_get_linearized(z->zone_dn));
816 		TALLOC_FREE(tmp_ctx);
817 		return WERR_INTERNAL_DB_ERROR;
818 	}
819 
820 	for (i = 0; i < element->num_values; i++) {
821 		prop = talloc_zero(element, struct dnsp_DnsProperty);
822 		if (prop == NULL) {
823 			TALLOC_FREE(tmp_ctx);
824 			return WERR_NOT_ENOUGH_MEMORY;
825 		}
826 		err = ndr_pull_struct_blob(
827 			&(element->values[i]),
828 			tmp_ctx,
829 			prop,
830 			(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
831 		if (!NDR_ERR_CODE_IS_SUCCESS(err)){
832 			/*
833 			 * If we can't pull it then try again parsing
834 			 * it again.  A Windows server in the domain
835 			 * will permit the addition of an invalidly
836 			 * formed property with a 0 length and cause a
837 			 * failure here
838 			 */
839 			struct dnsp_DnsProperty_short
840 				*short_property
841 				= talloc_zero(element,
842 					      struct dnsp_DnsProperty_short);
843 			if (short_property == NULL) {
844 				TALLOC_FREE(tmp_ctx);
845 				return WERR_NOT_ENOUGH_MEMORY;
846 			}
847 			err = ndr_pull_struct_blob_all(
848 				&(element->values[i]),
849 				tmp_ctx,
850 				short_property,
851 				(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty_short);
852 			if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
853 				/*
854 				 * Unknown invalid data should be
855 				 * ignored and logged to match Windows
856 				 * behaviour
857 				 */
858 				DBG_NOTICE("dnsserver: couldn't PULL "
859 					   "dnsProperty value#%d in "
860 					   "zone %s while trying to "
861 					   "reset id %d\n",
862 					   i,
863 					   ldb_dn_get_linearized(z->zone_dn),
864 					   prop_id);
865 				continue;
866 			}
867 
868 			/*
869 			 * Initialise the parts of the property not
870 			 * overwritten by value() in the IDL for
871 			 * re-push
872 			 */
873 			*prop = (struct dnsp_DnsProperty){
874 				.namelength = short_property->namelength,
875 				.id = short_property->id,
876 				.name = short_property->name
877 				/* .data will be filled in below */
878 			};
879 		}
880 
881 		if (prop->id == prop_id) {
882 			switch (prop_id) {
883 			case DSPROPERTY_ZONE_AGING_STATE:
884 				prop->data.aging_enabled = n_p->dwParam;
885 				break;
886 			case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
887 				prop->data.norefresh_hours = n_p->dwParam;
888 				break;
889 			case DSPROPERTY_ZONE_REFRESH_INTERVAL:
890 				prop->data.refresh_hours = n_p->dwParam;
891 				break;
892 			case DSPROPERTY_ZONE_ALLOW_UPDATE:
893 				prop->data.allow_update_flag = n_p->dwParam;
894 				break;
895 			}
896 
897 			err = ndr_push_struct_blob(
898 				&(element->values[i]),
899 				tmp_ctx,
900 				prop,
901 				(ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
902 			if (!NDR_ERR_CODE_IS_SUCCESS(err)){
903 				DBG_ERR("dnsserver: couldn't PUSH dns prop id "
904 					"%d in zone %s\n",
905 					prop->id,
906 					ldb_dn_get_linearized(z->zone_dn));
907 				TALLOC_FREE(tmp_ctx);
908 				return WERR_INTERNAL_DB_ERROR;
909 			}
910 		}
911 	}
912 
913 	element->flags = LDB_FLAG_MOD_REPLACE;
914 	ret = ldb_modify(samdb, res->msgs[0]);
915 	if (ret != LDB_SUCCESS) {
916 		TALLOC_FREE(tmp_ctx);
917 		DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
918 			z->name,
919 			n_p->pszNodeName,
920 			ldb_errstring(samdb));
921 		return WERR_INTERNAL_DB_ERROR;
922 	}
923 	TALLOC_FREE(tmp_ctx);
924 
925 	return WERR_OK;
926 }
927 
928 /* Create dnsZone record to database and set security descriptor */
dnsserver_db_do_create_zone(TALLOC_CTX * tmp_ctx,struct ldb_context * samdb,struct ldb_dn * zone_dn,struct dnsserver_zone * z)929 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
930 					  struct ldb_context *samdb,
931 					  struct ldb_dn *zone_dn,
932 					  struct dnsserver_zone *z)
933 {
934 	const char * const attrs[] = { "objectSID", NULL };
935 	struct ldb_message *msg;
936 	struct ldb_result *res;
937 	struct ldb_message_element *el;
938 	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";
939 	char *sddl;
940 	struct dom_sid dnsadmins_sid;
941 	const struct dom_sid *domain_sid;
942 	struct security_descriptor *secdesc;
943 	struct dnsp_DnsProperty *prop;
944 	DATA_BLOB *sd_encoded;
945 	enum ndr_err_code ndr_err;
946 	int ret;
947 
948 	/* Get DnsAdmins SID */
949 	ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
950 			 LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
951 	if (ret != LDB_SUCCESS || res->count != 1) {
952 		return WERR_INTERNAL_DB_ERROR;
953 	}
954 
955 	el = ldb_msg_find_element(res->msgs[0], "objectSID");
956 	if (el == NULL || el->num_values != 1) {
957 		return WERR_INTERNAL_DB_ERROR;
958 	}
959 
960 	ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
961 				(ndr_pull_flags_fn_t)ndr_pull_dom_sid);
962 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
963 		return WERR_INTERNAL_DB_ERROR;
964 	}
965 
966 	/* create security descriptor with DnsAdmins GUID in sddl template */
967 	sddl = talloc_asprintf(tmp_ctx, sddl_template,
968 			       dom_sid_string(tmp_ctx, &dnsadmins_sid));
969 	if (sddl == NULL) {
970 		return WERR_NOT_ENOUGH_MEMORY;
971 	}
972 	talloc_free(res);
973 
974 	domain_sid = samdb_domain_sid(samdb);
975 	if (domain_sid == NULL) {
976 		return WERR_INTERNAL_DB_ERROR;
977 	}
978 
979 	secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
980 	if (secdesc == NULL) {
981 		return WERR_GEN_FAILURE;
982 	}
983 
984 	msg = ldb_msg_new(tmp_ctx);
985 	W_ERROR_HAVE_NO_MEMORY(msg);
986 
987 	msg->dn = zone_dn;
988 	ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
989 	if (ret != LDB_SUCCESS) {
990 		return WERR_NOT_ENOUGH_MEMORY;
991 	}
992 
993 	sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
994 	W_ERROR_HAVE_NO_MEMORY(sd_encoded);
995 
996 	ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
997 			(ndr_push_flags_fn_t)ndr_push_security_descriptor);
998 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
999 		return WERR_GEN_FAILURE;
1000 	}
1001 
1002 	ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
1003 	if (ret != LDB_SUCCESS) {
1004 		return WERR_NOT_ENOUGH_MEMORY;
1005 	}
1006 
1007 	/* dns zone Properties */
1008 	prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
1009 	W_ERROR_HAVE_NO_MEMORY(prop);
1010 
1011 	prop->version = 1;
1012 
1013 	/* zone type */
1014 	prop->id = DSPROPERTY_ZONE_TYPE;
1015 	prop->data.zone_type = z->zoneinfo->dwZoneType;
1016 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1017 		return WERR_NOT_ENOUGH_MEMORY;
1018 	}
1019 
1020 	/* allow update */
1021 	prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
1022 	prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
1023 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1024 		return WERR_NOT_ENOUGH_MEMORY;
1025 	}
1026 
1027 	/* secure time */
1028 	prop->id = DSPROPERTY_ZONE_SECURE_TIME;
1029 	prop->data.zone_secure_time = 0;
1030 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1031 		return WERR_NOT_ENOUGH_MEMORY;
1032 	}
1033 
1034 	/* norefresh interval */
1035 	prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
1036 	prop->data.norefresh_hours = 168;
1037 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1038 		return WERR_NOT_ENOUGH_MEMORY;
1039 	}
1040 
1041 	/* refresh interval */
1042 	prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
1043 	prop->data.refresh_hours = 168;
1044 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1045 		return WERR_NOT_ENOUGH_MEMORY;
1046 	}
1047 
1048 	/* aging state */
1049 	prop->id = DSPROPERTY_ZONE_AGING_STATE;
1050 	prop->data.aging_enabled = z->zoneinfo->fAging;
1051 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1052 		return WERR_NOT_ENOUGH_MEMORY;
1053 	}
1054 
1055 	/* aging enabled time */
1056 	prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
1057 	prop->data.next_scavenging_cycle_hours = 0;
1058 	if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
1059 		return WERR_NOT_ENOUGH_MEMORY;
1060 	}
1061 
1062 	talloc_free(prop);
1063 
1064 	ret = ldb_add(samdb, msg);
1065 	if (ret != LDB_SUCCESS) {
1066 		DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
1067 		      z->name, ldb_errstring(samdb)));
1068 
1069 		if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1070 			return WERR_ACCESS_DENIED;
1071 		}
1072 
1073 		return WERR_INTERNAL_DB_ERROR;
1074 	}
1075 
1076 	return WERR_OK;
1077 }
1078 
1079 
1080 /* Create new dnsZone record and @ record (SOA + NS) */
dnsserver_db_create_zone(struct ldb_context * samdb,struct dnsserver_partition * partitions,struct dnsserver_zone * zone,struct loadparm_context * lp_ctx)1081 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
1082 				struct dnsserver_partition *partitions,
1083 				struct dnsserver_zone *zone,
1084 				struct loadparm_context *lp_ctx)
1085 {
1086 	struct dnsserver_partition *p;
1087 	bool in_forest = false;
1088 	WERROR status;
1089 	struct ldb_dn *dn;
1090 	TALLOC_CTX *tmp_ctx;
1091 	struct dnsp_DnssrvRpcRecord *dns_rec;
1092 	struct dnsp_soa soa;
1093 	char *tmpstr, *server_fqdn, *soa_email;
1094 	struct ldb_val name_val = data_blob_string_const(zone->name);
1095 
1096 	/* We only support primary zones for now */
1097 	if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
1098 		return WERR_CALL_NOT_IMPLEMENTED;
1099 	}
1100 
1101 	/* Get the correct partition */
1102 	if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
1103 		in_forest = true;
1104 	}
1105 	for (p = partitions; p; p = p->next) {
1106 		if (in_forest == p->is_forest) {
1107 			break;
1108 		}
1109 	}
1110 	if (p == NULL) {
1111 		return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
1112 	}
1113 
1114 	tmp_ctx = talloc_new(NULL);
1115 	W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
1116 
1117 	dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
1118 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
1119 
1120 	if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
1121 		talloc_free(tmp_ctx);
1122 		return WERR_NOT_ENOUGH_MEMORY;
1123 	}
1124 
1125 	if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
1126 		talloc_free(tmp_ctx);
1127 		return WERR_NOT_ENOUGH_MEMORY;
1128 	}
1129 
1130 	/* Add dnsZone record */
1131 	status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
1132 	if (!W_ERROR_IS_OK(status)) {
1133 		talloc_free(tmp_ctx);
1134 		return status;
1135 	}
1136 
1137 	if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
1138 		talloc_free(tmp_ctx);
1139 		return WERR_NOT_ENOUGH_MEMORY;
1140 	}
1141 
1142 	dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
1143 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
1144 
1145 	tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
1146 				 lpcfg_netbios_name(lp_ctx),
1147 				 lpcfg_realm(lp_ctx));
1148 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
1149 	server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
1150 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
1151 	talloc_free(tmpstr);
1152 
1153 	tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
1154 				  lpcfg_realm(lp_ctx));
1155 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
1156 	soa_email = strlower_talloc(tmp_ctx, tmpstr);
1157 	W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
1158 	talloc_free(tmpstr);
1159 
1160 	/* SOA Record - values same as defined in provision/sambadns.py */
1161 	soa.serial = 1;
1162 	soa.refresh = 900;
1163 	soa.retry = 600;
1164 	soa.expire = 86400;
1165 	soa.minimum = 3600;
1166 	soa.mname = server_fqdn;
1167 	soa.rname = soa_email;
1168 
1169 	dns_rec[0].wType = DNS_TYPE_SOA;
1170 	dns_rec[0].rank = DNS_RANK_ZONE;
1171 	dns_rec[0].dwSerial = soa.serial;
1172 	dns_rec[0].dwTtlSeconds = 3600;
1173 	dns_rec[0].dwTimeStamp = 0;
1174 	dns_rec[0].data.soa = soa;
1175 
1176 	/* NS Record */
1177 	dns_rec[1].wType = DNS_TYPE_NS;
1178 	dns_rec[1].rank = DNS_RANK_ZONE;
1179 	dns_rec[1].dwSerial = soa.serial;
1180 	dns_rec[1].dwTtlSeconds = 3600;
1181 	dns_rec[1].dwTimeStamp = 0;
1182 	dns_rec[1].data.ns = server_fqdn;
1183 
1184 	/* Add @ Record */
1185 	status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
1186 
1187 	talloc_free(tmp_ctx);
1188 	return status;
1189 }
1190 
1191 
1192 /* Delete dnsZone record and all DNS records in the zone */
dnsserver_db_delete_zone(struct ldb_context * samdb,struct dnsserver_zone * zone)1193 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
1194 				struct dnsserver_zone *zone)
1195 {
1196 	int ret;
1197 
1198 	ret = ldb_transaction_start(samdb);
1199 	if (ret != LDB_SUCCESS) {
1200 		return WERR_INTERNAL_DB_ERROR;
1201 	}
1202 
1203 	ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
1204 	if (ret != LDB_SUCCESS) {
1205 		ldb_transaction_cancel(samdb);
1206 
1207 		if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1208 			return WERR_ACCESS_DENIED;
1209 		}
1210 		return WERR_INTERNAL_DB_ERROR;
1211 	}
1212 
1213 	ret = ldb_transaction_commit(samdb);
1214 	if (ret != LDB_SUCCESS) {
1215 		return WERR_INTERNAL_DB_ERROR;
1216 	}
1217 
1218 	return WERR_OK;
1219 }
1220