81a2d2070a03b963e23677ce6176720deb13ce98
[metze/samba/wip.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);
57
58         /* Forest Partition */
59         p = talloc_zero(mem_ctx, struct dnsserver_partition);
60         if (p == NULL) {
61                 goto failed;
62         }
63
64         p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
65         if (p->partition_dn == NULL) {
66                 goto failed;
67         }
68
69         p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
70         p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED;
71         p->is_forest = true;
72
73         DLIST_ADD_END(partitions, p);
74
75         return partitions;
76
77 failed:
78         return NULL;
79
80 }
81
82
83 /* Search for all dnsZone records */
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);
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_NOT_ENOUGH_MEMORY;
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_GEN_FAILURE;
340                         }
341
342                         ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
343                         if (ret != LDB_SUCCESS) {
344                                 return WERR_NOT_ENOUGH_MEMORY;
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         char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
368         int ret;
369
370         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
371                         "(&(objectClass=dnsNode)(name=%s))",
372                          encoded_name);
373         if (ret != LDB_SUCCESS) {
374                 return WERR_INTERNAL_DB_ERROR;
375         }
376
377         if (res->count > 0) {
378                 talloc_free(res);
379                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
380         }
381
382         dn = ldb_dn_copy(mem_ctx, z->zone_dn);
383         W_ERROR_HAVE_NO_MEMORY(dn);
384
385         if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
386                 return WERR_NOT_ENOUGH_MEMORY;
387         }
388
389         return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
390 }
391
392
393 /* Add a DNS record */
394 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
395                                         struct ldb_context *samdb,
396                                         struct dnsserver_zone *z,
397                                         const char *name,
398                                         struct DNS_RPC_RECORD *add_record)
399 {
400         const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
401         struct ldb_result *res;
402         struct dnsp_DnssrvRpcRecord *rec = NULL;
403         struct ldb_message_element *el;
404         struct ldb_dn *dn;
405         enum ndr_err_code ndr_err;
406         NTTIME t;
407         int ret, i;
408         int serial;
409         WERROR werr;
410         bool was_tombstoned = false;
411         char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
412
413         werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
414         if (!W_ERROR_IS_OK(werr)) {
415                 return werr;
416         }
417
418         /* Set the correct rank for the record. */
419         if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
420                 if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
421                         rec->rank = DNS_RANK_NS_GLUE;
422                 } else {
423                         rec->rank |= DNS_RANK_ZONE;
424                 }
425         } else if (strcmp(z->name, ".") == 0) {
426                 rec->rank |= DNS_RANK_ROOT_HINT;
427         }
428
429         serial = dnsserver_update_soa(mem_ctx, samdb, z);
430         if (serial < 0) {
431                 return WERR_INTERNAL_DB_ERROR;
432         }
433
434         unix_to_nt_time(&t, time(NULL));
435         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
436         t /= 3600;         /* convert to hours */
437
438         rec->dwSerial = serial;
439         rec->dwTimeStamp = t;
440
441         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
442                         "(&(objectClass=dnsNode)(name=%s))",
443                          encoded_name);
444         if (ret != LDB_SUCCESS) {
445                 return WERR_INTERNAL_DB_ERROR;
446         }
447
448         if (res->count == 0) {
449                 dn = dnsserver_name_to_dn(mem_ctx, z, name);
450                 W_ERROR_HAVE_NO_MEMORY(dn);
451
452                 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
453         }
454
455         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
456         if (el == NULL) {
457                 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
458                 if (ret != LDB_SUCCESS) {
459                         return WERR_NOT_ENOUGH_MEMORY;
460                 }
461         }
462
463         was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
464                                                    "dNSTombstoned", false);
465         if (was_tombstoned) {
466                 el->num_values = 0;
467         }
468
469         for (i=0; i<el->num_values; i++) {
470                 struct dnsp_DnssrvRpcRecord rec2;
471
472                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
473                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
474                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
475                         return WERR_GEN_FAILURE;
476                 }
477
478                 if (dns_record_match(rec, &rec2)) {
479                         break;
480                 }
481         }
482         if (i < el->num_values) {
483                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
484         }
485         if (i == el->num_values) {
486                 /* adding a new value */
487                 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
488                 W_ERROR_HAVE_NO_MEMORY(el->values);
489                 el->num_values++;
490         }
491
492         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
493                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
494         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
495                 return WERR_GEN_FAILURE;
496         }
497
498         el->flags = LDB_FLAG_MOD_REPLACE;
499
500         el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
501         if (el != NULL) {
502                 el->flags = LDB_FLAG_MOD_DELETE;
503         }
504
505         ret = ldb_modify(samdb, res->msgs[0]);
506         if (ret != LDB_SUCCESS) {
507                 return WERR_INTERNAL_DB_ERROR;
508         }
509
510         return WERR_OK;
511 }
512
513
514 /* Update a DNS record */
515 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
516                                         struct ldb_context *samdb,
517                                         struct dnsserver_zone *z,
518                                         const char *name,
519                                         struct DNS_RPC_RECORD *add_record,
520                                         struct DNS_RPC_RECORD *del_record)
521 {
522         const char * const attrs[] = { "dnsRecord", NULL };
523         struct ldb_result *res;
524         struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
525         struct ldb_message_element *el;
526         enum ndr_err_code ndr_err;
527         NTTIME t;
528         int ret, i;
529         int serial;
530         WERROR werr;
531         char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
532
533         werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
534         if (!W_ERROR_IS_OK(werr)) {
535                 return werr;
536         }
537
538         werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
539         if (!W_ERROR_IS_OK(werr)) {
540                 return werr;
541         }
542
543         unix_to_nt_time(&t, time(NULL));
544         t /= 10*1000*1000;
545
546         arec->dwTimeStamp = t;
547
548         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
549                         "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
550                          encoded_name);
551         if (ret != LDB_SUCCESS) {
552                 return WERR_INTERNAL_DB_ERROR;
553         }
554
555         if (res->count == 0) {
556                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
557         }
558
559         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
560         if (el == NULL || el->num_values == 0) {
561                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
562         }
563
564         for (i=0; i<el->num_values; i++) {
565                 struct dnsp_DnssrvRpcRecord rec2;
566
567                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
568                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
569                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
570                         return WERR_GEN_FAILURE;
571                 }
572
573                 if (dns_record_match(arec, &rec2)) {
574                         break;
575                 }
576         }
577         if (i < el->num_values) {
578                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
579         }
580
581
582         for (i=0; i<el->num_values; i++) {
583                 struct dnsp_DnssrvRpcRecord rec2;
584
585                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
586                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
587                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
588                         return WERR_GEN_FAILURE;
589                 }
590
591                 if (dns_record_match(drec, &rec2)) {
592                         break;
593                 }
594         }
595         if (i == el->num_values) {
596                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
597         }
598
599         /* If updating SOA record, use specified serial, otherwise increment */
600         if (arec->wType != DNS_TYPE_SOA) {
601                 serial = dnsserver_update_soa(mem_ctx, samdb, z);
602                 if (serial < 0) {
603                         return WERR_INTERNAL_DB_ERROR;
604                 }
605                 arec->dwSerial = serial;
606         }
607
608         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
609                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
610         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
611                 return WERR_GEN_FAILURE;
612         }
613
614         el->flags = LDB_FLAG_MOD_REPLACE;
615         ret = ldb_modify(samdb, res->msgs[0]);
616         if (ret != LDB_SUCCESS) {
617                 return WERR_INTERNAL_DB_ERROR;
618         }
619
620         return WERR_OK;
621 }
622
623
624 /* Delete a DNS record */
625 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
626                                         struct ldb_context *samdb,
627                                         struct dnsserver_zone *z,
628                                         const char *name,
629                                         struct DNS_RPC_RECORD *del_record)
630 {
631         const char * const attrs[] = { "dnsRecord", NULL };
632         struct ldb_result *res;
633         struct dnsp_DnssrvRpcRecord *rec = NULL;
634         struct ldb_message_element *el;
635         enum ndr_err_code ndr_err;
636         int ret, i;
637         int serial;
638         WERROR werr;
639
640         serial = dnsserver_update_soa(mem_ctx, samdb, z);
641         if (serial < 0) {
642                 return WERR_INTERNAL_DB_ERROR;
643         }
644
645         werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
646         if (!W_ERROR_IS_OK(werr)) {
647                 return werr;
648         }
649
650         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
651                         "(&(objectClass=dnsNode)(name=%s))",
652                          ldb_binary_encode_string(mem_ctx, name));
653         if (ret != LDB_SUCCESS) {
654                 return WERR_INTERNAL_DB_ERROR;
655         }
656
657         if (res->count == 0) {
658                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
659         }
660         if (res->count > 1) {
661                 return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
662         }
663
664         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
665         if (el == NULL || el->num_values == 0) {
666                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
667         }
668
669         for (i=0; i<el->num_values; i++) {
670                 struct dnsp_DnssrvRpcRecord rec2;
671
672                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
673                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
674                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
675                         return WERR_GEN_FAILURE;
676                 }
677
678                 if (dns_record_match(rec, &rec2)) {
679                         break;
680                 }
681         }
682         if (i == el->num_values) {
683                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
684         }
685         if (i < el->num_values-1) {
686                 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
687         }
688         el->num_values--;
689
690         if (el->num_values == 0) {
691                 ret = ldb_delete(samdb, res->msgs[0]->dn);
692         } else {
693                 el->flags = LDB_FLAG_MOD_REPLACE;
694                 ret = ldb_modify(samdb, res->msgs[0]);
695         }
696         if (ret != LDB_SUCCESS) {
697                 return WERR_INTERNAL_DB_ERROR;
698         }
699
700         return WERR_OK;
701 }
702
703
704 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
705                                              struct ldb_message *msg,
706                                              struct dnsp_DnsProperty *prop)
707 {
708         DATA_BLOB *prop_blob;
709         enum ndr_err_code ndr_err;
710         int ret;
711
712         prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
713         if (prop_blob == NULL) return false;
714
715         ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
716                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
717         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
718                 return false;
719         }
720         ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
721         if (ret != LDB_SUCCESS) {
722                 return false;
723         }
724         return true;
725 }
726
727
728 /* Create dnsZone record to database and set security descriptor */
729 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
730                                           struct ldb_context *samdb,
731                                           struct ldb_dn *zone_dn,
732                                           struct dnsserver_zone *z)
733 {
734         const char * const attrs[] = { "objectSID", NULL };
735         struct ldb_message *msg;
736         struct ldb_result *res;
737         struct ldb_message_element *el;
738         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";
739         char *sddl;
740         struct dom_sid dnsadmins_sid;
741         const struct dom_sid *domain_sid;
742         struct security_descriptor *secdesc;
743         struct dnsp_DnsProperty *prop;
744         DATA_BLOB *sd_encoded;
745         enum ndr_err_code ndr_err;
746         int ret;
747
748         /* Get DnsAdmins SID */
749         ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
750                          LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
751         if (ret != LDB_SUCCESS || res->count != 1) {
752                 return WERR_INTERNAL_DB_ERROR;
753         }
754
755         el = ldb_msg_find_element(res->msgs[0], "objectSID");
756         if (el == NULL || el->num_values != 1) {
757                 return WERR_INTERNAL_DB_ERROR;
758         }
759
760         ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
761                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
762         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
763                 return WERR_INTERNAL_DB_ERROR;
764         }
765
766         /* create security descriptor with DnsAdmins GUID in sddl template */
767         sddl = talloc_asprintf(tmp_ctx, sddl_template,
768                                dom_sid_string(tmp_ctx, &dnsadmins_sid));
769         if (sddl == NULL) {
770                 return WERR_NOT_ENOUGH_MEMORY;
771         }
772         talloc_free(res);
773
774         domain_sid = samdb_domain_sid(samdb);
775         if (domain_sid == NULL) {
776                 return WERR_INTERNAL_DB_ERROR;
777         }
778
779         secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
780         if (secdesc == NULL) {
781                 return WERR_GEN_FAILURE;
782         }
783
784         msg = ldb_msg_new(tmp_ctx);
785         W_ERROR_HAVE_NO_MEMORY(msg);
786
787         msg->dn = zone_dn;
788         ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
789         if (ret != LDB_SUCCESS) {
790                 return WERR_NOT_ENOUGH_MEMORY;
791         }
792
793         sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
794         W_ERROR_HAVE_NO_MEMORY(sd_encoded);
795
796         ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
797                         (ndr_push_flags_fn_t)ndr_push_security_descriptor);
798         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
799                 return WERR_GEN_FAILURE;
800         }
801
802         ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
803         if (ret != LDB_SUCCESS) {
804                 return WERR_NOT_ENOUGH_MEMORY;
805         }
806
807         /* dns zone Properties */
808         prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
809         W_ERROR_HAVE_NO_MEMORY(prop);
810
811         prop->version = 1;
812
813         /* zone type */
814         prop->id = DSPROPERTY_ZONE_TYPE;
815         prop->data.zone_type = z->zoneinfo->dwZoneType;
816         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
817                 return WERR_NOT_ENOUGH_MEMORY;
818         }
819
820         /* allow update */
821         prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
822         prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
823         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
824                 return WERR_NOT_ENOUGH_MEMORY;
825         }
826
827         /* secure time */
828         prop->id = DSPROPERTY_ZONE_SECURE_TIME;
829         prop->data.zone_secure_time = 0;
830         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
831                 return WERR_NOT_ENOUGH_MEMORY;
832         }
833
834         /* norefresh interval */
835         prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
836         prop->data.norefresh_hours = 168;
837         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
838                 return WERR_NOT_ENOUGH_MEMORY;
839         }
840
841         /* refresh interval */
842         prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
843         prop->data.refresh_hours = 168;
844         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
845                 return WERR_NOT_ENOUGH_MEMORY;
846         }
847
848         /* aging state */
849         prop->id = DSPROPERTY_ZONE_AGING_STATE;
850         prop->data.aging_enabled = z->zoneinfo->fAging;
851         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
852                 return WERR_NOT_ENOUGH_MEMORY;
853         }
854
855         /* aging enabled time */
856         prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
857         prop->data.next_scavenging_cycle_hours = 0;
858         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
859                 return WERR_NOT_ENOUGH_MEMORY;
860         }
861
862         talloc_free(prop);
863
864         ret = ldb_add(samdb, msg);
865         if (ret != LDB_SUCCESS) {
866                 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
867                       z->name, ldb_errstring(samdb)));
868                 return WERR_INTERNAL_DB_ERROR;
869         }
870
871         return WERR_OK;
872 }
873
874
875 /* Create new dnsZone record and @ record (SOA + NS) */
876 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
877                                 struct dnsserver_partition *partitions,
878                                 struct dnsserver_zone *zone,
879                                 struct loadparm_context *lp_ctx)
880 {
881         struct dnsserver_partition *p;
882         bool in_forest = false;
883         WERROR status;
884         struct ldb_dn *dn;
885         TALLOC_CTX *tmp_ctx;
886         struct dnsp_DnssrvRpcRecord *dns_rec;
887         struct dnsp_soa soa;
888         char *tmpstr, *server_fqdn, *soa_email;
889         NTTIME t;
890
891         /* We only support primary zones for now */
892         if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
893                 return WERR_CALL_NOT_IMPLEMENTED;
894         }
895
896         /* Get the correct partition */
897         if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
898                 in_forest = true;
899         }
900         for (p = partitions; p; p = p->next) {
901                 if (in_forest == p->is_forest) {
902                         break;
903                 }
904         }
905         if (p == NULL) {
906                 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
907         }
908
909         tmp_ctx = talloc_new(NULL);
910         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
911
912         dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
913         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
914
915         if(!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS", zone->name)) {
916                 talloc_free(tmp_ctx);
917                 return WERR_NOT_ENOUGH_MEMORY;
918         }
919
920         /* Add dnsZone record */
921         status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
922         if (!W_ERROR_IS_OK(status)) {
923                 talloc_free(tmp_ctx);
924                 return status;
925         }
926
927         if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
928                 talloc_free(tmp_ctx);
929                 return WERR_NOT_ENOUGH_MEMORY;
930         }
931
932         dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
933         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
934
935         tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
936                                  lpcfg_netbios_name(lp_ctx),
937                                  lpcfg_realm(lp_ctx));
938         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
939         server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
940         W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
941         talloc_free(tmpstr);
942
943         tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
944                                   lpcfg_realm(lp_ctx));
945         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
946         soa_email = strlower_talloc(tmp_ctx, tmpstr);
947         W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
948         talloc_free(tmpstr);
949
950         unix_to_nt_time(&t, time(NULL));
951         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
952         t /= 3600;         /* convert to hours */
953
954         /* SOA Record - values same as defined in provision/sambadns.py */
955         soa.serial = 1;
956         soa.refresh = 900;
957         soa.retry = 600;
958         soa.expire = 86400;
959         soa.minimum = 3600;
960         soa.mname = server_fqdn;
961         soa.rname = soa_email;
962
963         dns_rec[0].wType = DNS_TYPE_SOA;
964         dns_rec[0].rank = DNS_RANK_ZONE;
965         dns_rec[0].dwSerial = soa.serial;
966         dns_rec[0].dwTtlSeconds = 3600;
967         dns_rec[0].dwTimeStamp = (uint32_t)t;
968         dns_rec[0].data.soa = soa;
969
970         /* NS Record */
971         dns_rec[1].wType = DNS_TYPE_NS;
972         dns_rec[1].rank = DNS_RANK_ZONE;
973         dns_rec[1].dwSerial = soa.serial;
974         dns_rec[1].dwTtlSeconds = 3600;
975         dns_rec[1].dwTimeStamp = (uint32_t)t;
976         dns_rec[1].data.ns = server_fqdn;
977
978         /* Add @ Record */
979         status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
980
981         talloc_free(tmp_ctx);
982         return status;
983 }
984
985
986 /* Delete dnsZone record and all DNS records in the zone */
987 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
988                                 struct dnsserver_zone *zone)
989 {
990         int ret;
991
992         ret = ldb_transaction_start(samdb);
993         if (ret != LDB_SUCCESS) {
994                 return WERR_INTERNAL_DB_ERROR;
995         }
996
997         ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
998         if (ret != LDB_SUCCESS) {
999                 ldb_transaction_cancel(samdb);
1000                 return WERR_INTERNAL_DB_ERROR;
1001         }
1002
1003         ret = ldb_transaction_commit(samdb);
1004         if (ret != LDB_SUCCESS) {
1005                 return WERR_INTERNAL_DB_ERROR;
1006         }
1007
1008         return WERR_OK;
1009 }