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