2 Unix SMB/CIFS implementation.
6 Copyright (C) Amitay Isaacs 2011
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.
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.
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/>.
23 #include "dnsserver.h"
24 #include "lib/util/dlinklist.h"
25 #include "librpc/gen_ndr/ndr_dnsp.h"
26 #include "dsdb/samdb/samdb.h"
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)
33 struct dnsserver_partition *partitions, *p;
37 /* Domain partition */
38 p = talloc_zero(mem_ctx, struct dnsserver_partition);
43 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
44 if (p->partition_dn == NULL) {
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;
52 DLIST_ADD_END(partitions, p, NULL);
54 /* Forest Partition */
55 p = talloc_zero(mem_ctx, struct dnsserver_partition);
60 p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
61 if (p->partition_dn == NULL) {
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;
69 DLIST_ADD_END(partitions, p, NULL);
79 /* Search for all dnsZone records */
80 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
81 struct ldb_context *samdb,
82 struct dnsserver_partition *p)
85 const char * const attrs[] = {"name", NULL};
87 struct ldb_result *res;
88 struct dnsserver_zone *zones, *z;
91 tmp_ctx = talloc_new(mem_ctx);
92 if (tmp_ctx == NULL) {
96 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
100 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
104 ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
105 attrs, "(objectClass=dnsZone)");
106 if (ret != LDB_SUCCESS) {
107 DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
108 ldb_dn_get_linearized(dn)));
113 for(i=0; i<res->count; i++) {
115 z = talloc_zero(mem_ctx, struct dnsserver_zone);
121 name = talloc_strdup(z,
122 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
123 if (strcmp(name, "RootDNSServers") == 0) {
125 z->name = talloc_strdup(z, ".");
129 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
131 DLIST_ADD_END(zones, z, NULL);
132 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
138 talloc_free(tmp_ctx);
143 /* Find DNS partition information */
144 struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
145 struct ldb_context *samdb,
146 struct dnsserver_partition *p)
148 const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
149 const char * const attrs_none[] = { NULL };
150 struct ldb_result *res;
151 struct ldb_message_element *el;
153 struct dnsserver_partition_info *partinfo;
154 int i, ret, instance_type;
157 tmp_ctx = talloc_new(mem_ctx);
158 if (tmp_ctx == NULL) {
162 partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
163 if (partinfo == NULL) {
164 talloc_free(tmp_ctx);
168 /* Search for the active replica and state */
169 ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
171 if (ret != LDB_SUCCESS || res->count != 1) {
175 /* Set the state of the partition */
176 instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
177 if (instance_type == -1) {
178 partinfo->dwState = DNS_DP_STATE_UNKNOWN;
179 } else if (instance_type & INSTANCE_TYPE_NC_COMING) {
180 partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
181 } else if (instance_type & INSTANCE_TYPE_NC_GOING) {
182 partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
184 partinfo->dwState = DNS_DP_OKAY;
187 el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
189 partinfo->dwReplicaCount = 0;
190 partinfo->ReplicaArray = NULL;
192 partinfo->dwReplicaCount = el->num_values;
193 partinfo->ReplicaArray = talloc_zero_array(partinfo,
194 struct DNS_RPC_DP_REPLICA *,
196 if (partinfo->ReplicaArray == NULL) {
199 for (i=0; i<el->num_values; i++) {
200 partinfo->ReplicaArray[i] = talloc_zero(partinfo,
201 struct DNS_RPC_DP_REPLICA);
202 if (partinfo->ReplicaArray[i] == NULL) {
205 partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
207 (const char *)el->values[i].data);
208 if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
215 /* Search for cross-reference object */
216 dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
221 ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
222 "(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
223 if (ret != LDB_SUCCESS || res->count != 1) {
226 partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
227 if (partinfo->pszCrDn == NULL) {
232 talloc_free(tmp_ctx);
236 talloc_free(tmp_ctx);
237 talloc_free(partinfo);
242 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
243 struct ldb_context *samdb,
244 struct dnsserver_zone *z)
246 const char * const attrs[] = { "dnsRecord", NULL };
247 struct ldb_result *res;
248 struct dnsp_DnssrvRpcRecord rec;
249 struct ldb_message_element *el;
250 enum ndr_err_code ndr_err;
251 int ret, i, serial = -1;
254 unix_to_nt_time(&t, time(NULL));
255 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
256 t /= 3600; /* convert to hours */
258 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
259 "(&(objectClass=dnsNode)(name=@))");
260 if (ret != LDB_SUCCESS || res->count == 0) {
264 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
269 for (i=0; i<el->num_values; i++) {
270 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
271 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
272 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
276 if (rec.wType == DNS_TYPE_SOA) {
277 serial = rec.data.soa.serial + 1;
278 rec.dwSerial = serial;
279 rec.dwTimeStamp = (uint32_t)t;
280 rec.data.soa.serial = serial;
282 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
283 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
292 el->flags = LDB_FLAG_MOD_REPLACE;
293 ret = ldb_modify(samdb, res->msgs[0]);
294 if (ret != LDB_SUCCESS) {
303 /* Add DNS record to the database */
304 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
305 struct ldb_context *samdb,
308 struct dnsp_DnssrvRpcRecord *rec)
310 struct ldb_message *msg;
313 enum ndr_err_code ndr_err;
316 msg = ldb_msg_new(mem_ctx);
317 W_ERROR_HAVE_NO_MEMORY(msg);
320 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
321 if (ret != LDB_SUCCESS) {
325 if (num_rec > 0 && rec) {
326 for (i=0; i<num_rec; i++) {
327 ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
328 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
329 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
330 return WERR_GENERAL_FAILURE;
333 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
334 if (ret != LDB_SUCCESS) {
340 ret = ldb_add(samdb, msg);
341 if (ret != LDB_SUCCESS) {
342 return WERR_INTERNAL_DB_ERROR;
349 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
350 struct ldb_context *samdb,
351 struct dnsserver_zone *z,
354 const char * const attrs[] = { "name", NULL };
355 struct ldb_result *res;
359 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
360 "(&(objectClass=dnsNode)(name=%s))", name);
361 if (ret != LDB_SUCCESS) {
362 return WERR_INTERNAL_DB_ERROR;
365 if (res->count > 0) {
367 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
370 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
371 W_ERROR_HAVE_NO_MEMORY(dn);
373 if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
377 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
381 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
382 struct ldb_context *samdb,
383 struct dnsserver_zone *z,
385 struct DNS_RPC_RECORD *add_record)
387 const char * const attrs[] = { "dnsRecord", NULL };
388 struct ldb_result *res;
389 struct dnsp_DnssrvRpcRecord *rec;
390 struct ldb_message_element *el;
392 enum ndr_err_code ndr_err;
397 rec = dns_to_dnsp_copy(mem_ctx, add_record);
398 W_ERROR_HAVE_NO_MEMORY(rec);
400 serial = dnsserver_update_soa(mem_ctx, samdb, z);
402 return WERR_INTERNAL_DB_ERROR;
405 unix_to_nt_time(&t, time(NULL));
406 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
407 t /= 3600; /* convert to hours */
409 rec->dwSerial = serial;
410 rec->dwTimeStamp = t;
412 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
413 "(&(objectClass=dnsNode)(name=%s))", name);
414 if (ret != LDB_SUCCESS) {
415 return WERR_INTERNAL_DB_ERROR;
418 if (res->count == 0) {
419 dn = dnsserver_name_to_dn(mem_ctx, z, name);
420 W_ERROR_HAVE_NO_MEMORY(dn);
422 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
425 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
427 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
428 if (ret != LDB_SUCCESS) {
433 for (i=0; i<el->num_values; i++) {
434 struct dnsp_DnssrvRpcRecord rec2;
436 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
437 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
438 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
439 return WERR_GENERAL_FAILURE;
442 if (dns_record_match(rec, &rec2)) {
446 if (i < el->num_values) {
447 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
449 if (i == el->num_values) {
450 /* adding a new value */
451 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
452 W_ERROR_HAVE_NO_MEMORY(el->values);
456 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
457 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
458 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
459 return WERR_GENERAL_FAILURE;
462 el->flags = LDB_FLAG_MOD_REPLACE;
463 ret = ldb_modify(samdb, res->msgs[0]);
464 if (ret != LDB_SUCCESS) {
465 return WERR_INTERNAL_DB_ERROR;
471 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
472 struct ldb_context *samdb,
473 struct dnsserver_zone *z,
475 struct DNS_RPC_RECORD *add_record,
476 struct DNS_RPC_RECORD *del_record)
478 const char * const attrs[] = { "dnsRecord", NULL };
479 struct ldb_result *res;
480 struct dnsp_DnssrvRpcRecord *arec, *drec;
481 struct ldb_message_element *el;
482 enum ndr_err_code ndr_err;
487 serial = dnsserver_update_soa(mem_ctx, samdb, z);
489 return WERR_INTERNAL_DB_ERROR;
492 arec = dns_to_dnsp_copy(mem_ctx, add_record);
493 W_ERROR_HAVE_NO_MEMORY(arec);
495 drec = dns_to_dnsp_copy(mem_ctx, del_record);
496 W_ERROR_HAVE_NO_MEMORY(drec);
498 unix_to_nt_time(&t, time(NULL));
501 arec->dwSerial = serial;
502 arec->dwTimeStamp = t;
504 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
505 "(&(objectClass=dnsNode)(name=%s))", name);
506 if (ret != LDB_SUCCESS) {
507 return WERR_INTERNAL_DB_ERROR;
510 if (res->count == 0) {
511 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
514 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
515 if (el == NULL || el->num_values == 0) {
516 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
519 for (i=0; i<el->num_values; i++) {
520 struct dnsp_DnssrvRpcRecord rec2;
522 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
523 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
524 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
525 return WERR_GENERAL_FAILURE;
528 if (dns_record_match(arec, &rec2)) {
532 if (i < el->num_values) {
533 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
537 for (i=0; i<el->num_values; i++) {
538 struct dnsp_DnssrvRpcRecord rec2;
540 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
541 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
542 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
543 return WERR_GENERAL_FAILURE;
546 if (dns_record_match(drec, &rec2)) {
550 if (i == el->num_values) {
551 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
554 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
555 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
556 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
557 return WERR_GENERAL_FAILURE;
560 el->flags = LDB_FLAG_MOD_REPLACE;
561 ret = ldb_modify(samdb, res->msgs[0]);
562 if (ret != LDB_SUCCESS) {
563 return WERR_INTERNAL_DB_ERROR;
569 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
570 struct ldb_context *samdb,
571 struct dnsserver_zone *z,
573 struct DNS_RPC_RECORD *del_record)
575 const char * const attrs[] = { "dnsRecord", NULL };
576 struct ldb_result *res;
577 struct dnsp_DnssrvRpcRecord *rec;
578 struct ldb_message_element *el;
579 enum ndr_err_code ndr_err;
583 serial = dnsserver_update_soa(mem_ctx, samdb, z);
585 return WERR_INTERNAL_DB_ERROR;
588 rec = dns_to_dnsp_copy(mem_ctx, del_record);
589 W_ERROR_HAVE_NO_MEMORY(rec);
591 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
592 "(&(objectClass=dnsNode)(name=%s))", name);
593 if (ret != LDB_SUCCESS) {
594 return WERR_INTERNAL_DB_ERROR;
597 if (res->count == 0) {
598 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
601 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
602 if (el == NULL || el->num_values == 0) {
603 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
606 for (i=0; i<el->num_values; i++) {
607 struct dnsp_DnssrvRpcRecord rec2;
609 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
610 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
611 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
612 return WERR_GENERAL_FAILURE;
615 if (dns_record_match(rec, &rec2)) {
619 if (i == el->num_values) {
620 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
622 if (i < el->num_values-1) {
623 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
627 if (el->num_values == 0) {
628 ret = ldb_delete(samdb, res->msgs[0]->dn);
630 el->flags = LDB_FLAG_MOD_REPLACE;
631 ret = ldb_modify(samdb, res->msgs[0]);
633 if (ret != LDB_SUCCESS) {
634 return WERR_INTERNAL_DB_ERROR;