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