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"
27 struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
28 struct ldb_context *samdb,
32 const char *domain_prefix = "DC=DomainDnsZones";
33 const char *forest_prefix = "DC=ForestDnsZones";
35 const char * const attrs[] = {"name", NULL};
36 struct ldb_dn *dn_base, *partition_dn, *dn;
37 struct ldb_result *res;
38 struct dnsserver_zone *zones, *z;
41 tmp_ctx = talloc_new(mem_ctx);
42 if (tmp_ctx == NULL) {
47 dn_base = ldb_get_root_basedn(samdb);
49 dn_base = ldb_get_default_basedn(samdb);
52 partition_dn = ldb_dn_copy(tmp_ctx, dn_base);
53 if (partition_dn == NULL) {
58 prefix = forest_prefix;
60 prefix = domain_prefix;
63 if (!ldb_dn_add_child_fmt(partition_dn, "%s", prefix)) {
67 dn = ldb_dn_copy(tmp_ctx, partition_dn);
71 if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
75 ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
76 attrs, "(&(objectClass=dnsZone)(!(name=RootDNSServers)))");
77 if (ret != LDB_SUCCESS) {
78 DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
79 ldb_dn_get_linearized(dn)));
84 for(i=0; i<res->count; i++) {
85 z = talloc_zero(mem_ctx, struct dnsserver_zone);
90 z->name = talloc_strdup(z,
91 ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
92 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
93 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
94 z->partition_dn = talloc_steal(z, partition_dn);
96 DLIST_ADD_END(zones, z, NULL);
102 talloc_free(tmp_ctx);
107 static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
108 struct ldb_context *samdb,
109 struct dnsserver_zone *z)
111 const char * const attrs[] = { "dnsRecord", NULL };
112 struct ldb_result *res;
113 struct dnsp_DnssrvRpcRecord rec;
114 struct ldb_message_element *el;
115 enum ndr_err_code ndr_err;
116 int ret, i, serial = -1;
119 unix_to_nt_time(&t, time(NULL));
120 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
121 t /= 3600; /* convert to hours */
123 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
124 "(&(objectClass=dnsNode)(name=@))");
125 if (ret != LDB_SUCCESS || res->count == 0) {
129 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
134 for (i=0; i<el->num_values; i++) {
135 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
136 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
137 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
141 if (rec.wType == DNS_TYPE_SOA) {
142 serial = rec.data.soa.serial + 1;
143 rec.dwSerial = serial;
144 rec.dwTimeStamp = (uint32_t)t;
145 rec.data.soa.serial = serial;
147 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
148 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
149 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157 el->flags = LDB_FLAG_MOD_REPLACE;
158 ret = ldb_modify(samdb, res->msgs[0]);
159 if (ret != LDB_SUCCESS) {
168 static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
169 struct ldb_context *samdb,
171 struct dnsp_DnssrvRpcRecord *rec)
173 struct ldb_message *msg;
176 enum ndr_err_code ndr_err;
178 msg = ldb_msg_new(mem_ctx);
179 W_ERROR_HAVE_NO_MEMORY(msg);
182 ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
183 if (ret != LDB_SUCCESS) {
188 ndr_err = ndr_push_struct_blob(&v, mem_ctx, rec,
189 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
190 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
191 return WERR_GENERAL_FAILURE;
194 ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
195 if (ret != LDB_SUCCESS) {
200 ret = ldb_add(samdb, msg);
201 if (ret != LDB_SUCCESS) {
202 return WERR_INTERNAL_DB_ERROR;
209 WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
210 struct ldb_context *samdb,
211 struct dnsserver_zone *z,
214 const char * const attrs[] = { "name", NULL };
215 struct ldb_result *res;
219 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
220 "(&(objectClass=dnsNode)(name=%s))", name);
221 if (ret != LDB_SUCCESS) {
222 return WERR_INTERNAL_DB_ERROR;
225 if (res->count > 0) {
227 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
230 dn = ldb_dn_copy(mem_ctx, z->zone_dn);
231 W_ERROR_HAVE_NO_MEMORY(dn);
233 if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
237 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, NULL);
241 WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
242 struct ldb_context *samdb,
243 struct dnsserver_zone *z,
245 struct DNS_RPC_RECORD *add_record)
247 const char * const attrs[] = { "dnsRecord", NULL };
248 struct ldb_result *res;
249 struct dnsp_DnssrvRpcRecord *rec;
250 struct ldb_message_element *el;
252 enum ndr_err_code ndr_err;
257 rec = dns_to_dnsp_copy(mem_ctx, add_record);
258 W_ERROR_HAVE_NO_MEMORY(rec);
260 serial = dnsserver_update_soa(mem_ctx, samdb, z);
262 return WERR_INTERNAL_DB_ERROR;
265 unix_to_nt_time(&t, time(NULL));
266 t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */
267 t /= 3600; /* convert to hours */
269 rec->dwSerial = serial;
270 rec->dwTimeStamp = t;
272 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
273 "(&(objectClass=dnsNode)(name=%s))", name);
274 if (ret != LDB_SUCCESS) {
275 return WERR_INTERNAL_DB_ERROR;
278 if (res->count == 0) {
279 dn = dnsserver_name_to_dn(mem_ctx, z, name);
280 W_ERROR_HAVE_NO_MEMORY(dn);
282 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, rec);
285 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
287 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
288 if (ret != LDB_SUCCESS) {
293 for (i=0; i<el->num_values; i++) {
294 struct dnsp_DnssrvRpcRecord rec2;
296 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
297 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
298 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
299 return WERR_GENERAL_FAILURE;
302 if (dns_record_match(rec, &rec2)) {
306 if (i < el->num_values) {
307 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
309 if (i == el->num_values) {
310 /* adding a new value */
311 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
312 W_ERROR_HAVE_NO_MEMORY(el->values);
316 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
317 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
318 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
319 return WERR_GENERAL_FAILURE;
322 el->flags = LDB_FLAG_MOD_REPLACE;
323 ret = ldb_modify(samdb, res->msgs[0]);
324 if (ret != LDB_SUCCESS) {
325 return WERR_INTERNAL_DB_ERROR;
331 WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
332 struct ldb_context *samdb,
333 struct dnsserver_zone *z,
335 struct DNS_RPC_RECORD *add_record,
336 struct DNS_RPC_RECORD *del_record)
338 const char * const attrs[] = { "dnsRecord", NULL };
339 struct ldb_result *res;
340 struct dnsp_DnssrvRpcRecord *arec, *drec;
341 struct ldb_message_element *el;
342 enum ndr_err_code ndr_err;
347 serial = dnsserver_update_soa(mem_ctx, samdb, z);
349 return WERR_INTERNAL_DB_ERROR;
352 arec = dns_to_dnsp_copy(mem_ctx, add_record);
353 W_ERROR_HAVE_NO_MEMORY(arec);
355 drec = dns_to_dnsp_copy(mem_ctx, del_record);
356 W_ERROR_HAVE_NO_MEMORY(drec);
358 unix_to_nt_time(&t, time(NULL));
361 arec->dwSerial = serial;
362 arec->dwTimeStamp = t;
364 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
365 "(&(objectClass=dnsNode)(name=%s))", name);
366 if (ret != LDB_SUCCESS) {
367 return WERR_INTERNAL_DB_ERROR;
370 if (res->count == 0) {
371 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
374 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
375 if (el == NULL || el->num_values == 0) {
376 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
379 for (i=0; i<el->num_values; i++) {
380 struct dnsp_DnssrvRpcRecord rec2;
382 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
383 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
385 return WERR_GENERAL_FAILURE;
388 if (dns_record_match(arec, &rec2)) {
392 if (i < el->num_values) {
393 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
397 for (i=0; i<el->num_values; i++) {
398 struct dnsp_DnssrvRpcRecord rec2;
400 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
401 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
402 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
403 return WERR_GENERAL_FAILURE;
406 if (dns_record_match(drec, &rec2)) {
410 if (i == el->num_values) {
411 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
414 ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
415 (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
416 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
417 return WERR_GENERAL_FAILURE;
420 el->flags = LDB_FLAG_MOD_REPLACE;
421 ret = ldb_modify(samdb, res->msgs[0]);
422 if (ret != LDB_SUCCESS) {
423 return WERR_INTERNAL_DB_ERROR;
429 WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
430 struct ldb_context *samdb,
431 struct dnsserver_zone *z,
433 struct DNS_RPC_RECORD *del_record)
435 const char * const attrs[] = { "dnsRecord", NULL };
436 struct ldb_result *res;
437 struct dnsp_DnssrvRpcRecord *rec;
438 struct ldb_message_element *el;
439 enum ndr_err_code ndr_err;
443 serial = dnsserver_update_soa(mem_ctx, samdb, z);
445 return WERR_INTERNAL_DB_ERROR;
448 rec = dns_to_dnsp_copy(mem_ctx, del_record);
449 W_ERROR_HAVE_NO_MEMORY(rec);
451 ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
452 "(&(objectClass=dnsNode)(name=%s))", name);
453 if (ret != LDB_SUCCESS) {
454 return WERR_INTERNAL_DB_ERROR;
457 if (res->count == 0) {
458 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
461 el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
462 if (el == NULL || el->num_values == 0) {
463 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
466 for (i=0; i<el->num_values; i++) {
467 struct dnsp_DnssrvRpcRecord rec2;
469 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
470 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
471 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
472 return WERR_GENERAL_FAILURE;
475 if (dns_record_match(rec, &rec2)) {
479 if (i == el->num_values) {
480 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
482 if (i < el->num_values-1) {
483 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
487 if (el->num_values == 0) {
488 ret = ldb_delete(samdb, res->msgs[0]->dn);
490 el->flags = LDB_FLAG_MOD_REPLACE;
491 ret = ldb_modify(samdb, res->msgs[0]);
493 if (ret != LDB_SUCCESS) {
494 return WERR_INTERNAL_DB_ERROR;