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