a181e069b65df8ab663c7fd930dc0bf3e43326e0
[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 "dsdb/samdb/samdb.h"
27
28 /* There are only 2 fixed partitions for DNS */
29 struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
30                                                         struct dnsserver_serverinfo *serverinfo,
31                                                         struct ldb_context *samdb)
32 {
33         struct dnsserver_partition *partitions, *p;
34
35         partitions = NULL;
36
37         /* Domain partition */
38         p = talloc_zero(mem_ctx, struct dnsserver_partition);
39         if (p == NULL) {
40                 goto failed;
41         }
42
43         p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
44         if (p->partition_dn == NULL) {
45                 goto failed;
46         }
47
48         p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
49         p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_DOMAIN_DEFAULT | DNS_DP_ENLISTED;
50         p->is_forest = false;
51
52         DLIST_ADD_END(partitions, p, NULL);
53
54         /* Forest Partition */
55         p = talloc_zero(mem_ctx, struct dnsserver_partition);
56         if (p == NULL) {
57                 goto failed;
58         }
59
60         p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
61         if (p->partition_dn == NULL) {
62                 goto failed;
63         }
64
65         p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
66         p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED;
67         p->is_forest = true;
68
69         DLIST_ADD_END(partitions, p, NULL);
70
71         return partitions;
72
73 failed:
74         return NULL;
75
76 }
77
78 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
79                                                 struct ldb_context *samdb,
80                                                 struct dnsserver_partition *p)
81 {
82         TALLOC_CTX *tmp_ctx;
83         const char * const attrs[] = {"name", NULL};
84         struct ldb_dn *dn;
85         struct ldb_result *res;
86         struct dnsserver_zone *zones, *z;
87         int i, ret;
88
89         tmp_ctx = talloc_new(mem_ctx);
90         if (tmp_ctx == NULL) {
91                 return NULL;
92         }
93
94         dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
95         if (dn == NULL) {
96                 goto failed;
97         }
98         if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
99                 goto failed;
100         }
101
102         ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
103                           attrs, "(objectClass=dnsZone)");
104         if (ret != LDB_SUCCESS) {
105                 DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
106                         ldb_dn_get_linearized(dn)));
107                 goto failed;
108         }
109
110         zones = NULL;
111         for(i=0; i<res->count; i++) {
112                 char *name;
113                 z = talloc_zero(mem_ctx, struct dnsserver_zone);
114                 if (z == NULL) {
115                         goto failed;
116                 }
117
118                 z->partition = p;
119                 name = talloc_strdup(z,
120                                 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
121                 if (strcmp(name, "RootDNSServers") == 0) {
122                         talloc_free(name);
123                         z->name = talloc_strdup(z, ".");
124                 } else {
125                         z->name = name;
126                 }
127                 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
128
129                 DLIST_ADD_END(zones, z, NULL);
130                 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
131         }
132
133         return zones;
134
135 failed:
136         talloc_free(tmp_ctx);
137         return NULL;
138 }
139
140
141 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
142                                 struct ldb_context *samdb,
143                                 struct dnsserver_zone *z)
144 {
145         const char * const attrs[] = { "dnsRecord", NULL };
146         struct ldb_result *res;
147         struct dnsp_DnssrvRpcRecord rec;
148         struct ldb_message_element *el;
149         enum ndr_err_code ndr_err;
150         int ret, i, serial = -1;
151         NTTIME t;
152
153         unix_to_nt_time(&t, time(NULL));
154         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
155         t /= 3600;         /* convert to hours */
156
157         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
158                         "(&(objectClass=dnsNode)(name=@))");
159         if (ret != LDB_SUCCESS || res->count == 0) {
160                 return -1;
161         }
162
163         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
164         if (el == NULL) {
165                 return -1;
166         }
167
168         for (i=0; i<el->num_values; i++) {
169                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
170                                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
171                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
172                         continue;
173                 }
174
175                 if (rec.wType == DNS_TYPE_SOA) {
176                         serial = rec.data.soa.serial + 1;
177                         rec.dwSerial = serial;
178                         rec.dwTimeStamp = (uint32_t)t;
179                         rec.data.soa.serial = serial;
180
181                         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
182                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
183                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
184                                 return -1;
185                         }
186                         break;
187                 }
188         }
189
190         if (serial != -1) {
191                 el->flags = LDB_FLAG_MOD_REPLACE;
192                 ret = ldb_modify(samdb, res->msgs[0]);
193                 if (ret != LDB_SUCCESS) {
194                         return -1;
195                 }
196         }
197
198         return serial;
199 }
200
201
202 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
203                                 struct ldb_context *samdb,
204                                 struct ldb_dn *dn,
205                                 struct dnsp_DnssrvRpcRecord *rec)
206 {
207         struct ldb_message *msg;
208         struct ldb_val v;
209         int ret;
210         enum ndr_err_code ndr_err;
211
212         msg = ldb_msg_new(mem_ctx);
213         W_ERROR_HAVE_NO_MEMORY(msg);
214
215         msg->dn = dn;
216         ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
217         if (ret != LDB_SUCCESS) {
218                 return WERR_NOMEM;
219         }
220
221         if (rec) {
222                 ndr_err = ndr_push_struct_blob(&v, mem_ctx, rec,
223                                 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
224                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
225                         return WERR_GENERAL_FAILURE;
226                 }
227
228                 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
229                 if (ret != LDB_SUCCESS) {
230                         return WERR_NOMEM;
231                 }
232         }
233
234         ret = ldb_add(samdb, msg);
235         if (ret != LDB_SUCCESS) {
236                 return WERR_INTERNAL_DB_ERROR;
237         }
238
239         return WERR_OK;
240 }
241
242
243 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
244                                         struct ldb_context *samdb,
245                                         struct dnsserver_zone *z,
246                                         const char *name)
247 {
248         const char * const attrs[] = { "name", NULL };
249         struct ldb_result *res;
250         struct ldb_dn *dn;
251         int ret;
252
253         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
254                         "(&(objectClass=dnsNode)(name=%s))", name);
255         if (ret != LDB_SUCCESS) {
256                 return WERR_INTERNAL_DB_ERROR;
257         }
258
259         if (res->count > 0) {
260                 talloc_free(res);
261                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
262         }
263
264         dn = ldb_dn_copy(mem_ctx, z->zone_dn);
265         W_ERROR_HAVE_NO_MEMORY(dn);
266
267         if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
268                 return WERR_NOMEM;
269         }
270
271         return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, NULL);
272 }
273
274
275 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
276                                         struct ldb_context *samdb,
277                                         struct dnsserver_zone *z,
278                                         const char *name,
279                                         struct DNS_RPC_RECORD *add_record)
280 {
281         const char * const attrs[] = { "dnsRecord", NULL };
282         struct ldb_result *res;
283         struct dnsp_DnssrvRpcRecord *rec;
284         struct ldb_message_element *el;
285         struct ldb_dn *dn;
286         enum ndr_err_code ndr_err;
287         NTTIME t;
288         int ret, i;
289         int serial;
290
291         rec = dns_to_dnsp_copy(mem_ctx, add_record);
292         W_ERROR_HAVE_NO_MEMORY(rec);
293
294         serial = dnsserver_update_soa(mem_ctx, samdb, z);
295         if (serial < 0) {
296                 return WERR_INTERNAL_DB_ERROR;
297         }
298
299         unix_to_nt_time(&t, time(NULL));
300         t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
301         t /= 3600;         /* convert to hours */
302
303         rec->dwSerial = serial;
304         rec->dwTimeStamp = t;
305
306         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
307                         "(&(objectClass=dnsNode)(name=%s))", name);
308         if (ret != LDB_SUCCESS) {
309                 return WERR_INTERNAL_DB_ERROR;
310         }
311
312         if (res->count == 0) {
313                 dn = dnsserver_name_to_dn(mem_ctx, z, name);
314                 W_ERROR_HAVE_NO_MEMORY(dn);
315
316                 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, rec);
317         }
318
319         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
320         if (el == NULL) {
321                 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
322                 if (ret != LDB_SUCCESS) {
323                         return WERR_NOMEM;
324                 }
325         }
326
327         for (i=0; i<el->num_values; i++) {
328                 struct dnsp_DnssrvRpcRecord rec2;
329
330                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
331                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
332                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
333                         return WERR_GENERAL_FAILURE;
334                 }
335
336                 if (dns_record_match(rec, &rec2)) {
337                         break;
338                 }
339         }
340         if (i < el->num_values) {
341                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
342         }
343         if (i == el->num_values) {
344                 /* adding a new value */
345                 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
346                 W_ERROR_HAVE_NO_MEMORY(el->values);
347                 el->num_values++;
348         }
349
350         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
351                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
352         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
353                 return WERR_GENERAL_FAILURE;
354         }
355
356         el->flags = LDB_FLAG_MOD_REPLACE;
357         ret = ldb_modify(samdb, res->msgs[0]);
358         if (ret != LDB_SUCCESS) {
359                 return WERR_INTERNAL_DB_ERROR;
360         }
361
362         return WERR_OK;
363 }
364
365 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
366                                         struct ldb_context *samdb,
367                                         struct dnsserver_zone *z,
368                                         const char *name,
369                                         struct DNS_RPC_RECORD *add_record,
370                                         struct DNS_RPC_RECORD *del_record)
371 {
372         const char * const attrs[] = { "dnsRecord", NULL };
373         struct ldb_result *res;
374         struct dnsp_DnssrvRpcRecord *arec, *drec;
375         struct ldb_message_element *el;
376         enum ndr_err_code ndr_err;
377         NTTIME t;
378         int ret, i;
379         int serial;
380
381         serial = dnsserver_update_soa(mem_ctx, samdb, z);
382         if (serial < 0) {
383                 return WERR_INTERNAL_DB_ERROR;
384         }
385
386         arec = dns_to_dnsp_copy(mem_ctx, add_record);
387         W_ERROR_HAVE_NO_MEMORY(arec);
388
389         drec = dns_to_dnsp_copy(mem_ctx, del_record);
390         W_ERROR_HAVE_NO_MEMORY(drec);
391
392         unix_to_nt_time(&t, time(NULL));
393         t /= 10*1000*1000;
394
395         arec->dwSerial = serial;
396         arec->dwTimeStamp = t;
397
398         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
399                         "(&(objectClass=dnsNode)(name=%s))", name);
400         if (ret != LDB_SUCCESS) {
401                 return WERR_INTERNAL_DB_ERROR;
402         }
403
404         if (res->count == 0) {
405                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
406         }
407
408         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
409         if (el == NULL || el->num_values == 0) {
410                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
411         }
412
413         for (i=0; i<el->num_values; i++) {
414                 struct dnsp_DnssrvRpcRecord rec2;
415
416                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
417                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
418                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
419                         return WERR_GENERAL_FAILURE;
420                 }
421
422                 if (dns_record_match(arec, &rec2)) {
423                         break;
424                 }
425         }
426         if (i < el->num_values) {
427                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
428         }
429
430
431         for (i=0; i<el->num_values; i++) {
432                 struct dnsp_DnssrvRpcRecord rec2;
433
434                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
435                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
436                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
437                         return WERR_GENERAL_FAILURE;
438                 }
439
440                 if (dns_record_match(drec, &rec2)) {
441                         break;
442                 }
443         }
444         if (i == el->num_values) {
445                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
446         }
447
448         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
449                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
450         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
451                 return WERR_GENERAL_FAILURE;
452         }
453
454         el->flags = LDB_FLAG_MOD_REPLACE;
455         ret = ldb_modify(samdb, res->msgs[0]);
456         if (ret != LDB_SUCCESS) {
457                 return WERR_INTERNAL_DB_ERROR;
458         }
459
460         return WERR_OK;
461 }
462
463 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
464                                         struct ldb_context *samdb,
465                                         struct dnsserver_zone *z,
466                                         const char *name,
467                                         struct DNS_RPC_RECORD *del_record)
468 {
469         const char * const attrs[] = { "dnsRecord", NULL };
470         struct ldb_result *res;
471         struct dnsp_DnssrvRpcRecord *rec;
472         struct ldb_message_element *el;
473         enum ndr_err_code ndr_err;
474         int ret, i;
475         int serial;
476
477         serial = dnsserver_update_soa(mem_ctx, samdb, z);
478         if (serial < 0) {
479                 return WERR_INTERNAL_DB_ERROR;
480         }
481
482         rec = dns_to_dnsp_copy(mem_ctx, del_record);
483         W_ERROR_HAVE_NO_MEMORY(rec);
484
485         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
486                         "(&(objectClass=dnsNode)(name=%s))", name);
487         if (ret != LDB_SUCCESS) {
488                 return WERR_INTERNAL_DB_ERROR;
489         }
490
491         if (res->count == 0) {
492                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
493         }
494
495         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
496         if (el == NULL || el->num_values == 0) {
497                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
498         }
499
500         for (i=0; i<el->num_values; i++) {
501                 struct dnsp_DnssrvRpcRecord rec2;
502
503                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
504                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
505                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
506                         return WERR_GENERAL_FAILURE;
507                 }
508
509                 if (dns_record_match(rec, &rec2)) {
510                         break;
511                 }
512         }
513         if (i == el->num_values) {
514                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
515         }
516         if (i < el->num_values-1) {
517                 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
518         }
519         el->num_values--;
520
521         if (el->num_values == 0) {
522                 ret = ldb_delete(samdb, res->msgs[0]->dn);
523         } else {
524                 el->flags = LDB_FLAG_MOD_REPLACE;
525                 ret = ldb_modify(samdb, res->msgs[0]);
526         }
527         if (ret != LDB_SUCCESS) {
528                 return WERR_INTERNAL_DB_ERROR;
529         }
530
531         return WERR_OK;
532 }