dns_server: clobber MNAME in the SOA
authorAndrew Bartlett <abartlet@samba.org>
Tue, 11 Apr 2017 00:43:22 +0000 (12:43 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 10 Jun 2017 19:48:21 +0000 (21:48 +0200)
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 <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
python/samba/samdb.py
selftest/knownfail.d/dns
source4/dns_server/dlz_bind9.c
source4/dns_server/dnsserver_common.c
source4/dns_server/dnsserver_common.h
source4/dns_server/pydns.c

index 638fa06ec8a86512f979205f09164afe6e74480c..6fe680d30d8a219357a6ac3e89f7970511249ee9 100644 (file)
@@ -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
index 6553c1fffe0ea126150b9a3828163ebe03ef161d..c40041d18924b60d4a8f34b10330ae613620b15a 100644 (file)
@@ -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\)
index 897699a6317c0e46a3308dd40ead1b2b36b11f44..7096f4749b2adc531c27b876d7b7ff01f0f696ec 100644 (file)
@@ -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));
index fbfa5fa4eaefcdb1222b1511bd96d211932552a0..d0c0a2fdbb4f407308f990a564d241b0639f1357 100644 (file)
@@ -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;
index 293831f0acb3ccc8ab79785cd7af143f8ee70ff7..b615e2dcfae65d142e7e9529b7e5ce28dc038329 100644 (file)
@@ -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);
index cb41faa1441213d3078fde536299d5c8de9410ba..63fa80e92b3c65b371ebcfbb1cbf542befd698ad 100644 (file)
@@ -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);