NTSTATUS dns_common_zones(struct ldb_context *samdb,
			  TALLOC_CTX *mem_ctx,
			  struct ldb_dn *base_dn,
			  struct dns_server_zone **zones_ret)
{
	const struct timeval start = timeval_current();
	int ret;
	static const char * const attrs[] = { "name", NULL};
	struct ldb_result *res;
	int i;
	struct dns_server_zone *new_list = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS result = NT_STATUS_OK;

	if (base_dn) {
		/* This search will work against windows */
		ret = dsdb_search(samdb, frame, &res,
				  base_dn, LDB_SCOPE_SUBTREE,
				  attrs, 0, "(objectClass=dnsZone)");
	} else {
		/* TODO: this search does not work against windows */
		ret = dsdb_search(samdb, frame, &res, NULL,
				  LDB_SCOPE_SUBTREE,
				  attrs,
				  DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
				  "(objectClass=dnsZone)");
	}
	if (ret != LDB_SUCCESS) {
		TALLOC_FREE(frame);
		result = NT_STATUS_INTERNAL_DB_CORRUPTION;
		goto exit;
	}

	TYPESAFE_QSORT(res->msgs, res->count, dns_common_sort_zones);

	for (i=0; i < res->count; i++) {
		struct dns_server_zone *z;

		z = talloc_zero(mem_ctx, struct dns_server_zone);
		if (z == NULL) {
			TALLOC_FREE(frame);
			result = NT_STATUS_NO_MEMORY;
			goto exit;
		}

		z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
		talloc_steal(z, z->name);
		z->dn = talloc_move(z, &res->msgs[i]->dn);
		/*
		 * Ignore the RootDNSServers zone and zones that we don't support yet
		 * RootDNSServers should never be returned (Windows DNS server don't)
		 * ..TrustAnchors should never be returned as is, (Windows returns
		 * TrustAnchors) and for the moment we don't support DNSSEC so we'd better
		 * not return this zone.
		 */
		if ((strcmp(z->name, "RootDNSServers") == 0) ||
		    (strcmp(z->name, "..TrustAnchors") == 0))
		{
			DEBUG(10, ("Ignoring zone %s\n", z->name));
			talloc_free(z);
			continue;
		}
		DLIST_ADD_END(new_list, z);
	}

	*zones_ret = new_list;
	TALLOC_FREE(frame);
	result = NT_STATUS_OK;
exit:
	DNS_COMMON_LOG_OPERATION(
		nt_errstr(result),
		&start,
		NULL,
		base_dn == NULL ? NULL : ldb_dn_get_linearized(base_dn),
		NULL);
	return result;
}
NTSTATUS dns_common_zones(struct ldb_context *samdb,
			  TALLOC_CTX *mem_ctx,
			  struct ldb_dn *base_dn,
			  struct dns_server_zone **zones_ret)
{
	const struct timeval start = timeval_current();
	int ret;
	static const char * const attrs[] = { "name", NULL};
	struct ldb_result *res;
	int i;
	struct dns_server_zone *new_list = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS result = NT_STATUS_OK;

	if (base_dn) {
		 
		ret = dsdb_search(samdb, frame, &res,
				  base_dn, LDB_SCOPE_SUBTREE,
				  attrs, 0, "(objectClass=dnsZone)");
	} else {
		 
		ret = dsdb_search(samdb, frame, &res, NULL,
				  LDB_SCOPE_SUBTREE,
				  attrs,
				  DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
				  "(objectClass=dnsZone)");
	}
	if (ret != LDB_SUCCESS) {
		TALLOC_FREE(frame);
		result = NT_STATUS_INTERNAL_DB_CORRUPTION;
		goto exit;
	}

	TYPESAFE_QSORT(res->msgs, res->count, dns_common_sort_zones);

	for (i=0; i < res->count; i++) {
		struct dns_server_zone *z;

		z = talloc_zero(mem_ctx, struct dns_server_zone);
		if (z == NULL) {
			TALLOC_FREE(frame);
			result = NT_STATUS_NO_MEMORY;
			goto exit;
		}

		z->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
		talloc_steal(z, z->name);
		z->dn = talloc_move(z, &res->msgs[i]->dn);
		 
		if ((strcmp(z->name, "RootDNSServers") == 0) ||
		    (strcmp(z->name, "..TrustAnchors") == 0))
		{
			DEBUG(10, ("Ignoring zone %s\n", z->name));
			talloc_free(z);
			continue;
		}
		DLIST_ADD_END(new_list, z);
	}

	*zones_ret = new_list;
	TALLOC_FREE(frame);
	result = NT_STATUS_OK;
exit:
	DNS_COMMON_LOG_OPERATION(
		nt_errstr(result),
		&start,
		NULL,
		base_dn == NULL ? NULL : ldb_dn_get_linearized(base_dn),
		NULL);
	return result;
}