[SCM] Samba Shared Repository - branch master updated

Andrew Tridgell tridge at samba.org
Sun Dec 5 21:49:02 MST 2010


The branch, master has been updated
       via  9f6f1b0 s4-dns: a dlz module for bind9
      from  521e96c idtree: fix overflow for v. large ids on allocation and removal

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 9f6f1b009866b8f697bcfad8b1451395732b78c1
Author: Andrew Tridgell <tridge at samba.org>
Date:   Mon Dec 6 14:12:07 2010 +1100

    s4-dns: a dlz module for bind9
    
    this module can be loaded into bind9 if bind9 has been built with the
    --with-dlz-dlopen option. It provides access bind9 access to the
    DNS records in SAMDB.
    
    You can then start bind9 with this in named.conf:
    
    dlz "Samba zone" {
    	database "dlopen /usr/lib/samba/modules/bind9/dlz_bind9.so";
    };
    
    See http://git.samba.org/tridge/bind9.git for a bind9 tree with the
    dlz_dlopen driver. See also the discussion on the bind-workers mailing
    list
    
    Autobuild-User: Andrew Tridgell <tridge at samba.org>
    Autobuild-Date: Mon Dec  6 05:48:30 CET 2010 on sn-devel-104

-----------------------------------------------------------------------

Summary of changes:
 source4/dns_server/dlz_bind9.c   |  523 ++++++++++++++++++++++++++++++++++++++
 source4/dns_server/dlz_bind9.h   |   49 ++++
 source4/dns_server/wscript_build |    7 +
 3 files changed, 579 insertions(+), 0 deletions(-)
 create mode 100644 source4/dns_server/dlz_bind9.c
 create mode 100644 source4/dns_server/dlz_bind9.h


Changeset truncated at 500 lines:

diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c
new file mode 100644
index 0000000..0260a79
--- /dev/null
+++ b/source4/dns_server/dlz_bind9.c
@@ -0,0 +1,523 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   bind9 dlz driver for Samba
+
+   Copyright (C) 2010 Andrew Tridgell
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "talloc.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "auth/session.h"
+#include "gen_ndr/ndr_dnsp.h"
+#include "dlz_bind9.h"
+
+struct dlz_bind9_data {
+	struct ldb_context *samdb;
+	struct tevent_context *ev_ctx;
+	struct loadparm_context *lp;
+
+	/* helper functions from the dlz_dlopen driver */
+	void (*log)(int level, const char *fmt, ...);
+	isc_result_t (*putrr)(dns_sdlzlookup_t *handle, const char *type,
+			      dns_ttl_t ttl, const char *data);
+	isc_result_t (*putnamedrr)(dns_sdlzlookup_t *handle, const char *name,
+				   const char *type, dns_ttl_t ttl, const char *data);
+};
+
+/*
+  return the version of the API
+ */
+_PUBLIC_ int dlz_version(void)
+{
+	return DLZ_DLOPEN_VERSION;
+}
+
+/*
+   remember a helper function from the bind9 dlz_dlopen driver
+ */
+static void b9_add_helper(struct dlz_bind9_data *state, const char *helper_name, void *ptr)
+{
+	if (strcmp(helper_name, "log") == 0) {
+		state->log = ptr;
+	}
+	if (strcmp(helper_name, "putrr") == 0) {
+		state->putrr = ptr;
+	}
+	if (strcmp(helper_name, "putnamedrr") == 0) {
+		state->putnamedrr = ptr;
+	}
+}
+
+/*
+  format a record for bind9
+ */
+static bool b9_format(struct dlz_bind9_data *state,
+		      TALLOC_CTX *mem_ctx,
+		      struct dnsp_DnssrvRpcRecord *rec,
+		      const char **type, const char **data)
+{
+	switch (rec->wType) {
+	case DNS_TYPE_A:
+		*type = "a";
+		*data = rec->data.ipv4;
+		break;
+
+	case DNS_TYPE_AAAA:
+		*type = "aaaa";
+		*data = rec->data.ipv6;
+		break;
+
+	case DNS_TYPE_CNAME:
+		*type = "cname";
+		*data = rec->data.cname;
+		break;
+
+	case DNS_TYPE_TXT:
+		*type = "txt";
+		*data = rec->data.txt;
+		break;
+
+	case DNS_TYPE_PTR:
+		*type = "ptr";
+		*data = rec->data.ptr;
+		break;
+
+	case DNS_TYPE_SRV:
+		*type = "srv";
+		*data = talloc_asprintf(mem_ctx, "%u %u %u %s",
+					rec->data.srv.wPriority,
+					rec->data.srv.wWeight,
+					rec->data.srv.wPort,
+					rec->data.srv.nameTarget);
+		break;
+
+	case DNS_TYPE_MX:
+		*type = "mx";
+		*data = talloc_asprintf(mem_ctx, "%u %s",
+					rec->data.srv.wPriority,
+					rec->data.srv.nameTarget);
+		break;
+
+	case DNS_TYPE_HINFO:
+		*type = "hinfo";
+		*data = talloc_asprintf(mem_ctx, "%s %s",
+					rec->data.hinfo.cpu,
+					rec->data.hinfo.os);
+		break;
+
+	case DNS_TYPE_NS:
+		*type = "ns";
+		*data = rec->data.ns;
+		break;
+
+	case DNS_TYPE_SOA:
+		*type = "soa";
+		*data = talloc_asprintf(mem_ctx, "%s %s %u %u %u %u %u",
+					rec->data.soa.mname,
+					rec->data.soa.rname,
+					rec->data.soa.serial,
+					rec->data.soa.refresh,
+					rec->data.soa.retry,
+					rec->data.soa.expire,
+					rec->data.soa.minimum);
+		break;
+
+	default:
+		state->log(ISC_LOG_ERROR, "samba b9_putrr: unhandled record type %u",
+			   rec->wType);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+  send a resource recond to bind9
+ */
+static isc_result_t b9_putrr(struct dlz_bind9_data *state,
+			     void *handle, struct dnsp_DnssrvRpcRecord *rec,
+			     const char **types)
+{
+	isc_result_t result;
+	const char *type, *data;
+	TALLOC_CTX *tmp_ctx = talloc_new(state);
+
+	if (!b9_format(state, tmp_ctx, rec, &type, &data)) {
+		return ISC_R_FAILURE;
+	}
+
+	if (data == NULL) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOMEMORY;
+	}
+
+	if (types) {
+		int i;
+		for (i=0; types[i]; i++) {
+			if (strcmp(types[i], type) == 0) break;
+		}
+		if (types[i] == NULL) {
+			/* skip it */
+			return ISC_R_SUCCESS;
+		}
+	}
+
+	/* FIXME: why does dlz insist on all TTL values being the same
+	   for the same name? */
+	result = state->putrr(handle, type, /* rec->dwTtlSeconds */ 900, data);
+	if (result != ISC_R_SUCCESS) {
+		state->log(ISC_LOG_ERROR, "Failed to put rr");
+	}
+	talloc_free(tmp_ctx);
+	return result;
+}
+
+
+/*
+  send a named resource recond to bind9
+ */
+static isc_result_t b9_putnamedrr(struct dlz_bind9_data *state,
+				  void *handle, const char *name,
+				  struct dnsp_DnssrvRpcRecord *rec)
+{
+	isc_result_t result;
+	const char *type, *data;
+	TALLOC_CTX *tmp_ctx = talloc_new(state);
+
+	if (!b9_format(state, tmp_ctx, rec, &type, &data)) {
+		return ISC_R_FAILURE;
+	}
+
+	if (data == NULL) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOMEMORY;
+	}
+
+	/* FIXME: why does dlz insist on all TTL values being the same
+	   for the same name? */
+	result = state->putnamedrr(handle, name, type, /* rec->dwTtlSeconds */ 900, data);
+	if (result != ISC_R_SUCCESS) {
+		state->log(ISC_LOG_ERROR, "Failed to put named rr '%s'", name);
+	}
+	talloc_free(tmp_ctx);
+	return result;
+}
+
+
+/*
+  called to initialise the driver
+ */
+_PUBLIC_ isc_result_t dlz_create(const char *dlzname,
+				 unsigned int argc, char *argv[],
+				 void *driverarg, void **dbdata, ...)
+{
+	struct dlz_bind9_data *state;
+	const char *helper_name;
+	va_list ap;
+	isc_result_t result;
+	const char *url;
+	TALLOC_CTX *tmp_ctx;
+	int ret;
+	struct ldb_dn *dn;
+
+	state = talloc_zero(NULL, struct dlz_bind9_data);
+	if (state == NULL) {
+		return ISC_R_NOMEMORY;
+	}
+
+	tmp_ctx = talloc_new(state);
+
+	/* fill in the helper functions */
+	va_start(ap, dbdata);
+	while ((helper_name = va_arg(ap, const char *)) != NULL) {
+		b9_add_helper(state, helper_name, va_arg(ap, void*));
+	}
+	va_end(ap);
+
+	state->lp = loadparm_init_global(true);
+	if (state->lp == NULL) {
+		result = ISC_R_NOMEMORY;
+		goto failed;
+	}
+
+	state->ev_ctx = tevent_context_init(state);
+	if (state->ev_ctx == NULL) {
+		result = ISC_R_NOMEMORY;
+		goto failed;
+	}
+
+	state->samdb = ldb_init(state, state->ev_ctx);
+	if (state->samdb == NULL) {
+		state->log(ISC_LOG_ERROR, "samba dlz_bind9: Failed to create ldb");
+		result = ISC_R_FAILURE;
+		goto failed;
+	}
+
+	url = talloc_asprintf(tmp_ctx, "ldapi://%s",
+			      private_path(tmp_ctx, state->lp, "ldap_priv/ldapi"));
+	if (url == NULL) {
+		result = ISC_R_NOMEMORY;
+		goto failed;
+	}
+
+	ret = ldb_connect(state->samdb, url, 0, NULL);
+	if (ret == -1) {
+		state->log(ISC_LOG_ERROR, "samba dlz_bind9: Failed to connect to %s - %s",
+			   url, ldb_errstring(state->samdb));
+		result = ISC_R_FAILURE;
+		goto failed;
+	}
+
+	dn = ldb_get_default_basedn(state->samdb);
+	if (dn == NULL) {
+		state->log(ISC_LOG_ERROR, "samba dlz_bind9: Unable to get basedn for %s - %s",
+			   url, ldb_errstring(state->samdb));
+		result = ISC_R_FAILURE;
+		goto failed;
+	}
+
+	state->log(ISC_LOG_INFO, "samba dlz_bind9: started for DN %s",
+		   ldb_dn_get_linearized(dn));
+
+	*dbdata = state;
+
+	talloc_free(tmp_ctx);
+	return ISC_R_SUCCESS;
+
+failed:
+	talloc_free(state);
+	return result;
+}
+
+/*
+  shutdown the backend
+ */
+_PUBLIC_ void dlz_destroy(void *driverarg, void *dbdata)
+{
+	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
+	state->log(ISC_LOG_INFO, "samba dlz_bind9: shutting down");
+	talloc_free(state);
+}
+
+
+/*
+  see if we handle a given zone
+ */
+_PUBLIC_ isc_result_t dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
+{
+	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
+	if (strcasecmp(lpcfg_dnsdomain(state->lp), name) == 0) {
+		return ISC_R_SUCCESS;
+	}
+	return ISC_R_NOTFOUND;
+}
+
+
+/*
+  lookup one record
+ */
+_PUBLIC_ isc_result_t dlz_lookup_types(struct dlz_bind9_data *state,
+				       const char *zone, const char *name,
+				       void *driverarg, dns_sdlzlookup_t *lookup,
+				       const char **types)
+{
+	struct ldb_dn *dn;
+	TALLOC_CTX *tmp_ctx = talloc_new(state);
+	const char *attrs[] = { "dnsRecord", NULL };
+	int ret, i;
+	struct ldb_result *res;
+	struct ldb_message_element *el;
+
+	dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
+	if (dn == NULL) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOMEMORY;
+	}
+
+	if (!ldb_dn_add_child_fmt(dn, "DC=%s,DC=%s,CN=MicrosoftDNS,DC=DomainDnsZones",
+				  name, zone)) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOMEMORY;
+	}
+
+	ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
+			 attrs, "objectClass=dnsNode");
+	if (ret != LDB_SUCCESS) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOTFOUND;
+	}
+
+	el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
+	if (el == NULL || el->num_values == 0) {
+		state->log(ISC_LOG_INFO, "failed to find %s",
+			   ldb_dn_get_linearized(dn));
+		talloc_free(tmp_ctx);
+		return ISC_R_NOTFOUND;
+	}
+
+	for (i=0; i<el->num_values; i++) {
+		struct dnsp_DnssrvRpcRecord rec;
+		enum ndr_err_code ndr_err;
+		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_bind9: 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);
+		if (result != ISC_R_SUCCESS) {
+			talloc_free(tmp_ctx);
+			return result;
+		}
+	}
+
+	talloc_free(tmp_ctx);
+	return ISC_R_SUCCESS;
+}
+
+/*
+  lookup one record
+ */
+_PUBLIC_ isc_result_t dlz_lookup(const char *zone, const char *name, void *driverarg,
+				 void *dbdata, dns_sdlzlookup_t *lookup)
+{
+	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
+	return dlz_lookup_types(state, zone, name, driverarg, lookup, NULL);
+}
+
+
+/*
+  see if a zone transfer is allowed
+ */
+_PUBLIC_ isc_result_t dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+				       const char *client)
+{
+	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
+
+	if (strcasecmp(lpcfg_dnsdomain(state->lp), name) == 0) {
+		/* TODO: check an ACL here? client is the IP of the requester */
+		state->log(ISC_LOG_INFO, "samba dlz_bind9: allowing zone transfer for '%s' by '%s'",
+			   name, client);
+		return ISC_R_SUCCESS;
+	}
+	return ISC_R_NOTFOUND;
+}
+
+/*
+  perform a zone transfer
+ */
+_PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
+				   dns_sdlzallnodes_t *allnodes)
+{
+	struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data);
+	const char *attrs[] = { "dnsRecord", NULL };
+	int ret, i, j;
+	struct ldb_dn *dn;
+	struct ldb_result *res;
+	TALLOC_CTX *tmp_ctx = talloc_new(state);
+
+
+	dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb));
+	if (dn == NULL) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOMEMORY;
+	}
+
+	if (!ldb_dn_add_child_fmt(dn, "DC=%s,CN=MicrosoftDNS,DC=DomainDnsZones", zone)) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOMEMORY;
+	}
+
+	ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
+			 attrs, "objectClass=dnsNode");
+	if (ret != LDB_SUCCESS) {
+		talloc_free(tmp_ctx);
+		return ISC_R_NOTFOUND;
+	}
+
+	for (i=0; i<res->count; i++) {
+		struct ldb_message_element *el;
+		TALLOC_CTX *el_ctx = talloc_new(tmp_ctx);
+		const char *rdn, *name;
+		const struct ldb_val *v;
+
+		el = ldb_msg_find_element(res->msgs[i], "dnsRecord");
+		if (el == NULL || el->num_values == 0) {
+			state->log(ISC_LOG_INFO, "failed to find dnsRecord for %s",
+				   ldb_dn_get_linearized(dn));
+			talloc_free(el_ctx);
+			continue;
+		}
+
+		v = ldb_dn_get_rdn_val(res->msgs[i]->dn);
+		if (v == NULL) {
+			state->log(ISC_LOG_INFO, "failed to find RDN for %s",
+				   ldb_dn_get_linearized(dn));
+			talloc_free(el_ctx);
+			continue;
+		}
+
+		rdn = talloc_strndup(el_ctx, (char *)v->data, v->length);
+		if (rdn == NULL) {
+			talloc_free(tmp_ctx);
+			return ISC_R_NOMEMORY;
+		}
+
+		if (strcmp(rdn, "@") == 0) {
+			name = zone;
+		} else {
+			name = talloc_asprintf(el_ctx, "%s.%s", rdn, zone);
+		}
+		if (name == NULL) {
+			talloc_free(tmp_ctx);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list