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 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
304 struct ldb_context *samdb,
306 struct dnsp_DnssrvRpcRecord *rec)
308 struct ldb_message *msg;
311 enum ndr_err_code ndr_err;
313 msg = ldb_msg_new(mem_ctx);
314 W_ERROR_HAVE_NO_MEMORY(msg);
317 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
318 if (ret != LDB_SUCCESS) {
323 ndr_err = ndr_push_struct_blob(&v, mem_ctx, rec,
324 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
325 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
326 return WERR_GENERAL_FAILURE;
329 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
330 if (ret != LDB_SUCCESS) {
335 ret = ldb_add(samdb, msg);
336 if (ret != LDB_SUCCESS) {
337 return WERR_INTERNAL_DB_ERROR;
344 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
345 struct ldb_context *samdb,
346 struct dnsserver_zone *z,
349 const char * const attrs[] = { "name", NULL };
350 struct ldb_result *res;
354 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
355 "(&(objectClass=dnsNode)(name=%s))", name);
356 if (ret != LDB_SUCCESS) {
357 return WERR_INTERNAL_DB_ERROR;
360 if (res->count > 0) {
362 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
365 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
366 W_ERROR_HAVE_NO_MEMORY(dn);
368 if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
372 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, NULL);
376 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
377 struct ldb_context *samdb,
378 struct dnsserver_zone *z,
380 struct DNS_RPC_RECORD *add_record)
382 const char * const attrs[] = { "dnsRecord", NULL };
383 struct ldb_result *res;
384 struct dnsp_DnssrvRpcRecord *rec;
385 struct ldb_message_element *el;
387 enum ndr_err_code ndr_err;
392 rec = dns_to_dnsp_copy(mem_ctx, add_record);
393 W_ERROR_HAVE_NO_MEMORY(rec);
395 serial = dnsserver_update_soa(mem_ctx, samdb, z);
397 return WERR_INTERNAL_DB_ERROR;
400 unix_to_nt_time(&t, time(NULL));
401 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
402 t /= 3600; /* convert to hours */
404 rec->dwSerial = serial;
405 rec->dwTimeStamp = t;
407 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
408 "(&(objectClass=dnsNode)(name=%s))", name);
409 if (ret != LDB_SUCCESS) {
410 return WERR_INTERNAL_DB_ERROR;
413 if (res->count == 0) {
414 dn = dnsserver_name_to_dn(mem_ctx, z, name);
415 W_ERROR_HAVE_NO_MEMORY(dn);
417 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, rec);
420 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
422 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
423 if (ret != LDB_SUCCESS) {
428 for (i=0; i<el->num_values; i++) {
429 struct dnsp_DnssrvRpcRecord rec2;
431 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
432 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
433 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
434 return WERR_GENERAL_FAILURE;
437 if (dns_record_match(rec, &rec2)) {
441 if (i < el->num_values) {
442 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
444 if (i == el->num_values) {
445 /* adding a new value */
446 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
447 W_ERROR_HAVE_NO_MEMORY(el->values);
451 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
452 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
453 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
454 return WERR_GENERAL_FAILURE;
457 el->flags = LDB_FLAG_MOD_REPLACE;
458 ret = ldb_modify(samdb, res->msgs[0]);
459 if (ret != LDB_SUCCESS) {
460 return WERR_INTERNAL_DB_ERROR;
466 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
467 struct ldb_context *samdb,
468 struct dnsserver_zone *z,
470 struct DNS_RPC_RECORD *add_record,
471 struct DNS_RPC_RECORD *del_record)
473 const char * const attrs[] = { "dnsRecord", NULL };
474 struct ldb_result *res;
475 struct dnsp_DnssrvRpcRecord *arec, *drec;
476 struct ldb_message_element *el;
477 enum ndr_err_code ndr_err;
482 serial = dnsserver_update_soa(mem_ctx, samdb, z);
484 return WERR_INTERNAL_DB_ERROR;
487 arec = dns_to_dnsp_copy(mem_ctx, add_record);
488 W_ERROR_HAVE_NO_MEMORY(arec);
490 drec = dns_to_dnsp_copy(mem_ctx, del_record);
491 W_ERROR_HAVE_NO_MEMORY(drec);
493 unix_to_nt_time(&t, time(NULL));
496 arec->dwSerial = serial;
497 arec->dwTimeStamp = t;
499 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
500 "(&(objectClass=dnsNode)(name=%s))", name);
501 if (ret != LDB_SUCCESS) {
502 return WERR_INTERNAL_DB_ERROR;
505 if (res->count == 0) {
506 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
509 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
510 if (el == NULL || el->num_values == 0) {
511 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
514 for (i=0; i<el->num_values; i++) {
515 struct dnsp_DnssrvRpcRecord rec2;
517 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
518 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
519 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
520 return WERR_GENERAL_FAILURE;
523 if (dns_record_match(arec, &rec2)) {
527 if (i < el->num_values) {
528 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
532 for (i=0; i<el->num_values; i++) {
533 struct dnsp_DnssrvRpcRecord rec2;
535 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
536 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
537 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
538 return WERR_GENERAL_FAILURE;
541 if (dns_record_match(drec, &rec2)) {
545 if (i == el->num_values) {
546 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
549 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
550 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
551 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
552 return WERR_GENERAL_FAILURE;
555 el->flags = LDB_FLAG_MOD_REPLACE;
556 ret = ldb_modify(samdb, res->msgs[0]);
557 if (ret != LDB_SUCCESS) {
558 return WERR_INTERNAL_DB_ERROR;
564 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
565 struct ldb_context *samdb,
566 struct dnsserver_zone *z,
568 struct DNS_RPC_RECORD *del_record)
570 const char * const attrs[] = { "dnsRecord", NULL };
571 struct ldb_result *res;
572 struct dnsp_DnssrvRpcRecord *rec;
573 struct ldb_message_element *el;
574 enum ndr_err_code ndr_err;
578 serial = dnsserver_update_soa(mem_ctx, samdb, z);
580 return WERR_INTERNAL_DB_ERROR;
583 rec = dns_to_dnsp_copy(mem_ctx, del_record);
584 W_ERROR_HAVE_NO_MEMORY(rec);
586 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
587 "(&(objectClass=dnsNode)(name=%s))", name);
588 if (ret != LDB_SUCCESS) {
589 return WERR_INTERNAL_DB_ERROR;
592 if (res->count == 0) {
593 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
596 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
597 if (el == NULL || el->num_values == 0) {
598 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
601 for (i=0; i<el->num_values; i++) {
602 struct dnsp_DnssrvRpcRecord rec2;
604 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
605 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
606 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
607 return WERR_GENERAL_FAILURE;
610 if (dns_record_match(rec, &rec2)) {
614 if (i == el->num_values) {
615 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
617 if (i < el->num_values-1) {
618 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
622 if (el->num_values == 0) {
623 ret = ldb_delete(samdb, res->msgs[0]->dn);
625 el->flags = LDB_FLAG_MOD_REPLACE;
626 ret = ldb_modify(samdb, res->msgs[0]);
628 if (ret != LDB_SUCCESS) {
629 return WERR_INTERNAL_DB_ERROR;