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);
78 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
79 struct ldb_context *samdb,
80 struct dnsserver_partition *p)
83 const char * const attrs[] = {"name", NULL};
85 struct ldb_result *res;
86 struct dnsserver_zone *zones, *z;
89 tmp_ctx = talloc_new(mem_ctx);
90 if (tmp_ctx == NULL) {
94 dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
98 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
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)));
111 for(i=0; i<res->count; i++) {
113 z = talloc_zero(mem_ctx, struct dnsserver_zone);
119 name = talloc_strdup(z,
120 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
121 if (strcmp(name, "RootDNSServers") == 0) {
123 z->name = talloc_strdup(z, ".");
127 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
129 DLIST_ADD_END(zones, z, NULL);
130 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
136 talloc_free(tmp_ctx);
141 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
142 struct ldb_context *samdb,
143 struct dnsserver_zone *z)
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;
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 */
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) {
163 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
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)) {
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;
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)) {
191 el->flags = LDB_FLAG_MOD_REPLACE;
192 ret = ldb_modify(samdb, res->msgs[0]);
193 if (ret != LDB_SUCCESS) {
202 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
203 struct ldb_context *samdb,
205 struct dnsp_DnssrvRpcRecord *rec)
207 struct ldb_message *msg;
210 enum ndr_err_code ndr_err;
212 msg = ldb_msg_new(mem_ctx);
213 W_ERROR_HAVE_NO_MEMORY(msg);
216 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
217 if (ret != LDB_SUCCESS) {
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;
228 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
229 if (ret != LDB_SUCCESS) {
234 ret = ldb_add(samdb, msg);
235 if (ret != LDB_SUCCESS) {
236 return WERR_INTERNAL_DB_ERROR;
243 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
244 struct ldb_context *samdb,
245 struct dnsserver_zone *z,
248 const char * const attrs[] = { "name", NULL };
249 struct ldb_result *res;
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;
259 if (res->count > 0) {
261 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
264 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
265 W_ERROR_HAVE_NO_MEMORY(dn);
267 if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
271 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, NULL);
275 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
276 struct ldb_context *samdb,
277 struct dnsserver_zone *z,
279 struct DNS_RPC_RECORD *add_record)
281 const char * const attrs[] = { "dnsRecord", NULL };
282 struct ldb_result *res;
283 struct dnsp_DnssrvRpcRecord *rec;
284 struct ldb_message_element *el;
286 enum ndr_err_code ndr_err;
291 rec = dns_to_dnsp_copy(mem_ctx, add_record);
292 W_ERROR_HAVE_NO_MEMORY(rec);
294 serial = dnsserver_update_soa(mem_ctx, samdb, z);
296 return WERR_INTERNAL_DB_ERROR;
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 */
303 rec->dwSerial = serial;
304 rec->dwTimeStamp = t;
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;
312 if (res->count == 0) {
313 dn = dnsserver_name_to_dn(mem_ctx, z, name);
314 W_ERROR_HAVE_NO_MEMORY(dn);
316 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, rec);
319 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
321 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
322 if (ret != LDB_SUCCESS) {
327 for (i=0; i<el->num_values; i++) {
328 struct dnsp_DnssrvRpcRecord rec2;
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;
336 if (dns_record_match(rec, &rec2)) {
340 if (i < el->num_values) {
341 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
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);
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;
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;
365 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
366 struct ldb_context *samdb,
367 struct dnsserver_zone *z,
369 struct DNS_RPC_RECORD *add_record,
370 struct DNS_RPC_RECORD *del_record)
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;
381 serial = dnsserver_update_soa(mem_ctx, samdb, z);
383 return WERR_INTERNAL_DB_ERROR;
386 arec = dns_to_dnsp_copy(mem_ctx, add_record);
387 W_ERROR_HAVE_NO_MEMORY(arec);
389 drec = dns_to_dnsp_copy(mem_ctx, del_record);
390 W_ERROR_HAVE_NO_MEMORY(drec);
392 unix_to_nt_time(&t, time(NULL));
395 arec->dwSerial = serial;
396 arec->dwTimeStamp = t;
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;
404 if (res->count == 0) {
405 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
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;
413 for (i=0; i<el->num_values; i++) {
414 struct dnsp_DnssrvRpcRecord rec2;
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;
422 if (dns_record_match(arec, &rec2)) {
426 if (i < el->num_values) {
427 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
431 for (i=0; i<el->num_values; i++) {
432 struct dnsp_DnssrvRpcRecord rec2;
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;
440 if (dns_record_match(drec, &rec2)) {
444 if (i == el->num_values) {
445 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
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;
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;
463 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
464 struct ldb_context *samdb,
465 struct dnsserver_zone *z,
467 struct DNS_RPC_RECORD *del_record)
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;
477 serial = dnsserver_update_soa(mem_ctx, samdb, z);
479 return WERR_INTERNAL_DB_ERROR;
482 rec = dns_to_dnsp_copy(mem_ctx, del_record);
483 W_ERROR_HAVE_NO_MEMORY(rec);
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;
491 if (res->count == 0) {
492 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
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;
500 for (i=0; i<el->num_values; i++) {
501 struct dnsp_DnssrvRpcRecord rec2;
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;
509 if (dns_record_match(rec, &rec2)) {
513 if (i == el->num_values) {
514 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
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));
521 if (el->num_values == 0) {
522 ret = ldb_delete(samdb, res->msgs[0]->dn);
524 el->flags = LDB_FLAG_MOD_REPLACE;
525 ret = ldb_modify(samdb, res->msgs[0]);
527 if (ret != LDB_SUCCESS) {
528 return WERR_INTERNAL_DB_ERROR;