From e2a9b414fe360a6478ee581ce69c35b38e9fead6 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Fri, 16 May 2014 18:33:42 +0200 Subject: [PATCH 01/24] provision: Correctly provision the SOA record minimum TTL This fixes bug #10466 Signed-off-by: Kai Blin Reviewed-by: Guenter Kukkukk Autobuild-User(master): Kai Blin Autobuild-Date(master): Wed May 21 10:55:00 CEST 2014 on sn-devel-104 (cherry picked from commit 634f116fbb89d723a627f4501b4cd89342cecb8e) --- python/samba/provision/sambadns.py | 1 + python/samba/tests/dns.py | 1 + 2 files changed, 2 insertions(+) diff --git a/python/samba/provision/sambadns.py b/python/samba/provision/sambadns.py index 53f1082..ce4a46a 100644 --- a/python/samba/provision/sambadns.py +++ b/python/samba/provision/sambadns.py @@ -125,6 +125,7 @@ class SOARecord(dnsp.DnssrvRpcRecord): soa.expire = expire soa.mname = mname soa.rname = rname + soa.minimum = minimum self.data = soa diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py index 79e4158..2983de3 100644 --- a/python/samba/tests/dns.py +++ b/python/samba/tests/dns.py @@ -289,6 +289,7 @@ class TestSimpleQueries(DNSTest): self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY) self.assertEquals(response.ancount, 1) + self.assertEquals(response.answers[0].rdata.minimum, 3600) class TestDNSUpdates(DNSTest): -- 1.9.1 From 91c6782b70969de041993025845ed1dacf79af55 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 17:55:57 +0200 Subject: [PATCH 02/24] s4:dns_server: handle WERR_DNS_ERROR_NAME_DOES_NOT_EXIST in werr_to_dns_err() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit deb21a9afe77591743fda522355a5a9eb08fb27b) --- source4/dns_server/dns_utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index 72782cf..86f7e7c 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -43,6 +43,8 @@ uint8_t werr_to_dns_err(WERROR werr) return DNS_RCODE_SERVFAIL; } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) { return DNS_RCODE_NXDOMAIN; + } else if (W_ERROR_EQUAL(WERR_DNS_ERROR_NAME_DOES_NOT_EXIST, werr)) { + return DNS_RCODE_NXDOMAIN; } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) { return DNS_RCODE_NOTIMP; } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) { -- 1.9.1 From 454239bc3d61de1e57909cdece73fbf2e03d2bcf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 08:19:50 +0200 Subject: [PATCH 03/24] s4:dns_server: map LDB_ERR_NO_SUCH_OBJECT to WERR_DNS_ERROR_NAME_DOES_NOT_EXIST This is the correct fix for commit 8b24c43b382740106474e26dec59e1419ba77306 and Bug: https://bugzilla.samba.org/show_bug.cgi?id=9559 With this change we have a consistent behavior between internal server and the bind dlz module. We keep a dangling LDAP object without dnsRecord attribute arround forever. This will be fixed in the following commits. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit d0f424a23dc915d9fce625438d2bd63519757cba) --- source4/dns_server/dns_update.c | 21 ++++++++++++++++----- source4/dns_server/dns_utils.c | 17 ++++++++--------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index 9edc40b..c439d8d 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -82,6 +82,9 @@ static WERROR check_one_prerequisite(struct dns_server *dns, /* */ werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount); + if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { + return DNS_ERR(NAME_ERROR); + } W_ERROR_NOT_OK_RETURN(werror); if (acount == 0) { @@ -91,6 +94,9 @@ static WERROR check_one_prerequisite(struct dns_server *dns, /* */ werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount); + if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { + return DNS_ERR(NXRRSET); + } if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) { return DNS_ERR(NXRRSET); } @@ -131,10 +137,11 @@ static WERROR check_one_prerequisite(struct dns_server *dns, /* */ werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount); + if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { + werror = WERR_OK; + } if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) { werror = WERR_OK; - ans = NULL; - acount = 0; } for (i = 0; i < acount; i++) { @@ -163,6 +170,9 @@ static WERROR check_one_prerequisite(struct dns_server *dns, *final_result = false; werror = dns_lookup_records(dns, mem_ctx, dn, &ans, &acount); + if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { + return DNS_ERR(NXRRSET); + } if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) { return DNS_ERR(NXRRSET); } @@ -421,12 +431,13 @@ static WERROR handle_one_update(struct dns_server *dns, W_ERROR_NOT_OK_RETURN(werror); werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rcount); - if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) { - recs = NULL; - rcount = 0; + if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { needs_add = true; werror = WERR_OK; } + if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) { + werror = WERR_OK; + } W_ERROR_NOT_OK_RETURN(werror); if (update->rr_class == zone->question_class) { diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index 86f7e7c..14ca2f4 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -194,8 +194,14 @@ WERROR dns_lookup_records(struct dns_server *dns, struct ldb_message *msg = NULL; struct dnsp_DnssrvRpcRecord *recs; + *records = NULL; + *rec_count = 0; + ret = dsdb_search_one(dns->samdb, mem_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "%s", "(objectClass=dnsNode)"); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST; + } if (ret != LDB_SUCCESS) { /* TODO: we need to check if there's a glue record we need to * create a referral to */ @@ -204,8 +210,6 @@ WERROR dns_lookup_records(struct dns_server *dns, el = ldb_msg_find_element(msg, attrs[0]); if (el == NULL) { - *records = NULL; - *rec_count = 0; return DNS_ERR(NAME_ERROR); } @@ -278,13 +282,8 @@ WERROR dns_replace_records(struct dns_server *dns, if (needs_add) { return WERR_OK; } - /* No entries left, delete the dnsNode object */ - ret = ldb_delete(dns->samdb, msg->dn); - if (ret != LDB_SUCCESS) { - DEBUG(0, ("Deleting record failed; %d\n", ret)); - return DNS_ERR(SERVER_FAILURE); - } - return WERR_OK; + /* TODO: Delete object? */ + el->flags = LDB_FLAG_MOD_DELETE; } if (needs_add) { -- 1.9.1 From 35e0adadce15d4d55db5d2aa6d1c19e9a58e55ff Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 08:01:11 +0200 Subject: [PATCH 04/24] s4:dns_server: split out a private 'dnsserver_common' library This will contain common code for the internal dns server, the dlz_bind9 module and the rpc dns management server. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 99d5a5ead4f33723c25e8716a79d34b53822521e) --- source4/dns_server/dns_server.h | 4 +-- source4/dns_server/dns_utils.c | 33 ----------------- source4/dns_server/dnsserver_common.c | 68 +++++++++++++++++++++++++++++++++++ source4/dns_server/dnsserver_common.h | 28 +++++++++++++++ source4/dns_server/wscript_build | 8 ++++- 5 files changed, 105 insertions(+), 36 deletions(-) create mode 100644 source4/dns_server/dnsserver_common.c create mode 100644 source4/dns_server/dnsserver_common.h diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h index efe4db8..2459616 100644 --- a/source4/dns_server/dns_server.h +++ b/source4/dns_server/dns_server.h @@ -86,7 +86,6 @@ WERROR dns_server_process_update(struct dns_server *dns, struct dns_res_rec **updates, uint16_t *update_count, struct dns_res_rec **additional, uint16_t *arcount); -uint8_t werr_to_dns_err(WERROR werror); bool dns_name_match(const char *zone, const char *name, size_t *host_part_len); bool dns_name_equal(const char *name1, const char *name2); bool dns_records_match(struct dnsp_DnssrvRpcRecord *rec1, @@ -124,5 +123,6 @@ WERROR dns_sign_tsig(struct dns_server *dns, struct dns_name_packet *packet, uint16_t error); -#define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str +#include "source4/dns_server/dnsserver_common.h" + #endif /* __DNS_SERVER_H__ */ diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index 14ca2f4..461e58d 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -33,39 +33,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS -uint8_t werr_to_dns_err(WERROR werr) -{ - if (W_ERROR_EQUAL(WERR_OK, werr)) { - return DNS_RCODE_OK; - } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), werr)) { - return DNS_RCODE_FORMERR; - } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE), werr)) { - return DNS_RCODE_SERVFAIL; - } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) { - return DNS_RCODE_NXDOMAIN; - } else if (W_ERROR_EQUAL(WERR_DNS_ERROR_NAME_DOES_NOT_EXIST, werr)) { - return DNS_RCODE_NXDOMAIN; - } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) { - return DNS_RCODE_NOTIMP; - } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) { - return DNS_RCODE_REFUSED; - } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN), werr)) { - return DNS_RCODE_YXDOMAIN; - } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET), werr)) { - return DNS_RCODE_YXRRSET; - } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET), werr)) { - return DNS_RCODE_NXRRSET; - } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH), werr)) { - return DNS_RCODE_NOTAUTH; - } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) { - return DNS_RCODE_NOTZONE; - } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) { - return DNS_RCODE_BADKEY; - } - DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr))); - return DNS_RCODE_SERVFAIL; -} - bool dns_name_match(const char *zone, const char *name, size_t *host_part_len) { size_t zl = strlen(zone); diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c new file mode 100644 index 0000000..997ce03 --- /dev/null +++ b/source4/dns_server/dnsserver_common.c @@ -0,0 +1,68 @@ +/* + Unix SMB/CIFS implementation. + + DNS server utils + + Copyright (C) 2010 Kai Blin + Copyright (C) 2014 Stefan Metzmacher + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "libcli/util/ntstatus.h" +#include "libcli/util/werror.h" +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/ndr_dns.h" +#include "librpc/gen_ndr/ndr_dnsp.h" +#include +#include "dsdb/samdb/samdb.h" +#include "dsdb/common/util.h" +#include "dns_server/dnsserver_common.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_DNS + +uint8_t werr_to_dns_err(WERROR werr) +{ + if (W_ERROR_EQUAL(WERR_OK, werr)) { + return DNS_RCODE_OK; + } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), werr)) { + return DNS_RCODE_FORMERR; + } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE), werr)) { + return DNS_RCODE_SERVFAIL; + } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) { + return DNS_RCODE_NXDOMAIN; + } else if (W_ERROR_EQUAL(WERR_DNS_ERROR_NAME_DOES_NOT_EXIST, werr)) { + return DNS_RCODE_NXDOMAIN; + } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) { + return DNS_RCODE_NOTIMP; + } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) { + return DNS_RCODE_REFUSED; + } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN), werr)) { + return DNS_RCODE_YXDOMAIN; + } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET), werr)) { + return DNS_RCODE_YXRRSET; + } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET), werr)) { + return DNS_RCODE_NXRRSET; + } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH), werr)) { + return DNS_RCODE_NOTAUTH; + } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) { + return DNS_RCODE_NOTZONE; + } else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) { + return DNS_RCODE_BADKEY; + } + DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr))); + return DNS_RCODE_SERVFAIL; +} diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h new file mode 100644 index 0000000..41febe2 --- /dev/null +++ b/source4/dns_server/dnsserver_common.h @@ -0,0 +1,28 @@ +/* + Unix SMB/CIFS implementation. + + DNS server utils + + Copyright (C) 2014 Stefan Metzmacher + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __DNSSERVER_COMMON_H__ +#define __DNSSERVER_COMMON_H__ + +uint8_t werr_to_dns_err(WERROR werr); +#define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str + +#endif /* __DNSSERVER_COMMON_H__ */ diff --git a/source4/dns_server/wscript_build b/source4/dns_server/wscript_build index 280f8de..66e6b72 100644 --- a/source4/dns_server/wscript_build +++ b/source4/dns_server/wscript_build @@ -1,10 +1,16 @@ #!/usr/bin/env python +bld.SAMBA_LIBRARY('dnsserver_common', + source='dnsserver_common.c', + deps='samba-util errors ldbsamba clidns', + private_library=True, + ) + bld.SAMBA_MODULE('service_dns', source='dns_server.c dns_query.c dns_update.c dns_utils.c dns_crypto.c', subsystem='service', init_function='server_service_dns_init', - deps='samba-hostconfig LIBTSOCKET LIBSAMBA_TSOCKET ldbsamba clidns gensec auth samba_server_gensec', + deps='samba-hostconfig LIBTSOCKET LIBSAMBA_TSOCKET ldbsamba clidns gensec auth samba_server_gensec dnsserver_common', local_include=False, internal_module=False, enabled=bld.AD_DC_BUILD_IS_ENABLED() -- 1.9.1 From b0c324209af16960dc6653f87450be7c07a1cdcc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 08:24:10 +0200 Subject: [PATCH 05/24] s4:dns_server: split out dns_common_extract() and dns_common_lookup() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 342a087349f8a10833338a3fa49fbd4d4d29f3e5) --- source4/dns_server/dns_utils.c | 45 +------------------- source4/dns_server/dnsserver_common.c | 78 +++++++++++++++++++++++++++++++++++ source4/dns_server/dnsserver_common.h | 13 ++++++ 3 files changed, 92 insertions(+), 44 deletions(-) diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index 461e58d..3bfa98b 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -154,50 +154,7 @@ WERROR dns_lookup_records(struct dns_server *dns, struct dnsp_DnssrvRpcRecord **records, uint16_t *rec_count) { - static const char * const attrs[] = { "dnsRecord", NULL}; - struct ldb_message_element *el; - uint16_t ri; - int ret; - struct ldb_message *msg = NULL; - struct dnsp_DnssrvRpcRecord *recs; - - *records = NULL; - *rec_count = 0; - - ret = dsdb_search_one(dns->samdb, mem_ctx, &msg, dn, - LDB_SCOPE_BASE, attrs, 0, "%s", "(objectClass=dnsNode)"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST; - } - if (ret != LDB_SUCCESS) { - /* TODO: we need to check if there's a glue record we need to - * create a referral to */ - return DNS_ERR(NAME_ERROR); - } - - el = ldb_msg_find_element(msg, attrs[0]); - if (el == NULL) { - return DNS_ERR(NAME_ERROR); - } - - recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord, el->num_values); - if (recs == NULL) { - return WERR_NOMEM; - } - for (ri = 0; ri < el->num_values; ri++) { - struct ldb_val *v = &el->values[ri]; - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri], - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n")); - return DNS_ERR(SERVER_FAILURE); - } - } - *records = recs; - *rec_count = el->num_values; - return WERR_OK; + return dns_common_lookup(dns->samdb, mem_ctx, dn, records, rec_count); } WERROR dns_replace_records(struct dns_server *dns, diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 997ce03..c1d08b2 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -66,3 +66,81 @@ uint8_t werr_to_dns_err(WERROR werr) DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr))); return DNS_RCODE_SERVFAIL; } + +WERROR dns_common_extract(const struct ldb_message_element *el, + TALLOC_CTX *mem_ctx, + struct dnsp_DnssrvRpcRecord **records, + uint16_t *num_records) +{ + uint16_t ri; + struct dnsp_DnssrvRpcRecord *recs; + + *records = NULL; + *num_records = 0; + + recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord, + el->num_values); + if (recs == NULL) { + return WERR_NOMEM; + } + for (ri = 0; ri < el->num_values; ri++) { + struct ldb_val *v = &el->values[ri]; + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri], + (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + TALLOC_FREE(recs); + DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n")); + return DNS_ERR(SERVER_FAILURE); + } + } + *records = recs; + *num_records = el->num_values; + return WERR_OK; +} + +WERROR dns_common_lookup(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + struct dnsp_DnssrvRpcRecord **records, + uint16_t *num_records) +{ + static const char * const attrs[] = { + "dnsRecord", + NULL + }; + int ret; + WERROR werr; + struct ldb_message *msg = NULL; + struct ldb_message_element *el; + + *records = NULL; + *num_records = 0; + + ret = dsdb_search_one(samdb, mem_ctx, &msg, dn, + LDB_SCOPE_BASE, attrs, 0, + "(objectClass=dnsNode)"); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST; + } + if (ret != LDB_SUCCESS) { + /* TODO: we need to check if there's a glue record we need to + * create a referral to */ + return DNS_ERR(NAME_ERROR); + } + + el = ldb_msg_find_element(msg, "dnsRecord"); + if (el == NULL) { + TALLOC_FREE(msg); + return DNS_ERR(NAME_ERROR); + } + + werr = dns_common_extract(el, mem_ctx, records, num_records); + TALLOC_FREE(msg); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + return WERR_OK; +} diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index 41febe2..4731780 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -25,4 +25,17 @@ uint8_t werr_to_dns_err(WERROR werr); #define DNS_ERR(err_str) WERR_DNS_ERROR_RCODE_##err_str +struct ldb_message_element; + +WERROR dns_common_extract(const struct ldb_message_element *el, + TALLOC_CTX *mem_ctx, + struct dnsp_DnssrvRpcRecord **records, + uint16_t *num_records); + +WERROR dns_common_lookup(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + struct dnsp_DnssrvRpcRecord **records, + uint16_t *num_records); + #endif /* __DNSSERVER_COMMON_H__ */ -- 1.9.1 From 75820e9381448467aa9cd672de275bee8575a51f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 11:32:02 +0200 Subject: [PATCH 06/24] s4:dns_server: remove const from dns_replace_records() All callers are find we the record array gets modified. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 7e7df78bd7ae5575da7443b45c0e2e4167eebde2) --- source4/dns_server/dns_server.h | 2 +- source4/dns_server/dns_utils.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/dns_server/dns_server.h b/source4/dns_server/dns_server.h index 2459616..12ccc9b 100644 --- a/source4/dns_server/dns_server.h +++ b/source4/dns_server/dns_server.h @@ -101,7 +101,7 @@ WERROR dns_replace_records(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, bool needs_add, - const struct dnsp_DnssrvRpcRecord *records, + struct dnsp_DnssrvRpcRecord *records, uint16_t rec_count); WERROR dns_name2dn(struct dns_server *dns, TALLOC_CTX *mem_ctx, diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index 3bfa98b..cf1adcc 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -161,7 +161,7 @@ WERROR dns_replace_records(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, bool needs_add, - const struct dnsp_DnssrvRpcRecord *records, + struct dnsp_DnssrvRpcRecord *records, uint16_t rec_count) { struct ldb_message_element *el; -- 1.9.1 From 0e59d5bc419b12346cfd32cb7169da9727fa55ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 18:27:56 +0200 Subject: [PATCH 07/24] s4:dns_server: split out dns_common_replace() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 0689e795e073008d2ad539c0ef5ddbdc6d9efdac) --- source4/dns_server/dns_update.c | 2 - source4/dns_server/dns_utils.c | 70 ++----------------------------- source4/dns_server/dnsserver_common.c | 78 +++++++++++++++++++++++++++++++++++ source4/dns_server/dnsserver_common.h | 8 ++++ 4 files changed, 90 insertions(+), 68 deletions(-) diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index c439d8d..a589d63 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -312,8 +312,6 @@ static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx, r->wType = rrec->rr_type; r->dwTtlSeconds = rrec->ttl; r->rank = DNS_RANK_ZONE; - /* TODO: Autogenerate this somehow */ - r->dwSerial = 110; /* If we get QCLASS_ANY, we're done here */ if (rrec->rr_class == DNS_QCLASS_ANY) { diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index cf1adcc..c3a27fe 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -164,72 +164,10 @@ WERROR dns_replace_records(struct dns_server *dns, struct dnsp_DnssrvRpcRecord *records, uint16_t rec_count) { - struct ldb_message_element *el; - uint16_t i; - int ret; - struct ldb_message *msg = NULL; - - msg = ldb_msg_new(mem_ctx); - W_ERROR_HAVE_NO_MEMORY(msg); - - msg->dn = dn; - - ret = ldb_msg_add_empty(msg, "dnsRecord", LDB_FLAG_MOD_REPLACE, &el); - if (ret != LDB_SUCCESS) { - return DNS_ERR(SERVER_FAILURE); - } - - el->values = talloc_zero_array(el, struct ldb_val, rec_count); - if (rec_count > 0) { - W_ERROR_HAVE_NO_MEMORY(el->values); - } - - for (i = 0; i < rec_count; i++) { - static const struct dnsp_DnssrvRpcRecord zero; - struct ldb_val *v = &el->values[el->num_values]; - enum ndr_err_code ndr_err; - - if (memcmp(&records[i], &zero, sizeof(zero)) == 0) { - continue; - } - ndr_err = ndr_push_struct_blob(v, el->values, &records[i], - (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n")); - return DNS_ERR(SERVER_FAILURE); - } - el->num_values++; - } - - - if (el->num_values == 0) { - if (needs_add) { - return WERR_OK; - } - /* TODO: Delete object? */ - el->flags = LDB_FLAG_MOD_DELETE; - } - - if (needs_add) { - ret = ldb_msg_add_string(msg, "objectClass", "dnsNode"); - if (ret != LDB_SUCCESS) { - return DNS_ERR(SERVER_FAILURE); - } - - ret = ldb_add(dns->samdb, msg); - if (ret != LDB_SUCCESS) { - return DNS_ERR(SERVER_FAILURE); - } - - return WERR_OK; - } - - ret = ldb_modify(dns->samdb, msg); - if (ret != LDB_SUCCESS) { - return DNS_ERR(SERVER_FAILURE); - } - - return WERR_OK; + /* TODO: Autogenerate this somehow */ + uint32_t dwSerial = 110; + return dns_common_replace(dns->samdb, mem_ctx, dn, + needs_add, dwSerial, records, rec_count); } bool dns_authorative_for_zone(struct dns_server *dns, diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index c1d08b2..3a777e5 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -144,3 +144,81 @@ WERROR dns_common_lookup(struct ldb_context *samdb, return WERR_OK; } + +WERROR dns_common_replace(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + bool needs_add, + uint32_t serial, + struct dnsp_DnssrvRpcRecord *records, + uint16_t rec_count) +{ + struct ldb_message_element *el; + uint16_t i; + int ret; + struct ldb_message *msg = NULL; + + msg = ldb_msg_new(mem_ctx); + W_ERROR_HAVE_NO_MEMORY(msg); + + msg->dn = dn; + + ret = ldb_msg_add_empty(msg, "dnsRecord", LDB_FLAG_MOD_REPLACE, &el); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } + + el->values = talloc_zero_array(el, struct ldb_val, rec_count); + if (rec_count > 0) { + W_ERROR_HAVE_NO_MEMORY(el->values); + } + + for (i = 0; i < rec_count; i++) { + static const struct dnsp_DnssrvRpcRecord zero; + struct ldb_val *v = &el->values[el->num_values]; + enum ndr_err_code ndr_err; + + if (memcmp(&records[i], &zero, sizeof(zero)) == 0) { + continue; + } + + records[i].dwSerial = serial; + ndr_err = ndr_push_struct_blob(v, el->values, &records[i], + (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n")); + return DNS_ERR(SERVER_FAILURE); + } + el->num_values++; + } + + if (needs_add) { + if (el->num_values == 0) { + return WERR_OK; + } + + ret = ldb_msg_add_string(msg, "objectClass", "dnsNode"); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } + + ret = ldb_add(samdb, msg); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } + + return WERR_OK; + } + + if (el->num_values == 0) { + el->flags = LDB_FLAG_MOD_DELETE; + } + + ret = ldb_modify(samdb, msg); + if (ret != LDB_SUCCESS) { + NTSTATUS nt = dsdb_ldb_err_to_ntstatus(ret); + return ntstatus_to_werror(nt); + } + + return WERR_OK; +} diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index 4731780..1117ad1 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -38,4 +38,12 @@ WERROR dns_common_lookup(struct ldb_context *samdb, struct dnsp_DnssrvRpcRecord **records, uint16_t *num_records); +WERROR dns_common_replace(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + bool needs_add, + uint32_t serial, + struct dnsp_DnssrvRpcRecord *records, + uint16_t rec_count); + #endif /* __DNSSERVER_COMMON_H__ */ -- 1.9.1 From ab3ae74feed74241c5cd1f8a8e3c8d4f0b92aaf5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 09:32:00 +0200 Subject: [PATCH 08/24] s4:dns_server: use .wType = DNS_TYPE_TOMBSTONE instead of ZERO_STRUCT() The result is the same, but it is clearer. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 3ff025a02cca3ff209668edd419d0e440e9865c6) --- source4/dns_server/dns_update.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index a589d63..4ff82b4 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -521,7 +521,9 @@ static WERROR handle_one_update(struct dns_server *dns, continue; } - ZERO_STRUCT(recs[i]); + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } werror = dns_replace_records(dns, mem_ctx, dn, @@ -570,12 +572,16 @@ static WERROR handle_one_update(struct dns_server *dns, continue; } - ZERO_STRUCT(recs[i]); + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } } else { for (i = 0; i < rcount; i++) { - ZERO_STRUCT(recs[i]); + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } } @@ -591,7 +597,9 @@ static WERROR handle_one_update(struct dns_server *dns, } for (i = 0; i < rcount; i++) { if (recs[i].wType == update->rr_type) { - ZERO_STRUCT(recs[i]); + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } } @@ -635,7 +643,9 @@ static WERROR handle_one_update(struct dns_server *dns, for (i = 0; i < rcount; i++) { if (dns_records_match(del_rec, &recs[i])) { - ZERO_STRUCT(recs[i]); + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } } -- 1.9.1 From 3f7ff7fa91e2f66bcc551f5a12bfb261936e7106 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 08:54:17 +0200 Subject: [PATCH 09/24] s4:dns_server: make sure dns_common_lookup() doesn't return tombstones Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit a0a81ab01cb1d509b04f9af25177c8e0941b43aa) --- source4/dns_server/dns_utils.c | 3 +- source4/dns_server/dnsserver_common.c | 53 ++++++++++++++++++++++++++++++++--- source4/dns_server/dnsserver_common.h | 3 +- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/source4/dns_server/dns_utils.c b/source4/dns_server/dns_utils.c index c3a27fe..c757c15 100644 --- a/source4/dns_server/dns_utils.c +++ b/source4/dns_server/dns_utils.c @@ -154,7 +154,8 @@ WERROR dns_lookup_records(struct dns_server *dns, struct dnsp_DnssrvRpcRecord **records, uint16_t *rec_count) { - return dns_common_lookup(dns->samdb, mem_ctx, dn, records, rec_count); + return dns_common_lookup(dns->samdb, mem_ctx, dn, + records, rec_count, NULL); } WERROR dns_replace_records(struct dns_server *dns, diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 3a777e5..2866734 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -104,10 +104,12 @@ WERROR dns_common_lookup(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct dnsp_DnssrvRpcRecord **records, - uint16_t *num_records) + uint16_t *num_records, + bool *tombstoned) { static const char * const attrs[] = { "dnsRecord", + "dNSTombstoned", NULL }; int ret; @@ -118,9 +120,16 @@ WERROR dns_common_lookup(struct ldb_context *samdb, *records = NULL; *num_records = 0; - ret = dsdb_search_one(samdb, mem_ctx, &msg, dn, - LDB_SCOPE_BASE, attrs, 0, - "(objectClass=dnsNode)"); + if (tombstoned != NULL) { + *tombstoned = false; + ret = dsdb_search_one(samdb, mem_ctx, &msg, dn, + LDB_SCOPE_BASE, attrs, 0, + "(objectClass=dnsNode)"); + } else { + ret = dsdb_search_one(samdb, mem_ctx, &msg, dn, + LDB_SCOPE_BASE, attrs, 0, + "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))"); + } if (ret == LDB_ERR_NO_SUCH_OBJECT) { return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST; } @@ -130,9 +139,45 @@ WERROR dns_common_lookup(struct ldb_context *samdb, return DNS_ERR(NAME_ERROR); } + if (tombstoned != NULL) { + *tombstoned = ldb_msg_find_attr_as_bool(msg, + "dNSTombstoned", false); + } + el = ldb_msg_find_element(msg, "dnsRecord"); if (el == NULL) { TALLOC_FREE(msg); + if (tombstoned != NULL) { + struct dnsp_DnssrvRpcRecord *recs; + /* + * records produced by older Samba releases + * keep dnsNode objects without dnsRecord and + * without setting dNSTombstoned=TRUE. + * + * We just pretend they're tombstones. + */ + recs = talloc_array(mem_ctx, + struct dnsp_DnssrvRpcRecord, + 1); + if (recs == NULL) { + return WERR_NOMEM; + } + recs[0] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + /* + * A value of timestamp != 0 + * indicated that the object was already + * a tombstone, this will be used + * in dns_common_replace() + */ + .data.timestamp = 1, + }; + + *tombstoned = true; + *records = recs; + *num_records = 1; + return WERR_OK; + } return DNS_ERR(NAME_ERROR); } diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index 1117ad1..becd243 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -36,7 +36,8 @@ WERROR dns_common_lookup(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct dnsp_DnssrvRpcRecord **records, - uint16_t *num_records); + uint16_t *num_records, + bool *tombstoned); WERROR dns_common_replace(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, -- 1.9.1 From 04ad84e9db9560fb21588e5366dc3e74264edfb6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 10:44:41 +0200 Subject: [PATCH 10/24] s4:dns_server: add DNS_TYPE_TOMBSTONE support to dns_common_replace() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Pair-Programmed-With: Michael Adam Signed-off-by: Stefan Metzmacher Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit bb3ca930cc57964487bd23a74f4caabd1616a8bf) --- source4/dns_server/dnsserver_common.c | 81 +++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 2866734..c49d6ec 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -190,6 +190,22 @@ WERROR dns_common_lookup(struct ldb_context *samdb, return WERR_OK; } +static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1, + const struct dnsp_DnssrvRpcRecord *r2) +{ + if (r1->wType != r2->wType) { + /* + * The records are sorted with higher types first + */ + return r2->wType - r1->wType; + } + + /* + * Then we need to sort from the oldest to newest timestamp + */ + return r1->dwTimeStamp - r2->dwTimeStamp; +} + WERROR dns_common_replace(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, @@ -202,6 +218,8 @@ WERROR dns_common_replace(struct ldb_context *samdb, uint16_t i; int ret; struct ldb_message *msg = NULL; + bool was_tombstoned = false; + bool become_tombstoned = false; msg = ldb_msg_new(mem_ctx); W_ERROR_HAVE_NO_MEMORY(msg); @@ -213,17 +231,30 @@ WERROR dns_common_replace(struct ldb_context *samdb, return DNS_ERR(SERVER_FAILURE); } - el->values = talloc_zero_array(el, struct ldb_val, rec_count); + /* + * we have at least one value, + * which might be used for the tombstone marker + */ + el->values = talloc_zero_array(el, struct ldb_val, MAX(1, rec_count)); if (rec_count > 0) { W_ERROR_HAVE_NO_MEMORY(el->values); + + /* + * We store a sorted list with the high wType values first + * that's what windows does. It also simplifies the + * filtering of DNS_TYPE_TOMBSTONE records + */ + TYPESAFE_QSORT(records, rec_count, rec_cmp); } for (i = 0; i < rec_count; i++) { - static const struct dnsp_DnssrvRpcRecord zero; struct ldb_val *v = &el->values[el->num_values]; enum ndr_err_code ndr_err; - if (memcmp(&records[i], &zero, sizeof(zero)) == 0) { + if (records[i].wType == DNS_TYPE_TOMBSTONE) { + if (records[i].data.timestamp != 0) { + was_tombstoned = true; + } continue; } @@ -256,7 +287,49 @@ WERROR dns_common_replace(struct ldb_context *samdb, } if (el->num_values == 0) { - el->flags = LDB_FLAG_MOD_DELETE; + struct dnsp_DnssrvRpcRecord tbs; + struct ldb_val *v = &el->values[el->num_values]; + enum ndr_err_code ndr_err; + struct timeval tv; + + if (was_tombstoned) { + /* + * This is already a tombstoned object. + * Just leave it instead of updating the time stamp. + */ + return WERR_OK; + } + + tv = timeval_current(); + tbs = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + .dwSerial = serial, + .data.timestamp = timeval_to_nttime(&tv), + }; + + ndr_err = ndr_push_struct_blob(v, el->values, &tbs, + (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("Failed to push dnsp_DnssrvRpcRecord\n")); + return DNS_ERR(SERVER_FAILURE); + } + el->num_values++; + + become_tombstoned = true; + } + + if (was_tombstoned || become_tombstoned) { + ret = ldb_msg_add_empty(msg, "dNSTombstoned", + LDB_FLAG_MOD_REPLACE, NULL); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } + + ret = ldb_msg_add_fmt(msg, "dNSTombstoned", "%s", + become_tombstoned ? "TRUE" : "FALSE"); + if (ret != LDB_SUCCESS) { + return DNS_ERR(SERVER_FAILURE); + } } ret = ldb_modify(samdb, msg); -- 1.9.1 From 604d30bf21da6084ae48d4f7b3a4cf5b9ad5014e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 09:35:26 +0200 Subject: [PATCH 11/24] s4:dns_server: handle tombstones in handle_one_update() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 491715399ff7e1ab788fec5e254581dc312e2cef) --- source4/dns_server/dns_update.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index 4ff82b4..04e7d9a 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -400,7 +400,9 @@ static WERROR handle_one_update(struct dns_server *dns, uint16_t rcount = 0; struct ldb_dn *dn; uint16_t i; + uint16_t first = 0; WERROR werror; + bool tombstoned = false; bool needs_add = false; DEBUG(2, ("Looking at record: \n")); @@ -428,23 +430,29 @@ static WERROR handle_one_update(struct dns_server *dns, werror = dns_name2dn(dns, mem_ctx, update->name, &dn); W_ERROR_NOT_OK_RETURN(werror); - werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rcount); + werror = dns_common_lookup(dns->samdb, mem_ctx, dn, + &recs, &rcount, &tombstoned); if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { needs_add = true; werror = WERR_OK; } - if (W_ERROR_EQUAL(werror, DNS_ERR(NAME_ERROR))) { - werror = WERR_OK; - } W_ERROR_NOT_OK_RETURN(werror); + if (tombstoned) { + /* + * we need to keep the existing tombstone record + * and ignore it + */ + first = rcount; + } + if (update->rr_class == zone->question_class) { if (update->rr_type == DNS_QTYPE_CNAME) { /* * If there is a record in the directory * that's not a CNAME, ignore update */ - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (recs[i].wType != DNS_TYPE_CNAME) { DEBUG(5, ("Skipping update\n")); return WERR_OK; @@ -457,13 +465,14 @@ static WERROR handle_one_update(struct dns_server *dns, * per name, so replace everything with the new CNAME */ - rcount = 1; + rcount = first; recs = talloc_realloc(mem_ctx, recs, - struct dnsp_DnssrvRpcRecord, rcount); + struct dnsp_DnssrvRpcRecord, rcount + 1); W_ERROR_HAVE_NO_MEMORY(recs); - werror = dns_rr_to_dnsp(recs, update, &recs[0]); + werror = dns_rr_to_dnsp(recs, update, &recs[rcount]); W_ERROR_NOT_OK_RETURN(werror); + rcount += 1; werror = dns_replace_records(dns, mem_ctx, dn, needs_add, recs, rcount); @@ -475,7 +484,7 @@ static WERROR handle_one_update(struct dns_server *dns, * If there is a CNAME record for this name, * ignore update */ - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (recs[i].wType == DNS_TYPE_CNAME) { DEBUG(5, ("Skipping update\n")); return WERR_OK; @@ -490,7 +499,7 @@ static WERROR handle_one_update(struct dns_server *dns, * serial number is smaller than existing SOA's, * ignore update */ - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (recs[i].wType == DNS_TYPE_SOA) { uint16_t n, o; @@ -540,7 +549,7 @@ static WERROR handle_one_update(struct dns_server *dns, werror = dns_rr_to_dnsp(recs, update, &recs[rcount]); W_ERROR_NOT_OK_RETURN(werror); - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (!dns_records_match(&recs[i], &recs[rcount])) { continue; } @@ -562,7 +571,7 @@ static WERROR handle_one_update(struct dns_server *dns, } else if (update->rr_class == DNS_QCLASS_ANY) { if (update->rr_type == DNS_QTYPE_ALL) { if (dns_name_equal(update->name, zone->name)) { - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (recs[i].wType == DNS_TYPE_SOA) { continue; @@ -578,7 +587,7 @@ static WERROR handle_one_update(struct dns_server *dns, } } else { - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { recs[i] = (struct dnsp_DnssrvRpcRecord) { .wType = DNS_TYPE_TOMBSTONE, }; @@ -595,7 +604,7 @@ static WERROR handle_one_update(struct dns_server *dns, return WERR_OK; } } - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (recs[i].wType == update->rr_type) { recs[i] = (struct dnsp_DnssrvRpcRecord) { .wType = DNS_TYPE_TOMBSTONE, @@ -624,7 +633,7 @@ static WERROR handle_one_update(struct dns_server *dns, werror = dns_rr_to_dnsp(ns_rec, update, ns_rec); W_ERROR_NOT_OK_RETURN(werror); - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (dns_records_match(ns_rec, &recs[i])) { found = true; break; @@ -641,7 +650,7 @@ static WERROR handle_one_update(struct dns_server *dns, werror = dns_rr_to_dnsp(del_rec, update, del_rec); W_ERROR_NOT_OK_RETURN(werror); - for (i = 0; i < rcount; i++) { + for (i = first; i < rcount; i++) { if (dns_records_match(del_rec, &recs[i])) { recs[i] = (struct dnsp_DnssrvRpcRecord) { .wType = DNS_TYPE_TOMBSTONE, -- 1.9.1 From d05ba7f15ce14a146e8cdf28fffbad0d5068d3fd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 27 Feb 2014 09:59:51 +0100 Subject: [PATCH 12/24] s4:dlz_bind9: avoid some compiler warnings Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit fbebe7e756e4ccd0684e94e9b1e787f98f399ccc) --- source4/dns_server/dlz_bind9.c | 6 +++--- source4/dns_server/dlz_minimal.h | 2 +- source4/torture/dns/dlz_bind9.c | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index c0ed8e1..46c586e 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -459,7 +459,7 @@ static isc_result_t b9_putnamedrr(struct dlz_bind9_data *state, parse options */ static isc_result_t parse_options(struct dlz_bind9_data *state, - unsigned int argc, char *argv[], + unsigned int argc, const char **argv, struct b9_options *options) { int opt; @@ -470,7 +470,7 @@ static isc_result_t parse_options(struct dlz_bind9_data *state, { NULL } }; - pc = poptGetContext("dlz_bind9", argc, (const char **)argv, long_options, + pc = poptGetContext("dlz_bind9", argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { @@ -564,7 +564,7 @@ static int dlz_state_debug_unregister(struct dlz_bind9_data *state) called to initialise the driver */ _PUBLIC_ isc_result_t dlz_create(const char *dlzname, - unsigned int argc, char *argv[], + unsigned int argc, const char **argv, void **dbdata, ...) { struct dlz_bind9_data *state; diff --git a/source4/dns_server/dlz_minimal.h b/source4/dns_server/dlz_minimal.h index 5262cbd..98fb34e 100644 --- a/source4/dns_server/dlz_minimal.h +++ b/source4/dns_server/dlz_minimal.h @@ -100,7 +100,7 @@ int dlz_version(unsigned int *flags); /* * dlz_create() is required for all DLZ external drivers. */ -isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata, ...); +isc_result_t dlz_create(const char *dlzname, unsigned int argc, const char **argv, void **dbdata, ...); /* * dlz_destroy() is optional, and will be called when the driver is diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c index d7d1736..88ca27c 100644 --- a/source4/torture/dns/dlz_bind9.c +++ b/source4/torture/dns/dlz_bind9.c @@ -61,7 +61,7 @@ static bool test_dlz_bind9_create(struct torture_context *tctx) NULL }; tctx_static = tctx; - torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, discard_const_p(char *, argv), &dbdata, + torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata, "log", dlz_bind9_log_wrapper, NULL), ISC_R_SUCCESS, "Failed to create samba_dlz"); @@ -109,7 +109,7 @@ static bool test_dlz_bind9_configure(struct torture_context *tctx) NULL }; tctx_static = tctx; - torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, discard_const_p(char *, argv), &dbdata, + torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata, "log", dlz_bind9_log_wrapper, "writeable_zone", dlz_bind9_writeable_zone_hook, NULL), ISC_R_SUCCESS, @@ -144,7 +144,7 @@ static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech NULL }; tctx_static = tctx; - torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, discard_const_p(char *, argv), &dbdata, + torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata, "log", dlz_bind9_log_wrapper, "writeable_zone", dlz_bind9_writeable_zone_hook, NULL), ISC_R_SUCCESS, @@ -216,6 +216,7 @@ static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) /** * DNS torture module initialization */ +NTSTATUS torture_bind_dns_init(void); NTSTATUS torture_bind_dns_init(void) { struct torture_suite *suite; -- 1.9.1 From 3d628d584e504b5b6e2cb6e7cf9f2a5b227b166c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 17:57:13 +0200 Subject: [PATCH 13/24] s4:dlz_bind9: do an early talloc_free(el_ctx) in dlz_allnodes() We don't have to keep everything arround while walking the whole zone. Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 5d397c8198bcd2cdccc3deda57377d4696e6abd1) --- source4/dns_server/dlz_bind9.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index 46c586e..01700a5 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -980,6 +980,8 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, continue; } } + + talloc_free(el_ctx); } talloc_free(tmp_ctx); -- 1.9.1 From 4c792f3ce29278306dd9082d3a1772589690fd58 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Aug 2014 13:48:21 +0200 Subject: [PATCH 14/24] s4:torture:dlz_bind9: fix spnego tests The dlz_bind9 module uses the special dns-${NETBIOSNAME} account, and this is only available under the dns/hostname.domain SPN, not host/hostname. Also the dlz_ssumatch() function returns isc_boolean_t instead of isc_result_t. As ISC_R_SUCCESS and ISC_FALSE have the same value we didn't notice this problem. Change-Id: I48539c3f48f5dde9eaa2fff6da0f3be2f9f66311 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 76943bf0ac259fb8855bd123fe4bc85a103ba418) --- source4/torture/dns/dlz_bind9.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c index 88ca27c..0c5b153 100644 --- a/source4/torture/dns/dlz_bind9.c +++ b/source4/torture/dns/dlz_bind9.c @@ -158,9 +158,19 @@ static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed"); - status = gensec_set_target_hostname(gensec_client_context, torture_setting_string(tctx, "host", NULL)); + /* + * dlz_bind9 use the special dns/host.domain account + */ + status = gensec_set_target_hostname(gensec_client_context, + talloc_asprintf(tctx, + "%s.%s", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx))); torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed"); + status = gensec_set_target_service(gensec_client_context, "dns"); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed"); + status = gensec_set_credentials(gensec_client_context, cmdline_credentials); torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); @@ -181,7 +191,7 @@ static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech client_to_server.length, client_to_server.data, dbdata), - ISC_R_SUCCESS, + ISC_TRUE, "Failed to check key for update rights samba_dlz"); dlz_destroy(dbdata); -- 1.9.1 From 2a28c247bdf60b0593ec87e5ad8a9cc668d390bd Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 26 Aug 2014 10:24:27 +1200 Subject: [PATCH 15/24] torture-dns: Add test for dlz_bind9 lookups Change-Id: I3b9d1b56e3aa873fb8540b98e196b713b82332ca Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Andrew Bartlett Signed-off-by: Stefan Metzmacher (cherry picked from commit 2189470c2f55afe29e9e8dad1d2659a7eb2d06f9) --- source4/torture/dns/dlz_bind9.c | 224 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c index 0c5b153..327eb84 100644 --- a/source4/torture/dns/dlz_bind9.c +++ b/source4/torture/dns/dlz_bind9.c @@ -209,6 +209,229 @@ static bool test_dlz_bind9_spnego(struct torture_context *tctx) return test_dlz_bind9_gensec(tctx, "GSS-SPNEGO"); } +struct test_expected_record { + const char *name; + const char *type; + const char *data; + int ttl; + bool printed; +}; + +struct test_expected_rr { + struct torture_context *tctx; + const char *query_name; + size_t num_records; + struct test_expected_record *records; + size_t num_rr; +}; + +static bool dlz_bind9_putnamedrr_torture_hook(struct test_expected_rr *expected, + const char *name, + const char *type, + dns_ttl_t ttl, + const char *data) +{ + size_t i; + + torture_assert(expected->tctx, name != NULL, + talloc_asprintf(expected->tctx, + "Got unnamed record type[%s] data[%s]\n", + type, data)); + + expected->num_rr++; + torture_comment(expected->tctx, "%u: name[%s] type[%s] ttl[%u] data[%s]\n", + (unsigned)expected->num_rr, name, type, (unsigned)ttl, data); + + for (i = 0; i < expected->num_records; i++) { + if (expected->records[i].name != NULL) { + if (strcmp(name, expected->records[i].name) != 0) { + continue; + } + } + + if (strcmp(type, expected->records[i].type) != 0) { + continue; + } + + if (expected->records[i].data != NULL) { + if (strcmp(data, expected->records[i].data) != 0) { + continue; + } + } + + torture_assert_int_equal(expected->tctx, ttl, + expected->records[i].ttl, + talloc_asprintf(expected->tctx, + "TTL did not match expectations for type %s", + type)); + + expected->records[i].printed = true; + } + + return true; +} + +static isc_result_t dlz_bind9_putrr_hook(dns_sdlzlookup_t *lookup, + const char *type, + dns_ttl_t ttl, + const char *data) +{ + struct test_expected_rr *expected = + talloc_get_type_abort(lookup, struct test_expected_rr); + bool ok; + + ok = dlz_bind9_putnamedrr_torture_hook(expected, expected->query_name, + type, ttl, data); + if (!ok) { + return ISC_R_FAILURE; + } + + return ISC_R_SUCCESS; +} + +static isc_result_t dlz_bind9_putnamedrr_hook(dns_sdlzallnodes_t *allnodes, + const char *name, + const char *type, + dns_ttl_t ttl, + const char *data) +{ + struct test_expected_rr *expected = + talloc_get_type_abort(allnodes, struct test_expected_rr); + bool ok; + + ok = dlz_bind9_putnamedrr_torture_hook(expected, name, type, ttl, data); + if (!ok) { + return ISC_R_FAILURE; + } + + return ISC_R_SUCCESS; +} + +/* + * Tests some lookups + */ +static bool test_dlz_bind9_lookup(struct torture_context *tctx) +{ + size_t i; + void *dbdata; + const char *argv[] = { + "samba_dlz", + "-H", + lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"), + NULL + }; + struct test_expected_rr *expected1 = NULL; + struct test_expected_rr *expected2 = NULL; + + tctx_static = tctx; + torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata, + "log", dlz_bind9_log_wrapper, + "writeable_zone", dlz_bind9_writeable_zone_hook, + "putrr", dlz_bind9_putrr_hook, + "putnamedrr", dlz_bind9_putnamedrr_hook, + NULL), + ISC_R_SUCCESS, + "Failed to create samba_dlz"); + + torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata), + ISC_R_SUCCESS, + "Failed to configure samba_dlz"); + + expected1 = talloc_zero(tctx, struct test_expected_rr); + torture_assert(tctx, expected1 != NULL, "talloc failed"); + expected1->tctx = tctx; + + expected1->query_name = "@"; + + expected1->num_records = 4; + expected1->records = talloc_zero_array(expected1, + struct test_expected_record, + expected1->num_records); + torture_assert(tctx, expected1->records != NULL, "talloc failed"); + + expected1->records[0].name = expected1->query_name; + expected1->records[0].type = "soa"; + expected1->records[0].ttl = 3600; + expected1->records[0].data = talloc_asprintf(expected1->records, + "%s.%s hostmaster.%s 1 900 600 86400 3600", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx), + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, expected1->records[0].data != NULL, "talloc failed"); + + expected1->records[1].name = expected1->query_name; + expected1->records[1].type = "ns"; + expected1->records[1].ttl = 900; + expected1->records[1].data = talloc_asprintf(expected1->records, "%s.%s", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, expected1->records[1].data != NULL, "talloc failed"); + + expected1->records[2].name = expected1->query_name; + expected1->records[2].type = "aaaa"; + expected1->records[2].ttl = 900; + + expected1->records[3].name = expected1->query_name; + expected1->records[3].type = "a"; + expected1->records[3].ttl = 900; + + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Failed to lookup @"); + for (i = 0; i < expected1->num_records; i++) { + torture_assert(tctx, expected1->records[i].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run for type %s", + expected1->records[i].type)); + } + torture_assert_int_equal(tctx, expected1->num_rr, + expected1->num_records, + "Got too much data"); + + expected2 = talloc_zero(tctx, struct test_expected_rr); + torture_assert(tctx, expected2 != NULL, "talloc failed"); + expected2->tctx = tctx; + + expected2->query_name = torture_setting_string(tctx, "host", NULL); + torture_assert(tctx, expected2->query_name != NULL, "unknown host"); + + expected2->num_records = 2; + expected2->records = talloc_zero_array(expected2, + struct test_expected_record, + expected2->num_records); + torture_assert(tctx, expected2->records != NULL, "talloc failed"); + + expected2->records[0].name = expected2->query_name; + expected2->records[0].type = "aaaa"; + expected2->records[0].ttl = 900; + + expected2->records[1].name = expected2->query_name; + expected2->records[1].type = "a"; + expected2->records[1].ttl = 900; + + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected2->query_name, dbdata, + (dns_sdlzlookup_t *)expected2), + ISC_R_SUCCESS, + "Failed to lookup hostname"); + for (i = 0; i < expected2->num_records; i++) { + torture_assert(tctx, expected2->records[i].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected2->records[i].name, + expected2->records[i].type)); + } + torture_assert_int_equal(tctx, expected2->num_rr, + expected2->num_records, + "Got too much data"); + + dlz_destroy(dbdata); + + return true; +} + static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create(ctx, "dlz_bind9"); @@ -220,6 +443,7 @@ static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) torture_suite_add_simple_test(suite, "configure", test_dlz_bind9_configure); torture_suite_add_simple_test(suite, "gssapi", test_dlz_bind9_gssapi); torture_suite_add_simple_test(suite, "spnego", test_dlz_bind9_spnego); + torture_suite_add_simple_test(suite, "lookup", test_dlz_bind9_lookup); return suite; } -- 1.9.1 From f7337337eb2e73dbd2124242da727084c211ded5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Aug 2014 10:34:17 +0200 Subject: [PATCH 16/24] torture-dns: Add test for dlz_bind9 zonedumps Change-Id: I074b3e4cdad1a0b69c085dcaa44d6f48e68e863b Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit e23621e9dab67c8997d24b2ac7e4fd181fc5907c) --- source4/torture/dns/dlz_bind9.c | 106 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c index 327eb84..e98db44 100644 --- a/source4/torture/dns/dlz_bind9.c +++ b/source4/torture/dns/dlz_bind9.c @@ -432,6 +432,111 @@ static bool test_dlz_bind9_lookup(struct torture_context *tctx) return true; } +/* + * Test some zone dumps + */ +static bool test_dlz_bind9_zonedump(struct torture_context *tctx) +{ + size_t i; + void *dbdata; + const char *argv[] = { + "samba_dlz", + "-H", + lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"), + NULL + }; + struct test_expected_rr *expected1 = NULL; + + tctx_static = tctx; + torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata, + "log", dlz_bind9_log_wrapper, + "writeable_zone", dlz_bind9_writeable_zone_hook, + "putrr", dlz_bind9_putrr_hook, + "putnamedrr", dlz_bind9_putnamedrr_hook, + NULL), + ISC_R_SUCCESS, + "Failed to create samba_dlz"); + + torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata), + ISC_R_SUCCESS, + "Failed to configure samba_dlz"); + + expected1 = talloc_zero(tctx, struct test_expected_rr); + torture_assert(tctx, expected1 != NULL, "talloc failed"); + expected1->tctx = tctx; + + expected1->num_records = 7; + expected1->records = talloc_zero_array(expected1, + struct test_expected_record, + expected1->num_records); + torture_assert(tctx, expected1->records != NULL, "talloc failed"); + + expected1->records[0].name = lpcfg_dnsdomain(tctx->lp_ctx); + expected1->records[0].type = "soa"; + expected1->records[0].ttl = 3600; + expected1->records[0].data = talloc_asprintf(expected1->records, + "%s.%s hostmaster.%s 1 900 600 86400 3600", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx), + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, expected1->records[0].data != NULL, "talloc failed"); + + expected1->records[1].name = lpcfg_dnsdomain(tctx->lp_ctx); + expected1->records[1].type = "ns"; + expected1->records[1].ttl = 900; + expected1->records[1].data = talloc_asprintf(expected1->records, "%s.%s", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, expected1->records[1].data != NULL, "talloc failed"); + + expected1->records[2].name = lpcfg_dnsdomain(tctx->lp_ctx); + expected1->records[2].type = "aaaa"; + expected1->records[2].ttl = 900; + + expected1->records[3].name = lpcfg_dnsdomain(tctx->lp_ctx); + expected1->records[3].type = "a"; + expected1->records[3].ttl = 900; + + expected1->records[4].name = talloc_asprintf(expected1->records, "%s.%s", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, expected1->records[4].name != NULL, "unknown host"); + expected1->records[4].type = "aaaa"; + expected1->records[4].ttl = 900; + + expected1->records[5].name = talloc_asprintf(expected1->records, "%s.%s", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, expected1->records[5].name != NULL, "unknown host"); + expected1->records[5].type = "a"; + expected1->records[5].ttl = 900; + + /* + * We expect multiple srv records + */ + expected1->records[6].name = NULL; + expected1->records[6].type = "srv"; + expected1->records[6].ttl = 900; + + torture_assert_int_equal(tctx, dlz_allnodes(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, (dns_sdlzallnodes_t *)expected1), + ISC_R_SUCCESS, + "Failed to configure samba_dlz"); + for (i = 0; i < expected1->num_records; i++) { + torture_assert(tctx, expected1->records[i].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[i].name, + expected1->records[i].type)); + } + torture_assert_int_equal(tctx, expected1->num_rr, 24, + "Got wrong record count"); + + dlz_destroy(dbdata); + + return true; +} + static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create(ctx, "dlz_bind9"); @@ -444,6 +549,7 @@ static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) torture_suite_add_simple_test(suite, "gssapi", test_dlz_bind9_gssapi); torture_suite_add_simple_test(suite, "spnego", test_dlz_bind9_spnego); torture_suite_add_simple_test(suite, "lookup", test_dlz_bind9_lookup); + torture_suite_add_simple_test(suite, "zonedump", test_dlz_bind9_zonedump); return suite; } -- 1.9.1 From 6de52fbf98d9a998b6b5cb26f0177c057ed53bfc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Aug 2014 12:04:59 +0200 Subject: [PATCH 17/24] torture-dns: Add test for dlz_bind9 updates Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 914a3667471ced3199f51db8bc1d4a6d3fbc4e8f) --- source4/torture/dns/dlz_bind9.c | 517 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 517 insertions(+) diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c index e98db44..fa6967d 100644 --- a/source4/torture/dns/dlz_bind9.c +++ b/source4/torture/dns/dlz_bind9.c @@ -537,6 +537,522 @@ static bool test_dlz_bind9_zonedump(struct torture_context *tctx) return true; } +/* + * Test some updates + */ +static bool test_dlz_bind9_update01(struct torture_context *tctx) +{ + NTSTATUS status; + struct gensec_security *gensec_client_context; + DATA_BLOB client_to_server, server_to_client; + void *dbdata; + void *version = NULL; + const char *argv[] = { + "samba_dlz", + "-H", + lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"), + NULL + }; + struct test_expected_rr *expected1 = NULL; + char *name = NULL; + char *data0 = NULL; + char *data1 = NULL; + char *data2 = NULL; + bool ret = false; + + tctx_static = tctx; + torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata, + "log", dlz_bind9_log_wrapper, + "writeable_zone", dlz_bind9_writeable_zone_hook, + "putrr", dlz_bind9_putrr_hook, + "putnamedrr", dlz_bind9_putnamedrr_hook, + NULL), + ISC_R_SUCCESS, + "Failed to create samba_dlz"); + + torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata), + ISC_R_SUCCESS, + "Failed to configure samba_dlz"); + + expected1 = talloc_zero(tctx, struct test_expected_rr); + torture_assert(tctx, expected1 != NULL, "talloc failed"); + expected1->tctx = tctx; + + expected1->query_name = __func__; + + name = talloc_asprintf(expected1, "%s.%s", + expected1->query_name, + lpcfg_dnsdomain(tctx->lp_ctx)); + torture_assert(tctx, name != NULL, "talloc failed"); + + expected1->num_records = 2; + expected1->records = talloc_zero_array(expected1, + struct test_expected_record, + expected1->num_records); + torture_assert(tctx, expected1->records != NULL, "talloc failed"); + + expected1->records[0].name = expected1->query_name; + expected1->records[0].type = "a"; + expected1->records[0].ttl = 3600; + expected1->records[0].data = "127.1.2.3"; + expected1->records[0].printed = false; + + data0 = talloc_asprintf(expected1, + "%s.\t" "%u\t" "%s\t" "%s\t" "%s", + name, + (unsigned)expected1->records[0].ttl, + "in", + expected1->records[0].type, + expected1->records[0].data); + torture_assert(tctx, data0 != NULL, "talloc failed"); + + expected1->records[1].name = expected1->query_name; + expected1->records[1].type = "a"; + expected1->records[1].ttl = 3600; + expected1->records[1].data = "127.3.2.1"; + expected1->records[1].printed = false; + + data1 = talloc_asprintf(expected1, + "%s.\t" "%u\t" "%s\t" "%s\t" "%s", + name, + (unsigned)expected1->records[1].ttl, + "in", + expected1->records[1].type, + expected1->records[1].data); + torture_assert(tctx, data1 != NULL, "talloc failed"); + + data2 = talloc_asprintf(expected1, + "%s.\t" "0\t" "in\t" "a\t" "127.3.3.3", + name); + torture_assert(tctx, data2 != NULL, "talloc failed"); + + /* + * Prepare session info + */ + status = gensec_client_start(tctx, &gensec_client_context, + lpcfg_gensec_settings(tctx, tctx->lp_ctx)); + torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed"); + + /* + * dlz_bind9 use the special dns/host.domain account + */ + status = gensec_set_target_hostname(gensec_client_context, + talloc_asprintf(tctx, + "%s.%s", + torture_setting_string(tctx, "host", NULL), + lpcfg_dnsdomain(tctx->lp_ctx))); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed"); + + status = gensec_set_target_service(gensec_client_context, "dns"); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed"); + + status = gensec_set_credentials(gensec_client_context, cmdline_credentials); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); + + status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSS-SPNEGO"); + torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed"); + + server_to_client = data_blob(NULL, 0); + + /* Do one step of the client-server update dance */ + status = gensec_update(gensec_client_context, tctx, tctx->ev, server_to_client, &client_to_server); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {; + torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed"); + } + + torture_assert_int_equal(tctx, dlz_ssumatch(cli_credentials_get_username(cmdline_credentials), + name, + "127.0.0.1", + expected1->records[0].type, + "key", + client_to_server.length, + client_to_server.data, + dbdata), + ISC_TRUE, + "Failed to check key for update rights samba_dlz"); + + /* + * We test the following: + * + * 1. lookup the records => NOT_FOUND + * 2. delete all records => NOT_FOUND + * 3. delete 1st record => NOT_FOUND + * 4. create 1st record => SUCCESS + * 5. lookup the records => found 1st + * 6. create 2nd record => SUCCESS + * 7. lookup the records => found 1st and 2nd + * 8. delete unknown record => NOT_FOUND + * 9. lookup the records => found 1st and 2nd + * 10. delete 1st record => SUCCESS + * 11. lookup the records => found 2nd + * 12. delete 2nd record => SUCCESS + * 13. lookup the records => NOT_FOUND + * 14. create 1st record => SUCCESS + * 15. lookup the records => found 1st + * 16. create 2nd record => SUCCESS + * 17. lookup the records => found 1st and 2nd + * 18. update 1st record => SUCCESS + * 19. lookup the records => found 1st and 2nd + * 20. delete all unknown type records => NOT_FOUND + * 21. lookup the records => found 1st and 2nd + * 22. delete all records => SUCCESS + * 23. lookup the records => NOT_FOUND + */ + + /* Step 1. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_NOTFOUND, + "Found hostname"); + torture_assert_int_equal(tctx, expected1->num_rr, 0, + "Got wrong record count"); + + /* Step 2. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_delrdataset(name, + expected1->records[0].type, + dbdata, version), + ISC_R_NOTFOUND, ret, cancel_version, + talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n", + name, expected1->records[0].type)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version); + + /* Step 3. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_subrdataset(name, data0, dbdata, version), + ISC_R_NOTFOUND, ret, cancel_version, + talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n", + name, data0)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version); + + /* Step 4. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_addrdataset(name, data0, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n", + name, data0)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 5. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 1, + "Got wrong record count"); + + /* Step 6. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_addrdataset(name, data1, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n", + name, data1)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 7. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert(tctx, expected1->records[1].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[1].name, + expected1->records[1].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 2, + "Got wrong record count"); + + /* Step 8. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_subrdataset(name, data2, dbdata, version), + ISC_R_NOTFOUND, ret, cancel_version, + talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n", + name, data2)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 9. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert(tctx, expected1->records[1].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[1].name, + expected1->records[1].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 2, + "Got wrong record count"); + + /* Step 10. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_subrdataset(name, data0, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n", + name, data0)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 11. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[1].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[1].name, + expected1->records[1].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 1, + "Got wrong record count"); + + /* Step 12. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_subrdataset(name, data1, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n", + name, data1)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 13. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_NOTFOUND, + "Found hostname"); + torture_assert_int_equal(tctx, expected1->num_rr, 0, + "Got wrong record count"); + + /* Step 14. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_addrdataset(name, data0, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n", + name, data0)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 15. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 1, + "Got wrong record count"); + + /* Step 16. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_addrdataset(name, data1, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n", + name, data1)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 17. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert(tctx, expected1->records[1].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[1].name, + expected1->records[1].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 2, + "Got wrong record count"); + + /* Step 18. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_addrdataset(name, data0, dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to update name[%s] data[%s]\n", + name, data0)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 19. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert(tctx, expected1->records[1].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[1].name, + expected1->records[1].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 2, + "Got wrong record count"); + + /* Step 20. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_delrdataset(name, "txt", dbdata, version), + ISC_R_FAILURE, ret, cancel_version, + talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n", + name, "txt")); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version); + + /* Step 21. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_SUCCESS, + "Not found hostname"); + torture_assert(tctx, expected1->records[0].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[0].name, + expected1->records[0].type)); + torture_assert(tctx, expected1->records[1].printed, + talloc_asprintf(tctx, + "Failed to have putrr callback run name[%s] for type %s", + expected1->records[1].name, + expected1->records[1].type)); + torture_assert_int_equal(tctx, expected1->num_rr, 2, + "Got wrong record count"); + + /* Step 22. */ + torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx), + dbdata, &version), + ISC_R_SUCCESS, + "Failed to start transaction"); + torture_assert_int_equal_goto(tctx, + dlz_delrdataset(name, + expected1->records[0].type, + dbdata, version), + ISC_R_SUCCESS, ret, cancel_version, + talloc_asprintf(tctx, "Failed to delete name[%s] type[%s]\n", + name, expected1->records[0].type)); + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version); + + /* Step 23. */ + expected1->num_rr = 0; + expected1->records[0].printed = false; + expected1->records[1].printed = false; + torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx), + expected1->query_name, dbdata, + (dns_sdlzlookup_t *)expected1), + ISC_R_NOTFOUND, + "Found hostname"); + torture_assert_int_equal(tctx, expected1->num_rr, 0, + "Got wrong record count"); + + dlz_destroy(dbdata); + + return true; + +cancel_version: + dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version); + return ret; +} + static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) { struct torture_suite *suite = torture_suite_create(ctx, "dlz_bind9"); @@ -550,6 +1066,7 @@ static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx) torture_suite_add_simple_test(suite, "spnego", test_dlz_bind9_spnego); torture_suite_add_simple_test(suite, "lookup", test_dlz_bind9_lookup); torture_suite_add_simple_test(suite, "zonedump", test_dlz_bind9_zonedump); + torture_suite_add_simple_test(suite, "update01", test_dlz_bind9_update01); return suite; } -- 1.9.1 From 59fac755c04e481c8d8ef03b40cc7e2acc01cfaf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 08:40:32 +0200 Subject: [PATCH 18/24] s4:dlz_bind9: let dlz_bind9 use dns_common_lookup() for name lookup Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Change-Id: I2632fa0ce120a978f6f400fa5cbf18a7fbbd64a3 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 96dcebe8c20b9aa954a96a4deabe16957576be2c) --- source4/dns_server/dlz_bind9.c | 68 +++++++++++----------------------------- source4/dns_server/wscript_build | 6 ++-- 2 files changed, 21 insertions(+), 53 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index 01700a5..5cb9428 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -37,7 +37,7 @@ #include "messaging/messaging.h" #include "lib/cmdline/popt_common.h" #include "dlz_minimal.h" - +#include "dns_server/dnsserver_common.h" struct b9_options { const char *url; @@ -801,11 +801,10 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state, const char **types) { TALLOC_CTX *tmp_ctx = talloc_new(state); - const char *attrs[] = { "dnsRecord", NULL }; - int ret = LDB_SUCCESS, i; - struct ldb_result *res; - struct ldb_message_element *el; struct ldb_dn *dn; + WERROR werr = WERR_DNS_ERROR_NAME_DOES_NOT_EXIST; + struct dnsp_DnssrvRpcRecord *records = NULL; + uint16_t num_records = 0, i; for (i=0; zone_prefixes[i]; i++) { dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb)); @@ -819,38 +818,21 @@ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state, return ISC_R_NOMEMORY; } - ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, - attrs, "objectClass=dnsNode"); - if (ret == LDB_SUCCESS) { + werr = dns_common_lookup(state->samdb, tmp_ctx, dn, + &records, &num_records, NULL); + if (W_ERROR_IS_OK(werr)) { break; } } - if (ret != LDB_SUCCESS || res->count == 0) { + if (!W_ERROR_IS_OK(werr)) { talloc_free(tmp_ctx); return ISC_R_NOTFOUND; } - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL || el->num_values == 0) { - talloc_free(tmp_ctx); - return ISC_R_NOTFOUND; - } - - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec; - enum ndr_err_code ndr_err; + for (i=0; i < num_records; i++) { isc_result_t result; - ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(tmp_ctx); - return ISC_R_FAILURE; - } - - result = b9_putrr(state, lookup, &rec, types); + result = b9_putrr(state, lookup, &records[i], types); if (result != ISC_R_SUCCESS) { talloc_free(tmp_ctx); return result; @@ -1059,39 +1041,25 @@ _PUBLIC_ void dlz_closeversion(const char *zone, isc_boolean_t commit, */ static bool b9_has_soa(struct dlz_bind9_data *state, struct ldb_dn *dn, const char *zone) { - const char *attrs[] = { "dnsRecord", NULL }; - struct ldb_result *res; - struct ldb_message_element *el; TALLOC_CTX *tmp_ctx = talloc_new(state); - int ret, i; + WERROR werr; + struct dnsp_DnssrvRpcRecord *records = NULL; + uint16_t num_records = 0, i; if (!ldb_dn_add_child_fmt(dn, "DC=@,DC=%s", zone)) { talloc_free(tmp_ctx); return false; } - ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, - attrs, "objectClass=dnsNode"); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return false; - } - - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL) { + werr = dns_common_lookup(state->samdb, tmp_ctx, dn, + &records, &num_records, NULL); + if (!W_ERROR_IS_OK(werr)) { talloc_free(tmp_ctx); return false; } - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec; - enum ndr_err_code ndr_err; - ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - continue; - } - if (rec.wType == DNS_TYPE_SOA) { + for (i=0; i < num_records; i++) { + if (records[i].wType == DNS_TYPE_SOA) { talloc_free(tmp_ctx); return true; } diff --git a/source4/dns_server/wscript_build b/source4/dns_server/wscript_build index 66e6b72..a92ab67 100644 --- a/source4/dns_server/wscript_build +++ b/source4/dns_server/wscript_build @@ -24,7 +24,7 @@ bld.SAMBA_LIBRARY('dlz_bind9', link_name='modules/bind9/dlz_bind9.so', realname='dlz_bind9.so', install_path='${MODULESDIR}/bind9', - deps='samba-hostconfig samdb-common gensec popt', + deps='samba-hostconfig samdb-common gensec popt dnsserver_common', enabled=bld.AD_DC_BUILD_IS_ENABLED()) bld.SAMBA_LIBRARY('dlz_bind9_9', @@ -34,12 +34,12 @@ bld.SAMBA_LIBRARY('dlz_bind9_9', link_name='modules/bind9/dlz_bind9_9.so', realname='dlz_bind9_9.so', install_path='${MODULESDIR}/bind9', - deps='samba-hostconfig samdb-common gensec popt', + deps='samba-hostconfig samdb-common gensec popt dnsserver_common', enabled=bld.AD_DC_BUILD_IS_ENABLED()) bld.SAMBA_LIBRARY('dlz_bind9_for_torture', source='dlz_bind9.c', cflags='-DBIND_VERSION_9_8', private_library=True, - deps='samba-hostconfig samdb-common gensec popt', + deps='samba-hostconfig samdb-common gensec popt dnsserver_common', enabled=bld.AD_DC_BUILD_IS_ENABLED()) -- 1.9.1 From 5828e1591f34244e4aa30bdbfe8e34c9a9d9f6ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 17:59:08 +0200 Subject: [PATCH 19/24] s4:dlz_bind9: let dlz_bind9 use dns_common_extract() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Change-Id: I7c661964a3da1a1981f022a06b9bef25bbd33479 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit dedcf30fd12821c272002e3b4cbfda4ca38650fd) --- source4/dns_server/dlz_bind9.c | 118 +++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index 5cb9428..a433acc 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -911,6 +911,9 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, TALLOC_CTX *el_ctx = talloc_new(tmp_ctx); const char *rdn, *name; const struct ldb_val *v; + WERROR werr; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; el = ldb_msg_find_element(res->msgs[i], "dnsRecord"); if (el == NULL || el->num_values == 0) { @@ -944,20 +947,18 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, return ISC_R_NOMEMORY; } - for (j=0; jnum_values; j++) { - struct dnsp_DnssrvRpcRecord rec; - enum ndr_err_code ndr_err; - isc_result_t result; + werr = dns_common_extract(el, el_ctx, &recs, &num_recs); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); + talloc_free(el_ctx); + continue; + } - ndr_err = ndr_pull_struct_blob(&el->values[j], el_ctx, &rec, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - continue; - } + for (j=0; j < num_recs; j++) { + isc_result_t result; - result = b9_putnamedrr(state, allnodes, name, &rec); + result = b9_putnamedrr(state, allnodes, name, &recs[j]); if (result != ISC_R_SUCCESS) { continue; } @@ -1462,8 +1463,11 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo const char *attrs[] = { "dnsRecord", NULL }; int ret, i; struct ldb_message_element *el; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; enum ndr_err_code ndr_err; NTTIME t; + WERROR werr; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_INFO, "samba_dlz: bad transaction version"); @@ -1523,22 +1527,19 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo } } + werr = dns_common_extract(el, rec, &recs, &num_recs); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); + talloc_free(rec); + return ISC_R_FAILURE; + } + /* there are existing records. We need to see if this will * replace a record or add to it */ - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec2; - - ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } - - if (b9_record_match(state, rec, &rec2)) { + for (i=0; i < num_recs; i++) { + if (b9_record_match(state, rec, &recs[i])) { break; } } @@ -1597,7 +1598,9 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo const char *attrs[] = { "dnsRecord", NULL }; int ret, i; struct ldb_message_element *el; - enum ndr_err_code ndr_err; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; + WERROR werr; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version"); @@ -1639,19 +1642,16 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo return ISC_R_FAILURE; } - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec2; - - ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } + werr = dns_common_extract(el, rec, &recs, &num_recs); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); + talloc_free(rec); + return ISC_R_FAILURE; + } - if (b9_record_match(state, rec, &rec2)) { + for (i=0; i < num_recs; i++) { + if (b9_record_match(state, rec, &recs[i])) { break; } } @@ -1703,11 +1703,15 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * isc_result_t result; struct ldb_result *res; const char *attrs[] = { "dnsRecord", NULL }; - int ret, i; + int ret; struct ldb_message_element *el; - enum ndr_err_code ndr_err; + int vi = 0; enum dns_record_type dns_type; bool found = false; + struct dnsp_DnssrvRpcRecord *recs = NULL; + uint16_t num_recs = 0; + uint16_t ri = 0; + WERROR werr; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_ERROR, "samba_dlz: bad transaction version"); @@ -1743,27 +1747,27 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * return ISC_R_NOTFOUND; } - for (i=0; inum_values; i++) { - struct dnsp_DnssrvRpcRecord rec2; + werr = dns_common_extract(el, tmp_ctx, &recs, &num_recs); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); + talloc_free(tmp_ctx); + return ISC_R_FAILURE; + } - ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec2, - (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(tmp_ctx); - return ISC_R_FAILURE; + for (ri=0; ri < num_recs; ri++) { + if (dns_type != recs[ri].wType) { + vi += 1; + continue; } - if (dns_type == rec2.wType) { - if (i < el->num_values-1) { - memmove(&el->values[i], &el->values[i+1], - sizeof(el->values[0])*((el->num_values-1)-i)); - } - el->num_values--; - i--; - found = true; + found = true; + + if (vi < el->num_values-1) { + memmove(&el->values[vi], &el->values[vi+1], + sizeof(el->values[0])*((el->num_values-1)-vi)); } + el->num_values--; } if (!found) { -- 1.9.1 From 12c5c326cbe3102285e74b89738b98e02769b3ff Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 18:51:39 +0200 Subject: [PATCH 20/24] s4:dlz_bind9: let dlz_bind9 use dns_common_replace() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Change-Id: I2fd2503230cbf89445594e49f39ac321769ff06e Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit fd952bf814835c4860ab10794225fbd583ee3ad5) --- source4/dns_server/dlz_bind9.c | 127 ++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 77 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index a433acc..b65545c 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -1300,32 +1300,15 @@ static isc_result_t b9_add_record(struct dlz_bind9_data *state, const char *name struct ldb_dn *dn, struct dnsp_DnssrvRpcRecord *rec) { - struct ldb_message *msg; - enum ndr_err_code ndr_err; - struct ldb_val v; - int ret; - - msg = ldb_msg_new(rec); - if (msg == NULL) { - return ISC_R_NOMEMORY; - } - msg->dn = dn; - ret = ldb_msg_add_string(msg, "objectClass", "dnsNode"); - if (ret != LDB_SUCCESS) { - return ISC_R_FAILURE; - } - - ndr_err = ndr_push_struct_blob(&v, rec, rec, (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ISC_R_FAILURE; - } - ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL); - if (ret != LDB_SUCCESS) { - return ISC_R_FAILURE; - } + WERROR werr; - ret = ldb_add(state->samdb, msg); - if (ret != LDB_SUCCESS) { + werr = dns_common_replace(state->samdb, rec, dn, + true,/* needs_add */ + state->soa_serial, + rec, 1); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to add %s - %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); return ISC_R_FAILURE; } @@ -1465,7 +1448,6 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo struct ldb_message_element *el; struct dnsp_DnssrvRpcRecord *recs = NULL; uint16_t num_recs = 0; - enum ndr_err_code ndr_err; NTTIME t; WERROR werr; @@ -1484,7 +1466,6 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo t /= 3600; /* convert to hours */ rec->rank = DNS_RANK_ZONE; - rec->dwSerial = state->soa_serial; rec->dwTimeStamp = (uint32_t)t; if (!b9_parse(state, rdatastr, rec)) { @@ -1543,25 +1524,26 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo break; } } - if (i == el->num_values) { + if (i == UINT16_MAX) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to already %u dnsRecord values for %s", + i, ldb_dn_get_linearized(dn)); + talloc_free(rec); + return ISC_R_FAILURE; + } + + if (i == num_recs) { /* adding a new value */ - el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1); - if (el->values == NULL) { + recs = talloc_realloc(rec, recs, + struct dnsp_DnssrvRpcRecord, + num_recs + 1); + if (recs == NULL) { talloc_free(rec); return ISC_R_NOMEMORY; } - el->num_values++; - } - - ndr_err = ndr_push_struct_blob(&el->values[i], rec, rec, - (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to push dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; + num_recs++; } + recs[i] = *rec; if (!b9_set_session_info(state, name)) { talloc_free(rec); @@ -1569,12 +1551,14 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo } /* modify the record */ - el->flags = LDB_FLAG_MOD_REPLACE; - ret = ldb_modify(state->samdb, res->msgs[0]); + werr = dns_common_replace(state->samdb, rec, dn, + false,/* needs_add */ + state->soa_serial, + recs, num_recs); b9_reset_session_info(state); - if (ret != LDB_SUCCESS) { + if (!W_ERROR_IS_OK(werr)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", - ldb_dn_get_linearized(dn), ldb_errstring(state->samdb)); + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); return ISC_R_FAILURE; } @@ -1652,35 +1636,31 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo for (i=0; i < num_recs; i++) { if (b9_record_match(state, rec, &recs[i])) { + recs[i] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; break; } } - if (i == el->num_values) { + if (i == num_recs) { talloc_free(rec); return ISC_R_NOTFOUND; } - if (i < el->num_values-1) { - memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i)); - } - el->num_values--; - if (!b9_set_session_info(state, name)) { talloc_free(rec); return ISC_R_FAILURE; } - if (el->num_values == 0) { - el->flags = LDB_FLAG_MOD_DELETE; - } else { - el->flags = LDB_FLAG_MOD_REPLACE; - } - ret = ldb_modify(state->samdb, res->msgs[0]); - + /* modify the record */ + werr = dns_common_replace(state->samdb, rec, dn, + false,/* needs_add */ + state->soa_serial, + recs, num_recs); b9_reset_session_info(state); - if (ret != LDB_SUCCESS) { + if (!W_ERROR_IS_OK(werr)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", - ldb_dn_get_linearized(dn), ldb_errstring(state->samdb)); + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); return ISC_R_FAILURE; } @@ -1705,7 +1685,6 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * const char *attrs[] = { "dnsRecord", NULL }; int ret; struct ldb_message_element *el; - int vi = 0; enum dns_record_type dns_type; bool found = false; struct dnsp_DnssrvRpcRecord *recs = NULL; @@ -1757,17 +1736,13 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * for (ri=0; ri < num_recs; ri++) { if (dns_type != recs[ri].wType) { - vi += 1; continue; } found = true; - - if (vi < el->num_values-1) { - memmove(&el->values[vi], &el->values[vi+1], - sizeof(el->values[0])*((el->num_values-1)-vi)); - } - el->num_values--; + recs[ri] = (struct dnsp_DnssrvRpcRecord) { + .wType = DNS_TYPE_TOMBSTONE, + }; } if (!found) { @@ -1780,17 +1755,15 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * return ISC_R_FAILURE; } - if (el->num_values == 0) { - el->flags = LDB_FLAG_MOD_DELETE; - } else { - el->flags = LDB_FLAG_MOD_REPLACE; - } - ret = ldb_modify(state->samdb, res->msgs[0]); - + /* modify the record */ + werr = dns_common_replace(state->samdb, tmp_ctx, dn, + false,/* needs_add */ + state->soa_serial, + recs, num_recs); b9_reset_session_info(state); - if (ret != LDB_SUCCESS) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to delete type %s in %s - %s", - type, ldb_dn_get_linearized(dn), ldb_errstring(state->samdb)); + if (!W_ERROR_IS_OK(werr)) { + state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", + ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(tmp_ctx); return ISC_R_FAILURE; } -- 1.9.1 From 5badf6f5c9782e8fa08ca9eaa21e725b618b9c75 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Jul 2014 20:12:08 +0200 Subject: [PATCH 21/24] s4:dlz_bind9: let dlz_bind9 use dns_common_lookup() before removing records Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 11bbfd932c113b3222bc93d59702271a3777b6f3) --- source4/dns_server/dlz_bind9.c | 53 ++++++------------------------------------ 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index b65545c..460976e 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -1578,12 +1578,9 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo struct dnsp_DnssrvRpcRecord *rec; struct ldb_dn *dn; isc_result_t result; - struct ldb_result *res; - const char *attrs[] = { "dnsRecord", NULL }; - int ret, i; - struct ldb_message_element *el; struct dnsp_DnssrvRpcRecord *recs = NULL; uint16_t num_recs = 0; + uint16_t i; WERROR werr; if (state->transaction_token != (void*)version) { @@ -1610,28 +1607,11 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo } /* get the existing records */ - ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - talloc_free(rec); - return ISC_R_NOTFOUND; - } - - /* there are existing records. We need to see if any match - */ - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL || el->num_values == 0) { - state->log(ISC_LOG_ERROR, "samba_dlz: no dnsRecord attribute for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } - - werr = dns_common_extract(el, rec, &recs, &num_recs); + werr = dns_common_lookup(state->samdb, rec, dn, + &recs, &num_recs, NULL); if (!W_ERROR_IS_OK(werr)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", - ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); - return ISC_R_FAILURE; + return ISC_R_NOTFOUND; } for (i=0; i < num_recs; i++) { @@ -1681,10 +1661,6 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * TALLOC_CTX *tmp_ctx; struct ldb_dn *dn; isc_result_t result; - struct ldb_result *res; - const char *attrs[] = { "dnsRecord", NULL }; - int ret; - struct ldb_message_element *el; enum dns_record_type dns_type; bool found = false; struct dnsp_DnssrvRpcRecord *recs = NULL; @@ -1712,26 +1688,11 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * } /* get the existing records */ - ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - talloc_free(tmp_ctx); - return ISC_R_NOTFOUND; - } - - /* there are existing records. We need to see if any match the type - */ - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL || el->num_values == 0) { - talloc_free(tmp_ctx); - return ISC_R_NOTFOUND; - } - - werr = dns_common_extract(el, tmp_ctx, &recs, &num_recs); + werr = dns_common_lookup(state->samdb, tmp_ctx, dn, + &recs, &num_recs, NULL); if (!W_ERROR_IS_OK(werr)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", - ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(tmp_ctx); - return ISC_R_FAILURE; + return ISC_R_NOTFOUND; } for (ri=0; ri < num_recs; ri++) { -- 1.9.1 From 0e927bb48ec03f489b55115d30a5e31eea43c941 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 31 Jul 2014 09:30:16 +0200 Subject: [PATCH 22/24] s4:dlz_bind9: let dlz_bind9 use dns_common_lookup() before add/modify Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Aug 27 15:21:19 CEST 2014 on sn-devel-104 (cherry picked from commit d68a2ebecd244181b1238635ee54dadd05835525) --- source4/dns_server/dlz_bind9.c | 77 ++++++++++++------------------------------ 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index 460976e..38b765a 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -1292,29 +1292,6 @@ _PUBLIC_ isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const return ISC_TRUE; } - -/* - add a new record - */ -static isc_result_t b9_add_record(struct dlz_bind9_data *state, const char *name, - struct ldb_dn *dn, - struct dnsp_DnssrvRpcRecord *rec) -{ - WERROR werr; - - werr = dns_common_replace(state->samdb, rec, dn, - true,/* needs_add */ - state->soa_serial, - rec, 1); - if (!W_ERROR_IS_OK(werr)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to add %s - %s", - ldb_dn_get_linearized(dn), win_errstr(werr)); - return ISC_R_FAILURE; - } - - return ISC_R_SUCCESS; -} - /* see if two DNS names are the same */ @@ -1442,12 +1419,12 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo struct dnsp_DnssrvRpcRecord *rec; struct ldb_dn *dn; isc_result_t result; - struct ldb_result *res; - const char *attrs[] = { "dnsRecord", NULL }; - int ret, i; - struct ldb_message_element *el; + bool tombstoned = false; + bool needs_add = false; struct dnsp_DnssrvRpcRecord *recs = NULL; uint16_t num_recs = 0; + uint16_t first = 0; + uint16_t i; NTTIME t; WERROR werr; @@ -1482,33 +1459,12 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo } /* get any existing records */ - ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - if (!b9_set_session_info(state, name)) { - talloc_free(rec); - return ISC_R_FAILURE; - } - result = b9_add_record(state, name, dn, rec); - b9_reset_session_info(state); - talloc_free(rec); - if (result == ISC_R_SUCCESS) { - state->log(ISC_LOG_INFO, "samba_dlz: added %s %s", name, rdatastr); - } - return result; - } - - el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); - if (el == NULL) { - ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", LDB_FLAG_MOD_ADD, &el); - if (ret != LDB_SUCCESS) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to add dnsRecord for %s", - ldb_dn_get_linearized(dn)); - talloc_free(rec); - return ISC_R_FAILURE; - } + werr = dns_common_lookup(state->samdb, rec, dn, + &recs, &num_recs, &tombstoned); + if (W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) { + needs_add = true; + werr = WERR_OK; } - - werr = dns_common_extract(el, rec, &recs, &num_recs); if (!W_ERROR_IS_OK(werr)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s, %s", ldb_dn_get_linearized(dn), win_errstr(werr)); @@ -1516,10 +1472,18 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo return ISC_R_FAILURE; } + if (tombstoned) { + /* + * we need to keep the existing tombstone record + * and ignore it + */ + first = num_recs; + } + /* there are existing records. We need to see if this will * replace a record or add to it */ - for (i=0; i < num_recs; i++) { + for (i=first; i < num_recs; i++) { if (b9_record_match(state, rec, &recs[i])) { break; } @@ -1552,12 +1516,13 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo /* modify the record */ werr = dns_common_replace(state->samdb, rec, dn, - false,/* needs_add */ + needs_add, state->soa_serial, recs, num_recs); b9_reset_session_info(state); if (!W_ERROR_IS_OK(werr)) { - state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", + state->log(ISC_LOG_ERROR, "samba_dlz: failed to %s %s - %s", + needs_add ? "add" : "modify", ldb_dn_get_linearized(dn), win_errstr(werr)); talloc_free(rec); return ISC_R_FAILURE; -- 1.9.1 From 9fd9b66f0454481c60eba31a4a501a12665af27a Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 31 Jul 2014 17:24:52 +1000 Subject: [PATCH 23/24] s4-rpc: dnsserver: Do not search for deleted DNS entries Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Amitay Isaacs Reviewed-by: Stefan Metzmacher --- source4/rpc_server/dnsserver/dcerpc_dnsserver.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c index d54940a..dee69fe 100644 --- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c +++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c @@ -1625,7 +1625,8 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate, } ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn, - LDB_SCOPE_ONELEVEL, attrs, "(&(objectClass=dnsNode)(name=@))"); + LDB_SCOPE_ONELEVEL, attrs, + "(&(objectClass=dnsNode)(name=@)(!(dNSTombstoned=TRUE)))"); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return WERR_INTERNAL_DB_ERROR; @@ -1657,8 +1658,9 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate, if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) { for (i=0; isamdb, tmp_ctx, &res, z->zone_dn, - LDB_SCOPE_ONELEVEL, attrs, - "(&(objectClass=dnsNode)(name=%s))", add_names[i]); + LDB_SCOPE_ONELEVEL, attrs, + "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))", + add_names[i]); if (ret != LDB_SUCCESS || res->count == 0) { talloc_free(res); continue; @@ -1722,11 +1724,12 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, /* search all records under parent tree */ if (strcasecmp(name, z->name) == 0) { ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn, - LDB_SCOPE_ONELEVEL, attrs, "(objectClass=dnsNode)"); + LDB_SCOPE_ONELEVEL, attrs, + "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))"); } else { ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn, - LDB_SCOPE_ONELEVEL, attrs, - "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s)))", + LDB_SCOPE_ONELEVEL, attrs, + "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s))(!(dNSTombstoned=TRUE)))", name, name); } if (ret != LDB_SUCCESS) { @@ -1801,7 +1804,8 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, name = dns_split_node_name(tmp_ctx, add_names[i], z2->name); ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z2->zone_dn, LDB_SCOPE_ONELEVEL, attrs, - "(&(objectClass=dnsNode)(name=%s))", name); + "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))", + name); talloc_free(name); if (ret != LDB_SUCCESS) { continue; -- 1.9.1 From 2e2321b697b749d036dd55dfcab5148930ed003a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 4 Sep 2014 07:19:46 +0200 Subject: [PATCH 24/24] s4-rpc: dnsserver: handle updates of tombstoned dnsNode objects Bug: https://bugzilla.samba.org/show_bug.cgi?id=10749 Signed-off-by: Stefan Metzmacher Reviewed-by: Amitay Isaacs --- source4/rpc_server/dnsserver/dnsdb.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source4/rpc_server/dnsserver/dnsdb.c b/source4/rpc_server/dnsserver/dnsdb.c index 24e9e89..e567f5a 100644 --- a/source4/rpc_server/dnsserver/dnsdb.c +++ b/source4/rpc_server/dnsserver/dnsdb.c @@ -395,7 +395,7 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx, const char *name, struct DNS_RPC_RECORD *add_record) { - const char * const attrs[] = { "dnsRecord", NULL }; + const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL }; struct ldb_result *res; struct dnsp_DnssrvRpcRecord *rec; struct ldb_message_element *el; @@ -404,6 +404,7 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx, NTTIME t; int ret, i; int serial; + bool was_tombstoned = false; rec = dns_to_dnsp_copy(mem_ctx, add_record); W_ERROR_HAVE_NO_MEMORY(rec); @@ -452,6 +453,12 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx, } } + was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0], + "dNSTombstoned", false); + if (was_tombstoned) { + el->num_values = 0; + } + for (i=0; inum_values; i++) { struct dnsp_DnssrvRpcRecord rec2; @@ -482,6 +489,12 @@ WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx, } el->flags = LDB_FLAG_MOD_REPLACE; + + el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned"); + if (el != NULL) { + el->flags = LDB_FLAG_MOD_DELETE; + } + ret = ldb_modify(samdb, res->msgs[0]); if (ret != LDB_SUCCESS) { return WERR_INTERNAL_DB_ERROR; @@ -520,7 +533,7 @@ WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx, arec->dwTimeStamp = t; ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs, - "(&(objectClass=dnsNode)(name=%s))", name); + "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))", name); if (ret != LDB_SUCCESS) { return WERR_INTERNAL_DB_ERROR; } -- 1.9.1