From c1bf6d24936b5255b9a714f8f252e281b7f82c9f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 11 Apr 2017 12:43:22 +1200 Subject: [PATCH 1/1] dns_server: clobber MNAME in the SOA Otherwise, we always report the first server we created/provisioned the AD domain on which does not match AD behaviour. AD is multi-master so all RW servers are a master. Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam --- python/samba/samdb.py | 2 +- selftest/knownfail.d/dns | 1 - source4/dns_server/dlz_bind9.c | 2 +- source4/dns_server/dnsserver_common.c | 53 +++++++++++++++++++++++++-- source4/dns_server/dnsserver_common.h | 3 +- source4/dns_server/pydns.c | 8 +++- 6 files changed, 60 insertions(+), 9 deletions(-) diff --git a/python/samba/samdb.py b/python/samba/samdb.py index 638fa06ec8a..6fe680d30d8 100644 --- a/python/samba/samdb.py +++ b/python/samba/samdb.py @@ -940,7 +940,7 @@ accountExpires: %u def dns_extract(self, el): '''Return the NDR database structures from a dnsRecord element''' - return dsdb_dns.extract(el) + return dsdb_dns.extract(self, el) def dns_replace(self, dns_name, new_records): '''Do a DNS modification on the database, sets the NDR database diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns index 6553c1fffe0..c40041d1892 100644 --- a/selftest/knownfail.d/dns +++ b/selftest/knownfail.d/dns @@ -42,7 +42,6 @@ samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\) # The very first DC will have DNS records, but subsequent DCs only get entries into # the dns_hosts_file in our selftest env -samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_a_query\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_a_query_tcp\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_mx_query\(vampire_dc:local\) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index 897699a6317..7096f4749b2 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -997,7 +997,7 @@ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, return ISC_R_NOMEMORY; } - werr = dns_common_extract(el, el_ctx, &recs, &num_recs); + werr = dns_common_extract(state->samdb, 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)); diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index fbfa5fa4eae..d0c0a2fdbb4 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -69,7 +69,8 @@ uint8_t werr_to_dns_err(WERROR werr) return DNS_RCODE_SERVFAIL; } -WERROR dns_common_extract(const struct ldb_message_element *el, +WERROR dns_common_extract(struct ldb_context *samdb, + const struct ldb_message_element *el, TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord **records, uint16_t *num_records) @@ -86,9 +87,13 @@ WERROR dns_common_extract(const struct ldb_message_element *el, return WERR_NOT_ENOUGH_MEMORY; } for (ri = 0; ri < el->num_values; ri++) { + bool am_rodc; + int ret; + const char *attrs[] = { "dnsHostName", NULL }; + const char *dnsHostName; struct ldb_val *v = &el->values[ri]; enum ndr_err_code ndr_err; - + struct ldb_result *res = NULL; 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)) { @@ -96,7 +101,49 @@ WERROR dns_common_extract(const struct ldb_message_element *el, DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n")); return DNS_ERR(SERVER_FAILURE); } + + /* + * In AD, except on an RODC (where we should list a random RWDC, + * we should over-stamp the MNAME with our own hostname + */ + if (recs[ri].wType != DNS_TYPE_SOA) { + continue; + } + + ret = samdb_rodc(samdb, &am_rodc); + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to confirm we are not an RODC: %s\n", + ldb_errstring(samdb))); + return DNS_ERR(SERVER_FAILURE); + } + + if (am_rodc) { + continue; + } + + ret = dsdb_search_dn(samdb, mem_ctx, &res, NULL, + attrs, 0); + + if (res->count != 1 || ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s", + ldb_errstring(samdb))); + return DNS_ERR(SERVER_FAILURE); + } + + dnsHostName + = ldb_msg_find_attr_as_string(res->msgs[0], + "dnsHostName", + NULL); + + if (dnsHostName == NULL) { + DEBUG(0, ("Failed to get dnsHostName from rootDSE")); + return DNS_ERR(SERVER_FAILURE); + } + + recs[ri].data.soa.mname + = talloc_steal(recs, dnsHostName); } + *records = recs; *num_records = el->num_values; return WERR_OK; @@ -189,7 +236,7 @@ WERROR dns_common_lookup(struct ldb_context *samdb, } } - werr = dns_common_extract(el, mem_ctx, records, num_records); + werr = dns_common_extract(samdb, el, mem_ctx, records, num_records); TALLOC_FREE(msg); if (!W_ERROR_IS_OK(werr)) { return werr; diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index 293831f0acb..b615e2dcfae 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -35,7 +35,8 @@ struct dns_server_zone { struct ldb_dn *dn; }; -WERROR dns_common_extract(const struct ldb_message_element *el, +WERROR dns_common_extract(struct ldb_context *samdb, + const struct ldb_message_element *el, TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord **records, uint16_t *num_records); diff --git a/source4/dns_server/pydns.c b/source4/dns_server/pydns.c index cb41faa1441..63fa80e92b3 100644 --- a/source4/dns_server/pydns.c +++ b/source4/dns_server/pydns.c @@ -160,17 +160,21 @@ static PyObject *py_dsdb_dns_lookup(PyObject *self, static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args) { + struct ldb_context *samdb; PyObject *py_dns_el, *ret; + PyObject *py_ldb = NULL; TALLOC_CTX *frame; WERROR werr; struct ldb_message_element *dns_el; struct dnsp_DnssrvRpcRecord *records; uint16_t num_records; - if (!PyArg_ParseTuple(args, "O", &py_dns_el)) { + if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dns_el)) { return NULL; } + PyErr_LDB_OR_RAISE(py_ldb, samdb); + if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) { PyErr_SetString(PyExc_TypeError, "ldb MessageElement object required"); @@ -180,7 +184,7 @@ static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args) frame = talloc_stackframe(); - werr = dns_common_extract(dns_el, + werr = dns_common_extract(samdb, dns_el, frame, &records, &num_records); -- 2.34.1