s4-rpc: dnsserver: dns_name_equal() returns boolean
[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 /* There are only 2 fixed partitions for DNS */
33 struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
34                                                         struct dnsserver_serverinfo *serverinfo,
35                                                         struct ldb_context *samdb)
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, NULL);
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, NULL);
74
75         return partitions;
76
77 failed:
78         return NULL;
79
80 }
81
82
83 /* Search for all dnsZone records */
84 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
85                                                 struct ldb_context *samdb,
86                                                 struct dnsserver_partition *p)
87 {
88         TALLOC_CTX *tmp_ctx;
89         const char * const attrs[] = {"name", NULL};
90         struct ldb_dn *dn;
91         struct ldb_result *res;
92         struct dnsserver_zone *zones, *z;
93         int i, ret;
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                 z = talloc_zero(mem_ctx, struct dnsserver_zone);
120                 if (z == NULL) {
121                         goto failed;
122                 }
123
124                 z->partition = p;
125                 name = talloc_strdup(z,
126                                 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
127                 if (strcmp(name, "..TrustAnchors") == 0) {
128                         talloc_free(z);
129                         continue;
130                 }
131                 if (strcmp(name, "RootDNSServers") == 0) {
132                         talloc_free(name);
133                         z->name = talloc_strdup(z, ".");
134                 } else {
135                         z->name = name;
136                 }
137                 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
138
139                 DLIST_ADD_END(zones, z, NULL);
140                 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
141         }
142
143         return zones;
144
145 failed:
146         talloc_free(tmp_ctx);
147         return NULL;
148 }
149
150
151 /* Find DNS partition information */
152 struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
153                                                         struct ldb_context *samdb,
154                                                         struct dnsserver_partition *p)
155 {
156         const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
157         const char * const attrs_none[] = { NULL };
158         struct ldb_result *res;
159         struct ldb_message_element *el;
160         struct ldb_dn *dn;
161         struct dnsserver_partition_info *partinfo;
162         int i, ret, instance_type;
163         TALLOC_CTX *tmp_ctx;
164
165         tmp_ctx = talloc_new(mem_ctx);
166         if (tmp_ctx == NULL) {
167                 return NULL;
168         }
169
170         partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
171         if (partinfo == NULL) {
172                 talloc_free(tmp_ctx);
173                 return NULL;
174         }
175
176         /* Search for the active replica and state */
177         ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
178                         attrs, NULL);
179         if (ret != LDB_SUCCESS || res->count != 1) {
180                 goto failed;
181         }
182
183         /* Set the state of the partition */
184         instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
185         if (instance_type == -1) {
186                 partinfo->dwState = DNS_DP_STATE_UNKNOWN;
187         } else if (instance_type & INSTANCE_TYPE_NC_COMING) {
188                 partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
189         } else if (instance_type & INSTANCE_TYPE_NC_GOING) {
190                 partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
191         } else {
192                 partinfo->dwState = DNS_DP_OKAY;
193         }
194
195         el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
196         if (el == NULL) {
197                 partinfo->dwReplicaCount = 0;
198                 partinfo->ReplicaArray = NULL;
199         } else {
200                 partinfo->dwReplicaCount = el->num_values;
201                 partinfo->ReplicaArray = talloc_zero_array(partinfo,
202                                                            struct DNS_RPC_DP_REPLICA *,
203                                                            el->num_values);
204                 if (partinfo->ReplicaArray == NULL) {
205                         goto failed;
206                 }
207                 for (i=0; i<el->num_values; i++) {
208                         partinfo->ReplicaArray[i] = talloc_zero(partinfo,
209                                                         struct DNS_RPC_DP_REPLICA);
210                         if (partinfo->ReplicaArray[i] == NULL) {
211                                 goto failed;
212                         }
213                         partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
214                                                                         partinfo,
215                                                                         (const char *)el->values[i].data);
216                         if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
217                                 goto failed;
218                         }
219                 }
220         }
221         talloc_free(res);
222
223         /* Search for cross-reference object */
224         dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
225         if (dn == NULL) {
226                 goto failed;
227         }
228
229         ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
230                         "(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
231         if (ret != LDB_SUCCESS || res->count != 1) {
232                 goto failed;
233         }
234         partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
235         if (partinfo->pszCrDn == NULL) {
236                 goto failed;
237         }
238         talloc_free(res);
239
240         talloc_free(tmp_ctx);
241         return partinfo;
242
243 failed:
244         talloc_free(tmp_ctx);
245         talloc_free(partinfo);
246         return NULL;
247 }
248
249
250 /* Increment serial number and update timestamp */
251 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
252                                 struct ldb_context *samdb,
253                                 struct dnsserver_zone *z)
254 {
255         const char * const attrs[] = { "dnsRecord", NULL };
256         struct ldb_result *res;
257         struct dnsp_DnssrvRpcRecord rec;
258         struct ldb_message_element *el;
259         enum ndr_err_code ndr_err;
260         int ret, i, serial = -1;
261         NTTIME t;
262
263         unix_to_nt_time(&t, time(NULL));
264         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
265         t /= 3600;         /* convert to hours */
266
267         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
268                         "(&(objectClass=dnsNode)(name=@))");
269         if (ret != LDB_SUCCESS || res->count == 0) {
270                 return -1;
271         }
272
273         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
274         if (el == NULL) {
275                 return -1;
276         }
277
278         for (i=0; i<el->num_values; i++) {
279                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
280                                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
281                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282                         continue;
283                 }
284
285                 if (rec.wType == DNS_TYPE_SOA) {
286                         serial = rec.data.soa.serial + 1;
287                         rec.dwSerial = serial;
288                         rec.dwTimeStamp = (uint32_t)t;
289                         rec.data.soa.serial = serial;
290
291                         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
292                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
293                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
294                                 return -1;
295                         }
296                         break;
297                 }
298         }
299
300         if (serial != -1) {
301                 el->flags = LDB_FLAG_MOD_REPLACE;
302                 ret = ldb_modify(samdb, res->msgs[0]);
303                 if (ret != LDB_SUCCESS) {
304                         return -1;
305                 }
306         }
307
308         return serial;
309 }
310
311
312 /* Add DNS record to the database */
313 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
314                                 struct ldb_context *samdb,
315                                 struct ldb_dn *dn,
316                                 int num_rec,
317                                 struct dnsp_DnssrvRpcRecord *rec)
318 {
319         struct ldb_message *msg;
320         struct ldb_val v;
321         int ret;
322         enum ndr_err_code ndr_err;
323         int i;
324
325         msg = ldb_msg_new(mem_ctx);
326         W_ERROR_HAVE_NO_MEMORY(msg);
327
328         msg->dn = dn;
329         ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
330         if (ret != LDB_SUCCESS) {
331                 return WERR_NOMEM;
332         }
333
334         if (num_rec > 0 && rec) {
335                 for (i=0; i<num_rec; i++) {
336                         ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
337                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
338                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
339                                 return WERR_GENERAL_FAILURE;
340                         }
341
342                         ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
343                         if (ret != LDB_SUCCESS) {
344                                 return WERR_NOMEM;
345                         }
346                 }
347         }
348
349         ret = ldb_add(samdb, msg);
350         if (ret != LDB_SUCCESS) {
351                 return WERR_INTERNAL_DB_ERROR;
352         }
353
354         return WERR_OK;
355 }
356
357
358 /* Add dnsNode record to the database with DNS record */
359 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
360                                         struct ldb_context *samdb,
361                                         struct dnsserver_zone *z,
362                                         const char *name)
363 {
364         const char * const attrs[] = { "name", NULL };
365         struct ldb_result *res;
366         struct ldb_dn *dn;
367         int ret;
368
369         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
370                         "(&(objectClass=dnsNode)(name=%s))", name);
371         if (ret != LDB_SUCCESS) {
372                 return WERR_INTERNAL_DB_ERROR;
373         }
374
375         if (res->count > 0) {
376                 talloc_free(res);
377                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
378         }
379
380         dn = ldb_dn_copy(mem_ctx, z->zone_dn);
381         W_ERROR_HAVE_NO_MEMORY(dn);
382
383         if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
384                 return WERR_NOMEM;
385         }
386
387         return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
388 }
389
390
391 /* Add a DNS record */
392 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
393                                         struct ldb_context *samdb,
394                                         struct dnsserver_zone *z,
395                                         const char *name,
396                                         struct DNS_RPC_RECORD *add_record)
397 {
398         const char * const attrs[] = { "dnsRecord", NULL };
399         struct ldb_result *res;
400         struct dnsp_DnssrvRpcRecord *rec;
401         struct ldb_message_element *el;
402         struct ldb_dn *dn;
403         enum ndr_err_code ndr_err;
404         NTTIME t;
405         int ret, i;
406         int serial;
407
408         rec = dns_to_dnsp_copy(mem_ctx, add_record);
409         W_ERROR_HAVE_NO_MEMORY(rec);
410
411         /* Set the correct rank for the record.
412          * FIXME: add logic to check for glue records */
413         if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
414                 rec->rank |= DNS_RANK_ZONE;
415         } else if (strcmp(z->name, ".") == 0) {
416                 rec->rank |= DNS_RANK_ROOT_HINT;
417         }
418
419         serial = dnsserver_update_soa(mem_ctx, samdb, z);
420         if (serial < 0) {
421                 return WERR_INTERNAL_DB_ERROR;
422         }
423
424         unix_to_nt_time(&t, time(NULL));
425         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
426         t /= 3600;         /* convert to hours */
427
428         rec->dwSerial = serial;
429         rec->dwTimeStamp = t;
430
431         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
432                         "(&(objectClass=dnsNode)(name=%s))", name);
433         if (ret != LDB_SUCCESS) {
434                 return WERR_INTERNAL_DB_ERROR;
435         }
436
437         if (res->count == 0) {
438                 dn = dnsserver_name_to_dn(mem_ctx, z, name);
439                 W_ERROR_HAVE_NO_MEMORY(dn);
440
441                 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
442         }
443
444         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
445         if (el == NULL) {
446                 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
447                 if (ret != LDB_SUCCESS) {
448                         return WERR_NOMEM;
449                 }
450         }
451
452         for (i=0; i<el->num_values; i++) {
453                 struct dnsp_DnssrvRpcRecord rec2;
454
455                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
456                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
457                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
458                         return WERR_GENERAL_FAILURE;
459                 }
460
461                 if (dns_record_match(rec, &rec2)) {
462                         break;
463                 }
464         }
465         if (i < el->num_values) {
466                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
467         }
468         if (i == el->num_values) {
469                 /* adding a new value */
470                 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
471                 W_ERROR_HAVE_NO_MEMORY(el->values);
472                 el->num_values++;
473         }
474
475         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
476                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
477         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
478                 return WERR_GENERAL_FAILURE;
479         }
480
481         el->flags = LDB_FLAG_MOD_REPLACE;
482         ret = ldb_modify(samdb, res->msgs[0]);
483         if (ret != LDB_SUCCESS) {
484                 return WERR_INTERNAL_DB_ERROR;
485         }
486
487         return WERR_OK;
488 }
489
490
491 /* Update a DNS record */
492 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
493                                         struct ldb_context *samdb,
494                                         struct dnsserver_zone *z,
495                                         const char *name,
496                                         struct DNS_RPC_RECORD *add_record,
497                                         struct DNS_RPC_RECORD *del_record)
498 {
499         const char * const attrs[] = { "dnsRecord", NULL };
500         struct ldb_result *res;
501         struct dnsp_DnssrvRpcRecord *arec, *drec;
502         struct ldb_message_element *el;
503         enum ndr_err_code ndr_err;
504         NTTIME t;
505         int ret, i;
506         int serial;
507
508         serial = dnsserver_update_soa(mem_ctx, samdb, z);
509         if (serial < 0) {
510                 return WERR_INTERNAL_DB_ERROR;
511         }
512
513         arec = dns_to_dnsp_copy(mem_ctx, add_record);
514         W_ERROR_HAVE_NO_MEMORY(arec);
515
516         drec = dns_to_dnsp_copy(mem_ctx, del_record);
517         W_ERROR_HAVE_NO_MEMORY(drec);
518
519         unix_to_nt_time(&t, time(NULL));
520         t /= 10*1000*1000;
521
522         arec->dwSerial = serial;
523         arec->dwTimeStamp = t;
524
525         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
526                         "(&(objectClass=dnsNode)(name=%s))", name);
527         if (ret != LDB_SUCCESS) {
528                 return WERR_INTERNAL_DB_ERROR;
529         }
530
531         if (res->count == 0) {
532                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
533         }
534
535         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
536         if (el == NULL || el->num_values == 0) {
537                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
538         }
539
540         for (i=0; i<el->num_values; i++) {
541                 struct dnsp_DnssrvRpcRecord rec2;
542
543                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
544                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
545                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
546                         return WERR_GENERAL_FAILURE;
547                 }
548
549                 if (dns_record_match(arec, &rec2)) {
550                         break;
551                 }
552         }
553         if (i < el->num_values) {
554                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
555         }
556
557
558         for (i=0; i<el->num_values; i++) {
559                 struct dnsp_DnssrvRpcRecord rec2;
560
561                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
562                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
563                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
564                         return WERR_GENERAL_FAILURE;
565                 }
566
567                 if (dns_record_match(drec, &rec2)) {
568                         break;
569                 }
570         }
571         if (i == el->num_values) {
572                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
573         }
574
575         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
576                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
577         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
578                 return WERR_GENERAL_FAILURE;
579         }
580
581         el->flags = LDB_FLAG_MOD_REPLACE;
582         ret = ldb_modify(samdb, res->msgs[0]);
583         if (ret != LDB_SUCCESS) {
584                 return WERR_INTERNAL_DB_ERROR;
585         }
586
587         return WERR_OK;
588 }
589
590
591 /* Delete a DNS record */
592 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
593                                         struct ldb_context *samdb,
594                                         struct dnsserver_zone *z,
595                                         const char *name,
596                                         struct DNS_RPC_RECORD *del_record)
597 {
598         const char * const attrs[] = { "dnsRecord", NULL };
599         struct ldb_result *res;
600         struct dnsp_DnssrvRpcRecord *rec;
601         struct ldb_message_element *el;
602         enum ndr_err_code ndr_err;
603         int ret, i;
604         int serial;
605
606         serial = dnsserver_update_soa(mem_ctx, samdb, z);
607         if (serial < 0) {
608                 return WERR_INTERNAL_DB_ERROR;
609         }
610
611         rec = dns_to_dnsp_copy(mem_ctx, del_record);
612         W_ERROR_HAVE_NO_MEMORY(rec);
613
614         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
615                         "(&(objectClass=dnsNode)(name=%s))", name);
616         if (ret != LDB_SUCCESS) {
617                 return WERR_INTERNAL_DB_ERROR;
618         }
619
620         if (res->count == 0) {
621                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
622         }
623
624         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
625         if (el == NULL || el->num_values == 0) {
626                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
627         }
628
629         for (i=0; i<el->num_values; i++) {
630                 struct dnsp_DnssrvRpcRecord rec2;
631
632                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
633                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
634                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
635                         return WERR_GENERAL_FAILURE;
636                 }
637
638                 if (dns_record_match(rec, &rec2)) {
639                         break;
640                 }
641         }
642         if (i == el->num_values) {
643                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
644         }
645         if (i < el->num_values-1) {
646                 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
647         }
648         el->num_values--;
649
650         if (el->num_values == 0) {
651                 ret = ldb_delete(samdb, res->msgs[0]->dn);
652         } else {
653                 el->flags = LDB_FLAG_MOD_REPLACE;
654                 ret = ldb_modify(samdb, res->msgs[0]);
655         }
656         if (ret != LDB_SUCCESS) {
657                 return WERR_INTERNAL_DB_ERROR;
658         }
659
660         return WERR_OK;
661 }
662
663
664 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
665                                              struct ldb_message *msg,
666                                              struct dnsp_DnsProperty *prop)
667 {
668         DATA_BLOB *prop_blob;
669         enum ndr_err_code ndr_err;
670         int ret;
671
672         prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
673         if (prop_blob == NULL) return false;
674
675         ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
676                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
677         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
678                 return false;
679         }
680         ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
681         if (ret != LDB_SUCCESS) {
682                 return false;
683         }
684         return true;
685 }
686
687
688 /* Create dnsZone record to database and set security descriptor */
689 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
690                                           struct ldb_context *samdb,
691                                           struct ldb_dn *zone_dn,
692                                           struct dnsserver_zone *z)
693 {
694         const char * const attrs[] = { "objectSID", NULL };
695         struct ldb_message *msg;
696         struct ldb_result *res;
697         struct ldb_message_element *el;
698         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";
699         char *sddl;
700         struct dom_sid dnsadmins_sid;
701         const struct dom_sid *domain_sid;
702         struct security_descriptor *secdesc;
703         struct dnsp_DnsProperty *prop;
704         DATA_BLOB *sd_encoded;
705         enum ndr_err_code ndr_err;
706         int ret;
707
708         /* Get DnsAdmins SID */
709         ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
710                          LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
711         if (ret != LDB_SUCCESS || res->count != 1) {
712                 return WERR_INTERNAL_DB_ERROR;
713         }
714
715         el = ldb_msg_find_element(res->msgs[0], "objectSID");
716         if (el == NULL || el->num_values != 1) {
717                 return WERR_INTERNAL_DB_ERROR;
718         }
719
720         ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
721                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
722         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
723                 return WERR_INTERNAL_DB_ERROR;
724         }
725
726         /* create security descriptor with DnsAdmins GUID in sddl template */
727         sddl = talloc_asprintf(tmp_ctx, sddl_template,
728                                dom_sid_string(tmp_ctx, &dnsadmins_sid));
729         if (sddl == NULL) {
730                 return WERR_NOMEM;
731         }
732         talloc_free(res);
733
734         domain_sid = samdb_domain_sid(samdb);
735         if (domain_sid == NULL) {
736                 return WERR_INTERNAL_DB_ERROR;
737         }
738
739         secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
740         if (secdesc == NULL) {
741                 return WERR_GENERAL_FAILURE;
742         }
743
744         msg = ldb_msg_new(tmp_ctx);
745         W_ERROR_HAVE_NO_MEMORY(msg);
746
747         msg->dn = zone_dn;
748         ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
749         if (ret != LDB_SUCCESS) {
750                 return WERR_NOMEM;
751         }
752
753         sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
754         W_ERROR_HAVE_NO_MEMORY(sd_encoded);
755
756         ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
757                         (ndr_push_flags_fn_t)ndr_push_security_descriptor);
758         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
759                 return WERR_GENERAL_FAILURE;
760         }
761
762         ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
763         if (ret != LDB_SUCCESS) {
764                 return WERR_NOMEM;
765         }
766
767         /* dns zone Properties */
768         prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
769         W_ERROR_HAVE_NO_MEMORY(prop);
770
771         prop->version = 1;
772
773         /* zone type */
774         prop->id = DSPROPERTY_ZONE_TYPE;
775         prop->data.zone_type = z->zoneinfo->dwZoneType;
776         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
777                 return WERR_NOMEM;
778         }
779
780         /* allow update */
781         prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
782         prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
783         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
784                 return WERR_NOMEM;
785         }
786
787         /* secure time */
788         prop->id = DSPROPERTY_ZONE_SECURE_TIME;
789         prop->data.zone_secure_time = 0;
790         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
791                 return WERR_NOMEM;
792         }
793
794         /* norefresh interval */
795         prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
796         prop->data.norefresh_hours = 168;
797         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
798                 return WERR_NOMEM;
799         }
800
801         /* refresh interval */
802         prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
803         prop->data.refresh_hours = 168;
804         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
805                 return WERR_NOMEM;
806         }
807
808         /* aging state */
809         prop->id = DSPROPERTY_ZONE_AGING_STATE;
810         prop->data.aging_enabled = z->zoneinfo->fAging;
811         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
812                 return WERR_NOMEM;
813         }
814
815         /* aging enabled time */
816         prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
817         prop->data.next_scavenging_cycle_hours = 0;
818         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
819                 return WERR_NOMEM;
820         }
821
822         talloc_free(prop);
823
824         ret = ldb_add(samdb, msg);
825         if (ret != LDB_SUCCESS) {
826                 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
827                       z->name, ldb_errstring(samdb)));
828                 return WERR_INTERNAL_DB_ERROR;
829         }
830
831         return WERR_OK;
832 }
833
834
835 /* Create new dnsZone record and @ record (SOA + NS) */
836 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
837                                 struct dnsserver_partition *partitions,
838                                 struct dnsserver_zone *zone,
839                                 struct loadparm_context *lp_ctx)
840 {
841         struct dnsserver_partition *p;
842         bool in_forest = false;
843         WERROR status;
844         struct ldb_dn *dn;
845         TALLOC_CTX *tmp_ctx;
846         struct dnsp_DnssrvRpcRecord *dns_rec;
847         struct dnsp_soa soa;
848         char *tmpstr, *server_fqdn, *soa_email;
849         NTTIME t;
850
851         /* We only support primary zones for now */
852         if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
853                 return WERR_CALL_NOT_IMPLEMENTED;
854         }
855
856         /* Get the correct partition */
857         if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
858                 in_forest = true;
859         }
860         for (p = partitions; p; p = p->next) {
861                 if (in_forest == p->is_forest) {
862                         break;
863                 }
864         }
865         if (p == NULL) {
866                 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
867         }
868
869         tmp_ctx = talloc_new(NULL);
870         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
871
872         dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
873         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
874
875         if(!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS", zone->name)) {
876                 talloc_free(tmp_ctx);
877                 return WERR_NOMEM;
878         }
879
880         /* Add dnsZone record */
881         status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
882         if (!W_ERROR_IS_OK(status)) {
883                 talloc_free(tmp_ctx);
884                 return status;
885         }
886
887         if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
888                 talloc_free(tmp_ctx);
889                 return WERR_NOMEM;
890         }
891
892         dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
893         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
894
895         tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
896                                  lpcfg_netbios_name(lp_ctx),
897                                  lpcfg_realm(lp_ctx));
898         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
899         server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
900         W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
901         talloc_free(tmpstr);
902
903         tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
904                                   lpcfg_realm(lp_ctx));
905         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
906         soa_email = strlower_talloc(tmp_ctx, tmpstr);
907         W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
908         talloc_free(tmpstr);
909
910         unix_to_nt_time(&t, time(NULL));
911         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
912         t /= 3600;         /* convert to hours */
913
914         /* SOA Record - values same as defined in provision/sambadns.py */
915         soa.serial = 1;
916         soa.refresh = 900;
917         soa.retry = 600;
918         soa.expire = 86400;
919         soa.minimum = 3600;
920         soa.mname = server_fqdn;
921         soa.rname = soa_email;
922
923         dns_rec[0].wType = DNS_TYPE_SOA;
924         dns_rec[0].rank = DNS_RANK_ZONE;
925         dns_rec[0].dwSerial = soa.serial;
926         dns_rec[0].dwTtlSeconds = 3600;
927         dns_rec[0].dwTimeStamp = (uint32_t)t;
928         dns_rec[0].data.soa = soa;
929
930         /* NS Record */
931         dns_rec[1].wType = DNS_TYPE_NS;
932         dns_rec[1].rank = DNS_RANK_ZONE;
933         dns_rec[1].dwSerial = soa.serial;
934         dns_rec[1].dwTimeStamp = (uint32_t)t;
935         dns_rec[1].data.ns = server_fqdn;
936
937         /* Add @ Record */
938         status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
939
940         talloc_free(tmp_ctx);
941         return status;
942 }
943
944
945 /* Delete dnsZone record and all DNS records in the zone */
946 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
947                                 struct dnsserver_zone *zone)
948 {
949         int ret;
950
951         ret = ldb_transaction_start(samdb);
952         if (ret != LDB_SUCCESS) {
953                 return WERR_INTERNAL_DB_ERROR;
954         }
955
956         ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
957         if (ret != LDB_SUCCESS) {
958                 ldb_transaction_cancel(samdb);
959                 return WERR_INTERNAL_DB_ERROR;
960         }
961
962         ret = ldb_transaction_commit(samdb);
963         if (ret != LDB_SUCCESS) {
964                 return WERR_INTERNAL_DB_ERROR;
965         }
966
967         return WERR_OK;
968 }