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