s4-dns: Added DCERPC dns server for DNS management
authorAmitay Isaacs <amitay@gmail.com>
Tue, 27 Sep 2011 06:53:45 +0000 (16:53 +1000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 20 Oct 2011 03:53:05 +0000 (05:53 +0200)
dnsserver.h - typedefs and prototypes
dnsserver.c - RPC API and implementation methods
dnsdb.c     - samdb operations
dnsdata.c   - functions to manipulate dns structures
dnsutils.c  - function for serverinfo and zoneinfo structures

Signed-off-by: Andrew Tridgell <tridge@samba.org>
lib/param/loadparm.c
source4/rpc_server/dnsserver/dcerpc_dnsserver.c [new file with mode: 0644]
source4/rpc_server/dnsserver/dnsdata.c [new file with mode: 0644]
source4/rpc_server/dnsserver/dnsdb.c [new file with mode: 0644]
source4/rpc_server/dnsserver/dnsserver.h [new file with mode: 0644]
source4/rpc_server/dnsserver/dnsutils.c [new file with mode: 0644]
source4/rpc_server/wscript_build

index 0918cce236ec67b15f6b0f95532cf1eaa07545c5..4274e9bca3e32ef3f56fecb52c38dc59a14c67c8 100644 (file)
@@ -3298,7 +3298,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "ntvfs handler", "unixuid default");
        lpcfg_do_global_parameter(lp_ctx, "max connections", "-1");
 
-       lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi winreg dssetup unixinfo browser eventlog6 backupkey");
+       lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi winreg dssetup unixinfo browser eventlog6 backupkey dnsserver");
        lpcfg_do_global_parameter(lp_ctx, "server services", "smb rpc nbt wrepl ldap cldap kdc drepl winbind ntp_signd kcc dnsupdate");
        lpcfg_do_global_parameter(lp_ctx, "ntptr providor", "simple_ldb");
        /* the winbind method for domain controllers is for both RODC
diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
new file mode 100644 (file)
index 0000000..66162c5
--- /dev/null
@@ -0,0 +1,2021 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   DNS Server
+
+   Copyright (C) Amitay Isaacs 2011
+
+   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 "rpc_server/dcerpc_server.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_dnsserver.h"
+#include "dnsserver.h"
+#include "lib/ldb/include/ldb_private.h"
+
+struct dnsserver_state {
+       struct loadparm_context *lp_ctx;
+       struct ldb_context *samdb;
+       struct dnsserver_zone *zones;
+       int zones_count;
+       struct dnsserver_serverinfo *serverinfo;
+};
+
+
+/* Utility functions */
+
+static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_call)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *zones, *z;
+
+       dsstate = talloc_get_type(dce_call->context->private_data, struct dnsserver_state);
+       if (dsstate != NULL) {
+               return dsstate;
+       }
+
+       dsstate = talloc_zero(dce_call->context, struct dnsserver_state);
+       if (dsstate == NULL) {
+               return NULL;
+       }
+
+       dsstate->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
+       /* FIXME: create correct auth_session_info for connecting user */
+       dsstate->samdb = samdb_connect(dsstate, dce_call->event_ctx, dsstate->lp_ctx,
+                               dce_call->conn->auth_state.session_info, 0);
+       if (dsstate->samdb == NULL) {
+               DEBUG(0,("dnsserver: Failed to open samdb"));
+               goto failed;
+       }
+
+       /* Initialize server info */
+       dsstate->serverinfo = dnsserver_init_serverinfo(dsstate,
+                                                       dsstate->lp_ctx,
+                                                       dsstate->samdb);
+       if (dsstate->serverinfo == NULL) {
+               goto failed;
+       }
+
+       /* Search for DNS zones */
+       zones = dnsserver_db_enumerate_zones(dsstate, dsstate->samdb, true);
+       if (zones == NULL) {
+               goto failed;
+       }
+       for (z = zones; z; z = z->next) {
+               z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo, true);
+               if (z->zoneinfo == NULL) {
+                       goto failed;
+               }
+               DLIST_ADD_END(dsstate->zones, z, NULL);
+               dsstate->zones_count++;
+       }
+
+       zones = dnsserver_db_enumerate_zones(dsstate, dsstate->samdb, false);
+       if (zones == NULL) {
+               goto failed;
+       }
+       for (z = zones; z; z = z->next) {
+               z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo, false);
+               if (z->zoneinfo == NULL) {
+                       goto failed;
+               }
+               DLIST_ADD_END(dsstate->zones, z, NULL);
+               dsstate->zones_count++;
+       }
+
+       dce_call->context->private_data = dsstate;
+
+       return dsstate;
+
+failed:
+       talloc_free(dsstate);
+       dsstate = NULL;
+       return NULL;
+}
+
+
+/* dnsserver query functions */
+
+/* [MS-DNSP].pdf Section 3.1.1.1 DNS Server Configuration Information */
+static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *operation,
+                                       const unsigned int client_version,
+                                       enum DNS_RPC_TYPEID *typeid,
+                                       union DNSSRV_RPC_UNION *r)
+{
+       uint8_t is_integer, is_addresses, is_string, is_wstring, is_stringlist;
+       uint32_t answer_integer;
+       struct IP4_ARRAY *answer_iparray;
+       struct DNS_ADDR_ARRAY *answer_addrarray;
+       char *answer_string;
+       struct DNS_RPC_UTF8_STRING_LIST *answer_stringlist;
+       struct dnsserver_serverinfo *serverinfo;
+
+       serverinfo = dsstate->serverinfo;
+
+       if (strcasecmp(operation, "ServerInfo") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_W2K) {
+                       *typeid = DNSSRV_TYPEID_SERVER_INFO_W2K;
+                       r->ServerInfoW2K = talloc_zero(mem_ctx, struct DNS_RPC_SERVER_INFO_W2K);
+
+                       r->ServerInfoW2K->dwVersion = serverinfo->dwVersion;
+                       r->ServerInfoW2K->fBootMethod = serverinfo->fBootMethod;
+                       r->ServerInfoW2K->fAdminConfigured = serverinfo->fAdminConfigured;
+                       r->ServerInfoW2K->fAllowUpdate = serverinfo->fAllowUpdate;
+                       r->ServerInfoW2K->fDsAvailable = serverinfo->fDsAvailable;
+                       r->ServerInfoW2K->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
+                       r->ServerInfoW2K->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
+                       r->ServerInfoW2K->aipServerAddrs = ip4_array_copy(mem_ctx, serverinfo->aipServerAddrs);
+                       r->ServerInfoW2K->aipListenAddrs = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+                       r->ServerInfoW2K->aipForwarders = ip4_array_copy(mem_ctx, serverinfo->aipForwarders);
+                       r->ServerInfoW2K->dwLogLevel = serverinfo->dwLogLevel;
+                       r->ServerInfoW2K->dwDebugLevel = serverinfo->dwDebugLevel;
+                       r->ServerInfoW2K->dwForwardTimeout = serverinfo->dwForwardTimeout;
+                       r->ServerInfoW2K->dwRpcProtocol = serverinfo->dwRpcProtocol;
+                       r->ServerInfoW2K->dwNameCheckFlag = serverinfo->dwNameCheckFlag;
+                       r->ServerInfoW2K->cAddressAnswerLimit = serverinfo->cAddressAnswerLimit;
+                       r->ServerInfoW2K->dwRecursionRetry = serverinfo->dwRecursionRetry;
+                       r->ServerInfoW2K->dwRecursionTimeout = serverinfo->dwRecursionTimeout;
+                       r->ServerInfoW2K->dwMaxCacheTtl = serverinfo->dwMaxCacheTtl;
+                       r->ServerInfoW2K->dwDsPollingInterval = serverinfo->dwDsPollingInterval;
+                       r->ServerInfoW2K->dwScavengingInterval = serverinfo->dwScavengingInterval;
+                       r->ServerInfoW2K->dwDefaultRefreshInterval = serverinfo->dwDefaultRefreshInterval;
+                       r->ServerInfoW2K->dwDefaultNoRefreshInterval = serverinfo->dwDefaultNoRefreshInterval;
+                       r->ServerInfoW2K->fAutoReverseZones = serverinfo->fAutoReverseZones;
+                       r->ServerInfoW2K->fAutoCacheUpdate = serverinfo->fAutoCacheUpdate;
+                       r->ServerInfoW2K->fRecurseAfterForwarding = serverinfo->fRecurseAfterForwarding;
+                       r->ServerInfoW2K->fForwardDelegations = serverinfo->fForwardDelegations;
+                       r->ServerInfoW2K->fNoRecursion = serverinfo->fNoRecursion;
+                       r->ServerInfoW2K->fSecureResponses = serverinfo->fSecureResponses;
+                       r->ServerInfoW2K->fRoundRobin = serverinfo->fRoundRobin;
+                       r->ServerInfoW2K->fLocalNetPriority = serverinfo->fLocalNetPriority;
+                       r->ServerInfoW2K->fBindSecondaries = serverinfo->fBindSecondaries;
+                       r->ServerInfoW2K->fWriteAuthorityNs = serverinfo->fWriteAuthorityNs;
+                       r->ServerInfoW2K->fStrictFileParsing = serverinfo->fStrictFileParsing;
+                       r->ServerInfoW2K->fLooseWildcarding = serverinfo->fLooseWildcarding;
+                       r->ServerInfoW2K->fDefaultAgingState = serverinfo->fDefaultAgingState;
+
+               } else if (client_version == DNS_CLIENT_VERSION_DOTNET) {
+                       *typeid = DNSSRV_TYPEID_SERVER_INFO_DOTNET;
+                       r->ServerInfoDotNet = talloc_zero(mem_ctx, struct DNS_RPC_SERVER_INFO_DOTNET);
+
+                       r->ServerInfoDotNet->dwRpcStructureVersion = 0x01;
+                       r->ServerInfoDotNet->dwVersion = serverinfo->dwVersion;
+                       r->ServerInfoDotNet->fBootMethod = serverinfo->fBootMethod;
+                       r->ServerInfoDotNet->fAdminConfigured = serverinfo->fAdminConfigured;
+                       r->ServerInfoDotNet->fAllowUpdate = serverinfo->fAllowUpdate;
+                       r->ServerInfoDotNet->fDsAvailable = serverinfo->fDsAvailable;
+                       r->ServerInfoDotNet->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
+                       r->ServerInfoDotNet->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
+                       r->ServerInfoDotNet->aipServerAddrs = ip4_array_copy(mem_ctx, serverinfo->aipServerAddrs);
+                       r->ServerInfoDotNet->aipListenAddrs = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+                       r->ServerInfoDotNet->aipForwarders = ip4_array_copy(mem_ctx, serverinfo->aipForwarders);
+                       r->ServerInfoDotNet->aipLogFilter = ip4_array_copy(mem_ctx, serverinfo->aipLogFilter);
+                       r->ServerInfoDotNet->pwszLogFilePath = talloc_strdup(mem_ctx, serverinfo->pwszLogFilePath);
+                       r->ServerInfoDotNet->pszDomainName = talloc_strdup(mem_ctx, serverinfo->pszDomainName);
+                       r->ServerInfoDotNet->pszForestName = talloc_strdup(mem_ctx, serverinfo->pszForestName);
+                       r->ServerInfoDotNet->pszDomainDirectoryPartition = talloc_strdup(mem_ctx, serverinfo->pszDomainDirectoryPartition);
+                       r->ServerInfoDotNet->pszForestDirectoryPartition = talloc_strdup(mem_ctx, serverinfo->pszForestDirectoryPartition);
+                       r->ServerInfoDotNet->dwLogLevel = serverinfo->dwLogLevel;
+                       r->ServerInfoDotNet->dwDebugLevel = serverinfo->dwDebugLevel;
+                       r->ServerInfoDotNet->dwForwardTimeout = serverinfo->dwForwardTimeout;
+                       r->ServerInfoDotNet->dwRpcProtocol = serverinfo->dwRpcProtocol;
+                       r->ServerInfoDotNet->dwNameCheckFlag = serverinfo->dwNameCheckFlag;
+                       r->ServerInfoDotNet->cAddressAnswerLimit = serverinfo->cAddressAnswerLimit;
+                       r->ServerInfoDotNet->dwRecursionRetry = serverinfo->dwRecursionRetry;
+                       r->ServerInfoDotNet->dwRecursionTimeout = serverinfo->dwRecursionTimeout;
+                       r->ServerInfoDotNet->dwMaxCacheTtl = serverinfo->dwMaxCacheTtl;
+                       r->ServerInfoDotNet->dwDsPollingInterval = serverinfo->dwDsPollingInterval;
+                       r->ServerInfoDotNet->dwLocalNetPriorityNetMask = serverinfo->dwLocalNetPriorityNetMask;
+                       r->ServerInfoDotNet->dwScavengingInterval = serverinfo->dwScavengingInterval;
+                       r->ServerInfoDotNet->dwDefaultRefreshInterval = serverinfo->dwDefaultRefreshInterval;
+                       r->ServerInfoDotNet->dwDefaultNoRefreshInterval = serverinfo->dwDefaultNoRefreshInterval;
+                       r->ServerInfoDotNet->dwLastScavengeTime = serverinfo->dwLastScavengeTime;
+                       r->ServerInfoDotNet->dwEventLogLevel = serverinfo->dwEventLogLevel;
+                       r->ServerInfoDotNet->dwLogFileMaxSize = serverinfo->dwLogFileMaxSize;
+                       r->ServerInfoDotNet->dwDsForestVersion = serverinfo->dwDsForestVersion;
+                       r->ServerInfoDotNet->dwDsDomainVersion = serverinfo->dwDsDomainVersion;
+                       r->ServerInfoDotNet->dwDsDsaVersion = serverinfo->dwDsDsaVersion;
+                       r->ServerInfoDotNet->fAutoReverseZones = serverinfo->fAutoReverseZones;
+                       r->ServerInfoDotNet->fAutoCacheUpdate = serverinfo->fAutoCacheUpdate;
+                       r->ServerInfoDotNet->fRecurseAfterForwarding = serverinfo->fRecurseAfterForwarding;
+                       r->ServerInfoDotNet->fForwardDelegations = serverinfo->fForwardDelegations;
+                       r->ServerInfoDotNet->fNoRecursion = serverinfo->fNoRecursion;
+                       r->ServerInfoDotNet->fSecureResponses = serverinfo->fSecureResponses;
+                       r->ServerInfoDotNet->fRoundRobin = serverinfo->fRoundRobin;
+                       r->ServerInfoDotNet->fLocalNetPriority = serverinfo->fLocalNetPriority;
+                       r->ServerInfoDotNet->fBindSecondaries = serverinfo->fBindSecondaries;
+                       r->ServerInfoDotNet->fWriteAuthorityNs = serverinfo->fWriteAuthorityNs;
+                       r->ServerInfoDotNet->fStrictFileParsing = serverinfo->fStrictFileParsing;
+                       r->ServerInfoDotNet->fLooseWildcarding = serverinfo->fLooseWildcarding;
+                       r->ServerInfoDotNet->fDefaultAgingState = serverinfo->fDefaultAgingState;
+
+               } else if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       *typeid = DNSSRV_TYPEID_SERVER_INFO;
+                       r->ServerInfo = talloc_zero(mem_ctx, struct DNS_RPC_SERVER_INFO_LONGHORN);
+
+                       r->ServerInfo->dwRpcStructureVersion = 0x02;
+                       r->ServerInfo->dwVersion = serverinfo->dwVersion;
+                       r->ServerInfo->fBootMethod = serverinfo->fBootMethod;
+                       r->ServerInfo->fAdminConfigured = serverinfo->fAdminConfigured;
+                       r->ServerInfo->fAllowUpdate = serverinfo->fAllowUpdate;
+                       r->ServerInfo->fDsAvailable = serverinfo->fDsAvailable;
+                       r->ServerInfo->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
+                       r->ServerInfo->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
+                       r->ServerInfo->aipServerAddrs = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipServerAddrs);
+                       r->ServerInfo->aipListenAddrs = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipListenAddrs);
+                       r->ServerInfo->aipForwarders = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipForwarders);
+                       r->ServerInfo->aipLogFilter = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipLogFilter);
+                       r->ServerInfo->pwszLogFilePath = talloc_strdup(mem_ctx, serverinfo->pwszLogFilePath);
+                       r->ServerInfo->pszDomainName = talloc_strdup(mem_ctx, serverinfo->pszDomainName);
+                       r->ServerInfo->pszForestName = talloc_strdup(mem_ctx, serverinfo->pszForestName);
+                       r->ServerInfo->pszDomainDirectoryPartition = talloc_strdup(mem_ctx, serverinfo->pszDomainDirectoryPartition);
+                       r->ServerInfo->pszForestDirectoryPartition = talloc_strdup(mem_ctx, serverinfo->pszForestDirectoryPartition);
+                       r->ServerInfo->dwLogLevel = serverinfo->dwLogLevel;
+                       r->ServerInfo->dwDebugLevel = serverinfo->dwDebugLevel;
+                       r->ServerInfo->dwForwardTimeout = serverinfo->dwForwardTimeout;
+                       r->ServerInfo->dwRpcProtocol = serverinfo->dwRpcProtocol;
+                       r->ServerInfo->dwNameCheckFlag = serverinfo->dwNameCheckFlag;
+                       r->ServerInfo->cAddressAnswerLimit = serverinfo->cAddressAnswerLimit;
+                       r->ServerInfo->dwRecursionRetry = serverinfo->dwRecursionRetry;
+                       r->ServerInfo->dwRecursionTimeout = serverinfo->dwRecursionTimeout;
+                       r->ServerInfo->dwMaxCacheTtl = serverinfo->dwMaxCacheTtl;
+                       r->ServerInfo->dwDsPollingInterval = serverinfo->dwDsPollingInterval;
+                       r->ServerInfo->dwLocalNetPriorityNetMask = serverinfo->dwLocalNetPriorityNetMask;
+                       r->ServerInfo->dwScavengingInterval = serverinfo->dwScavengingInterval;
+                       r->ServerInfo->dwDefaultRefreshInterval = serverinfo->dwDefaultRefreshInterval;
+                       r->ServerInfo->dwDefaultNoRefreshInterval = serverinfo->dwDefaultNoRefreshInterval;
+                       r->ServerInfo->dwLastScavengeTime = serverinfo->dwLastScavengeTime;
+                       r->ServerInfo->dwEventLogLevel = serverinfo->dwEventLogLevel;
+                       r->ServerInfo->dwLogFileMaxSize = serverinfo->dwLogFileMaxSize;
+                       r->ServerInfo->dwDsForestVersion = serverinfo->dwDsForestVersion;
+                       r->ServerInfo->dwDsDomainVersion = serverinfo->dwDsDomainVersion;
+                       r->ServerInfo->dwDsDsaVersion = serverinfo->dwDsDsaVersion;
+                       r->ServerInfo->fReadOnlyDC = serverinfo->fReadOnlyDC;
+                       r->ServerInfo->fAutoReverseZones = serverinfo->fAutoReverseZones;
+                       r->ServerInfo->fAutoCacheUpdate = serverinfo->fAutoCacheUpdate;
+                       r->ServerInfo->fRecurseAfterForwarding = serverinfo->fRecurseAfterForwarding;
+                       r->ServerInfo->fForwardDelegations = serverinfo->fForwardDelegations;
+                       r->ServerInfo->fNoRecursion = serverinfo->fNoRecursion;
+                       r->ServerInfo->fSecureResponses = serverinfo->fSecureResponses;
+                       r->ServerInfo->fRoundRobin = serverinfo->fRoundRobin;
+                       r->ServerInfo->fLocalNetPriority = serverinfo->fLocalNetPriority;
+                       r->ServerInfo->fBindSecondaries = serverinfo->fBindSecondaries;
+                       r->ServerInfo->fWriteAuthorityNs = serverinfo->fWriteAuthorityNs;
+                       r->ServerInfo->fStrictFileParsing = serverinfo->fStrictFileParsing;
+                       r->ServerInfo->fLooseWildcarding = serverinfo->fLooseWildcarding;
+                       r->ServerInfo->fDefaultAgingState = serverinfo->fDefaultAgingState;
+               }
+               return WERR_OK;
+       }
+
+       is_integer = 0;
+
+       if (strcasecmp(operation, "AddressAnswerLimit") == 0) {
+               answer_integer = serverinfo->cAddressAnswerLimit;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AdminConfigured") == 0) {
+               answer_integer = serverinfo->fAdminConfigured;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AllowCNAMEAtNS") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AllowUpdate") == 0) {
+               answer_integer = serverinfo->fAllowUpdate;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AutoCacheUpdate") == 0) {
+               answer_integer = serverinfo->fAutoCacheUpdate;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AutoConfigFileZones") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "BindSecondaries") == 0) {
+               answer_integer = serverinfo->fBindSecondaries;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "BootMethod") == 0) {
+               answer_integer = serverinfo->fBootMethod;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DebugLevel") == 0) {
+               answer_integer = serverinfo->dwDebugLevel;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DefaultAgingState") == 0) {
+               answer_integer = serverinfo->fDefaultAgingState;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DefaultNoRefreshInterval") == 0) {
+               answer_integer = serverinfo->dwDefaultNoRefreshInterval;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DefaultRefreshInterval") == 0) {
+               answer_integer = serverinfo->dwDefaultRefreshInterval;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DeleteOutsideGlue") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DisjointNets") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsLazyUpdateInterval") == 0) {
+               answer_integer = 3; /* seconds */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsPollingInterval") == 0) {
+               answer_integer = serverinfo->dwDsPollingInterval;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsTombstoneInterval") == 0) {
+               answer_integer = 0x00127500; /* 14 days */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableRegistryBoot") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EventLogLevel") == 0) {
+               answer_integer = serverinfo->dwEventLogLevel;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceSoaSerial") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceSaoRetry") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceSoaRefresh") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceSoaMinimumTtl") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForwardDelegations") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForwardingTimeout") == 0) {
+               answer_integer = serverinfo->dwForwardTimeout;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "IsSlave") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LocalNetPriority") == 0) {
+               answer_integer = serverinfo->fLocalNetPriority;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LogFileMaxSize") == 0) {
+               answer_integer = serverinfo->dwLogFileMaxSize;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LogLevel") == 0) {
+               answer_integer = serverinfo->dwLogLevel;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LooseWildcarding") == 0) {
+               answer_integer = serverinfo->fLooseWildcarding;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaxCacheTtl") == 0) {
+               answer_integer = serverinfo->dwMaxCacheTtl;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaxNegativeCacheTtl") == 0) {
+               answer_integer = 0x00000384; /* 15 minutes */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "NameCheckFlag") == 0) {
+               answer_integer = serverinfo->dwNameCheckFlag;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "NoRecursion") == 0) {
+               answer_integer = serverinfo->fNoRecursion;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "NoUpdateDelegations") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "PublishAutonet") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "QuietRecvFaultInterval") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "QuietRecvLogInterval") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RecursionRetry") == 0) {
+               answer_integer = serverinfo->dwRecursionRetry;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RecursionTimeout") == 0) {
+               answer_integer = serverinfo->dwRecursionTimeout;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ReloadException") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RoundRobin") == 0) {
+               answer_integer = serverinfo->fRoundRobin;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RpcProtocol") == 0) {
+               answer_integer = serverinfo->dwRpcProtocol;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SecureResponses") == 0) {
+               answer_integer = serverinfo->fSecureResponses;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SendPort") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ScavengingInterval") == 0) {
+               answer_integer = serverinfo->dwScavengingInterval;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SocketPoolSize") == 0) {
+               answer_integer = 0x000009C4;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "StrictFileParsing") == 0) {
+               answer_integer = serverinfo->fStrictFileParsing;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SyncDnsZoneSerial") == 0) {
+               answer_integer = 2; /* ZONE_SERIAL_SYNC_XFER */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "UpdateOptions") == 0) {
+               answer_integer = 0x0000030F; /* DNS_DEFAULT_UPDATE_OPTIONS */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "UseSystemEvengLog") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "Version") == 0) {
+               answer_integer = serverinfo->dwVersion;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "XfrConnectTimeout") == 0) {
+               answer_integer = 0x0000001E;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "WriteAuthorityNs") == 0) {
+               answer_integer = serverinfo->fWriteAuthorityNs;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AdditionalRecursionTimeout") == 0) {
+               answer_integer = 0x00000004;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AppendMsZoneTransferFlag") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AutoCreateDelegations") == 0) {
+               answer_integer = 0; /* DNS_ACD_DONT_CREATE */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "BreakOnAscFailure") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "CacheEmptyAuthResponses") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DirectoryPartitionAutoEnlistInterval") == 0) {
+               answer_integer = 0x00015180; /* 1 day */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DisableAutoReverseZones") == 0) {
+               answer_integer = ~serverinfo->fAutoReverseZones;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EDnsCacheTimeout") == 0) {
+               answer_integer = 0x00000384; /* 15 minutes */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableDirectoryPartitions") == 0) {
+               answer_integer = serverinfo->fDsAvailable;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableDnsSec") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableEDnsProbes") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableEDnsReception") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableIPv6") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableIQueryResponseGeneration") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableSendErrorSuppression") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableUpdateForwarding") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableWinsR") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceDsaBehaviorVersion") == 0) {
+               answer_integer = serverinfo->dwDsDsaVersion;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceDomainBehaviorVersion") == 0) {
+               answer_integer = serverinfo->dwDsDsaVersion;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceForestBehaviorVersion") == 0) {
+               answer_integer = serverinfo->dwDsDsaVersion;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "HeapDebug") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LameDelegationTtl") == 0) {
+               answer_integer = 0; /* seconds */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LocalNetPriorityNetMask") == 0) {
+               answer_integer = serverinfo->dwLocalNetPriorityNetMask;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaxCacheSize") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaxResourceRecordsInNonSecureUpdate") == 0) {
+               answer_integer = 0x0000001E;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "OperationsLogLevel") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "OperationsLogLevel2") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaximumUdpPacketSize") == 0) {
+               answer_integer = 0x00004000; /* maximum possible */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RecurseToInternetRootMask") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SelfTest") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SilentlyIgnoreCNameUpdateConflicts") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "TcpReceivePacketSize") == 0) {
+               answer_integer = 0x00010000;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "XfrThrottleMultiplier") == 0) {
+               answer_integer = 0x0000000A;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AllowMsdcsLookupRetry") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "AllowReadOnlyZoneTransfer") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsBackGroundLoadPaused") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsMinimumBackgroundLoadThreads") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsRemoteReplicationDelay") == 0) {
+               answer_integer = 0x0000001E; /* 30 seconds */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableDuplicateQuerySuppresion") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableGlobalNamesSupport") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableVersionQuery") == 0) {
+               answer_integer = 1; /* DNS_VERSION_QUERY_FULL */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableRsoForRodc") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForceRODCMode") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesAlwaysQuerySrv") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesBlockUpdates") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesEnableEDnsProbes") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesPreferAAAA") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesQueryOrder") == 0) {
+               answer_integer = 1;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesSendTimeout") == 0) {
+               answer_integer = 3; /* seconds */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "GlobalNamesServerQueryInterval") == 0) {
+               answer_integer = 0x00005460; /* 6 hours */
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RemoteIPv4RankBoost") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RemoteIPv6RankBoost") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaximumRodcRsoAttemptsPerCycle") == 0) {
+               answer_integer = 0x00000064;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "MaximumRodcRsoQueueLength") == 0) {
+               answer_integer = 0x0000012C;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "EnableGlobalQueryBlockList") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "OpenACLOnProxyUpdates") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "CacheLockingPercent") == 0) {
+               answer_integer = 0x00000064;
+               is_integer = 1;
+       }
+
+       if (is_integer == 1) {
+               *typeid = DNSSRV_TYPEID_DWORD;
+               r->Dword = answer_integer;
+               return WERR_OK;
+       }
+
+       is_addresses = 0;
+
+       if (strcasecmp(operation, "Forwarders") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipForwarders);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, serverinfo->aipForwarders);
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "ListenAddresses") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipListenAddrs);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "BreakOnReceiveFrom") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = NULL;
+               } else {
+                       answer_iparray = NULL;
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "BreakOnUpdateFrom") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = NULL;
+               } else {
+                       answer_iparray = NULL;
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "LogIPFilterList") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipLogFilter);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, serverinfo->aipLogFilter);
+               }
+               is_addresses = 1;
+       }
+
+       if (is_addresses == 1) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       *typeid = DNSSRV_TYPEID_ADDRARRAY;
+                       r->AddrArray = answer_addrarray;
+               } else {
+                       *typeid = DNSSRV_TYPEID_IPARRAY;
+                       r->IpArray = answer_iparray;
+               }
+               return WERR_OK;
+       }
+
+       is_string = is_wstring = 0;
+
+       if (strcasecmp(operation, "DomainDirectoryPartitionBaseName") == 0) {
+               answer_string = talloc_strdup(mem_ctx, "DomainDnsZones");
+               if (! answer_string) {
+                       return WERR_OUTOFMEMORY;
+               }
+               is_string = 1;
+       } else if (strcasecmp(operation, "ForestDirectoryPartitionBaseName") == 0) {
+               answer_string = talloc_strdup(mem_ctx, "ForestDnsZones");
+               if (! answer_string) {
+                       return WERR_OUTOFMEMORY;
+               }
+               is_string = 1;
+       } else if (strcasecmp(operation, "LogFilePath") == 0) {
+               answer_string = talloc_strdup(mem_ctx, serverinfo->pwszLogFilePath);
+               is_wstring = 1;
+       } else if (strcasecmp(operation, "ServerLevelPluginDll") == 0) {
+               answer_string = NULL;
+               is_wstring = 1;
+       } else if (strcasecmp(operation, "DsBackgroundPauseName") == 0) {
+               answer_string = NULL;
+               is_string = 1;
+       } else if (strcasecmp(operation, "DsNotRoundRobinTypes") == 0) {
+               answer_string = NULL;
+               is_string = 1;
+       }
+
+       if (is_string == 1) {
+               *typeid = DNSSRV_TYPEID_LPSTR;
+               r->String = answer_string;
+               return WERR_OK;
+       } else if (is_wstring == 1) {
+               *typeid = DNSSRV_TYPEID_LPWSTR;
+               r->WideString = answer_string;
+               return WERR_OK;
+       }
+
+       is_stringlist = 0;
+
+       if (strcasecmp(operation, "GlobalQueryBlockList") == 0) {
+               answer_stringlist = NULL;
+               is_stringlist = 1;
+       } else if (strcasecmp(operation, "SocketPoolExcludedPortRanges") == 0) {
+               answer_stringlist = NULL;
+               is_stringlist = 1;
+       }
+
+       if (is_stringlist == 1) {
+               *typeid = DNSSRV_TYPEID_UTF8_STRING_LIST;
+               r->Utf8StringList = answer_stringlist;
+               return WERR_OK;
+       }
+
+       DEBUG(0,("dnsserver: Invalid server operation %s", operation));
+       return WERR_DNS_ERROR_INVALID_PROPERTY;
+}
+
+/* [MS-DNSP].pdf Section 3.1.1.2 Zone Configuration Information */
+static WERROR dnsserver_query_zone(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct dnsserver_zone *z,
+                                       const char *operation,
+                                       const unsigned int client_version,
+                                       enum DNS_RPC_TYPEID *typeid,
+                                       union DNSSRV_RPC_UNION *r)
+{
+       uint8_t is_integer, is_addresses, is_string;
+       uint32_t answer_integer;
+       struct IP4_ARRAY *answer_iparray;
+       struct DNS_ADDR_ARRAY *answer_addrarray;
+       char *answer_string;
+       struct dnsserver_zoneinfo *zoneinfo;
+
+       zoneinfo = z->zoneinfo;
+
+       if (strcasecmp(operation, "Zone") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_W2K) {
+                       *typeid = DNSSRV_TYPEID_ZONE_W2K;
+                       r->ZoneW2K = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_W2K);
+
+                       r->ZoneW2K->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                       r->ZoneW2K->Flags = zoneinfo->Flags;
+                       r->ZoneW2K->ZoneType = zoneinfo->dwZoneType;
+                       r->ZoneW2K->Version = zoneinfo->Version;
+               } else {
+                       *typeid = DNSSRV_TYPEID_ZONE;
+                       r->Zone = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_DOTNET);
+
+                       r->Zone->dwRpcStructureVersion = 0x01;
+                       r->Zone->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                       r->Zone->Flags = zoneinfo->Flags;
+                       r->Zone->ZoneType = zoneinfo->dwZoneType;
+                       r->Zone->Version = zoneinfo->Version;
+                       r->Zone->dwDpFlags = zoneinfo->dwDpFlags;
+                       r->Zone->pszDpFqdn = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+               }
+               return WERR_OK;
+       }
+
+       if (strcasecmp(operation, "ZoneInfo") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_W2K) {
+                       *typeid = DNSSRV_TYPEID_ZONE_INFO_W2K;
+                       r->ZoneInfoW2K = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_INFO_W2K);
+
+                       r->ZoneInfoW2K->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                       r->ZoneInfoW2K->dwZoneType = zoneinfo->dwZoneType;
+                       r->ZoneInfoW2K->fReverse = zoneinfo->fReverse;
+                       r->ZoneInfoW2K->fAllowUpdate = zoneinfo->fAllowUpdate;
+                       r->ZoneInfoW2K->fPaused = zoneinfo->fPaused;
+                       r->ZoneInfoW2K->fShutdown = zoneinfo->fShutdown;
+                       r->ZoneInfoW2K->fAutoCreated = zoneinfo->fAutoCreated;
+                       r->ZoneInfoW2K->fUseDatabase = zoneinfo->fUseDatabase;
+                       r->ZoneInfoW2K->pszDataFile = talloc_strdup(mem_ctx, zoneinfo->pszDataFile);
+                       r->ZoneInfoW2K->aipMasters = ip4_array_copy(mem_ctx, zoneinfo->aipMasters);
+                       r->ZoneInfoW2K->fSecureSecondaries = zoneinfo->fSecureSecondaries;
+                       r->ZoneInfoW2K->fNotifyLevel = zoneinfo->fNotifyLevel;
+                       r->ZoneInfoW2K->aipSecondaries = ip4_array_copy(mem_ctx, zoneinfo->aipSecondaries);
+                       r->ZoneInfoW2K->aipNotify = ip4_array_copy(mem_ctx, zoneinfo->aipNotify);
+                       r->ZoneInfoW2K->fUseWins = zoneinfo->fUseWins;
+                       r->ZoneInfoW2K->fUseNbstat = zoneinfo->fUseNbstat;
+                       r->ZoneInfoW2K->fAging = zoneinfo->fAging;
+                       r->ZoneInfoW2K->dwNoRefreshInterval = zoneinfo->dwNoRefreshInterval;
+                       r->ZoneInfoW2K->dwRefreshInterval = zoneinfo->dwRefreshInterval;
+                       r->ZoneInfoW2K->dwAvailForScavengeTime = zoneinfo->dwAvailForScavengeTime;
+                       r->ZoneInfoW2K->aipScavengeServers = ip4_array_copy(mem_ctx, zoneinfo->aipScavengeServers);
+
+               } else if (client_version == DNS_CLIENT_VERSION_DOTNET) {
+                       *typeid = DNSSRV_TYPEID_ZONE_INFO_DOTNET;
+                       r->ZoneInfoDotNet = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_INFO_DOTNET);
+
+                       r->ZoneInfoDotNet->dwRpcStructureVersion = 0x01;
+                       r->ZoneInfoDotNet->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                       r->ZoneInfoDotNet->dwZoneType = zoneinfo->dwZoneType;
+                       r->ZoneInfoDotNet->fReverse = zoneinfo->fReverse;
+                       r->ZoneInfoDotNet->fAllowUpdate = zoneinfo->fAllowUpdate;
+                       r->ZoneInfoDotNet->fPaused = zoneinfo->fPaused;
+                       r->ZoneInfoDotNet->fShutdown = zoneinfo->fShutdown;
+                       r->ZoneInfoDotNet->fAutoCreated = zoneinfo->fAutoCreated;
+                       r->ZoneInfoDotNet->fUseDatabase = zoneinfo->fUseDatabase;
+                       r->ZoneInfoDotNet->pszDataFile = talloc_strdup(mem_ctx, zoneinfo->pszDataFile);
+                       r->ZoneInfoDotNet->aipMasters = ip4_array_copy(mem_ctx, zoneinfo->aipMasters);
+                       r->ZoneInfoDotNet->fSecureSecondaries = zoneinfo->fSecureSecondaries;
+                       r->ZoneInfoDotNet->fNotifyLevel = zoneinfo->fNotifyLevel;
+                       r->ZoneInfoDotNet->aipSecondaries = ip4_array_copy(mem_ctx, zoneinfo->aipSecondaries);
+                       r->ZoneInfoDotNet->aipNotify = ip4_array_copy(mem_ctx, zoneinfo->aipNotify);
+                       r->ZoneInfoDotNet->fUseWins = zoneinfo->fUseWins;
+                       r->ZoneInfoDotNet->fUseNbstat = zoneinfo->fUseNbstat;
+                       r->ZoneInfoDotNet->fAging = zoneinfo->fAging;
+                       r->ZoneInfoDotNet->dwNoRefreshInterval = zoneinfo->dwNoRefreshInterval;
+                       r->ZoneInfoDotNet->dwRefreshInterval = zoneinfo->dwRefreshInterval;
+                       r->ZoneInfoDotNet->dwAvailForScavengeTime = zoneinfo->dwAvailForScavengeTime;
+                       r->ZoneInfoDotNet->aipScavengeServers = ip4_array_copy(mem_ctx, zoneinfo->aipScavengeServers);
+                       r->ZoneInfoDotNet->dwForwarderTimeout = zoneinfo->dwForwarderTimeout;
+                       r->ZoneInfoDotNet->fForwarderSlave = zoneinfo->fForwarderSlave;
+                       r->ZoneInfoDotNet->aipLocalMasters = ip4_array_copy(mem_ctx, zoneinfo->aipLocalMasters);
+                       r->ZoneInfoDotNet->dwDpFlags = zoneinfo->dwDpFlags;
+                       r->ZoneInfoDotNet->pszDpFqdn = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+                       r->ZoneInfoDotNet->pwszZoneDn = talloc_strdup(mem_ctx, zoneinfo->pwszZoneDn);
+                       r->ZoneInfoDotNet->dwLastSuccessfulSoaCheck = zoneinfo->dwLastSuccessfulSoaCheck;
+                       r->ZoneInfoDotNet->dwLastSuccessfulXfr = zoneinfo->dwLastSuccessfulXfr;
+
+               } else {
+                       *typeid = DNSSRV_TYPEID_ZONE_INFO;
+                       r->ZoneInfo = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_INFO_LONGHORN);
+
+                       r->ZoneInfo->dwRpcStructureVersion = 0x02;
+                       r->ZoneInfo->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                       r->ZoneInfo->dwZoneType = zoneinfo->dwZoneType;
+                       r->ZoneInfo->fReverse = zoneinfo->fReverse;
+                       r->ZoneInfo->fAllowUpdate = zoneinfo->fAllowUpdate;
+                       r->ZoneInfo->fPaused = zoneinfo->fPaused;
+                       r->ZoneInfo->fShutdown = zoneinfo->fShutdown;
+                       r->ZoneInfo->fAutoCreated = zoneinfo->fAutoCreated;
+                       r->ZoneInfo->fUseDatabase = zoneinfo->fUseDatabase;
+                       r->ZoneInfo->pszDataFile = talloc_strdup(mem_ctx, zoneinfo->pszDataFile);
+                       r->ZoneInfo->aipMasters = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipMasters);
+                       r->ZoneInfo->fSecureSecondaries = zoneinfo->fSecureSecondaries;
+                       r->ZoneInfo->fNotifyLevel = zoneinfo->fNotifyLevel;
+                       r->ZoneInfo->aipSecondaries = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipSecondaries);
+                       r->ZoneInfo->aipNotify = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipNotify);
+                       r->ZoneInfo->fUseWins = zoneinfo->fUseWins;
+                       r->ZoneInfo->fUseNbstat = zoneinfo->fUseNbstat;
+                       r->ZoneInfo->fAging = zoneinfo->fAging;
+                       r->ZoneInfo->dwNoRefreshInterval = zoneinfo->dwNoRefreshInterval;
+                       r->ZoneInfo->dwRefreshInterval = zoneinfo->dwRefreshInterval;
+                       r->ZoneInfo->dwAvailForScavengeTime = zoneinfo->dwAvailForScavengeTime;
+                       r->ZoneInfo->aipScavengeServers = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipScavengeServers);
+                       r->ZoneInfo->dwForwarderTimeout = zoneinfo->dwForwarderTimeout;
+                       r->ZoneInfo->fForwarderSlave = zoneinfo->fForwarderSlave;
+                       r->ZoneInfo->aipLocalMasters = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipLocalMasters);
+                       r->ZoneInfo->dwDpFlags = zoneinfo->dwDpFlags;
+                       r->ZoneInfo->pszDpFqdn = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+                       r->ZoneInfo->pwszZoneDn = talloc_strdup(mem_ctx, zoneinfo->pwszZoneDn);
+                       r->ZoneInfo->dwLastSuccessfulSoaCheck = zoneinfo->dwLastSuccessfulSoaCheck;
+                       r->ZoneInfo->dwLastSuccessfulXfr = zoneinfo->dwLastSuccessfulXfr;
+
+                       r->ZoneInfo->fQueuedForBackgroundLoad = zoneinfo->fQueuedForBackgroundLoad;
+                       r->ZoneInfo->fBackgroundLoadInProgress = zoneinfo->fBackgroundLoadInProgress;
+                       r->ZoneInfo->fReadOnlyZone = zoneinfo->fReadOnlyZone;
+                       r->ZoneInfo->dwLastXfrAttempt = zoneinfo->dwLastXfrAttempt;
+                       r->ZoneInfo->dwLastXfrResult = zoneinfo->dwLastXfrResult;
+               }
+
+               return WERR_OK;
+       }
+
+       is_integer = 0;
+
+       if (strcasecmp(operation, "AllowUpdate") == 0) {
+               answer_integer = zoneinfo->fAllowUpdate;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "Secured") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "DsIntegrated") == 0) {
+               answer_integer = zoneinfo->fUseDatabase;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "LogUpdates") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "NoRefreshInterval") == 0) {
+               answer_integer = zoneinfo->dwNoRefreshInterval;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "NotifyLevel") == 0) {
+               answer_integer = zoneinfo->fNotifyLevel;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "RefreshInterval") == 0) {
+               answer_integer = zoneinfo->dwRefreshInterval;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "SecureSecondaries") == 0) {
+               answer_integer = zoneinfo->fSecureSecondaries;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "Type") == 0) {
+               answer_integer = zoneinfo->dwZoneType;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "Aging") == 0) {
+               answer_integer = zoneinfo->fAging;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForwarderSlave") == 0) {
+               answer_integer = zoneinfo->fForwarderSlave;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "ForwarderTimeout") == 0) {
+               answer_integer = zoneinfo->dwForwarderTimeout;
+               is_integer = 1;
+       } else if (strcasecmp(operation, "Unicode") == 0) {
+               answer_integer = 0;
+               is_integer = 1;
+       }
+
+       if (is_integer == 1) {
+               *typeid = DNSSRV_TYPEID_DWORD;
+               r->Dword = answer_integer;
+               return WERR_OK;
+       }
+
+       is_addresses = 0;
+
+       if (strcasecmp(operation, "AllowNSRecordsAutoCreation") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = NULL;
+               } else {
+                       answer_iparray = NULL;
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "ScavengeServers") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipScavengeServers);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, zoneinfo->aipScavengeServers);
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "MasterServers") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipMasters);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, zoneinfo->aipMasters);
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "LocalMasterServers") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipLocalMasters);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, zoneinfo->aipLocalMasters);
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "NotifyServers") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipNotify);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, zoneinfo->aipNotify);
+               }
+               is_addresses = 1;
+       } else if (strcasecmp(operation, "SecondaryServers") == 0) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipSecondaries);
+               } else {
+                       answer_iparray = ip4_array_copy(mem_ctx, zoneinfo->aipSecondaries);
+               }
+               is_addresses = 1;
+       }
+
+       if (is_addresses == 1) {
+               if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
+                       *typeid = DNSSRV_TYPEID_ADDRARRAY;
+                       r->AddrArray = answer_addrarray;
+               } else {
+                       *typeid = DNSSRV_TYPEID_IPARRAY;
+                       r->IpArray = answer_iparray;
+               }
+               return WERR_OK;
+       }
+
+       is_string = 0;
+
+       if (strcasecmp(operation, "DatabaseFile") == 0) {
+               answer_string = talloc_strdup(mem_ctx, zoneinfo->pszDataFile);
+               is_string = 1;
+       } else if (strcasecmp(operation, "ApplicationDirectoryPartition") == 0) {
+               answer_string = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+               is_string = 1;
+       } else if (strcasecmp(operation, "BreakOnNameUpdate") == 0) {
+               answer_string = NULL;
+               is_string = 1;
+       }
+
+       if (is_string == 1) {
+               *typeid = DNSSRV_TYPEID_LPSTR;
+               r->String = answer_string;
+               return WERR_OK;
+       }
+
+       DEBUG(0,("dnsserver: Invalid zone operation %s", operation));
+       return WERR_DNS_ERROR_INVALID_PROPERTY;
+
+}
+
+/* dnsserver operation functions */
+
+/* [MS-DNSP].pdf Section 3.1.1.1 DNS Server Configuration Information */
+static WERROR dnsserver_operate_server(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *operation,
+                                       const unsigned int client_version,
+                                       enum DNS_RPC_TYPEID typeid,
+                                       union DNSSRV_RPC_UNION *r)
+{
+       bool valid_operation = false;
+
+       if (strcasecmp(operation, "ResetDwordProperty") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "Restart") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ClearDebugLog") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ClearCache") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "WriteDirtyZones") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ZoneCreate") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ClearStatistics") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "EnlistDirectoryPartition") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "StartScavenging") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "AbortScavenging") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "AutoConfigure") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ExportSettings") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "PrepareForDemotion") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "PrepareForUninstall") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DeleteNode") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DeleteRecord") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "WriteBackFile") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ListenAddresses") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "Forwarders") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "LogFilePath") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "LogIpFilterList") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ForestDirectoryPartitionBaseName") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DomainDirectoryPartitionBaseName") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "GlobalQueryBlockList") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "BreakOnReceiveFrom") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "BreakOnUpdateFrom") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ServerLevelPluginDll") == 0) {
+               valid_operation = true;
+       }
+
+       if (valid_operation) {
+               DEBUG(0, ("dnsserver: server operation '%s' not implemented", operation));
+               return WERR_CALL_NOT_IMPLEMENTED;
+       }
+
+       DEBUG(0, ("dnsserver: invalid server operation '%s'", operation));
+       return WERR_DNS_ERROR_INVALID_PROPERTY;
+}
+
+static WERROR dnsserver_complex_operate_server(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       const char *operation,
+                                       const unsigned int client_version,
+                                       enum DNS_RPC_TYPEID typeid_in,
+                                       union DNSSRV_RPC_UNION *rin,
+                                       enum DNS_RPC_TYPEID *typeid_out,
+                                       union DNSSRV_RPC_UNION *rout)
+{
+       int valid_operation = 0;
+       struct dnsserver_zone *z;
+       bool list_zones;
+       int i;
+
+       if (strcasecmp(operation, "QueryDwordProperty") == 0) {
+               if (typeid_in == DNSSRV_TYPEID_LPSTR) {
+                       return dnsserver_query_server(dsstate, mem_ctx,
+                                                       rin->String,
+                                                       client_version,
+                                                       typeid_out,
+                                                       rout);
+               }
+       } else if (strcasecmp(operation, "EnumZones") == 0) {
+               if (typeid_in != DNSSRV_TYPEID_DWORD) {
+                       return WERR_DNS_ERROR_INVALID_PROPERTY;
+               }
+               if ((rin->Dword & (DNS_ZONE_REQUEST_PRIMARY |
+                                       DNS_ZONE_REQUEST_FORWARD |
+                                       DNS_ZONE_REQUEST_DS)) > 0) {
+                       list_zones = true;
+               } else {
+                       list_zones = false;
+               }
+
+               if (client_version == DNS_CLIENT_VERSION_W2K) {
+                       *typeid_out = DNSSRV_TYPEID_ZONE_LIST_W2K;
+                       rout->ZoneListW2K = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_LIST_W2K);
+
+                       if (!list_zones) {
+                               rout->ZoneListW2K->dwZoneCount = 0;
+                               rout->ZoneListW2K->ZoneArray = NULL;
+
+                               return WERR_OK;
+                       }
+
+                       rout->ZoneListW2K->ZoneArray = talloc_zero_array(mem_ctx, struct DNS_RPC_ZONE_W2K *, dsstate->zones_count);
+                       if (rout->ZoneListW2K->ZoneArray == NULL) {
+                               return WERR_NOMEM;
+                       }
+
+                       for (z = dsstate->zones, i=0; z; z = z->next, i++) {
+                               rout->ZoneListW2K->ZoneArray[i] = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_W2K);
+
+                               rout->ZoneListW2K->ZoneArray[i]->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                               rout->ZoneListW2K->ZoneArray[i]->Flags = z->zoneinfo->Flags;
+                               rout->ZoneListW2K->ZoneArray[i]->ZoneType = z->zoneinfo->dwZoneType;
+                               rout->ZoneListW2K->ZoneArray[i]->Version = z->zoneinfo->Version;
+                       }
+                       rout->ZoneListW2K->dwZoneCount = dsstate->zones_count;
+
+               } else {
+                       *typeid_out = DNSSRV_TYPEID_ZONE_LIST;
+                       rout->ZoneList = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_LIST_DOTNET);
+
+                       if (!list_zones) {
+                               rout->ZoneList->dwRpcStructureVersion = 1;
+                               rout->ZoneList->dwZoneCount = 0;
+                               rout->ZoneList->ZoneArray = NULL;
+
+                               return WERR_OK;
+                       }
+
+                       rout->ZoneList->ZoneArray = talloc_zero_array(mem_ctx, struct DNS_RPC_ZONE_DOTNET *, dsstate->zones_count);
+                       if (rout->ZoneList->ZoneArray == NULL) {
+                               return WERR_NOMEM;
+                       }
+
+                       for (z = dsstate->zones, i=0; z; z = z->next, i++) {
+                               rout->ZoneList->ZoneArray[i] = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_DOTNET);
+
+                               rout->ZoneList->ZoneArray[i]->dwRpcStructureVersion = 1;
+                               rout->ZoneList->ZoneArray[i]->pszZoneName = talloc_strdup(mem_ctx, z->name);
+                               rout->ZoneList->ZoneArray[i]->Flags = z->zoneinfo->Flags;
+                               rout->ZoneList->ZoneArray[i]->ZoneType = z->zoneinfo->dwZoneType;
+                               rout->ZoneList->ZoneArray[i]->Version = z->zoneinfo->Version;
+                               rout->ZoneList->ZoneArray[i]->dwDpFlags = z->zoneinfo->dwDpFlags;
+                               rout->ZoneList->ZoneArray[i]->pszDpFqdn = talloc_strdup(mem_ctx, z->zoneinfo->pszDpFqdn);
+                       }
+                       rout->ZoneList->dwRpcStructureVersion = 1;
+                       rout->ZoneList->dwZoneCount = dsstate->zones_count;
+               }
+               return WERR_OK;
+       } else if (strcasecmp(operation, "EnumZones2") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "EnumDirectoryPartitions") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DirectoryPartitionInfo") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "Statistics") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "IpValidate") == 0) {
+               valid_operation = true;
+       }
+
+       if (valid_operation) {
+               DEBUG(0, ("dnsserver: server complex operation '%s' not implemented", operation));
+               return WERR_CALL_NOT_IMPLEMENTED;
+       }
+
+       DEBUG(0, ("dnsserver: invalid server complex operation '%s'", operation));
+       return WERR_DNS_ERROR_INVALID_PROPERTY;
+}
+
+/* [MS-DNSP].pdf Section 3.1.1.2 Zone Configuration Information */
+static WERROR dnsserver_operate_zone(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct dnsserver_zone *z,
+                                       unsigned int request_filter,
+                                       const char *operation,
+                                       const unsigned int client_version,
+                                       enum DNS_RPC_TYPEID typeid,
+                                       union DNSSRV_RPC_UNION *r)
+{
+       bool valid_operation = false;
+
+       if (strcasecmp(operation, "ResetDwordProperty") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ZoneTypeReset") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "PauseZone") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ResumeZone") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DeleteZone") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ReloadZone") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "RefreshZone") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ExpireZone") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "IncrementVersion") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "WriteBackFile") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DeleteZoneFromDs") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "UpdateZoneFromDs") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ZoneExport") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ZoneChangeDirectoryPartition") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DeleteNode") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DeleteRecordSet") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ForceAgingOnNode") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "DatabaseFile") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "MasterServers") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "LocalMasterServers") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "NotifyServers") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "SecondaryServers") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ScavengingServers") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "AllowNSRecordsAutoCreation") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "BreakOnNameUpdate") == 0) {
+               valid_operation = true;
+       } else if (strcasecmp(operation, "ApplicationDirectoryPartition") == 0) {
+               valid_operation = true;
+       }
+
+       if (valid_operation) {
+               DEBUG(0, ("dnsserver: zone operation '%s' not implemented", operation));
+               return WERR_CALL_NOT_IMPLEMENTED;
+       }
+
+       DEBUG(0, ("dnsserver: invalid zone operation '%s'", operation));
+       return WERR_DNS_ERROR_INVALID_PROPERTY;
+}
+
+static WERROR dnsserver_complex_operate_zone(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct dnsserver_zone *z,
+                                       const char *operation,
+                                       const unsigned int client_version,
+                                       enum DNS_RPC_TYPEID typeid_in,
+                                       union DNSSRV_RPC_UNION *rin,
+                                       enum DNS_RPC_TYPEID *typeid_out,
+                                       union DNSSRV_RPC_UNION *rout)
+{
+       if (strcasecmp(operation, "QueryDwordProperty") == 0) {
+               if (typeid_in == DNSSRV_TYPEID_LPSTR) {
+                       return dnsserver_query_zone(dsstate, mem_ctx, z,
+                                               rin->String,
+                                               client_version,
+                                               typeid_out,
+                                               rout);
+
+               }
+       }
+
+       DEBUG(0,("dnsserver: Invalid zone operation %s", operation));
+       return WERR_DNS_ERROR_INVALID_PROPERTY;
+}
+
+/* dnsserver enumerate function */
+
+static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       unsigned int client_version,
+                                       const char *node_name,
+                                       enum dns_record_type record_type,
+                                       unsigned int select_flag,
+                                       unsigned int *buffer_length,
+                                       struct DNS_RPC_RECORDS_ARRAY **buffer)
+{
+       TALLOC_CTX *tmp_ctx;
+       const char * const attrs[] = { "name", "dnsRecord", NULL };
+       struct ldb_result *res;
+       struct ldb_dn *dn;
+       struct DNS_RPC_RECORDS_ARRAY *recs;
+       char **add_names;
+       char *rname;
+       int add_count;
+       int i, ret, len;
+       WERROR status;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+       dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(dsstate->samdb));
+       W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
+
+       if (!ldb_dn_add_child_fmt(dn, "DC=RootDNSServers,CN=MicrosoftDNS,DC=DomainDnsZones")) {
+               talloc_free(tmp_ctx);
+               return WERR_NOMEM;
+       }
+
+       ret = ldb_search(dsstate->samdb, tmp_ctx, &res, dn,
+                               LDB_SCOPE_ONELEVEL, attrs, "(&(objectClass=dnsNode)(name=@))");
+       if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               return WERR_INTERNAL_DB_ERROR;
+       }
+       if (res->count == 0) {
+               talloc_free(tmp_ctx);
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       recs = talloc_zero(mem_ctx, struct DNS_RPC_RECORDS_ARRAY);
+       W_ERROR_HAVE_NO_MEMORY_AND_FREE(recs, tmp_ctx);
+
+       add_names = NULL;
+       add_count = 0;
+
+       for (i=0; i<res->count; i++) {
+               status = dns_fill_records_array(tmp_ctx, NULL, record_type,
+                                               select_flag, NULL,
+                                               res->msgs[i], recs,
+                                               &add_names, &add_count);
+               if (!W_ERROR_IS_OK(status)) {
+                       talloc_free(tmp_ctx);
+                       return status;
+               }
+       }
+       talloc_free(res);
+
+       /* Add any additional records */
+       if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) {
+               for (i=0; i<add_count; i++) {
+                       ret = ldb_search(dsstate->samdb, tmp_ctx, &res, dn,
+                                       LDB_SCOPE_ONELEVEL, attrs,
+                                       "(&(objectClass=dnsNode)(name=%s))", add_names[i]);
+                       if (ret != LDB_SUCCESS || res->count == 0) {
+                               talloc_free(res);
+                               continue;
+                       }
+
+                       len = strlen(add_names[i]);
+                       if (add_names[i][len-1] == '.') {
+                               rname = talloc_strdup(tmp_ctx, add_names[i]);
+                       } else {
+                               rname = talloc_asprintf(tmp_ctx, "%s.", add_names[i]);
+                       }
+                       status = dns_fill_records_array(tmp_ctx, NULL, DNS_TYPE_A,
+                                                       select_flag, rname,
+                                                       res->msgs[0], recs,
+                                                       NULL, NULL);
+                       talloc_free(rname);
+                       talloc_free(res);
+               }
+       }
+
+       talloc_free(tmp_ctx);
+
+       *buffer_length = ndr_size_DNS_RPC_RECORDS_ARRAY(recs, 0);
+       *buffer = recs;
+
+       return WERR_OK;
+}
+
+
+static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct dnsserver_zone *z,
+                                       unsigned int client_version,
+                                       const char *node_name,
+                                       const char *start_child,
+                                       enum dns_record_type record_type,
+                                       unsigned int select_flag,
+                                       const char *filter_start,
+                                       const char *filter_stop,
+                                       unsigned int *buffer_length,
+                                       struct DNS_RPC_RECORDS_ARRAY **buffer)
+{
+       TALLOC_CTX *tmp_ctx;
+       char *name, *branch_name;
+       const char * const attrs[] = { "name", "dnsRecord", NULL };
+       struct ldb_result *res;
+       struct DNS_RPC_RECORDS_ARRAY *recs;
+       char **add_names = NULL;
+       const char *ptr;
+       char *rname;
+       int add_count = 0;
+       int i, ret, len;
+       WERROR status;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+       name = dns_split_node_name(tmp_ctx, node_name, z->name);
+       W_ERROR_HAVE_NO_MEMORY_AND_FREE(name, tmp_ctx);
+
+       /* search all records under parent tree */
+       if (strcmp(name, z->name) == 0) {
+               ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+                               LDB_SCOPE_ONELEVEL, attrs, "(objectClass=dnsNode)");
+       } else {
+               ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+                               LDB_SCOPE_ONELEVEL, attrs,
+                               "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s)))",
+                               name, name);
+       }
+       if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               return WERR_INTERNAL_DB_ERROR;
+       }
+       if (res->count == 0) {
+               talloc_free(tmp_ctx);
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       recs = talloc_zero(mem_ctx, struct DNS_RPC_RECORDS_ARRAY);
+       W_ERROR_HAVE_NO_MEMORY_AND_FREE(recs, tmp_ctx);
+
+       /* Sort the names, so that the first record is the parent record */
+       ldb_qsort(res->msgs, res->count, sizeof(struct ldb_message *), name,
+                       (ldb_qsort_cmp_fn_t)dns_name_compare);
+
+       /* Add the parent record with blank name */
+       ptr = ldb_msg_find_attr_as_string(res->msgs[0], "name", NULL);
+       if (strcmp(ptr, name) == 0 || strcmp(ptr, "@") == 0) {
+               /* parent record found */
+               if (select_flag & DNS_RPC_VIEW_ONLY_CHILDREN) {
+                       status = WERR_OK;
+               } else {
+                       status = dns_fill_records_array(tmp_ctx, z, record_type,
+                                                       select_flag, NULL,
+                                                       res->msgs[0], recs,
+                                                       &add_names, &add_count);
+               }
+               i = 1;
+       } else {
+               /* parent record not in the search */
+               if (select_flag & DNS_RPC_VIEW_ONLY_CHILDREN) {
+                       status = WERR_OK;
+               } else {
+                       status = dns_fill_records_array(tmp_ctx, z, record_type,
+                                                       select_flag, NULL,
+                                                       NULL, recs,
+                                                       &add_names, &add_count);
+               }
+               i = 0;
+       }
+
+       if (!W_ERROR_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+
+       /* Add all the children records */
+       if (!(select_flag & DNS_RPC_VIEW_NO_CHILDREN)) {
+               for ( ; i<res->count; i++) {
+                       char *name2;
+                       const char *tmp_str;
+
+                       ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
+                       name2 = dns_split_node_name(tmp_ctx, ptr, name);
+                       tmp_str = strrchr(name2, '.');
+                       if (tmp_str == NULL) {
+                               branch_name = talloc_strdup(tmp_ctx, name2);
+                       } else {
+                               /* Skip '.' */
+                               branch_name = talloc_strdup(tmp_ctx, &tmp_str[1]);
+                       }
+                       talloc_free(name2);
+
+                       status = dns_fill_records_array(tmp_ctx, z, record_type,
+                                                       select_flag, branch_name,
+                                                       res->msgs[i], recs,
+                                                       &add_names, &add_count);
+                       if (!W_ERROR_IS_OK(status)) {
+                               talloc_free(tmp_ctx);
+                               return status;
+                       }
+
+                       talloc_free(branch_name);
+               }
+       }
+       talloc_free(res);
+
+       talloc_free(name);
+
+       /* Add any additional records */
+       if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) {
+               for (i=0; i<add_count; i++) {
+                       name = dns_split_node_name(tmp_ctx, add_names[i], z->name);
+                       ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+                                       LDB_SCOPE_ONELEVEL, attrs,
+                                       "(&(objectClass=dnsNode)(name=%s))", name);
+                       talloc_free(name);
+                       if (ret != LDB_SUCCESS || res->count == 0) {
+                               talloc_free(res);
+                               continue;
+                       }
+
+                       len = strlen(add_names[i]);
+                       if (add_names[i][len-1] == '.') {
+                               rname = talloc_strdup(tmp_ctx, add_names[i]);
+                       } else {
+                               rname = talloc_asprintf(tmp_ctx, "%s.", add_names[i]);
+                       }
+                       status = dns_fill_records_array(tmp_ctx, NULL, DNS_TYPE_A,
+                                                       select_flag, rname,
+                                                       res->msgs[0], recs,
+                                                       NULL, NULL);
+                       talloc_free(rname);
+                       talloc_free(res);
+               }
+       }
+
+       *buffer_length = ndr_size_DNS_RPC_RECORDS_ARRAY(recs, 0);
+       *buffer = recs;
+
+       return WERR_OK;
+}
+
+/* dnsserver update function */
+
+static WERROR dnsserver_update_record(struct dnsserver_state *dsstate,
+                                       TALLOC_CTX *mem_ctx,
+                                       struct dnsserver_zone *z,
+                                       unsigned int client_version,
+                                       const char *node_name,
+                                       struct DNS_RPC_RECORD_BUF *add_buf,
+                                       struct DNS_RPC_RECORD_BUF *del_buf)
+{
+       TALLOC_CTX *tmp_ctx;
+       char *name;
+       WERROR status;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+       name = dns_split_node_name(tmp_ctx, node_name, z->name);
+       W_ERROR_HAVE_NO_MEMORY_AND_FREE(name, tmp_ctx);
+
+       if (add_buf != NULL) {
+               if (del_buf == NULL) {
+                       /* Add record */
+                       status = dnsserver_db_add_record(tmp_ctx, dsstate->samdb,
+                                                               z, name,
+                                                               &add_buf->rec);
+               } else {
+                       /* Update record */
+                       status = dnsserver_db_update_record(tmp_ctx, dsstate->samdb,
+                                                               z, name,
+                                                               &add_buf->rec,
+                                                               &del_buf->rec);
+               }
+       } else {
+               if (del_buf == NULL) {
+                       /* Add empty node */
+                       status = dnsserver_db_add_empty_node(tmp_ctx, dsstate->samdb,
+                                                               z, name);
+               } else {
+                       /* Delete record */
+                       status = dnsserver_db_delete_record(tmp_ctx, dsstate->samdb,
+                                                               z, name,
+                                                               &del_buf->rec);
+               }
+       }
+
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+
+/* dnsserver interface functions */
+
+static WERROR dcesrv_DnssrvOperation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvOperation *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z = NULL;
+       uint32_t request_filter = 0;
+       WERROR ret;
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.dwContext == 0) {
+               if (r->in.pszZone != NULL) {
+                       request_filter = dnsserver_zone_to_request_filter(r->in.pszZone);
+               }
+       } else {
+               request_filter = r->in.dwContext;
+       }
+
+       if (r->in.pszZone == NULL) {
+               ret = dnsserver_operate_server(dsstate, mem_ctx,
+                                               r->in.pszOperation,
+                                               DNS_CLIENT_VERSION_W2K,
+                                               r->in.dwTypeId,
+                                               &r->in.pData);
+       } else {
+               ret = dnsserver_operate_zone(dsstate, mem_ctx, z,
+                                               request_filter,
+                                               r->in.pszOperation,
+                                               DNS_CLIENT_VERSION_W2K,
+                                               r->in.dwTypeId,
+                                               &r->in.pData);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvOperation, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvQuery(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvQuery *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       ZERO_STRUCTP(r->out.pdwTypeId);
+       ZERO_STRUCTP(r->out.ppData);
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               /* FIXME: DNS Server Configuration Access Control List */
+               ret = dnsserver_query_server(dsstate, mem_ctx,
+                                               r->in.pszOperation,
+                                               DNS_CLIENT_VERSION_W2K,
+                                               r->out.pdwTypeId,
+                                               r->out.ppData);
+       } else {
+               z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+               if (z == NULL) {
+                       return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+               }
+
+               ret = dnsserver_query_zone(dsstate, mem_ctx, z,
+                                               r->in.pszOperation,
+                                               DNS_CLIENT_VERSION_W2K,
+                                               r->out.pdwTypeId,
+                                               r->out.ppData);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvQuery, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvComplexOperation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvComplexOperation *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       ZERO_STRUCTP(r->out.pdwTypeOut);
+       ZERO_STRUCTP(r->out.ppDataOut);
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               /* Server operation */
+               ret = dnsserver_complex_operate_server(dsstate, mem_ctx,
+                                                       r->in.pszOperation,
+                                                       DNS_CLIENT_VERSION_W2K,
+                                                       r->in.dwTypeIn,
+                                                       &r->in.pDataIn,
+                                                       r->out.pdwTypeOut,
+                                                       r->out.ppDataOut);
+       } else {
+               z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+               if (z == NULL) {
+                       return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+               }
+
+               ret = dnsserver_complex_operate_zone(dsstate, mem_ctx, z,
+                                                       r->in.pszOperation,
+                                                       DNS_CLIENT_VERSION_W2K,
+                                                       r->in.dwTypeIn,
+                                                       &r->in.pDataIn,
+                                                       r->out.pdwTypeOut,
+                                                       r->out.ppDataOut);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvComplexOperation, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvEnumRecords(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvEnumRecords *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       ZERO_STRUCTP(r->out.pdwBufferLength);
+       ZERO_STRUCTP(r->out.pBuffer);
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       if (strcasecmp(r->in.pszZone, "..RootHints") == 0) {
+               ret = dnsserver_enumerate_root_records(dsstate, mem_ctx,
+                                       DNS_CLIENT_VERSION_W2K,
+                                       r->in.pszNodeName,
+                                       r->in.wRecordType,
+                                       r->in.fSelectFlag,
+                                       r->out.pdwBufferLength,
+                                       r->out.pBuffer);
+       } else {
+               z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+               if (z == NULL) {
+                       return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+               }
+
+               ret = dnsserver_enumerate_records(dsstate, mem_ctx, z,
+                                       DNS_CLIENT_VERSION_W2K,
+                                       r->in.pszNodeName,
+                                       r->in.pszStartChild,
+                                       r->in.wRecordType,
+                                       r->in.fSelectFlag,
+                                       r->in.pszFilterStart,
+                                       r->in.pszFilterStop,
+                                       r->out.pdwBufferLength,
+                                       r->out.pBuffer);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvEnumRecords, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvUpdateRecord(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvUpdateRecord *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+       if (z == NULL) {
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       ret = dnsserver_update_record(dsstate, mem_ctx, z,
+                                       DNS_CLIENT_VERSION_W2K,
+                                       r->in.pszNodeName,
+                                       r->in.pAddRecord,
+                                       r->in.pDeleteRecord);
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvUpdateRecord, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvOperation2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvOperation2 *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z = NULL;
+       uint32_t request_filter = 0;
+       WERROR ret;
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.dwContext == 0) {
+               if (r->in.pszZone != NULL) {
+                       request_filter = dnsserver_zone_to_request_filter(r->in.pszZone);
+               }
+       } else {
+               request_filter = r->in.dwContext;
+       }
+
+       if (r->in.pszZone == NULL) {
+               ret = dnsserver_operate_server(dsstate, mem_ctx,
+                                               r->in.pszOperation,
+                                               r->in.dwClientVersion,
+                                               r->in.dwTypeId,
+                                               &r->in.pData);
+       } else {
+               ret = dnsserver_operate_zone(dsstate, mem_ctx, z,
+                                               request_filter,
+                                               r->in.pszOperation,
+                                               r->in.dwClientVersion,
+                                               r->in.dwTypeId,
+                                               &r->in.pData);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvOperation2, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvQuery2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvQuery2 *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       ZERO_STRUCTP(r->out.pdwTypeId);
+       ZERO_STRUCTP(r->out.ppData);
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               /* FIXME: DNS Server Configuration Access Control List */
+               ret = dnsserver_query_server(dsstate, mem_ctx,
+                                               r->in.pszOperation,
+                                               r->in.dwClientVersion,
+                                               r->out.pdwTypeId,
+                                               r->out.ppData);
+       } else {
+               z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+               if (z == NULL) {
+                       return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+               }
+
+               ret = dnsserver_query_zone(dsstate, mem_ctx, z,
+                                       r->in.pszOperation,
+                                       r->in.dwClientVersion,
+                                       r->out.pdwTypeId,
+                                       r->out.ppData);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvQuery2, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvComplexOperation2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvComplexOperation2 *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       ZERO_STRUCTP(r->out.pdwTypeOut);
+       ZERO_STRUCTP(r->out.ppDataOut);
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               /* Server operation */
+               ret =  dnsserver_complex_operate_server(dsstate, mem_ctx,
+                                                       r->in.pszOperation,
+                                                       r->in.dwClientVersion,
+                                                       r->in.dwTypeIn,
+                                                       &r->in.pDataIn,
+                                                       r->out.pdwTypeOut,
+                                                       r->out.ppDataOut);
+       } else {
+
+               z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+               if (z == NULL) {
+                       return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+               }
+
+               ret = dnsserver_complex_operate_zone(dsstate, mem_ctx, z,
+                                                       r->in.pszOperation,
+                                                       r->in.dwClientVersion,
+                                                       r->in.dwTypeIn,
+                                                       &r->in.pDataIn,
+                                                       r->out.pdwTypeOut,
+                                                       r->out.ppDataOut);
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvComplexOperation2, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvEnumRecords2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvEnumRecords2 *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       ZERO_STRUCTP(r->out.pdwBufferLength);
+       ZERO_STRUCTP(r->out.pBuffer);
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       if (strcasecmp(r->in.pszZone, "..RootHints") == 0) {
+               ret =  dnsserver_enumerate_root_records(dsstate, mem_ctx,
+                                       r->in.dwClientVersion,
+                                       r->in.pszNodeName,
+                                       r->in.wRecordType,
+                                       r->in.fSelectFlag,
+                                       r->out.pdwBufferLength,
+                                       r->out.pBuffer);
+       } else {
+               z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+               if (z == NULL) {
+                       return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+               }
+
+               ret =  dnsserver_enumerate_records(dsstate, mem_ctx, z,
+                                       r->in.dwClientVersion,
+                                       r->in.pszNodeName,
+                                       r->in.pszStartChild,
+                                       r->in.wRecordType,
+                                       r->in.fSelectFlag,
+                                       r->in.pszFilterStart,
+                                       r->in.pszFilterStop,
+                                       r->out.pdwBufferLength,
+                                       r->out.pBuffer);
+
+       }
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvEnumRecords2, NDR_IN, r);
+       }
+       return ret;
+}
+
+static WERROR dcesrv_DnssrvUpdateRecord2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct DnssrvUpdateRecord2 *r)
+{
+       struct dnsserver_state *dsstate;
+       struct dnsserver_zone *z;
+       WERROR ret;
+
+       if ((dsstate = dnsserver_connect(dce_call)) == NULL) {
+               return WERR_DNS_ERROR_DS_UNAVAILABLE;
+       }
+
+       if (r->in.pszZone == NULL) {
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+       if (z == NULL) {
+               return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+       }
+
+       ret = dnsserver_update_record(dsstate, mem_ctx, z,
+                                       r->in.dwClientVersion,
+                                       r->in.pszNodeName,
+                                       r->in.pAddRecord,
+                                       r->in.pDeleteRecord);
+
+       if (W_ERROR_EQUAL(ret, WERR_CALL_NOT_IMPLEMENTED)) {
+               NDR_PRINT_FUNCTION_DEBUG(DnssrvUpdateRecord2, NDR_IN, r);
+       }
+       return ret;
+}
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_dnsserver_s.c"
diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c
new file mode 100644 (file)
index 0000000..486290d
--- /dev/null
@@ -0,0 +1,795 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   DNS Server
+
+   Copyright (C) Amitay Isaacs 2011
+
+   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 "dnsserver.h"
+#include "lib/replace/system/network.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "librpc/gen_ndr/ndr_dnsserver.h"
+
+
+struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
+{
+       struct IP4_ARRAY *ret;
+
+       if (!ip4) {
+               return NULL;
+       }
+
+       ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
+       if (!ret) {
+               return ret;
+       }
+
+       ret->AddrCount = ip4->AddrCount;
+       if (ip4->AddrCount > 0) {
+               ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
+               if (ret->AddrArray) {
+                       memcpy(ret->AddrArray, ip4->AddrArray,
+                               sizeof(unsigned int) * ip4->AddrCount);
+               } else {
+                       talloc_free(ret);
+                       return NULL;
+               }
+       }
+       return ret;
+}
+
+
+struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
+                                                       struct IP4_ARRAY *ip4)
+{
+       struct DNS_ADDR_ARRAY *ret;
+       int i;
+
+       if (!ip4) {
+               return NULL;
+       }
+
+       ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
+       if (!ret) {
+               return ret;
+       }
+
+       ret->MaxCount = ip4->AddrCount;
+       ret->AddrCount = ip4->AddrCount;
+       ret->Family = AF_INET;
+       if (ip4->AddrCount > 0) {
+               ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
+               if (ret->AddrArray) {
+                       for (i=0; i<ip4->AddrCount; i++) {
+                               ret->AddrArray[i].MaxSa[0] = 0x02;
+                               ret->AddrArray[i].MaxSa[3] = 53;
+                               memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
+                                       sizeof(unsigned int));
+                               ret->AddrArray[i].DnsAddrUserDword[0] = 6;
+                       }
+
+               } else {
+                       talloc_free(ret);
+                       return NULL;
+               }
+       }
+       return ret;
+}
+
+
+struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
+                                               struct DNS_ADDR_ARRAY *addr)
+{
+       struct DNS_ADDR_ARRAY *ret;
+
+       if (!addr) {
+               return NULL;
+       }
+
+       ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
+       if (!ret) {
+               return ret;
+       }
+
+       ret->MaxCount = addr->MaxCount;
+       ret->AddrCount = addr->AddrCount;
+       ret->Family = addr->Family;
+       if (addr->AddrCount > 0) {
+               ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
+               if (ret->AddrArray) {
+                       memcpy(ret->AddrArray, addr->AddrArray,
+                               sizeof(struct DNS_ADDR) * addr->AddrCount);
+               } else {
+                       talloc_free(ret);
+                       return NULL;
+               }
+       }
+       return ret;
+}
+
+
+int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
+{
+       char *str = NULL, *ptr, **list;
+       int count = 0;
+
+       str = talloc_strdup(tmp_ctx, name);
+       if (!str) {
+               goto failed;
+       }
+
+       list = talloc_zero_array(tmp_ctx, char *, 0);
+       if (!list) {
+               goto failed;
+       }
+
+       ptr = strtok(str, ".");
+       while (ptr != NULL) {
+               count++;
+               list = talloc_realloc(tmp_ctx, list, char *, count);
+               if (!list) {
+                       goto failed;
+               }
+               list[count-1] = talloc_strdup(tmp_ctx, ptr);
+               if (list[count-1] == NULL) {
+                       goto failed;
+               }
+               ptr = strtok(NULL, ".");
+       }
+
+       talloc_free(str);
+
+       *components = list;
+       return count;
+
+failed:
+       if (str) {
+               talloc_free(str);
+       }
+       return -1;
+}
+
+
+char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
+{
+       char **nlist, **zlist;
+       char *prefix;
+       int ncount, zcount, i, match;
+
+       /*
+        * If node_name is "@", return the zone_name
+        * If node_name is ".", return NULL
+        * If there is no '.' in node_name, return the node_name as is.
+        *
+        * If node_name does not have zone_name in it, return the node_name as is.
+        *
+        * If node_name has additional components as compared to zone_name
+        *  return only the additional components as a prefix.
+        *
+        */
+       if (strcmp(node_name, "@") == 0) {
+               prefix = talloc_strdup(tmp_ctx, zone_name);
+       } else if (strcmp(node_name, ".") == 0) {
+               prefix = NULL;
+       } else if (strchr(node_name, '.') == NULL) {
+               prefix = talloc_strdup(tmp_ctx, node_name);
+       } else {
+               zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
+               ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
+               if (zcount < 0 || ncount < 0) {
+                       return NULL;
+               }
+
+               if (ncount < zcount) {
+                       prefix = talloc_strdup(tmp_ctx, node_name);
+               } else {
+                       match = 0;
+                       for (i=1; i<=zcount; i++) {
+                               if (strcmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
+                                       break;
+                               }
+                               match++;
+                       }
+
+                       if (match == ncount) {
+                               prefix = talloc_strdup(tmp_ctx, zone_name);
+                       } else {
+                               prefix = talloc_strdup(tmp_ctx, nlist[0]);
+                               if (prefix != NULL) {
+                                       for (i=1; i<ncount-match; i++) {
+                                               prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
+                                               if (prefix == NULL) {
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               talloc_free(zlist);
+               talloc_free(nlist);
+       }
+
+       return prefix;
+}
+
+
+void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
+                               struct DNS_RPC_RECORD *dns)
+{
+       int len;
+
+       ZERO_STRUCTP(dns);
+
+       dns->wDataLength = dnsp->wDataLength;
+       dns->wType = dnsp->wType;
+       dns->dwFlags = dnsp->rank;
+       dns->dwSerial = dnsp->dwSerial;
+       dns->dwTtlSeconds = dnsp->dwTtlSeconds;
+       dns->dwTimeStamp = dnsp->dwTimeStamp;
+
+       switch (dnsp->wType) {
+
+       case DNS_TYPE_TOMBSTONE:
+               dns->data.timestamp = dnsp->data.timestamp;
+               break;
+
+       case DNS_TYPE_A:
+               dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
+               break;
+
+       case DNS_TYPE_NS:
+               len = strlen(dnsp->data.ns);
+               if (dnsp->data.ns[len-1] == '.') {
+                       dns->data.name.len = len;
+                       dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
+               } else {
+                       dns->data.name.len = len+1;
+                       dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
+               }
+               break;
+
+       case DNS_TYPE_CNAME:
+               len = strlen(dnsp->data.cname);
+               if (dnsp->data.cname[len-1] == '.') {
+                       dns->data.name.len = len;
+                       dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
+               } else {
+                       dns->data.name.len = len+1;
+                       dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
+               }
+               break;
+
+       case DNS_TYPE_SOA:
+               dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
+               dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
+               dns->data.soa.dwRetry = dnsp->data.soa.retry;
+               dns->data.soa.dwExpire = dnsp->data.soa.expire;
+               dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
+
+               len = strlen(dnsp->data.soa.mname);
+               if (dnsp->data.soa.mname[len-1] == '.') {
+                       dns->data.soa.NamePrimaryServer.len = len;
+                       dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
+               } else {
+                       dns->data.soa.NamePrimaryServer.len = len+1;
+                       dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
+               }
+
+               len = strlen(dnsp->data.soa.rname);
+               if (dnsp->data.soa.rname[len-1] == '.') {
+                       dns->data.soa.ZoneAdministratorEmail.len = len;
+                       dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
+               } else {
+                       dns->data.soa.ZoneAdministratorEmail.len = len+1;
+                       dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
+               }
+               break;
+
+       case DNS_TYPE_PTR:
+               dns->data.ptr.len = strlen(dnsp->data.ptr);
+               dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
+               break;
+
+       case DNS_TYPE_MX:
+               dns->data.mx.wPreference = dnsp->data.mx.wPriority;
+               len = strlen(dnsp->data.mx.nameTarget);
+               if (dnsp->data.mx.nameTarget[len-1] == '.') {
+                       dns->data.mx.nameExchange.len = len;
+                       dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
+               } else {
+                       dns->data.mx.nameExchange.len = len+1;
+                       dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
+               }
+               break;
+
+       case DNS_TYPE_TXT:
+               dns->data.name.len = strlen(dnsp->data.txt);
+               dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.txt);
+               break;
+
+       case DNS_TYPE_AAAA:
+               dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
+               break;
+
+       case DNS_TYPE_SRV:
+               dns->data.srv.wPriority = dnsp->data.srv.wPriority;
+               dns->data.srv.wWeight = dnsp->data.srv.wWeight;
+               dns->data.srv.wPort = dnsp->data.srv.wPort;
+               len = strlen(dnsp->data.srv.nameTarget);
+               if (dnsp->data.srv.nameTarget[len-1] == '.') {
+                       dns->data.srv.nameTarget.len = len;
+                       dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
+               } else {
+                       dns->data.srv.nameTarget.len = len+1;
+                       dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
+               }
+               break;
+
+       default:
+               memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
+               DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
+       }
+
+}
+
+
+struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
+{
+       int len;
+       struct dnsp_DnssrvRpcRecord *dnsp;
+
+       dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
+       if (dnsp == NULL) {
+               return NULL;
+       }
+
+       dnsp->wDataLength = dns->wDataLength;
+       dnsp->wType = dns->wType;
+       dnsp->version = 5;
+       dnsp->rank = dns->dwFlags & 0x000000FF;
+       dnsp->dwSerial = dns->dwSerial;
+       dnsp->dwTtlSeconds = dns->dwTtlSeconds;
+       dnsp->dwTimeStamp = dns->dwTimeStamp;
+
+       switch (dns->wType) {
+
+       case DNS_TYPE_TOMBSTONE:
+               dnsp->data.timestamp = dns->data.timestamp;
+               break;
+
+       case DNS_TYPE_A:
+               dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4);
+               break;
+
+       case DNS_TYPE_NS:
+               len = dns->data.name.len;
+               if (dns->data.name.str[len-1] == '.') {
+                       dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
+               } else {
+                       dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str);
+               }
+               break;
+
+       case DNS_TYPE_CNAME:
+               len = dns->data.name.len;
+               if (dns->data.name.str[len-1] == '.') {
+                       dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
+               } else {
+                       dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str);
+               }
+               break;
+
+       case DNS_TYPE_SOA:
+               dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
+               dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
+               dnsp->data.soa.retry = dns->data.soa.dwRetry;
+               dnsp->data.soa.expire = dns->data.soa.dwExpire;
+               dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
+
+               len = dns->data.soa.NamePrimaryServer.len;
+               if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
+                       dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
+               } else {
+                       dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
+               }
+
+               len = dns->data.soa.ZoneAdministratorEmail.len;
+               if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') {
+                       dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1);
+               } else {
+                       dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str);
+               }
+               break;
+
+       case DNS_TYPE_PTR:
+               dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str);
+               break;
+
+       case DNS_TYPE_MX:
+               dnsp->data.mx.wPriority = dns->data.mx.wPreference;
+               len = dns->data.mx.nameExchange.len;
+               if (dns->data.mx.nameExchange.str[len-1] == '.') {
+                       dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1);
+               } else {
+                       dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str);
+               }
+               break;
+
+       case DNS_TYPE_TXT:
+               dnsp->data.txt = talloc_strdup(mem_ctx, dns->data.name.str);
+               break;
+
+       case DNS_TYPE_AAAA:
+               dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
+               break;
+
+       case DNS_TYPE_SRV:
+               dnsp->data.srv.wPriority = dns->data.srv.wPriority;
+               dnsp->data.srv.wWeight = dns->data.srv.wWeight;
+               dnsp->data.srv.wPort = dns->data.srv.wPort;
+
+               len = dns->data.srv.nameTarget.len;
+               if (dns->data.srv.nameTarget.str[len-1] == '.') {
+                       dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1);
+               } else {
+                       dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str);
+               }
+               break;
+
+       default:
+               memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
+               DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
+
+       }
+
+       return dnsp;
+}
+
+
+static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
+{
+       int i;
+       char **ptr = *add_names;
+       int count = *add_count;
+
+       for (i=0; i<count; i++) {
+               if (strcmp(ptr[i], name) == 0) {
+                       return;
+               }
+       }
+
+       ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
+       if (ptr == NULL) {
+               return;
+       }
+
+       ptr[count] = talloc_strdup(mem_ctx, name);
+       if (ptr[count] == NULL) {
+               return;
+       }
+
+       *add_names = ptr;
+       *add_count = count+1;
+}
+
+
+static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
+{
+       if (add_names == NULL) {
+               return;
+       }
+
+       switch (rec->wType) {
+
+       case DNS_TYPE_NS:
+               _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
+               break;
+
+       case DNS_TYPE_CNAME:
+               _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
+               break;
+
+       case DNS_TYPE_SOA:
+               _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
+               break;
+
+       case DNS_TYPE_MX:
+               _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
+               break;
+
+       case DNS_TYPE_SRV:
+               _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
+               break;
+
+       default:
+               break;
+       }
+}
+
+
+WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
+                               struct dnsserver_zone *z,
+                               enum dns_record_type record_type,
+                               unsigned int select_flag,
+                               const char *branch_name,
+                               struct ldb_message *msg,
+                               struct DNS_RPC_RECORDS_ARRAY *recs,
+                               char ***add_names,
+                               int *add_count)
+{
+       const char *nodename;
+       struct ldb_message_element *el;
+       int i, j;
+       bool found, node_is_rootzone;
+
+       /* Check if we already have created record for the branch */
+       found = false;
+       if (branch_name == NULL) {
+               i = 0;
+               if (recs->count > 0) {
+                       found = true;
+               }
+       } else {
+               for (i=0; i<recs->count; i++) {
+                       if (strcmp(branch_name, recs->rec[i].dnsNodeName.str) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+       }
+
+       /* If not, add empty record */
+       if (!found) {
+               if (recs->count == 0) {
+                       recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
+               } else {
+                       recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
+               }
+               if (recs->rec == NULL) {
+                       return WERR_NOMEM;
+               }
+               i = recs->count;
+               recs->rec[i].wLength = 0;
+               recs->rec[i].wRecordCount = 0;
+               recs->rec[i].dwChildCount = 0;
+
+               /* The base records returned with empty name */
+               /* Children records returned with names */
+               if (branch_name == NULL) {
+                       recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
+                       recs->rec[i].dnsNodeName.len = 0;
+               } else {
+                       recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
+                       recs->rec[i].dnsNodeName.len = strlen(branch_name);
+               }
+               recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
+               recs->count++;
+       }
+
+       /* Allow empty records */
+       if (msg == NULL) {
+               return WERR_OK;
+       }
+
+       nodename = ldb_msg_find_attr_as_string(msg, "name", NULL);
+
+       if (strcmp(nodename, "@") == 0) {
+               node_is_rootzone = true;
+       } else {
+               node_is_rootzone = false;
+
+               /* child record */
+               if (branch_name != NULL) {
+                       if (branch_name[strlen(branch_name)-1] != '.'
+                               && strcmp(nodename, branch_name) != 0) {
+                               recs->rec[i].dwChildCount++;
+                               return WERR_OK;
+                       }
+               }
+       }
+
+       el = ldb_msg_find_element(msg, "dnsRecord");
+       if (el == NULL || el->values == 0) {
+               DEBUG(0, ("dnsserver: Missing dnsRecord for %s\n", ldb_dn_get_linearized(msg->dn)));
+               return WERR_OK;
+       }
+
+       /* branch level record */
+       for (j=0; j<el->num_values; j++) {
+               struct dnsp_DnssrvRpcRecord dnsp_rec;
+               struct DNS_RPC_RECORD *dns_rec;
+               enum ndr_err_code ndr_err;
+
+               ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
+                                       (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
+                       return WERR_INTERNAL_DB_ERROR;
+               }
+
+               /* Match the records based on search criteria */
+               if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
+                       found = false;
+
+                       if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
+                               if (dnsp_rec.rank == DNS_RANK_ZONE) {
+                                       found = true;
+                               }
+                       }
+                       if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
+                               if (dnsp_rec.rank == DNS_RANK_ZONE) {
+                                       found = true;
+                               }
+                       }
+                       if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
+                               if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
+                                       found = true;
+                               }
+                       }
+                       if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
+                               if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
+                                       found = true;
+                               }
+                       }
+
+                       if (found) {
+                               recs->rec[i].records = talloc_realloc(recs,
+                                                       recs->rec[i].records,
+                                                       struct DNS_RPC_RECORD,
+                                                       recs->rec[i].wRecordCount+1);
+                               if (recs->rec[i].records == NULL) {
+                                       return WERR_NOMEM;
+                               }
+
+                               dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
+                               dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
+
+                               /* Fix record flags */
+                               if (node_is_rootzone) {
+                                       dns_rec->dwFlags |= (DNS_RPC_FLAG_ZONE_ROOT | DNS_RPC_FLAG_AUTH_ZONE_ROOT);
+                               }
+
+                               if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
+                                       dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
+                               }
+
+                               recs->rec[i].wRecordCount++;
+
+                               dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
+                       }
+               }
+       }
+
+       return WERR_OK;
+}
+
+
+int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
+                               char *search_name)
+{
+       const char *name1, *name2;
+       const char *ptr1, *ptr2;
+
+       name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
+       name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
+       if (name1 == NULL || name2 == NULL) {
+               return 0;
+       }
+
+       /* '@' record and the search_name record gets preference */
+       if (name1[0] == '@') {
+               return -1;
+       }
+       if (search_name && strcmp(name1, search_name) == 0) {
+               return -1;
+       }
+
+       if (name2[0] == '@') {
+               return 1;
+       }
+       if (search_name && strcmp(name2, search_name) == 0) {
+               return 1;
+       }
+
+       ptr1 = strrchr(name1, '.');
+       if (ptr1 == NULL) {
+               ptr1 = name1;
+       } else {
+               ptr1 = &ptr1[1];
+       }
+
+       ptr2 = strrchr(name2, '.');
+       if (ptr2 == NULL) {
+               ptr2 = name2;
+       } else {
+               ptr2 = &ptr2[1];
+       }
+
+       return strcasecmp(ptr1, ptr2);
+}
+
+
+bool dns_name_equal(const char *name1, const char *name2)
+{
+       size_t len1 = strlen(name1);
+       size_t len2 = strlen(name2);
+
+       if (name1[len1-1] == '.') len1--;
+       if (name2[len2-1] == '.') len2--;
+       if (len1 != len2) {
+               return false;
+       }
+       return strncasecmp(name1, name2, len1) == 0;
+}
+
+
+bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
+{
+       if (rec1->wType != rec2->wType) {
+               return false;
+       }
+
+       switch(rec1->wType) {
+       case DNS_TYPE_TOMBSTONE:
+               return true;
+
+       case DNS_TYPE_A:
+               return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
+
+       case DNS_TYPE_NS:
+               return dns_name_equal(rec1->data.ns, rec1->data.ns);
+
+       case DNS_TYPE_CNAME:
+               return dns_name_equal(rec1->data.cname, rec1->data.cname);
+
+       case DNS_TYPE_SOA:
+               return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) == 0 &&
+                       dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) == 0 &&
+                       rec1->data.soa.serial == rec2->data.soa.serial &&
+                       rec1->data.soa.refresh == rec2->data.soa.refresh &&
+                       rec1->data.soa.retry == rec2->data.soa.retry &&
+                       rec1->data.soa.expire == rec2->data.soa.expire &&
+                       rec1->data.soa.minimum == rec2->data.soa.minimum;
+
+       case DNS_TYPE_PTR:
+               return strcmp(rec1->data.ptr, rec2->data.ptr) == 0;
+
+       case DNS_TYPE_MX:
+               return rec1->data.mx.wPriority == rec2->data.srv.wPriority &&
+                       dns_name_equal(rec1->data.mx.nameTarget, rec2->data.srv.nameTarget);
+
+       case DNS_TYPE_TXT:
+               return strcmp(rec1->data.txt, rec2->data.txt) == 0;
+
+       case DNS_TYPE_AAAA:
+               return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
+
+       case DNS_TYPE_SRV:
+               return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
+                       rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
+                       rec1->data.srv.wPort == rec2->data.srv.wPort &&
+                       dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
+
+       default:
+               DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
+               break;
+       }
+
+       return false;
+}
diff --git a/source4/rpc_server/dnsserver/dnsdb.c b/source4/rpc_server/dnsserver/dnsdb.c
new file mode 100644 (file)
index 0000000..ac88190
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   DNS Server
+
+   Copyright (C) Amitay Isaacs 2011
+
+   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 "dnsserver.h"
+#include "lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+
+struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
+                                               struct ldb_context *samdb,
+                                               bool is_forest)
+{
+       TALLOC_CTX *tmp_ctx;
+       const char *domain_prefix = "DC=DomainDnsZones";
+       const char *forest_prefix = "DC=ForestDnsZones";
+       const char *prefix;
+       const char * const attrs[] = {"name", NULL};
+       struct ldb_dn *dn_base, *partition_dn, *dn;
+       struct ldb_result *res;
+       struct dnsserver_zone *zones, *z;
+       int i, ret;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (tmp_ctx == NULL) {
+               return NULL;
+       }
+
+       if (is_forest) {
+               dn_base = ldb_get_root_basedn(samdb);
+       } else {
+               dn_base = ldb_get_default_basedn(samdb);
+       }
+
+       partition_dn = ldb_dn_copy(tmp_ctx, dn_base);
+       if (partition_dn == NULL) {
+               goto failed;
+       }
+
+       if (is_forest) {
+               prefix = forest_prefix;
+       } else {
+               prefix = domain_prefix;
+       }
+
+       if (!ldb_dn_add_child_fmt(partition_dn, "%s", prefix)) {
+               goto failed;
+       }
+
+       dn = ldb_dn_copy(tmp_ctx, partition_dn);
+       if (dn == NULL) {
+               goto failed;
+       }
+       if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
+               goto failed;
+       }
+
+       ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
+                         attrs, "(&(objectClass=dnsZone)(!(name=RootDNSServers)))");
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
+                       ldb_dn_get_linearized(dn)));
+               goto failed;
+       }
+
+       zones = NULL;
+       for(i=0; i<res->count; i++) {
+               z = talloc_zero(mem_ctx, struct dnsserver_zone);
+               if (z == NULL) {
+                       goto failed;
+               }
+
+               z->name = talloc_strdup(z,
+                               ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL));
+               DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
+               z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
+               z->partition_dn = talloc_steal(z, partition_dn);
+
+               DLIST_ADD_END(zones, z, NULL);
+       }
+
+       return zones;
+
+failed:
+       talloc_free(tmp_ctx);
+       return NULL;
+}
+
+
+static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
+                               struct ldb_context *samdb,
+                               struct ldb_dn *dn,
+                               struct dnsp_DnssrvRpcRecord *rec)
+{
+       struct ldb_message *msg;
+       struct ldb_val v;
+       int ret;
+       enum ndr_err_code ndr_err;
+
+       msg = ldb_msg_new(mem_ctx);
+       W_ERROR_HAVE_NO_MEMORY(msg);
+
+       msg->dn = dn;
+       ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
+       if (ret != LDB_SUCCESS) {
+               return WERR_NOMEM;
+       }
+
+       if (rec) {
+               ndr_err = ndr_push_struct_blob(&v, mem_ctx, rec,
+                               (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_GENERAL_FAILURE;
+               }
+
+               ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
+               if (ret != LDB_SUCCESS) {
+                       return WERR_NOMEM;
+               }
+       }
+
+       ret = ldb_add(samdb, msg);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       return WERR_OK;
+}
+
+
+WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *name)
+{
+       const char * const attrs[] = { "name", NULL };
+       struct ldb_result *res;
+       struct ldb_dn *dn;
+       int ret;
+
+       ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
+                       "(&(objectClass=dnsNode)(name=%s))", name);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       if (res->count > 0) {
+               talloc_free(res);
+               return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
+       }
+
+       dn = ldb_dn_copy(mem_ctx, z->zone_dn);
+       W_ERROR_HAVE_NO_MEMORY(dn);
+
+       if (!ldb_dn_add_child_fmt(dn, "DC=%s", name)) {
+               return WERR_NOMEM;
+       }
+
+       return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, NULL);
+}
+
+
+WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *name,
+                                       struct DNS_RPC_RECORD *add_record)
+{
+       const char * const attrs[] = { "dnsRecord", NULL };
+       struct ldb_result *res;
+       struct dnsp_DnssrvRpcRecord *rec;
+       struct ldb_message_element *el;
+       struct ldb_dn *dn;
+       enum ndr_err_code ndr_err;
+       NTTIME t;
+       int ret, i;
+
+       rec = dns_to_dnsp_copy(mem_ctx, add_record);
+       W_ERROR_HAVE_NO_MEMORY(rec);
+
+       unix_to_nt_time(&t, time(NULL));
+       t /= 10*1000*1000;
+
+       rec->dwSerial = 0; /* FIXME: put soa serial value */
+       rec->dwTimeStamp = t;
+
+       ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+                       "(&(objectClass=dnsNode)(name=%s))", name);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       if (res->count == 0) {
+               dn = dnsserver_name_to_dn(mem_ctx, z, name);
+               W_ERROR_HAVE_NO_MEMORY(dn);
+
+               return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, rec);
+       }
+
+       el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
+       if (el == NULL) {
+               ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
+               if (ret != LDB_SUCCESS) {
+                       return WERR_NOMEM;
+               }
+       }
+
+       for (i=0; i<el->num_values; i++) {
+               struct dnsp_DnssrvRpcRecord rec2;
+
+               ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
+                                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_GENERAL_FAILURE;
+               }
+
+               if (dns_record_match(rec, &rec2)) {
+                       break;
+               }
+       }
+       if (i < el->num_values) {
+               return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
+       }
+       if (i == el->num_values) {
+               /* adding a new value */
+               el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
+               W_ERROR_HAVE_NO_MEMORY(el->values);
+               el->num_values++;
+       }
+
+       ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
+                                       (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return WERR_GENERAL_FAILURE;
+       }
+
+       el->flags = LDB_FLAG_MOD_REPLACE;
+       ret = ldb_modify(samdb, res->msgs[0]);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       return WERR_OK;
+}
+
+WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *name,
+                                       struct DNS_RPC_RECORD *add_record,
+                                       struct DNS_RPC_RECORD *del_record)
+{
+       const char * const attrs[] = { "dnsRecord", NULL };
+       struct ldb_result *res;
+       struct dnsp_DnssrvRpcRecord *arec, *drec;
+       struct ldb_message_element *el;
+       enum ndr_err_code ndr_err;
+       NTTIME t;
+       int ret, i;
+
+       arec = dns_to_dnsp_copy(mem_ctx, add_record);
+       W_ERROR_HAVE_NO_MEMORY(arec);
+
+       drec = dns_to_dnsp_copy(mem_ctx, del_record);
+       W_ERROR_HAVE_NO_MEMORY(drec);
+
+       unix_to_nt_time(&t, time(NULL));
+       t /= 10*1000*1000;
+
+       arec->dwSerial = 0; /* FIXME: put soa serial value */
+       arec->dwTimeStamp = t;
+
+       ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+                       "(&(objectClass=dnsNode)(name=%s))", name);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       if (res->count == 0) {
+               return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+       }
+
+       el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
+       if (el == NULL || el->num_values == 0) {
+               return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+       }
+
+       for (i=0; i<el->num_values; i++) {
+               struct dnsp_DnssrvRpcRecord rec2;
+
+               ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
+                                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_GENERAL_FAILURE;
+               }
+
+               if (dns_record_match(arec, &rec2)) {
+                       break;
+               }
+       }
+       if (i < el->num_values) {
+               return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
+       }
+
+
+       for (i=0; i<el->num_values; i++) {
+               struct dnsp_DnssrvRpcRecord rec2;
+
+               ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
+                                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_GENERAL_FAILURE;
+               }
+
+               if (dns_record_match(drec, &rec2)) {
+                       break;
+               }
+       }
+       if (i == el->num_values) {
+               return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+       }
+
+       ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
+                                       (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return WERR_GENERAL_FAILURE;
+       }
+
+       el->flags = LDB_FLAG_MOD_REPLACE;
+       ret = ldb_modify(samdb, res->msgs[0]);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       return WERR_OK;
+}
+
+WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *name,
+                                       struct DNS_RPC_RECORD *del_record)
+{
+       const char * const attrs[] = { "dnsRecord", NULL };
+       struct ldb_result *res;
+       struct dnsp_DnssrvRpcRecord *rec;
+       struct ldb_message_element *el;
+       enum ndr_err_code ndr_err;
+       int ret, i;
+
+       rec = dns_to_dnsp_copy(mem_ctx, del_record);
+       W_ERROR_HAVE_NO_MEMORY(rec);
+
+       ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+                       "(&(objectClass=dnsNode)(name=%s))", name);
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       if (res->count == 0) {
+               return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+       }
+
+       el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
+       if (el == NULL || el->num_values == 0) {
+               return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+       }
+
+       for (i=0; i<el->num_values; i++) {
+               struct dnsp_DnssrvRpcRecord rec2;
+
+               ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
+                                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return WERR_GENERAL_FAILURE;
+               }
+
+               if (dns_record_match(rec, &rec2)) {
+                       break;
+               }
+       }
+       if (i == el->num_values) {
+               return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+       }
+       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 (el->num_values == 0) {
+               ret = ldb_delete(samdb, res->msgs[0]->dn);
+       } else {
+               el->flags = LDB_FLAG_MOD_REPLACE;
+               ret = ldb_modify(samdb, res->msgs[0]);
+       }
+       if (ret != LDB_SUCCESS) {
+               return WERR_INTERNAL_DB_ERROR;
+       }
+
+       return WERR_OK;
+}
diff --git a/source4/rpc_server/dnsserver/dnsserver.h b/source4/rpc_server/dnsserver/dnsserver.h
new file mode 100644 (file)
index 0000000..5fc13c8
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   DNS Server
+
+   Copyright (C) Amitay Isaacs 2011
+
+   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/>.
+*/
+
+#ifndef __DNSSERVER_H__
+#define __DNSSERVER_H__
+
+#include "librpc/gen_ndr/dnsp.h"
+#include "librpc/gen_ndr/dnsserver.h"
+#include "param/param.h"
+#include "ldb.h"
+
+struct dnsserver_serverinfo {
+       uint32_t        dwVersion;
+       uint8_t         fBootMethod;
+       uint8_t         fAdminConfigured;
+       uint8_t         fAllowUpdate;
+       uint8_t         fDsAvailable;
+
+       char *          pszServerName;
+       char *          pszDsContainer;
+
+       uint32_t        dwDsForestVersion;
+       uint32_t        dwDsDomainVersion;
+       uint32_t        dwDsDsaVersion;
+       uint32_t        fReadOnlyDC;
+       char *          pszDomainName;
+       char *          pszForestName;
+       char *          pszDomainDirectoryPartition;
+       char *          pszForestDirectoryPartition;
+
+       struct IP4_ARRAY * aipServerAddrs;
+       struct IP4_ARRAY * aipListenAddrs;
+       struct IP4_ARRAY * aipForwarders;
+
+       struct IP4_ARRAY * aipLogFilter;
+       char *          pwszLogFilePath;
+
+       uint32_t        dwLogLevel;
+       uint32_t        dwDebugLevel;
+       uint32_t        dwEventLogLevel;
+       uint32_t        dwLogFileMaxSize;
+
+       uint32_t        dwForwardTimeout;
+       uint32_t        dwRpcProtocol;
+       uint32_t        dwNameCheckFlag;
+       uint32_t        cAddressAnswerLimit;
+       uint32_t        dwRecursionRetry;
+       uint32_t        dwRecursionTimeout;
+       uint32_t        dwMaxCacheTtl;
+       uint32_t        dwDsPollingInterval;
+       uint32_t        dwLocalNetPriorityNetMask;
+
+       uint32_t        dwScavengingInterval;
+       uint32_t        dwDefaultRefreshInterval;
+       uint32_t        dwDefaultNoRefreshInterval;
+       uint32_t        dwLastScavengeTime;
+
+       uint8_t         fAutoReverseZones;
+       uint8_t         fAutoCacheUpdate;
+
+       uint8_t         fRecurseAfterForwarding;
+       uint8_t         fForwardDelegations;
+       uint8_t         fNoRecursion;
+       uint8_t         fSecureResponses;
+
+       uint8_t         fRoundRobin;
+       uint8_t         fLocalNetPriority;
+
+       uint8_t         fBindSecondaries;
+       uint8_t         fWriteAuthorityNs;
+
+       uint8_t         fStrictFileParsing;
+       uint8_t         fLooseWildcarding;
+       uint8_t         fDefaultAgingState;
+};
+
+struct dnsserver_zoneinfo {
+       uint8_t         Version;
+       uint32_t        Flags;
+       uint8_t         dwZoneType;
+       uint8_t         fReverse;
+       uint8_t         fAllowUpdate;
+       uint8_t         fPaused;
+       uint8_t         fShutdown;
+       uint8_t         fAutoCreated;
+
+       uint8_t         fUseDatabase;
+       char *          pszDataFile;
+
+       struct IP4_ARRAY * aipMasters;
+
+       uint32_t        fSecureSecondaries;
+       uint32_t        fNotifyLevel;
+       struct IP4_ARRAY * aipSecondaries;
+       struct IP4_ARRAY * aipNotify;
+
+       uint32_t        fUseWins;
+       uint32_t        fUseNbstat;
+
+       uint32_t        fAging;
+       uint32_t        dwNoRefreshInterval;
+       uint32_t        dwRefreshInterval;
+       uint32_t        dwAvailForScavengeTime;
+       struct IP4_ARRAY * aipScavengeServers;
+
+       uint32_t        dwForwarderTimeout;
+       uint32_t        fForwarderSlave;
+
+       struct IP4_ARRAY * aipLocalMasters;
+
+       uint32_t        dwDpFlags;
+       char *          pszDpFqdn;
+       char *          pwszZoneDn;
+
+       uint32_t        dwLastSuccessfulSoaCheck;
+       uint32_t        dwLastSuccessfulXfr;
+
+       uint32_t        fQueuedForBackgroundLoad;
+       uint32_t        fBackgroundLoadInProgress;
+       uint8_t         fReadOnlyZone;
+
+       uint32_t        dwLastXfrAttempt;
+       uint32_t        dwLastXfrResult;
+};
+
+
+struct dnsserver_zone {
+       struct dnsserver_zone *prev, *next;
+       const char *name;
+       struct ldb_dn *partition_dn;
+       struct ldb_dn *zone_dn;
+       struct dnsserver_zoneinfo *zoneinfo;
+};
+
+
+/* Data structure manipulation functions from dnsdata.c */
+
+struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4);
+struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4);
+struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx, struct DNS_ADDR_ARRAY *addr);
+
+int dns_split_name_components(TALLOC_CTX *mem_ctx, const char *name, char ***components);
+char *dns_split_node_name(TALLOC_CTX *mem_ctx, const char *node_name, const char *zone_name);
+
+int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
+                       char *search_name);
+bool dns_name_equal(const char *name1, const char *name2);
+bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2);
+
+void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
+                       struct DNS_RPC_RECORD *dns);
+struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns);
+
+WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx, struct dnsserver_zone *z,
+                       enum dns_record_type record_type,
+                       unsigned int select_flag, const char *zone_name,
+                       struct ldb_message *msg, struct DNS_RPC_RECORDS_ARRAY *recs,
+                       char ***add_names, int *add_count);
+
+
+/* Utility functions from dnsutils.c */
+
+struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx,
+                                       struct loadparm_context *lp_ctx,
+                                       struct ldb_context *samdb);
+struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone,
+                                       struct dnsserver_serverinfo *serverinfo,
+                                       bool is_forest);
+struct dnsserver_zone *dnsserver_find_zone(struct dnsserver_zone *zones,
+                                       const char *zone_name);
+struct ldb_dn *dnsserver_name_to_dn(TALLOC_CTX *mem_ctx, struct dnsserver_zone *z,
+                                       const char *name);
+uint32_t dnsserver_zone_to_request_filter(const char *zone);
+
+
+/* Database functions from dnsdb.c */
+
+struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       bool is_forest);
+WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *node_name);
+WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *node_name,
+                                       struct DNS_RPC_RECORD *add_record);
+WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *node_name,
+                                       struct DNS_RPC_RECORD *add_record,
+                                       struct DNS_RPC_RECORD *del_record);
+WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
+                                       struct ldb_context *samdb,
+                                       struct dnsserver_zone *z,
+                                       const char *node_name,
+                                       struct DNS_RPC_RECORD *del_record);
+
+#endif /* __DNSSERVER_H__ */
diff --git a/source4/rpc_server/dnsserver/dnsutils.c b/source4/rpc_server/dnsserver/dnsutils.c
new file mode 100644 (file)
index 0000000..5449826
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   DNS Server
+
+   Copyright (C) Amitay Isaacs 2011
+
+   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 "dnsserver.h"
+#include "rpc_server/common/common.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/socket/netif.h"
+
+
+struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx,
+                                                       struct loadparm_context *lp_ctx,
+                                                       struct ldb_context *samdb)
+{
+       struct dnsserver_serverinfo *serverinfo;
+       struct dcerpc_server_info *dinfo;
+       struct ldb_dn *domain_dn, *forest_dn;
+       struct interface *ifaces;
+       int num_interfaces, i;
+
+       serverinfo = talloc_zero(mem_ctx, struct dnsserver_serverinfo);
+       if (serverinfo == NULL) {
+               return NULL;
+       }
+
+       dinfo = lpcfg_dcerpc_server_info(mem_ctx, lp_ctx);
+       if (dinfo) {
+               serverinfo->dwVersion = (dinfo->version_build & 0x0000FFFF) << 16 |
+                               (dinfo->version_minor & 0x000000FF) << 8 |
+                               (dinfo->version_major & 0x000000FF);
+               talloc_free(dinfo);
+       } else {
+               serverinfo->dwVersion = 0x0ECE0205; /* build, os_minor, os_major */;
+       }
+
+       serverinfo->fBootMethod = DNS_BOOT_METHOD_DIRECTORY;
+       serverinfo->fAdminConfigured = 0;
+       serverinfo->fAllowUpdate = 1;
+       serverinfo->fDsAvailable = 1;
+
+       serverinfo->pszServerName = talloc_asprintf(mem_ctx, "%s.%s",
+                                       lpcfg_netbios_name(lp_ctx),
+                                       lpcfg_dnsdomain(lp_ctx));
+
+       domain_dn = ldb_get_default_basedn(samdb);
+       forest_dn = ldb_get_root_basedn(samdb);
+
+       serverinfo->pszDsContainer = talloc_asprintf(mem_ctx,
+                                       "CN=MicrosoftDNS,DC=DomainDnsZones,%s",
+                                       ldb_dn_get_linearized(domain_dn));
+
+       serverinfo->dwDsForestVersion = dsdb_forest_functional_level(samdb);
+       serverinfo->dwDsDomainVersion = dsdb_functional_level(samdb);
+       serverinfo->dwDsDsaVersion = 4; /* need to do ldb search here */
+
+       serverinfo->pszDomainName = samdb_dn_to_dns_domain(mem_ctx, domain_dn);
+       serverinfo->pszForestName = samdb_dn_to_dns_domain(mem_ctx, forest_dn);
+
+       serverinfo->pszDomainDirectoryPartition = talloc_asprintf(mem_ctx,
+                                                       "DC=DomainDnsZones,%s",
+                                                       ldb_dn_get_linearized(domain_dn));
+       serverinfo->pszForestDirectoryPartition = talloc_asprintf(mem_ctx,
+                                                       "DC=ForestDnsZones,%s",
+                                                       ldb_dn_get_linearized(forest_dn));
+
+       load_interface_list(mem_ctx, lp_ctx, &ifaces);
+       num_interfaces = iface_list_count(ifaces);
+
+       serverinfo->aipServerAddrs = talloc_zero(mem_ctx, struct IP4_ARRAY);
+
+       if (serverinfo->aipServerAddrs) {
+               serverinfo->aipServerAddrs->AddrCount = num_interfaces;
+               if (num_interfaces > 0) {
+                       serverinfo->aipServerAddrs->AddrArray = talloc_zero_array(mem_ctx,
+                                                                       unsigned int,
+                                                                       num_interfaces);
+                       if (serverinfo->aipServerAddrs->AddrArray) {
+                               for (i=0; i<num_interfaces; i++) {
+                                       serverinfo->aipServerAddrs->AddrArray[i] = inet_addr(iface_list_n_ip(ifaces, i));
+                               }
+                       } else {
+                               serverinfo->aipServerAddrs->AddrCount = 0;
+                       }
+               }
+       }
+       talloc_free(ifaces);
+
+       /* Assume listen addresses are same as server addresses */
+       serverinfo->aipListenAddrs = serverinfo->aipServerAddrs;
+
+       serverinfo->aipForwarders = NULL;
+
+       serverinfo->aipLogFilter = NULL;
+       serverinfo->pwszLogFilePath = NULL;
+
+       serverinfo->dwLogLevel = 0;
+       serverinfo->dwDebugLevel = 0;
+       serverinfo->dwEventLogLevel = DNS_EVENT_LOG_INFORMATION_TYPE;
+       serverinfo->dwLogFileMaxSize = 0;
+
+       serverinfo->dwForwardTimeout = 3; /* seconds (default) */
+       serverinfo->dwRpcProtocol = 5;
+       serverinfo->dwNameCheckFlag = DNS_ALLOW_MULTIBYTE_NAMES;
+       serverinfo->cAddressAnswerLimit = 0;
+       serverinfo->dwRecursionRetry = 3 /* seconds (default) */;
+       serverinfo->dwRecursionTimeout = 8 /* seconds (default) */;
+       serverinfo->dwMaxCacheTtl = 0x00015180; /* 1 day (default) */;
+       serverinfo->dwDsPollingInterval = 0xB4; /* 3 minutes (default) */;
+       serverinfo->dwLocalNetPriorityNetMask = 0x000000FF;;
+
+       serverinfo->dwScavengingInterval = 0;
+       serverinfo->dwDefaultRefreshInterval = 0xA8; /* 7 days in hours */;
+       serverinfo->dwDefaultNoRefreshInterval = 0xA8; /* 7 days in hours */;;
+       serverinfo->dwLastScavengeTime = 0;
+
+       serverinfo->fAutoReverseZones = 0;
+       serverinfo->fAutoCacheUpdate = 0;
+
+       serverinfo->fRecurseAfterForwarding = 0;
+       serverinfo->fForwardDelegations = 1;
+       serverinfo->fNoRecursion = 0;
+       serverinfo->fSecureResponses = 0;
+
+       serverinfo->fRoundRobin = 1;
+       serverinfo->fLocalNetPriority = 0;
+
+       serverinfo->fBindSecondaries = 0;
+       serverinfo->fWriteAuthorityNs = 0;
+
+       serverinfo->fStrictFileParsing = 0;
+       serverinfo->fLooseWildcarding = 0 ;
+       serverinfo->fDefaultAgingState = 0;
+
+       return serverinfo;
+}
+
+
+struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone,
+                                               struct dnsserver_serverinfo *serverinfo,
+                                               bool is_forest)
+{
+       struct dnsserver_zoneinfo *zoneinfo;
+       uint32_t dp_flags;
+
+       zoneinfo = talloc_zero(zone, struct dnsserver_zoneinfo);
+       if (zoneinfo == NULL) {
+               return NULL;
+       }
+
+       dp_flags = DNS_DP_ENLISTED;
+       if (is_forest) {
+               dp_flags |= DNS_DP_FOREST_DEFAULT;
+       } else {
+               dp_flags |= DNS_DP_DOMAIN_DEFAULT;
+       }
+
+       zoneinfo->Version = 0x32;
+       zoneinfo->Flags = DNS_RPC_ZONE_DSINTEGRATED | DNS_RPC_ZONE_UPDATE_SECURE;
+       zoneinfo->dwZoneType = DNS_ZONE_TYPE_PRIMARY;
+       zoneinfo->fReverse = 0; /* We only support forward zones for now */
+       zoneinfo->fAllowUpdate = DNS_ZONE_UPDATE_SECURE;
+       zoneinfo->fPaused = 0;
+       zoneinfo->fShutdown = 0;
+       zoneinfo->fAutoCreated = 0;
+       zoneinfo->fUseDatabase = 1;
+       zoneinfo->pszDataFile = NULL;
+       zoneinfo->aipMasters = NULL;
+       zoneinfo->fSecureSecondaries = DNS_ZONE_SECSECURE_NO_XFER;
+       zoneinfo->fNotifyLevel = DNS_ZONE_NOTIFY_LIST_ONLY;
+       zoneinfo->aipSecondaries = NULL;
+       zoneinfo->aipNotify = NULL;
+       zoneinfo->fUseWins = 0;
+       zoneinfo->fUseNbstat = 0;
+       zoneinfo->fAging = 0;
+       zoneinfo->dwNoRefreshInterval = serverinfo->dwDefaultNoRefreshInterval;
+       zoneinfo->dwRefreshInterval = serverinfo->dwDefaultRefreshInterval;
+       zoneinfo->dwAvailForScavengeTime = 0;
+       zoneinfo->aipScavengeServers = NULL;
+       zoneinfo->dwForwarderTimeout = 0;
+       zoneinfo->fForwarderSlave = 0;
+       zoneinfo->aipLocalMasters = NULL;
+       zoneinfo->dwDpFlags = dp_flags;
+       zoneinfo->pszDpFqdn = samdb_dn_to_dns_domain(zone, zone->partition_dn);
+       zoneinfo->pwszZoneDn = discard_const_p(char, ldb_dn_get_linearized(zone->zone_dn));
+       zoneinfo->dwLastSuccessfulSoaCheck = 0;
+       zoneinfo->dwLastSuccessfulXfr = 0;
+       zoneinfo->fQueuedForBackgroundLoad = 0;
+       zoneinfo->fBackgroundLoadInProgress = 0;
+       zoneinfo->fReadOnlyZone = 0;
+       zoneinfo->dwLastXfrAttempt = 0;
+       zoneinfo->dwLastXfrResult = 0;
+
+       return zoneinfo;
+}
+
+struct dnsserver_zone *dnsserver_find_zone(struct dnsserver_zone *zones, const char *zone_name)
+{
+       struct dnsserver_zone *z = NULL;
+
+       for (z = zones; z; z = z->next) {
+               if (strcmp(zone_name, z->name) == 0) {
+                       break;
+               }
+       }
+
+       return z;
+}
+
+struct ldb_dn *dnsserver_name_to_dn(TALLOC_CTX *mem_ctx, struct dnsserver_zone *z, const char *name)
+{
+       struct ldb_dn *dn;
+       bool ret;
+
+       dn = ldb_dn_copy(mem_ctx, z->zone_dn);
+       if (dn == NULL) {
+               return NULL;
+       }
+       if (strcmp(name, z->name) == 0) {
+               ret = ldb_dn_add_child_fmt(dn, "DC=@");
+       } else {
+               ret = ldb_dn_add_child_fmt(dn, "DC=%s", name);
+       }
+       if (!ret) {
+               talloc_free(dn);
+               return NULL;
+       }
+
+       return dn;
+}
+
+uint32_t dnsserver_zone_to_request_filter(const char *zone_name)
+{
+       uint32_t request_filter;
+
+       if (strcmp(zone_name, "..AllZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_PRIMARY
+                       | DNS_ZONE_REQUEST_SECONDARY
+                       | DNS_ZONE_REQUEST_AUTO
+                       | DNS_ZONE_REQUEST_FORWARD
+                       | DNS_ZONE_REQUEST_REVERSE
+                       | DNS_ZONE_REQUEST_FORWARDER
+                       | DNS_ZONE_REQUEST_STUB
+                       | DNS_ZONE_REQUEST_DS
+                       | DNS_ZONE_REQUEST_NON_DS
+                       | DNS_ZONE_REQUEST_DOMAIN_DP
+                       | DNS_ZONE_REQUEST_FOREST_DP
+                       | DNS_ZONE_REQUEST_CUSTOM_DP
+                       | DNS_ZONE_REQUEST_LEGACY_DP;
+       } else if (strcmp(zone_name, "..AllZonesAndCache") == 0) {
+               request_filter = DNS_ZONE_REQUEST_PRIMARY
+                       | DNS_ZONE_REQUEST_SECONDARY
+                       | DNS_ZONE_REQUEST_CACHE
+                       | DNS_ZONE_REQUEST_AUTO
+                       | DNS_ZONE_REQUEST_FORWARD
+                       | DNS_ZONE_REQUEST_REVERSE
+                       | DNS_ZONE_REQUEST_FORWARDER
+                       | DNS_ZONE_REQUEST_STUB
+                       | DNS_ZONE_REQUEST_DS
+                       | DNS_ZONE_REQUEST_NON_DS
+                       | DNS_ZONE_REQUEST_DOMAIN_DP
+                       | DNS_ZONE_REQUEST_FOREST_DP
+                       | DNS_ZONE_REQUEST_CUSTOM_DP
+                       | DNS_ZONE_REQUEST_LEGACY_DP;
+       } else if (strcmp(zone_name, "..AllPrimaryZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_PRIMARY;
+       } else if (strcmp(zone_name, "..AllSecondaryZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_SECONDARY;
+       } else if (strcmp(zone_name, "..AllForwardZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_FORWARD;
+       } else if (strcmp(zone_name, "..AllReverseZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_REVERSE;
+       } else if (strcmp(zone_name, "..AllDsZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_DS;
+       } else if (strcmp(zone_name, "..AllNonDsZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_NON_DS;
+       } else if (strcmp(zone_name, "..AllPrimaryReverseZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_PRIMARY
+                       | DNS_ZONE_REQUEST_REVERSE;
+       } else if (strcmp(zone_name, "..AllPrimaryForwardZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_PRIMARY
+                       | DNS_ZONE_REQUEST_FORWARD;
+       } else if (strcmp(zone_name, "..AllSecondaryReverseZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_SECONDARY
+                       | DNS_ZONE_REQUEST_REVERSE;
+       } else if (strcmp(zone_name, "..AllSecondaryForwardZones") == 0) {
+               request_filter = DNS_ZONE_REQUEST_SECONDARY
+                       | DNS_ZONE_REQUEST_REVERSE;
+       }
+
+       return request_filter;
+}
index 127e396f6ca05f1f17ea348912f5a8d29657bed0..cf6d71227b0e182b3d89bb9bbc0f97d40af92fc0 100755 (executable)
@@ -137,6 +137,13 @@ bld.SAMBA_MODULE('dcerpc_eventlog',
        deps='DCERPC_COMMON'
        )
 
+bld.SAMBA_MODULE('dcerpc_dnsserver',
+    source='dnsserver/dcerpc_dnsserver.c dnsserver/dnsutils.c dnsserver/dnsdata.c dnsserver/dnsdb.c',
+    subsystem='dcerpc_server',
+    init_function='dcerpc_server_dnsserver_init',
+    deps='DCERPC_COMMON'
+    )
+
 bld.SAMBA_LIBRARY('dcerpc_server',
        source='dcerpc_server.c dcesrv_mgmt.c handles.c',
        pc_files='dcerpc_server.pc',