s4-rpc: dnsserver: When updating SOA record, use the specified serial
[obnox/samba/samba-obnox.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         arec = dns_to_dnsp_copy(mem_ctx, add_record);
509         W_ERROR_HAVE_NO_MEMORY(arec);
510
511         drec = dns_to_dnsp_copy(mem_ctx, del_record);
512         W_ERROR_HAVE_NO_MEMORY(drec);
513
514         unix_to_nt_time(&t, time(NULL));
515         t /= 10*1000*1000;
516
517         arec->dwTimeStamp = t;
518
519         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
520                         "(&(objectClass=dnsNode)(name=%s))", name);
521         if (ret != LDB_SUCCESS) {
522                 return WERR_INTERNAL_DB_ERROR;
523         }
524
525         if (res->count == 0) {
526                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
527         }
528
529         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
530         if (el == NULL || el->num_values == 0) {
531                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
532         }
533
534         for (i=0; i<el->num_values; i++) {
535                 struct dnsp_DnssrvRpcRecord rec2;
536
537                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
538                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
539                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
540                         return WERR_GENERAL_FAILURE;
541                 }
542
543                 if (dns_record_match(arec, &rec2)) {
544                         break;
545                 }
546         }
547         if (i < el->num_values) {
548                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
549         }
550
551
552         for (i=0; i<el->num_values; i++) {
553                 struct dnsp_DnssrvRpcRecord rec2;
554
555                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
556                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
557                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
558                         return WERR_GENERAL_FAILURE;
559                 }
560
561                 if (dns_record_match(drec, &rec2)) {
562                         break;
563                 }
564         }
565         if (i == el->num_values) {
566                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
567         }
568
569         /* If updating SOA record, use specified serial, otherwise increment */
570         if (arec->wType != DNS_TYPE_SOA) {
571                 serial = dnsserver_update_soa(mem_ctx, samdb, z);
572                 if (serial < 0) {
573                         return WERR_INTERNAL_DB_ERROR;
574                 }
575                 arec->dwSerial = serial;
576         }
577
578         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
579                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
580         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
581                 return WERR_GENERAL_FAILURE;
582         }
583
584         el->flags = LDB_FLAG_MOD_REPLACE;
585         ret = ldb_modify(samdb, res->msgs[0]);
586         if (ret != LDB_SUCCESS) {
587                 return WERR_INTERNAL_DB_ERROR;
588         }
589
590         return WERR_OK;
591 }
592
593
594 /* Delete a DNS record */
595 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
596                                         struct ldb_context *samdb,
597                                         struct dnsserver_zone *z,
598                                         const char *name,
599                                         struct DNS_RPC_RECORD *del_record)
600 {
601         const char * const attrs[] = { "dnsRecord", NULL };
602         struct ldb_result *res;
603         struct dnsp_DnssrvRpcRecord *rec;
604         struct ldb_message_element *el;
605         enum ndr_err_code ndr_err;
606         int ret, i;
607         int serial;
608
609         serial = dnsserver_update_soa(mem_ctx, samdb, z);
610         if (serial < 0) {
611                 return WERR_INTERNAL_DB_ERROR;
612         }
613
614         rec = dns_to_dnsp_copy(mem_ctx, del_record);
615         W_ERROR_HAVE_NO_MEMORY(rec);
616
617         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
618                         "(&(objectClass=dnsNode)(name=%s))", name);
619         if (ret != LDB_SUCCESS) {
620                 return WERR_INTERNAL_DB_ERROR;
621         }
622
623         if (res->count == 0) {
624                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
625         }
626
627         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
628         if (el == NULL || el->num_values == 0) {
629                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
630         }
631
632         for (i=0; i<el->num_values; i++) {
633                 struct dnsp_DnssrvRpcRecord rec2;
634
635                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
636                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
637                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
638                         return WERR_GENERAL_FAILURE;
639                 }
640
641                 if (dns_record_match(rec, &rec2)) {
642                         break;
643                 }
644         }
645         if (i == el->num_values) {
646                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
647         }
648         if (i < el->num_values-1) {
649                 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
650         }
651         el->num_values--;
652
653         if (el->num_values == 0) {
654                 ret = ldb_delete(samdb, res->msgs[0]->dn);
655         } else {
656                 el->flags = LDB_FLAG_MOD_REPLACE;
657                 ret = ldb_modify(samdb, res->msgs[0]);
658         }
659         if (ret != LDB_SUCCESS) {
660                 return WERR_INTERNAL_DB_ERROR;
661         }
662
663         return WERR_OK;
664 }
665
666
667 static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
668                                              struct ldb_message *msg,
669                                              struct dnsp_DnsProperty *prop)
670 {
671         DATA_BLOB *prop_blob;
672         enum ndr_err_code ndr_err;
673         int ret;
674
675         prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
676         if (prop_blob == NULL) return false;
677
678         ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
679                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
680         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
681                 return false;
682         }
683         ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
684         if (ret != LDB_SUCCESS) {
685                 return false;
686         }
687         return true;
688 }
689
690
691 /* Create dnsZone record to database and set security descriptor */
692 static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
693                                           struct ldb_context *samdb,
694                                           struct ldb_dn *zone_dn,
695                                           struct dnsserver_zone *z)
696 {
697         const char * const attrs[] = { "objectSID", NULL };
698         struct ldb_message *msg;
699         struct ldb_result *res;
700         struct ldb_message_element *el;
701         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";
702         char *sddl;
703         struct dom_sid dnsadmins_sid;
704         const struct dom_sid *domain_sid;
705         struct security_descriptor *secdesc;
706         struct dnsp_DnsProperty *prop;
707         DATA_BLOB *sd_encoded;
708         enum ndr_err_code ndr_err;
709         int ret;
710
711         /* Get DnsAdmins SID */
712         ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
713                          LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
714         if (ret != LDB_SUCCESS || res->count != 1) {
715                 return WERR_INTERNAL_DB_ERROR;
716         }
717
718         el = ldb_msg_find_element(res->msgs[0], "objectSID");
719         if (el == NULL || el->num_values != 1) {
720                 return WERR_INTERNAL_DB_ERROR;
721         }
722
723         ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
724                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
725         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
726                 return WERR_INTERNAL_DB_ERROR;
727         }
728
729         /* create security descriptor with DnsAdmins GUID in sddl template */
730         sddl = talloc_asprintf(tmp_ctx, sddl_template,
731                                dom_sid_string(tmp_ctx, &dnsadmins_sid));
732         if (sddl == NULL) {
733                 return WERR_NOMEM;
734         }
735         talloc_free(res);
736
737         domain_sid = samdb_domain_sid(samdb);
738         if (domain_sid == NULL) {
739                 return WERR_INTERNAL_DB_ERROR;
740         }
741
742         secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
743         if (secdesc == NULL) {
744                 return WERR_GENERAL_FAILURE;
745         }
746
747         msg = ldb_msg_new(tmp_ctx);
748         W_ERROR_HAVE_NO_MEMORY(msg);
749
750         msg->dn = zone_dn;
751         ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
752         if (ret != LDB_SUCCESS) {
753                 return WERR_NOMEM;
754         }
755
756         sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
757         W_ERROR_HAVE_NO_MEMORY(sd_encoded);
758
759         ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
760                         (ndr_push_flags_fn_t)ndr_push_security_descriptor);
761         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
762                 return WERR_GENERAL_FAILURE;
763         }
764
765         ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
766         if (ret != LDB_SUCCESS) {
767                 return WERR_NOMEM;
768         }
769
770         /* dns zone Properties */
771         prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
772         W_ERROR_HAVE_NO_MEMORY(prop);
773
774         prop->version = 1;
775
776         /* zone type */
777         prop->id = DSPROPERTY_ZONE_TYPE;
778         prop->data.zone_type = z->zoneinfo->dwZoneType;
779         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
780                 return WERR_NOMEM;
781         }
782
783         /* allow update */
784         prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
785         prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
786         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
787                 return WERR_NOMEM;
788         }
789
790         /* secure time */
791         prop->id = DSPROPERTY_ZONE_SECURE_TIME;
792         prop->data.zone_secure_time = 0;
793         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
794                 return WERR_NOMEM;
795         }
796
797         /* norefresh interval */
798         prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
799         prop->data.norefresh_hours = 168;
800         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
801                 return WERR_NOMEM;
802         }
803
804         /* refresh interval */
805         prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
806         prop->data.refresh_hours = 168;
807         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
808                 return WERR_NOMEM;
809         }
810
811         /* aging state */
812         prop->id = DSPROPERTY_ZONE_AGING_STATE;
813         prop->data.aging_enabled = z->zoneinfo->fAging;
814         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
815                 return WERR_NOMEM;
816         }
817
818         /* aging enabled time */
819         prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
820         prop->data.next_scavenging_cycle_hours = 0;
821         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
822                 return WERR_NOMEM;
823         }
824
825         talloc_free(prop);
826
827         ret = ldb_add(samdb, msg);
828         if (ret != LDB_SUCCESS) {
829                 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
830                       z->name, ldb_errstring(samdb)));
831                 return WERR_INTERNAL_DB_ERROR;
832         }
833
834         return WERR_OK;
835 }
836
837
838 /* Create new dnsZone record and @ record (SOA + NS) */
839 WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
840                                 struct dnsserver_partition *partitions,
841                                 struct dnsserver_zone *zone,
842                                 struct loadparm_context *lp_ctx)
843 {
844         struct dnsserver_partition *p;
845         bool in_forest = false;
846         WERROR status;
847         struct ldb_dn *dn;
848         TALLOC_CTX *tmp_ctx;
849         struct dnsp_DnssrvRpcRecord *dns_rec;
850         struct dnsp_soa soa;
851         char *tmpstr, *server_fqdn, *soa_email;
852         NTTIME t;
853
854         /* We only support primary zones for now */
855         if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
856                 return WERR_CALL_NOT_IMPLEMENTED;
857         }
858
859         /* Get the correct partition */
860         if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
861                 in_forest = true;
862         }
863         for (p = partitions; p; p = p->next) {
864                 if (in_forest == p->is_forest) {
865                         break;
866                 }
867         }
868         if (p == NULL) {
869                 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
870         }
871
872         tmp_ctx = talloc_new(NULL);
873         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
874
875         dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
876         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
877
878         if(!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS", zone->name)) {
879                 talloc_free(tmp_ctx);
880                 return WERR_NOMEM;
881         }
882
883         /* Add dnsZone record */
884         status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
885         if (!W_ERROR_IS_OK(status)) {
886                 talloc_free(tmp_ctx);
887                 return status;
888         }
889
890         if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
891                 talloc_free(tmp_ctx);
892                 return WERR_NOMEM;
893         }
894
895         dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
896         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
897
898         tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
899                                  lpcfg_netbios_name(lp_ctx),
900                                  lpcfg_realm(lp_ctx));
901         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
902         server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
903         W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
904         talloc_free(tmpstr);
905
906         tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
907                                   lpcfg_realm(lp_ctx));
908         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
909         soa_email = strlower_talloc(tmp_ctx, tmpstr);
910         W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
911         talloc_free(tmpstr);
912
913         unix_to_nt_time(&t, time(NULL));
914         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
915         t /= 3600;         /* convert to hours */
916
917         /* SOA Record - values same as defined in provision/sambadns.py */
918         soa.serial = 1;
919         soa.refresh = 900;
920         soa.retry = 600;
921         soa.expire = 86400;
922         soa.minimum = 3600;
923         soa.mname = server_fqdn;
924         soa.rname = soa_email;
925
926         dns_rec[0].wType = DNS_TYPE_SOA;
927         dns_rec[0].rank = DNS_RANK_ZONE;
928         dns_rec[0].dwSerial = soa.serial;
929         dns_rec[0].dwTtlSeconds = 3600;
930         dns_rec[0].dwTimeStamp = (uint32_t)t;
931         dns_rec[0].data.soa = soa;
932
933         /* NS Record */
934         dns_rec[1].wType = DNS_TYPE_NS;
935         dns_rec[1].rank = DNS_RANK_ZONE;
936         dns_rec[1].dwSerial = soa.serial;
937         dns_rec[1].dwTimeStamp = (uint32_t)t;
938         dns_rec[1].data.ns = server_fqdn;
939
940         /* Add @ Record */
941         status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
942
943         talloc_free(tmp_ctx);
944         return status;
945 }
946
947
948 /* Delete dnsZone record and all DNS records in the zone */
949 WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
950                                 struct dnsserver_zone *zone)
951 {
952         int ret;
953
954         ret = ldb_transaction_start(samdb);
955         if (ret != LDB_SUCCESS) {
956                 return WERR_INTERNAL_DB_ERROR;
957         }
958
959         ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
960         if (ret != LDB_SUCCESS) {
961                 ldb_transaction_cancel(samdb);
962                 return WERR_INTERNAL_DB_ERROR;
963         }
964
965         ret = ldb_transaction_commit(samdb);
966         if (ret != LDB_SUCCESS) {
967                 return WERR_INTERNAL_DB_ERROR;
968         }
969
970         return WERR_OK;
971 }