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