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 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
144 struct ldb_context *samdb,
145 struct dnsserver_zone *z)
147 const char * const attrs[] = { "dnsRecord", NULL };
148 struct ldb_result *res;
149 struct dnsp_DnssrvRpcRecord rec;
150 struct ldb_message_element *el;
151 enum ndr_err_code ndr_err;
152 int ret, i, serial = -1;
155 unix_to_nt_time(&t, time(NULL));
156 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
157 t /= 3600; /* convert to hours */
159 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
160 "(&(objectClass=dnsNode)(name=@))");
161 if (ret != LDB_SUCCESS || res->count == 0) {
165 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
170 for (i=0; i<el->num_values; i++) {
171 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
172 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
177 if (rec.wType == DNS_TYPE_SOA) {
178 serial = rec.data.soa.serial + 1;
179 rec.dwSerial = serial;
180 rec.dwTimeStamp = (uint32_t)t;
181 rec.data.soa.serial = serial;
183 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
184 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
193 el->flags = LDB_FLAG_MOD_REPLACE;
194 ret = ldb_modify(samdb, res->msgs[0]);
195 if (ret != LDB_SUCCESS) {
204 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
205 struct ldb_context *samdb,
207 struct dnsp_DnssrvRpcRecord *rec)
209 struct ldb_message *msg;
212 enum ndr_err_code ndr_err;
214 msg = ldb_msg_new(mem_ctx);
215 W_ERROR_HAVE_NO_MEMORY(msg);
218 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
219 if (ret != LDB_SUCCESS) {
224 ndr_err = ndr_push_struct_blob(&v, mem_ctx, rec,
225 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
227 return WERR_GENERAL_FAILURE;
230 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
231 if (ret != LDB_SUCCESS) {
236 ret = ldb_add(samdb, msg);
237 if (ret != LDB_SUCCESS) {
238 return WERR_INTERNAL_DB_ERROR;
245 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
246 struct ldb_context *samdb,
247 struct dnsserver_zone *z,
250 const char * const attrs[] = { "name", NULL };
251 struct ldb_result *res;
255 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
256 "(&(objectClass=dnsNode)(name=%s))", name);
257 if (ret != LDB_SUCCESS) {
258 return WERR_INTERNAL_DB_ERROR;
261 if (res->count > 0) {
263 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
266 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
267 W_ERROR_HAVE_NO_MEMORY(dn);
269 if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
273 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, NULL);
277 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
278 struct ldb_context *samdb,
279 struct dnsserver_zone *z,
281 struct DNS_RPC_RECORD *add_record)
283 const char * const attrs[] = { "dnsRecord", NULL };
284 struct ldb_result *res;
285 struct dnsp_DnssrvRpcRecord *rec;
286 struct ldb_message_element *el;
288 enum ndr_err_code ndr_err;
293 rec = dns_to_dnsp_copy(mem_ctx, add_record);
294 W_ERROR_HAVE_NO_MEMORY(rec);
296 serial = dnsserver_update_soa(mem_ctx, samdb, z);
298 return WERR_INTERNAL_DB_ERROR;
301 unix_to_nt_time(&t, time(NULL));
302 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
303 t /= 3600; /* convert to hours */
305 rec->dwSerial = serial;
306 rec->dwTimeStamp = t;
308 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
309 "(&(objectClass=dnsNode)(name=%s))", name);
310 if (ret != LDB_SUCCESS) {
311 return WERR_INTERNAL_DB_ERROR;
314 if (res->count == 0) {
315 dn = dnsserver_name_to_dn(mem_ctx, z, name);
316 W_ERROR_HAVE_NO_MEMORY(dn);
318 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, rec);
321 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
323 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
324 if (ret != LDB_SUCCESS) {
329 for (i=0; i<el->num_values; i++) {
330 struct dnsp_DnssrvRpcRecord rec2;
332 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
333 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
335 return WERR_GENERAL_FAILURE;
338 if (dns_record_match(rec, &rec2)) {
342 if (i < el->num_values) {
343 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
345 if (i == el->num_values) {
346 /* adding a new value */
347 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
348 W_ERROR_HAVE_NO_MEMORY(el->values);
352 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
353 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
354 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
355 return WERR_GENERAL_FAILURE;
358 el->flags = LDB_FLAG_MOD_REPLACE;
359 ret = ldb_modify(samdb, res->msgs[0]);
360 if (ret != LDB_SUCCESS) {
361 return WERR_INTERNAL_DB_ERROR;
367 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
368 struct ldb_context *samdb,
369 struct dnsserver_zone *z,
371 struct DNS_RPC_RECORD *add_record,
372 struct DNS_RPC_RECORD *del_record)
374 const char * const attrs[] = { "dnsRecord", NULL };
375 struct ldb_result *res;
376 struct dnsp_DnssrvRpcRecord *arec, *drec;
377 struct ldb_message_element *el;
378 enum ndr_err_code ndr_err;
383 serial = dnsserver_update_soa(mem_ctx, samdb, z);
385 return WERR_INTERNAL_DB_ERROR;
388 arec = dns_to_dnsp_copy(mem_ctx, add_record);
389 W_ERROR_HAVE_NO_MEMORY(arec);
391 drec = dns_to_dnsp_copy(mem_ctx, del_record);
392 W_ERROR_HAVE_NO_MEMORY(drec);
394 unix_to_nt_time(&t, time(NULL));
397 arec->dwSerial = serial;
398 arec->dwTimeStamp = t;
400 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
401 "(&(objectClass=dnsNode)(name=%s))", name);
402 if (ret != LDB_SUCCESS) {
403 return WERR_INTERNAL_DB_ERROR;
406 if (res->count == 0) {
407 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
410 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
411 if (el == NULL || el->num_values == 0) {
412 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
415 for (i=0; i<el->num_values; i++) {
416 struct dnsp_DnssrvRpcRecord rec2;
418 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
419 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
420 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
421 return WERR_GENERAL_FAILURE;
424 if (dns_record_match(arec, &rec2)) {
428 if (i < el->num_values) {
429 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
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(drec, &rec2)) {
446 if (i == el->num_values) {
447 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
450 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
451 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
452 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
453 return WERR_GENERAL_FAILURE;
456 el->flags = LDB_FLAG_MOD_REPLACE;
457 ret = ldb_modify(samdb, res->msgs[0]);
458 if (ret != LDB_SUCCESS) {
459 return WERR_INTERNAL_DB_ERROR;
465 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
466 struct ldb_context *samdb,
467 struct dnsserver_zone *z,
469 struct DNS_RPC_RECORD *del_record)
471 const char * const attrs[] = { "dnsRecord", NULL };
472 struct ldb_result *res;
473 struct dnsp_DnssrvRpcRecord *rec;
474 struct ldb_message_element *el;
475 enum ndr_err_code ndr_err;
479 serial = dnsserver_update_soa(mem_ctx, samdb, z);
481 return WERR_INTERNAL_DB_ERROR;
484 rec = dns_to_dnsp_copy(mem_ctx, del_record);
485 W_ERROR_HAVE_NO_MEMORY(rec);
487 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
488 "(&(objectClass=dnsNode)(name=%s))", name);
489 if (ret != LDB_SUCCESS) {
490 return WERR_INTERNAL_DB_ERROR;
493 if (res->count == 0) {
494 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
497 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
498 if (el == NULL || el->num_values == 0) {
499 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
502 for (i=0; i<el->num_values; i++) {
503 struct dnsp_DnssrvRpcRecord rec2;
505 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
506 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
507 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
508 return WERR_GENERAL_FAILURE;
511 if (dns_record_match(rec, &rec2)) {
515 if (i == el->num_values) {
516 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
518 if (i < el->num_values-1) {
519 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
523 if (el->num_values == 0) {
524 ret = ldb_delete(samdb, res->msgs[0]->dn);
526 el->flags = LDB_FLAG_MOD_REPLACE;
527 ret = ldb_modify(samdb, res->msgs[0]);
529 if (ret != LDB_SUCCESS) {
530 return WERR_INTERNAL_DB_ERROR;