summaryrefslogtreecommitdiffstats
path: root/source4/rpc_server/dnsserver
diff options
context:
space:
mode:
Diffstat (limited to 'source4/rpc_server/dnsserver')
-rw-r--r--source4/rpc_server/dnsserver/dcerpc_dnsserver.c2410
-rw-r--r--source4/rpc_server/dnsserver/dnsdata.c1121
-rw-r--r--source4/rpc_server/dnsserver/dnsdb.c1272
-rw-r--r--source4/rpc_server/dnsserver/dnsserver.h264
-rw-r--r--source4/rpc_server/dnsserver/dnsutils.c414
5 files changed, 5481 insertions, 0 deletions
diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
new file mode 100644
index 0000000..b1c7e2a
--- /dev/null
+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
@@ -0,0 +1,2410 @@
+/*
+ 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 "rpc_server/common/common.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_dnsserver.h"
+#include "dns_server/dnsserver_common.h"
+#include "dnsserver.h"
+
+#undef strcasecmp
+
+#define DCESRV_INTERFACE_DNSSERVER_BIND(context, iface) \
+ dcesrv_interface_dnsserver_bind(context, iface)
+static NTSTATUS dcesrv_interface_dnsserver_bind(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_require_integrity(context, iface);
+}
+
+#define DNSSERVER_STATE_MAGIC 0xc9657ab4
+struct dnsserver_state {
+ struct loadparm_context *lp_ctx;
+ struct ldb_context *samdb;
+ struct dnsserver_partition *partitions;
+ struct dnsserver_zone *zones;
+ int zones_count;
+ struct dnsserver_serverinfo *serverinfo;
+};
+
+
+/* Utility functions */
+
+static void dnsserver_reload_zones(struct dnsserver_state *dsstate)
+{
+ struct dnsserver_partition *p;
+ struct dnsserver_zone *zones, *z, *znext, *zmatch;
+ struct dnsserver_zone *old_list, *new_list;
+
+ old_list = dsstate->zones;
+ new_list = NULL;
+
+ for (p = dsstate->partitions; p; p = p->next) {
+ zones = dnsserver_db_enumerate_zones(dsstate, dsstate->samdb, p);
+ if (zones == NULL) {
+ continue;
+ }
+ for (z = zones; z; ) {
+ znext = z->next;
+ zmatch = dnsserver_find_zone(old_list, z->name);
+ if (zmatch == NULL) {
+ /* Missing zone */
+ z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo);
+ if (z->zoneinfo == NULL) {
+ continue;
+ }
+ DLIST_ADD_END(new_list, z);
+ p->zones_count++;
+ dsstate->zones_count++;
+ } else {
+ /* Existing zone */
+ talloc_free(z);
+ DLIST_REMOVE(old_list, zmatch);
+ DLIST_ADD_END(new_list, zmatch);
+ }
+ z = znext;
+ }
+ }
+
+ if (new_list == NULL) {
+ return;
+ }
+
+ /* Deleted zones */
+ for (z = old_list; z; ) {
+ znext = z->next;
+ z->partition->zones_count--;
+ dsstate->zones_count--;
+ talloc_free(z);
+ z = znext;
+ }
+
+ dsstate->zones = new_list;
+}
+
+
+static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_call)
+{
+ struct dnsserver_state *dsstate;
+ struct dnsserver_zone *zones, *z, *znext;
+ struct dnsserver_partition *partitions, *p;
+ NTSTATUS status;
+
+ dsstate = dcesrv_iface_state_find_conn(dce_call,
+ DNSSERVER_STATE_MAGIC,
+ struct dnsserver_state);
+ if (dsstate != NULL) {
+ return dsstate;
+ }
+
+ dsstate = talloc_zero(dce_call, struct dnsserver_state);
+ if (dsstate == NULL) {
+ return NULL;
+ }
+
+ dsstate->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+
+ dsstate->samdb = dcesrv_samdb_connect_as_user(dsstate, dce_call);
+ if (dsstate->samdb == NULL) {
+ DEBUG(0,("dnsserver: Failed to open samdb\n"));
+ 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 partitions */
+ partitions = dnsserver_db_enumerate_partitions(dsstate, dsstate->serverinfo, dsstate->samdb);
+ if (partitions == NULL) {
+ goto failed;
+ }
+ dsstate->partitions = partitions;
+
+ /* Search for DNS zones */
+ for (p = partitions; p; p = p->next) {
+ zones = dnsserver_db_enumerate_zones(dsstate, dsstate->samdb, p);
+ if (zones == NULL) {
+ goto failed;
+ }
+ for (z = zones; z; ) {
+ znext = z->next;
+ if (dnsserver_find_zone(dsstate->zones, z->name) == NULL) {
+ z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo);
+ if (z->zoneinfo == NULL) {
+ goto failed;
+ }
+ DLIST_ADD_END(dsstate->zones, z);
+ p->zones_count++;
+ dsstate->zones_count++;
+ } else {
+ /* Ignore duplicate zone */
+ DEBUG(3,("dnsserver: Ignoring duplicate zone '%s' from '%s'\n",
+ z->name, ldb_dn_get_linearized(z->zone_dn)));
+ }
+ z = znext;
+ }
+ }
+
+ status = dcesrv_iface_state_store_conn(dce_call,
+ DNSSERVER_STATE_MAGIC,
+ dsstate);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ 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 = NULL;
+ struct DNS_ADDR_ARRAY *answer_addrarray = NULL;
+ char *answer_string = NULL;
+ struct DNS_RPC_UTF8_STRING_LIST *answer_stringlist = NULL;
+ 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 = dns_addr_array_to_ip4_array(mem_ctx,
+ serverinfo->aipServerAddrs);
+ r->ServerInfoW2K->aipListenAddrs = dns_addr_array_to_ip4_array(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 = dns_addr_array_to_ip4_array(mem_ctx,
+ serverinfo->aipServerAddrs);
+ r->ServerInfoDotNet->aipListenAddrs = dns_addr_array_to_ip4_array(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 = serverinfo->aipServerAddrs;
+ r->ServerInfo->aipListenAddrs = 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;
+ answer_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 = serverinfo->aipListenAddrs;
+ } else {
+ answer_iparray = dns_addr_array_to_ip4_array(mem_ctx, serverinfo->aipListenAddrs);
+ }
+ is_addresses = 1;
+ } else if (strcasecmp(operation, "BreakOnReceiveFrom") == 0) {
+ is_addresses = 1;
+ } else if (strcasecmp(operation, "BreakOnUpdateFrom") == 0) {
+ 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) {
+ is_wstring = 1;
+ } else if (strcasecmp(operation, "DsBackgroundPauseName") == 0) {
+ is_string = 1;
+ } else if (strcasecmp(operation, "DsNotRoundRobinTypes") == 0) {
+ 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) {
+ is_stringlist = 1;
+ } else if (strcasecmp(operation, "SocketPoolExcludedPortRanges") == 0) {
+ 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\n", 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 = 0;
+ struct IP4_ARRAY *answer_iparray = NULL;
+ struct DNS_ADDR_ARRAY *answer_addrarray = NULL;
+ char *answer_string = NULL;
+ 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 = z->partition->dwDpFlags;
+ r->Zone->pszDpFqdn = talloc_strdup(mem_ctx, z->partition->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 = z->partition->dwDpFlags;
+ r->ZoneInfoDotNet->pszDpFqdn = talloc_strdup(mem_ctx, z->partition->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 = z->partition->dwDpFlags;
+ r->ZoneInfo->pszDpFqdn = talloc_strdup(mem_ctx, z->partition->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) {
+ 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, z->partition->pszDpFqdn);
+ is_string = 1;
+ } else if (strcasecmp(operation, "BreakOnNameUpdate") == 0) {
+ 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\n", 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) {
+ struct dnsserver_zone *z, *z2;
+ WERROR status;
+ size_t len;
+ const char *name;
+ z = talloc_zero(mem_ctx, struct dnsserver_zone);
+ W_ERROR_HAVE_NO_MEMORY(z);
+ z->partition = talloc_zero(z, struct dnsserver_partition);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(z->partition, z);
+ z->zoneinfo = talloc_zero(z, struct dnsserver_zoneinfo);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(z->zoneinfo, z);
+
+ if (typeid == DNSSRV_TYPEID_ZONE_CREATE_W2K) {
+ name = r->ZoneCreateW2K->pszZoneName;
+ z->zoneinfo->dwZoneType = r->ZoneCreateW2K->dwZoneType;
+ z->zoneinfo->fAllowUpdate = r->ZoneCreateW2K->fAllowUpdate;
+ z->zoneinfo->fAging = r->ZoneCreateW2K->fAging;
+ z->zoneinfo->Flags = r->ZoneCreateW2K->dwFlags;
+ } else if (typeid == DNSSRV_TYPEID_ZONE_CREATE_DOTNET) {
+ name = r->ZoneCreateDotNet->pszZoneName;
+ z->zoneinfo->dwZoneType = r->ZoneCreateDotNet->dwZoneType;
+ z->zoneinfo->fAllowUpdate = r->ZoneCreateDotNet->fAllowUpdate;
+ z->zoneinfo->fAging = r->ZoneCreateDotNet->fAging;
+ z->zoneinfo->Flags = r->ZoneCreateDotNet->dwFlags;
+ z->partition->dwDpFlags = r->ZoneCreateDotNet->dwDpFlags;
+ } else if (typeid == DNSSRV_TYPEID_ZONE_CREATE) {
+ name = r->ZoneCreate->pszZoneName;
+ z->zoneinfo->dwZoneType = r->ZoneCreate->dwZoneType;
+ z->zoneinfo->fAllowUpdate = r->ZoneCreate->fAllowUpdate;
+ z->zoneinfo->fAging = r->ZoneCreate->fAging;
+ z->zoneinfo->Flags = r->ZoneCreate->dwFlags;
+ z->partition->dwDpFlags = r->ZoneCreate->dwDpFlags;
+ } else {
+ talloc_free(z);
+ return WERR_DNS_ERROR_INVALID_PROPERTY;
+ }
+
+ len = strlen(name);
+ if (name[len-1] == '.') {
+ len -= 1;
+ }
+ z->name = talloc_strndup(z, name, len);
+ if (z->name == NULL) {
+ talloc_free(z);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ z2 = dnsserver_find_zone(dsstate->zones, z->name);
+ if (z2 != NULL) {
+ talloc_free(z);
+ return WERR_DNS_ERROR_ZONE_ALREADY_EXISTS;
+ }
+
+ status = dnsserver_db_create_zone(dsstate->samdb, dsstate->partitions, z,
+ dsstate->lp_ctx);
+ talloc_free(z);
+
+ if (W_ERROR_IS_OK(status)) {
+ dnsserver_reload_zones(dsstate);
+ }
+ return status;
+ } 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\n", operation));
+ return WERR_CALL_NOT_IMPLEMENTED;
+ }
+
+ DEBUG(0, ("dnsserver: invalid server operation '%s'\n", 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, **zlist;
+ size_t zcount;
+ bool found1, found2, found3, found4;
+ size_t 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;
+ }
+
+ zcount = 0;
+ zlist = talloc_zero_array(mem_ctx, struct dnsserver_zone *, 0);
+ for (z = dsstate->zones; z; z = z->next) {
+
+ /* Match the flags in groups
+ *
+ * Group1 : PRIMARY, SECONDARY, CACHE, AUTO
+ * Group2 : FORWARD, REVERSE, FORWARDER, STUB
+ * Group3 : DS, NON_DS, DOMAIN_DP, FOREST_DP
+ * Group4 : CUSTOM_DP, LEGACY_DP
+ */
+
+ /* Group 1 */
+ found1 = false;
+ if (rin->Dword & 0x0000000f) {
+ if (rin->Dword & DNS_ZONE_REQUEST_PRIMARY) {
+ if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
+ found1 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_SECONDARY) {
+ if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_SECONDARY) {
+ found1 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_CACHE) {
+ if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_CACHE) {
+ found1 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_AUTO) {
+ if (z->zoneinfo->fAutoCreated
+ || z->partition->dwDpFlags & DNS_DP_AUTOCREATED) {
+ found1 = true;
+ }
+ }
+ } else {
+ found1 = true;
+ }
+
+ /* Group 2 */
+ found2 = false;
+ if (rin->Dword & 0x000000f0) {
+ if (rin->Dword & DNS_ZONE_REQUEST_FORWARD) {
+ if (!(z->zoneinfo->fReverse)) {
+ found2 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_REVERSE) {
+ if (z->zoneinfo->fReverse) {
+ found2 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_FORWARDER) {
+ if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_FORWARDER) {
+ found2 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_STUB) {
+ if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_STUB) {
+ found2 = true;
+ }
+ }
+ } else {
+ found2 = true;
+ }
+
+ /* Group 3 */
+ found3 = false;
+ if (rin->Dword & 0x00000f00) {
+ if (rin->Dword & DNS_ZONE_REQUEST_DS) {
+ if (z->zoneinfo->Flags & DNS_RPC_ZONE_DSINTEGRATED) {
+ found3 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_NON_DS) {
+ if (!(z->zoneinfo->Flags & DNS_RPC_ZONE_DSINTEGRATED)) {
+ found3 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_DOMAIN_DP) {
+ if (!(z->partition->dwDpFlags & DNS_DP_DOMAIN_DEFAULT)) {
+ found3 = true;
+ }
+ }
+ if (rin->Dword & DNS_ZONE_REQUEST_FOREST_DP) {
+ if (!(z->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT)) {
+ found3 = true;
+ }
+ }
+ } else {
+ found3 = true;
+ }
+
+ /* Group 4 */
+ if (rin->Dword & 0x0000f000) {
+ found4 = false;
+ } else {
+ found4 = true;
+ }
+
+ if (found1 && found2 && found3 && found4) {
+ zlist = talloc_realloc(mem_ctx, zlist, struct dnsserver_zone *, zcount+1);
+ zlist[zcount] = z;
+ zcount++;
+ }
+ }
+
+ 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 (zcount == 0) {
+ rout->ZoneListW2K->dwZoneCount = 0;
+ rout->ZoneListW2K->ZoneArray = NULL;
+
+ return WERR_OK;
+ }
+
+ rout->ZoneListW2K->ZoneArray = talloc_zero_array(mem_ctx, struct DNS_RPC_ZONE_W2K *, zcount);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(rout->ZoneListW2K->ZoneArray, zlist);
+
+ for (i=0; i<zcount; i++) {
+ rout->ZoneListW2K->ZoneArray[i] = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_W2K);
+
+ rout->ZoneListW2K->ZoneArray[i]->pszZoneName = talloc_strdup(mem_ctx, zlist[i]->name);
+ rout->ZoneListW2K->ZoneArray[i]->Flags = zlist[i]->zoneinfo->Flags;
+ rout->ZoneListW2K->ZoneArray[i]->ZoneType = zlist[i]->zoneinfo->dwZoneType;
+ rout->ZoneListW2K->ZoneArray[i]->Version = zlist[i]->zoneinfo->Version;
+ }
+ rout->ZoneListW2K->dwZoneCount = zcount;
+
+ } else {
+ *typeid_out = DNSSRV_TYPEID_ZONE_LIST;
+ rout->ZoneList = talloc_zero(mem_ctx, struct DNS_RPC_ZONE_LIST_DOTNET);
+
+ if (zcount == 0) {
+ 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 *, zcount);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(rout->ZoneList->ZoneArray, zlist);
+
+ for (i=0; i<zcount; 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, zlist[i]->name);
+ rout->ZoneList->ZoneArray[i]->Flags = zlist[i]->zoneinfo->Flags;
+ rout->ZoneList->ZoneArray[i]->ZoneType = zlist[i]->zoneinfo->dwZoneType;
+ rout->ZoneList->ZoneArray[i]->Version = zlist[i]->zoneinfo->Version;
+ rout->ZoneList->ZoneArray[i]->dwDpFlags = zlist[i]->partition->dwDpFlags;
+ rout->ZoneList->ZoneArray[i]->pszDpFqdn = talloc_strdup(mem_ctx, zlist[i]->partition->pszDpFqdn);
+ }
+ rout->ZoneList->dwRpcStructureVersion = 1;
+ rout->ZoneList->dwZoneCount = zcount;
+ }
+ talloc_free(zlist);
+ return WERR_OK;
+ } else if (strcasecmp(operation, "EnumZones2") == 0) {
+ valid_operation = true;
+ } else if (strcasecmp(operation, "EnumDirectoryPartitions") == 0) {
+ if (typeid_in != DNSSRV_TYPEID_DWORD) {
+ return WERR_DNS_ERROR_INVALID_PROPERTY;
+ }
+
+ *typeid_out = DNSSRV_TYPEID_DP_LIST;
+ rout->DirectoryPartitionList = talloc_zero(mem_ctx, struct DNS_RPC_DP_LIST);
+
+ if (rin->Dword != 0) {
+ rout->DirectoryPartitionList->dwDpCount = 0;
+ rout->DirectoryPartitionList->DpArray = NULL;
+ } else {
+ struct DNS_RPC_DP_ENUM **dplist;
+ struct dnsserver_partition *p;
+ int pcount = 2;
+
+ dplist = talloc_zero_array(mem_ctx, struct DNS_RPC_DP_ENUM *, pcount);
+ W_ERROR_HAVE_NO_MEMORY(dplist);
+
+ p = dsstate->partitions;
+ for (i=0; i<pcount; i++) {
+ dplist[i] = talloc_zero(dplist, struct DNS_RPC_DP_ENUM);
+
+ dplist[i]->pszDpFqdn = talloc_strdup(mem_ctx, p->pszDpFqdn);
+ dplist[i]->dwFlags = p->dwDpFlags;
+ dplist[i]->dwZoneCount = p->zones_count;
+ p = p->next;
+ }
+
+ rout->DirectoryPartitionList->dwDpCount = pcount;
+ rout->DirectoryPartitionList->DpArray = dplist;
+ }
+ return WERR_OK;
+ } else if (strcasecmp(operation, "DirectoryPartitionInfo") == 0) {
+ struct dnsserver_partition *p;
+ struct dnsserver_partition_info *partinfo;
+ struct DNS_RPC_DP_INFO *dpinfo = NULL;
+
+ if (typeid_in != DNSSRV_TYPEID_LPSTR) {
+ return WERR_DNS_ERROR_INVALID_PROPERTY;
+ }
+
+ *typeid_out = DNSSRV_TYPEID_DP_INFO;
+
+ for (p = dsstate->partitions; p; p = p->next) {
+ if (strcasecmp(p->pszDpFqdn, rin->String) == 0) {
+ dpinfo = talloc_zero(mem_ctx, struct DNS_RPC_DP_INFO);
+ W_ERROR_HAVE_NO_MEMORY(dpinfo);
+
+ partinfo = dnsserver_db_partition_info(mem_ctx, dsstate->samdb, p);
+ W_ERROR_HAVE_NO_MEMORY(partinfo);
+
+ dpinfo->pszDpFqdn = talloc_strdup(dpinfo, p->pszDpFqdn);
+ dpinfo->pszDpDn = talloc_strdup(dpinfo, ldb_dn_get_linearized(p->partition_dn));
+ dpinfo->pszCrDn = talloc_steal(dpinfo, partinfo->pszCrDn);
+ dpinfo->dwFlags = p->dwDpFlags;
+ dpinfo->dwZoneCount = p->zones_count;
+ dpinfo->dwState = partinfo->dwState;
+ dpinfo->dwReplicaCount = partinfo->dwReplicaCount;
+ if (partinfo->dwReplicaCount > 0) {
+ dpinfo->ReplicaArray = talloc_steal(dpinfo,
+ partinfo->ReplicaArray);
+ } else {
+ dpinfo->ReplicaArray = NULL;
+ }
+ break;
+ }
+ }
+
+ if (dpinfo == NULL) {
+ return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
+ }
+
+ rout->DirectoryPartition = dpinfo;
+ return WERR_OK;
+ } 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\n", operation));
+ return WERR_CALL_NOT_IMPLEMENTED;
+ }
+
+ DEBUG(0, ("dnsserver: invalid server complex operation '%s'\n", 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) {
+
+ if (typeid != DNSSRV_TYPEID_NAME_AND_PARAM) {
+ return WERR_DNS_ERROR_INVALID_PROPERTY;
+ }
+
+ return dnsserver_db_do_reset_dword(dsstate->samdb, z,
+ r->NameAndParam);
+
+ } 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) {
+ WERROR status;
+ if (z == NULL) {
+ return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+ }
+ status = dnsserver_db_delete_zone(dsstate->samdb, z);
+ if (W_ERROR_IS_OK(status)) {
+ dnsserver_reload_zones(dsstate);
+ }
+ return status;
+ } 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\n", operation));
+ return WERR_CALL_NOT_IMPLEMENTED;
+ }
+
+ DEBUG(0, ("dnsserver: invalid zone operation '%s'\n", 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\n", 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;
+ struct dnsserver_zone *z;
+ const char * const attrs[] = { "name", "dnsRecord", NULL };
+ struct ldb_result *res;
+ 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);
+
+ z = dnsserver_find_zone(dsstate->zones, ".");
+ if (z == NULL) {
+ return WERR_DNS_ERROR_NAME_DOES_NOT_EXIST;
+ }
+
+ ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=@)(!(dNSTombstoned=TRUE)))");
+ 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], 0, 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++) {
+ char *encoded_name
+ = ldb_binary_encode_string(tmp_ctx,
+ add_names[i]);
+ ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ encoded_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], 0, recs,
+ NULL, NULL);
+ talloc_free(rname);
+ talloc_free(res);
+ if (!W_ERROR_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ }
+ }
+
+ 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;
+ const char * const attrs[] = { "name", "dnsRecord", NULL };
+ struct ldb_result *res = NULL;
+ struct DNS_RPC_RECORDS_ARRAY *recs = NULL;
+ char **add_names = NULL;
+ char *rname = NULL;
+ const char *preference_name = NULL;
+ int add_count = 0;
+ int i, ret, len;
+ WERROR status;
+ struct dns_tree *tree = NULL;
+ struct dns_tree *base = NULL;
+ struct dns_tree *node = NULL;
+
+ 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 (strcasecmp(name, z->name) == 0) {
+ ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
+ preference_name = "@";
+ } else {
+ char *encoded_name
+ = ldb_binary_encode_string(tmp_ctx, name);
+ ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s))(!(dNSTombstoned=TRUE)))",
+ encoded_name, encoded_name);
+ preference_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 records are in order by the child
+ * component below "name".
+ *
+ * A full tree sort is not required, so we pass in "name" so
+ * we know which level to sort, as only direct children are
+ * eventually returned
+ */
+ LDB_TYPESAFE_QSORT(res->msgs, res->count, name, dns_name_compare);
+
+ /* Build a tree of name components from dns name */
+ tree = dns_build_tree(tmp_ctx, preference_name, res);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(tree, tmp_ctx);
+
+ /* Find the parent record in the tree */
+ base = tree;
+ while (base->level != -1) {
+ base = base->children[0];
+ }
+
+ /* Add the parent record with blank name */
+ if (!(select_flag & DNS_RPC_VIEW_ONLY_CHILDREN)) {
+ status = dns_fill_records_array(tmp_ctx, z, record_type,
+ select_flag, NULL,
+ base->data, 0,
+ recs, &add_names, &add_count);
+ 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=0; i<base->num_children; i++) {
+ node = base->children[i];
+
+ status = dns_fill_records_array(tmp_ctx, z, record_type,
+ select_flag, node->name,
+ node->data, node->num_children,
+ recs, &add_names, &add_count);
+ if (!W_ERROR_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ }
+ }
+
+ TALLOC_FREE(res);
+ TALLOC_FREE(tree);
+ TALLOC_FREE(name);
+
+ /* Add any additional records */
+ if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) {
+ for (i=0; i<add_count; i++) {
+ struct dnsserver_zone *z2 = NULL;
+ struct ldb_message *msg = NULL;
+ /* Search all the available zones for additional name */
+ for (z2 = dsstate->zones; z2; z2 = z2->next) {
+ char *encoded_name;
+ name = dns_split_node_name(tmp_ctx, add_names[i], z2->name);
+ encoded_name
+ = ldb_binary_encode_string(tmp_ctx,
+ name);
+ ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z2->zone_dn,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ encoded_name);
+ TALLOC_FREE(name);
+ if (ret != LDB_SUCCESS) {
+ continue;
+ }
+ if (res->count == 1) {
+ msg = res->msgs[0];
+ break;
+ } else {
+ 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,
+ msg, 0, recs,
+ NULL, NULL);
+ TALLOC_FREE(rname);
+ TALLOC_FREE(res);
+ if (!W_ERROR_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ }
+ }
+
+ *buffer_length = ndr_size_DNS_RPC_RECORDS_ARRAY(recs, 0);
+ *buffer = recs;
+
+ return WERR_OK;
+}
+
+/*
+ * Check str1 + '.' + str2 = name, for example:
+ * ("dc0", "example.com", "dc0.example.com") = true
+ */
+static bool cname_self_reference(const char* node_name,
+ const char* zone_name,
+ struct DNS_RPC_NAME name) {
+ size_t node_len, zone_len;
+
+ if (node_name == NULL || zone_name == NULL) {
+ return false;
+ }
+
+ node_len = strlen(node_name);
+ zone_len = strlen(zone_name);
+
+ if (node_len == 0 ||
+ zone_len == 0 ||
+ (name.len != node_len + zone_len + 1)) {
+ return false;
+ }
+
+ if (strncmp(node_name, name.str, node_len) == 0 &&
+ name.str[node_len] == '.' &&
+ strncmp(zone_name, name.str + node_len + 1, zone_len) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+/* 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);
+
+ /* If node_name is @ or zone name, dns record is @ */
+ if (strcmp(node_name, "@") == 0 ||
+ strcmp(node_name, ".") == 0 ||
+ strcasecmp(node_name, z->name) == 0) {
+ name = talloc_strdup(tmp_ctx, "@");
+ } else {
+ name = dns_split_node_name(tmp_ctx, node_name, z->name);
+ }
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(name, tmp_ctx);
+
+ /* CNAMEs can't point to themselves */
+ if (add_buf != NULL && add_buf->rec.wType == DNS_TYPE_CNAME) {
+ if (cname_self_reference(node_name, z->name, add_buf->rec.data.name)) {
+ return WERR_DNS_ERROR_CNAME_LOOP;
+ }
+ }
+
+ 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 {
+ z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+ /*
+ * In the case that request_filter is not 0 and z is NULL,
+ * the request is for a multizone operation, which we do not
+ * yet support, so just error on NULL zone name.
+ */
+ if (z == NULL) {
+ return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+ }
+
+ 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 {
+ z = dnsserver_find_zone(dsstate->zones, r->in.pszZone);
+ /*
+ * In the case that request_filter is not 0 and z is NULL,
+ * the request is for a multizone operation, which we do not
+ * yet support, so just error on NULL zone name.
+ */
+ if (z == NULL) {
+ return WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST;
+ }
+
+ 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
index 0000000..e6d35fc
--- /dev/null
+++ b/source4/rpc_server/dnsserver/dnsdata.c
@@ -0,0 +1,1121 @@
+/*
+ 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 "dns_server/dnsserver_common.h"
+#include "lib/replace/system/network.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "librpc/gen_ndr/ndr_dnsserver.h"
+
+#undef strcasecmp
+
+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 IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
+ struct DNS_ADDR_ARRAY *ip)
+{
+ struct IP4_ARRAY *ret;
+ size_t i, count, curr;
+
+ if (ip == NULL) {
+ return NULL;
+ }
+ /* We must only return IPv4 addresses.
+ The passed DNS_ADDR_ARRAY may contain:
+ - only ipv4 addresses
+ - only ipv6 addresses
+ - a mixture of both
+ - an empty array
+ */
+ ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
+ if (!ret) {
+ return ret;
+ }
+ if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
+ ret->AddrCount = 0;
+ return ret;
+ }
+ /* Now only ipv4 addresses or a mixture are left */
+ count = 0;
+ for (i = 0; i < ip->AddrCount; i++) {
+ if (ip->AddrArray[i].MaxSa[0] == 0x02) {
+ /* Is ipv4 */
+ count++;
+ }
+ }
+ if (count == 0) {
+ /* should not happen */
+ ret->AddrCount = 0;
+ return ret;
+ }
+ ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
+ if (ret->AddrArray) {
+ curr = 0;
+ for (i = 0; i < ip->AddrCount; i++) {
+ if (ip->AddrArray[i].MaxSa[0] == 0x02) {
+ /* Is ipv4 */
+ memcpy(&ret->AddrArray[curr],
+ &ip->AddrArray[i].MaxSa[4],
+ sizeof(uint32_t));
+ curr++;
+ }
+ }
+ } else {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret->AddrCount = curr;
+ 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;
+
+ if (name == NULL) {
+ return 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:
+ 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 (strcasecmp(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 i, 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.EntombedTime = dnsp->data.EntombedTime;
+ 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.txt.count = dnsp->data.txt.count;
+ dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
+ for (i=0; i<dnsp->data.txt.count; i++) {
+ dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
+ dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
+ }
+ 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_RECORD_DATA));
+ DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d\n", dnsp->wType));
+ }
+
+}
+
+WERROR dns_to_dnsp_convert(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns,
+ struct dnsp_DnssrvRpcRecord **out_dnsp, bool check_name)
+{
+ WERROR res;
+ int i, len;
+ const char *name;
+ char *talloc_res = NULL;
+ struct dnsp_DnssrvRpcRecord *dnsp = NULL;
+
+ dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
+ if (dnsp == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ 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.EntombedTime = dns->data.EntombedTime;
+ break;
+
+ case DNS_TYPE_A:
+ talloc_res = talloc_strdup(mem_ctx, dns->data.ipv4);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.ipv4 = talloc_res;
+ break;
+
+ case DNS_TYPE_NS:
+ name = dns->data.name.str;
+ len = dns->data.name.len;
+
+ if (check_name) {
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+ }
+
+ if (len > 0 && name[len-1] == '.') {
+ talloc_res = talloc_strndup(mem_ctx, name, len-1);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.ns = talloc_res;
+ } else {
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.ns = talloc_res;
+ }
+
+ break;
+
+ case DNS_TYPE_CNAME:
+ name = dns->data.name.str;
+ len = dns->data.name.len;
+
+ if (check_name) {
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+ }
+
+ if (len > 0 && name[len-1] == '.') {
+ talloc_res = talloc_strndup(mem_ctx, name, len-1);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.cname = talloc_res;
+ } else {
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.cname = talloc_res;
+ }
+
+ 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;
+
+ name = dns->data.soa.NamePrimaryServer.str;
+ len = dns->data.soa.NamePrimaryServer.len;
+
+ if (check_name) {
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+ }
+
+ if (len > 0 && name[len-1] == '.') {
+ talloc_res = talloc_strndup(mem_ctx, name, len-1);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.soa.mname = talloc_res;
+ } else {
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.soa.mname = talloc_res;
+ }
+
+ name = dns->data.soa.ZoneAdministratorEmail.str;
+ len = dns->data.soa.ZoneAdministratorEmail.len;
+
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+
+ if (len > 0 && name[len-1] == '.') {
+ talloc_res = talloc_strndup(mem_ctx, name, len-1);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.soa.rname = talloc_res;
+ } else {
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.soa.rname = talloc_res;
+ }
+
+ break;
+
+ case DNS_TYPE_PTR:
+ name = dns->data.ptr.str;
+ len = dns->data.ptr.len;
+
+ if (check_name) {
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+ }
+
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.ptr = talloc_res;
+
+ break;
+
+ case DNS_TYPE_MX:
+ dnsp->data.mx.wPriority = dns->data.mx.wPreference;
+
+ name = dns->data.mx.nameExchange.str;
+ len = dns->data.mx.nameExchange.len;
+
+ if (check_name) {
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+ }
+
+ if (len > 0 && name[len-1] == '.') {
+ talloc_res = talloc_strndup(mem_ctx, name, len-1);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.mx.nameTarget = talloc_res;
+ } else {
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.mx.nameTarget = talloc_res;
+ }
+
+ break;
+
+ case DNS_TYPE_TXT:
+ dnsp->data.txt.count = dns->data.txt.count;
+ dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
+ for (i=0; i<dns->data.txt.count; i++) {
+ talloc_res = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.txt.str[i] = talloc_res;
+ }
+ 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;
+
+ name = dns->data.srv.nameTarget.str;
+ len = dns->data.srv.nameTarget.len;
+
+ if (check_name) {
+ res = dns_name_check(mem_ctx, len, name);
+ if (!W_ERROR_IS_OK(res)) {
+ return res;
+ }
+ }
+
+ if (len > 0 && name[len-1] == '.') {
+ talloc_res = talloc_strndup(mem_ctx, name, len-1);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.srv.nameTarget = talloc_res;
+ } else {
+ talloc_res = talloc_strdup(mem_ctx, name);
+ if (talloc_res == NULL) {
+ goto fail_nomemory;
+ }
+ dnsp->data.srv.nameTarget = talloc_res;
+ }
+
+ break;
+
+ default:
+ memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
+ DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d\n", dns->wType));
+ }
+
+ *out_dnsp = dnsp;
+ return WERR_OK;
+
+fail_nomemory:
+ return WERR_NOT_ENOUGH_MEMORY;
+}
+
+/* Initialize tree with given name as the root */
+static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
+{
+ struct dns_tree *tree;
+
+ tree = talloc_zero(mem_ctx, struct dns_tree);
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ tree->name = talloc_strdup(tree, name);
+ if (tree->name == NULL) {
+ talloc_free(tree);
+ return NULL;
+ }
+
+ tree->data = data;
+
+ return tree;
+}
+
+
+/* Add a child one level below */
+static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
+{
+ struct dns_tree *node;
+
+ node = talloc_zero(tree, struct dns_tree);
+ if (node == NULL) {
+ return NULL;
+ }
+
+ node->name = talloc_strdup(tree, name);
+ if (node->name == NULL) {
+ talloc_free(node);
+ return NULL;
+ }
+ node->level = tree->level + 1;
+ node->num_children = 0;
+ node->children = NULL;
+ node->data = data;
+
+ if (tree->num_children == 0) {
+ tree->children = talloc_zero(tree, struct dns_tree *);
+ } else {
+ tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
+ tree->num_children+1);
+ }
+ if (tree->children == NULL) {
+ talloc_free(node);
+ return NULL;
+ }
+ tree->children[tree->num_children] = node;
+ tree->num_children++;
+
+ return node;
+}
+
+/* Find a node that matches the name components */
+static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
+{
+ struct dns_tree *node, *next;
+ int i, j, start;
+
+ *match_count = -1;
+
+ if (strcmp(tree->name, "@") == 0) {
+ start = 0;
+ } else {
+ if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
+ return NULL;
+ }
+ start = 1;
+ *match_count = 0;
+ }
+
+ node = tree;
+ for (i=start; i<ncount; i++) {
+ if (node->num_children == 0) {
+ break;
+ }
+ next = NULL;
+ for (j=0; j<node->num_children; j++) {
+ if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
+ next = node->children[j];
+ *match_count = i;
+ break;
+ }
+ }
+ if (next == NULL) {
+ break;
+ } else {
+ node = next;
+ }
+ }
+
+ return node;
+}
+
+/* Build a 2-level tree for resulting dns names */
+struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
+{
+ struct dns_tree *root, *base, *tree, *node;
+ const char *ptr;
+ int rootcount, ncount;
+ char **nlist;
+ int i, level, match_count;
+
+ rootcount = dns_split_name_components(mem_ctx, name, &nlist);
+ if (rootcount <= 0) {
+ return NULL;
+ }
+
+ root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
+ if (root == NULL) {
+ talloc_free(nlist);
+ return NULL;
+ }
+
+ tree = root;
+ for (i=rootcount-2; i>=0; i--) {
+ tree = dns_tree_add(tree, nlist[i], NULL);
+ if (tree == NULL) {
+ goto failed;
+ }
+ }
+
+ base = tree;
+
+ /* Add all names in the result in a tree */
+ for (i=0; i<res->count; i++) {
+ ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
+ if (ptr == NULL) {
+ DBG_ERR("dnsserver: dns record has no name (%s)\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ goto failed;
+ }
+
+ /*
+ * This might be the sub-domain in the zone being
+ * requested, or @ for the root of the zone
+ */
+ if (strcasecmp(ptr, name) == 0) {
+ base->data = res->msgs[i];
+ continue;
+ }
+
+ ncount = dns_split_name_components(root, ptr, &nlist);
+ if (ncount < 0) {
+ goto failed;
+ }
+
+ /* Find matching node */
+ tree = dns_tree_find(root, ncount, nlist, &match_count);
+ if (tree == NULL) {
+ goto failed;
+ }
+
+ /* If the node is on leaf, then add record data */
+ if (match_count+1 == ncount) {
+ tree->data = res->msgs[i];
+ }
+
+ /* Add missing name components */
+ for (level=match_count+1; level<ncount; level++) {
+ if (tree->level == rootcount+1) {
+ break;
+ }
+ if (level == ncount-1) {
+ node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
+ } else {
+ node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
+ }
+ if (node == NULL) {
+ goto failed;
+ }
+ tree = node;
+ }
+
+ talloc_free(nlist);
+ }
+
+ /* Mark the base record, so it can be found easily */
+ base->level = -1;
+
+ return root;
+
+failed:
+ talloc_free(nlist);
+ talloc_free(root);
+ return NULL;
+}
+
+
+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 (strcasecmp(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) {
+ talloc_free(ptr);
+ 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,
+ int num_children,
+ struct DNS_RPC_RECORDS_ARRAY *recs,
+ char ***add_names,
+ int *add_count)
+{
+ struct ldb_message_element *el;
+ const char *ptr;
+ int i, j;
+ bool 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_NOT_ENOUGH_MEMORY;
+ }
+ i = recs->count;
+ recs->rec[i].wLength = 0;
+ recs->rec[i].wRecordCount = 0;
+ recs->rec[i].dwChildCount = num_children;
+ recs->rec[i].dwFlags = 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;
+ }
+
+ /* Do not return RR records, if the node has children */
+ if (branch_name != NULL && num_children > 0) {
+ return WERR_OK;
+ }
+
+ ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
+ if (ptr == NULL) {
+ DBG_ERR("dnsserver: dns record has no name (%s)\n",
+ ldb_dn_get_linearized(msg->dn));
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ if (el == NULL || el->values == 0) {
+ return WERR_OK;
+ }
+
+ /* Add RR records */
+ 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)\n", 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;
+ } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
+ /*
+ * If branch_name is NULL, we're
+ * explicitly asked to also return
+ * DNS_RANK_NS_GLUE records
+ */
+ if (branch_name == NULL) {
+ 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_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_NOT_ENOUGH_MEMORY;
+ }
+
+ dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
+ dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
+
+ /* Fix record flags */
+ if (strcmp(ptr, "@") == 0) {
+ dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
+
+ if (dnsp_rec.rank == DNS_RANK_ZONE) {
+ dns_rec->dwFlags |= 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(struct ldb_message * const *m1, struct ldb_message * const *m2,
+ const 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;
+ }
+
+ /* Compare the last components of names.
+ * If search_name is not NULL, compare the second last components of names */
+ ptr1 = strrchr(name1, '.');
+ if (ptr1 == NULL) {
+ ptr1 = name1;
+ } else {
+ if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
+ ptr1--;
+ while (ptr1 != name1) {
+ ptr1--;
+ if (*ptr1 == '.') {
+ break;
+ }
+ }
+ }
+ if (*ptr1 == '.') {
+ ptr1 = &ptr1[1];
+ }
+ }
+
+ ptr2 = strrchr(name2, '.');
+ if (ptr2 == NULL) {
+ ptr2 = name2;
+ } else {
+ if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
+ ptr2--;
+ while (ptr2 != name2) {
+ ptr2--;
+ if (*ptr2 == '.') {
+ break;
+ }
+ }
+ }
+ if (*ptr2 == '.') {
+ ptr2 = &ptr2[1];
+ }
+ }
+
+ return strcasecmp(ptr1, ptr2);
+}
diff --git a/source4/rpc_server/dnsserver/dnsdb.c b/source4/rpc_server/dnsserver/dnsdb.c
new file mode 100644
index 0000000..bde54a0
--- /dev/null
+++ b/source4/rpc_server/dnsserver/dnsdb.c
@@ -0,0 +1,1272 @@
+/*
+ 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"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "dsdb/samdb/samdb.h"
+#include "libcli/security/security.h"
+#include "dsdb/common/util.h"
+
+#undef strcasecmp
+
+/* There are only 2 fixed partitions for DNS */
+struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
+ struct dnsserver_serverinfo *serverinfo,
+ struct ldb_context *samdb)
+{
+ struct dnsserver_partition *partitions, *p;
+
+ partitions = NULL;
+
+ /* Domain partition */
+ p = talloc_zero(mem_ctx, struct dnsserver_partition);
+ if (p == NULL) {
+ goto failed;
+ }
+
+ p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
+ if (p->partition_dn == NULL) {
+ goto failed;
+ }
+
+ p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
+ p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_DOMAIN_DEFAULT | DNS_DP_ENLISTED;
+ p->is_forest = false;
+
+ DLIST_ADD_END(partitions, p);
+
+ /* Forest Partition */
+ p = talloc_zero(mem_ctx, struct dnsserver_partition);
+ if (p == NULL) {
+ goto failed;
+ }
+
+ p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
+ if (p->partition_dn == NULL) {
+ goto failed;
+ }
+
+ p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
+ p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED;
+ p->is_forest = true;
+
+ DLIST_ADD_END(partitions, p);
+
+ return partitions;
+
+failed:
+ return NULL;
+
+}
+
+
+/* Search for all dnsZone records */
+struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
+ struct ldb_context *samdb,
+ struct dnsserver_partition *p)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char * const attrs[] = {"name", "dNSProperty", NULL};
+ struct ldb_dn *dn;
+ struct ldb_result *res;
+ struct dnsserver_zone *zones, *z;
+ int i, j, ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ dn = ldb_dn_copy(tmp_ctx, p->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)");
+ 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++) {
+ char *name;
+ struct ldb_message_element *element = NULL;
+ struct dnsp_DnsProperty *props = NULL;
+ enum ndr_err_code err;
+ z = talloc_zero(mem_ctx, struct dnsserver_zone);
+ if (z == NULL) {
+ goto failed;
+ }
+
+ z->partition = p;
+ name = talloc_strdup(z,
+ ldb_msg_find_attr_as_string(res->msgs[i],
+ "name", NULL));
+ if (strcmp(name, "..TrustAnchors") == 0) {
+ talloc_free(z);
+ continue;
+ }
+ if (strcmp(name, "RootDNSServers") == 0) {
+ talloc_free(name);
+ z->name = talloc_strdup(z, ".");
+ } else {
+ z->name = name;
+ }
+ z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
+
+ DLIST_ADD_END(zones, z);
+ DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
+
+ element = ldb_msg_find_element(res->msgs[i], "dNSProperty");
+ if(element != NULL){
+ props = talloc_zero_array(tmp_ctx,
+ struct dnsp_DnsProperty,
+ element->num_values);
+ for (j = 0; j < element->num_values; j++ ) {
+ err = ndr_pull_struct_blob(
+ &(element->values[j]),
+ mem_ctx,
+ &props[j],
+ (ndr_pull_flags_fn_t)
+ ndr_pull_dnsp_DnsProperty);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)){
+ /*
+ * Per Microsoft we must
+ * ignore invalid data here
+ * and continue as a Windows
+ * server can put in a
+ * structure with an invalid
+ * length.
+ *
+ * We can safely fill in an
+ * extra empty property here
+ * because
+ * dns_zoneinfo_load_zone_property()
+ * just ignores
+ * DSPROPERTY_ZONE_EMPTY
+ */
+ ZERO_STRUCT(props[j]);
+ props[j].id = DSPROPERTY_ZONE_EMPTY;
+ continue;
+ }
+ }
+ z->tmp_props = props;
+ z->num_props = element->num_values;
+ }
+ }
+ return zones;
+
+failed:
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+
+/* Find DNS partition information */
+struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
+ struct ldb_context *samdb,
+ struct dnsserver_partition *p)
+{
+ const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
+ const char * const attrs_none[] = { NULL };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+ struct ldb_dn *dn;
+ struct dnsserver_partition_info *partinfo;
+ int i, ret, instance_type;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
+ if (partinfo == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ /* Search for the active replica and state */
+ ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
+ attrs, NULL);
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ goto failed;
+ }
+
+ /* Set the state of the partition */
+ instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
+ if (instance_type == -1) {
+ partinfo->dwState = DNS_DP_STATE_UNKNOWN;
+ } else if (instance_type & INSTANCE_TYPE_NC_COMING) {
+ partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
+ } else if (instance_type & INSTANCE_TYPE_NC_GOING) {
+ partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
+ } else {
+ partinfo->dwState = DNS_DP_OKAY;
+ }
+
+ el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
+ if (el == NULL) {
+ partinfo->dwReplicaCount = 0;
+ partinfo->ReplicaArray = NULL;
+ } else {
+ partinfo->dwReplicaCount = el->num_values;
+ partinfo->ReplicaArray = talloc_zero_array(partinfo,
+ struct DNS_RPC_DP_REPLICA *,
+ el->num_values);
+ if (partinfo->ReplicaArray == NULL) {
+ goto failed;
+ }
+ for (i=0; i<el->num_values; i++) {
+ partinfo->ReplicaArray[i] = talloc_zero(partinfo,
+ struct DNS_RPC_DP_REPLICA);
+ if (partinfo->ReplicaArray[i] == NULL) {
+ goto failed;
+ }
+ partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
+ partinfo,
+ (const char *)el->values[i].data);
+ if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
+ goto failed;
+ }
+ }
+ }
+ talloc_free(res);
+
+ /* Search for cross-reference object */
+ dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
+ if (dn == NULL) {
+ goto failed;
+ }
+
+ ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
+ "(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ goto failed;
+ }
+ partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
+ if (partinfo->pszCrDn == NULL) {
+ goto failed;
+ }
+ talloc_free(res);
+
+ talloc_free(tmp_ctx);
+ return partinfo;
+
+failed:
+ talloc_free(tmp_ctx);
+ talloc_free(partinfo);
+ return NULL;
+}
+
+
+/* Increment serial number and update timestamp */
+static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
+ struct ldb_context *samdb,
+ struct dnsserver_zone *z,
+ WERROR *werr)
+{
+ 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, serial = -1;
+
+ *werr = WERR_INTERNAL_DB_ERROR;
+
+ ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=@))");
+ if (ret != LDB_SUCCESS || res->count == 0) {
+ return -1;
+ }
+
+ el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
+ if (el == NULL) {
+ return -1;
+ }
+
+ for (i=0; i<el->num_values; i++) {
+ ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ continue;
+ }
+
+ if (rec.wType == DNS_TYPE_SOA) {
+ serial = rec.data.soa.serial + 1;
+ rec.dwSerial = serial;
+ rec.dwTimeStamp = 0;
+ rec.data.soa.serial = serial;
+
+ 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)) {
+ *werr = WERR_NOT_ENOUGH_MEMORY;
+ return -1;
+ }
+ break;
+ }
+ }
+
+ if (serial != -1) {
+ el->flags = LDB_FLAG_MOD_REPLACE;
+ ret = ldb_modify(samdb, res->msgs[0]);
+ if (ret != LDB_SUCCESS) {
+ if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ *werr = WERR_ACCESS_DENIED;
+ }
+ return -1;
+ }
+ }
+
+ *werr = WERR_OK;
+
+ return serial;
+}
+
+
+/* Add DNS record to the database */
+static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
+ struct ldb_context *samdb,
+ struct ldb_dn *dn,
+ int num_rec,
+ struct dnsp_DnssrvRpcRecord *rec)
+{
+ struct ldb_message *msg;
+ struct ldb_val v;
+ int ret;
+ enum ndr_err_code ndr_err;
+ int i;
+
+ 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_NOT_ENOUGH_MEMORY;
+ }
+
+ if (num_rec > 0 && rec) {
+ for (i=0; i<num_rec; i++) {
+ ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_GEN_FAILURE;
+ }
+
+ ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
+ if (ret != LDB_SUCCESS) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+
+ ret = ldb_add(samdb, msg);
+ if (ret != LDB_SUCCESS) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ return WERR_OK;
+}
+
+
+/* Add dnsNode record to the database with DNS record */
+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;
+ char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
+ struct ldb_val name_val = data_blob_string_const(name);
+ int ret;
+
+ ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
+ "(&(objectClass=dnsNode)(name=%s))",
+ encoded_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_val(dn, "DC", name_val)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
+}
+
+static void set_record_rank(struct dnsserver_zone *z,
+ const char *name,
+ struct dnsp_DnssrvRpcRecord *rec)
+{
+ if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
+ if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
+ rec->rank = DNS_RANK_NS_GLUE;
+ } else {
+ rec->rank = DNS_RANK_ZONE;
+ }
+ } else if (strcmp(z->name, ".") == 0) {
+ rec->rank = DNS_RANK_ROOT_HINT;
+ }
+}
+
+
+/* Add a DNS record */
+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", "dNSTombstoned", NULL };
+ struct ldb_result *res;
+ struct dnsp_DnssrvRpcRecord *rec = NULL;
+ struct ldb_message_element *el;
+ struct ldb_dn *dn;
+ enum ndr_err_code ndr_err;
+ int ret, i;
+ int serial;
+ WERROR werr;
+ bool was_tombstoned = false;
+ char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
+
+ werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ /* Set the correct rank for the record. */
+ set_record_rank(z, name, rec);
+
+ serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
+ if (serial < 0) {
+ return werr;
+ }
+
+ rec->dwSerial = serial;
+ rec->dwTimeStamp = 0;
+
+ ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s))",
+ encoded_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, 1, 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_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
+ "dNSTombstoned", false);
+ if (was_tombstoned) {
+ el->num_values = 0;
+ }
+
+ 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_GEN_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_GEN_FAILURE;
+ }
+
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
+ if (el != NULL) {
+ el->flags = LDB_FLAG_MOD_DELETE;
+ }
+
+ ret = ldb_modify(samdb, res->msgs[0]);
+ if (ret != LDB_SUCCESS) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ return WERR_OK;
+}
+
+
+/* Update a DNS record */
+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 rec2;
+ struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
+ struct ldb_message_element *el;
+ enum ndr_err_code ndr_err;
+ int ret, i;
+ int serial;
+ WERROR werr;
+ bool updating_ttl = false;
+ char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
+
+ werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ encoded_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++) {
+ 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_GEN_FAILURE;
+ }
+
+ if (dns_record_match(arec, &rec2)) {
+ break;
+ }
+ }
+ if (i < el->num_values) {
+ /*
+ * The record already exists, which is an error UNLESS we are
+ * doing an in-place update.
+ *
+ * Therefore we need to see if drec also matches, in which
+ * case it's OK, though we can only update dwTtlSeconds and
+ * reset the timestamp to zero.
+ */
+ updating_ttl = dns_record_match(drec, &rec2);
+ if (! updating_ttl) {
+ return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
+ }
+ /* In this case the next loop is redundant */
+ }
+
+ for (i=0; i<el->num_values; i++) {
+ 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_GEN_FAILURE;
+ }
+
+ if (dns_record_match(drec, &rec2)) {
+ /*
+ * we are replacing this one with arec, which is done
+ * by pushing arec into el->values[i] below, after the
+ * various manipulations.
+ */
+ break;
+ }
+ }
+ if (i == el->num_values) {
+ return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+ }
+
+ /*
+ * If we're updating a SOA record, use the specified serial.
+ *
+ * Otherwise, if we are updating ttl in place (i.e., not changing
+ * .wType and .data on a record), we should increment the existing
+ * serial, and save to the SOA.
+ *
+ * Outside of those two cases, we look for the zone's SOA record and
+ * use its serial.
+ */
+ if (arec->wType != DNS_TYPE_SOA) {
+ if (updating_ttl) {
+ /*
+ * In this case, we keep some of the old values.
+ */
+ arec->dwSerial = rec2.dwSerial;
+ arec->dwReserved = rec2.dwReserved;
+ /*
+ * TODO: if the old TTL and the new TTL are
+ * different, the serial number is incremented.
+ */
+ } else {
+ arec->dwReserved = 0;
+ serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
+ if (serial < 0) {
+ return werr;
+ }
+ arec->dwSerial = serial;
+ }
+ }
+
+ /* Set the correct rank for the record. */
+ set_record_rank(z, name, arec);
+ /*
+ * Successful RPC updates *always* zero timestamp and flags and set
+ * version.
+ */
+ arec->dwTimeStamp = 0;
+ arec->version = 5;
+ arec->flags = 0;
+
+ 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_GEN_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;
+}
+
+
+/* Delete a DNS record */
+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 = NULL;
+ struct ldb_message_element *el;
+ enum ndr_err_code ndr_err;
+ int ret, i;
+ int serial;
+ WERROR werr;
+
+ serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
+ if (serial < 0) {
+ return werr;
+ }
+
+ werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s))",
+ ldb_binary_encode_string(mem_ctx, name));
+ if (ret != LDB_SUCCESS) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ if (res->count == 0) {
+ return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
+ }
+ if (res->count > 1) {
+ return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
+ }
+
+ 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_GEN_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;
+}
+
+
+static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg,
+ struct dnsp_DnsProperty *prop)
+{
+ DATA_BLOB *prop_blob;
+ enum ndr_err_code ndr_err;
+ int ret;
+
+ prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (prop_blob == NULL) return false;
+
+ ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
+ if (ret != LDB_SUCCESS) {
+ return false;
+ }
+ return true;
+}
+
+WERROR dnsserver_db_do_reset_dword(struct ldb_context *samdb,
+ struct dnsserver_zone *z,
+ struct DNS_RPC_NAME_AND_PARAM *n_p)
+{
+ struct ldb_message_element *element = NULL;
+ struct dnsp_DnsProperty *prop = NULL;
+ enum ndr_err_code err;
+ TALLOC_CTX *tmp_ctx = NULL;
+ const char * const attrs[] = {"dNSProperty", NULL};
+ struct ldb_result *res = NULL;
+ int i, ret, prop_id;
+
+ if (strcasecmp(n_p->pszNodeName, "Aging") == 0) {
+ z->zoneinfo->fAging = n_p->dwParam;
+ prop_id = DSPROPERTY_ZONE_AGING_STATE;
+ } else if (strcasecmp(n_p->pszNodeName, "RefreshInterval") == 0) {
+ z->zoneinfo->dwRefreshInterval = n_p->dwParam;
+ prop_id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
+ } else if (strcasecmp(n_p->pszNodeName, "NoRefreshInterval") == 0) {
+ z->zoneinfo->dwNoRefreshInterval = n_p->dwParam;
+ prop_id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
+ } else if (strcasecmp(n_p->pszNodeName, "AllowUpdate") == 0) {
+ z->zoneinfo->fAllowUpdate = n_p->dwParam;
+ prop_id = DSPROPERTY_ZONE_ALLOW_UPDATE;
+ } else {
+ return WERR_UNKNOWN_PROPERTY;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ ret = ldb_search(samdb, tmp_ctx, &res, z->zone_dn, LDB_SCOPE_BASE,
+ attrs, "(objectClass=dnsZone)");
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("dnsserver: no zone: %s\n",
+ ldb_dn_get_linearized(z->zone_dn));
+ TALLOC_FREE(tmp_ctx);
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ if (res->count != 1) {
+ DBG_ERR("dnsserver: duplicate zone: %s\n",
+ ldb_dn_get_linearized(z->zone_dn));
+ TALLOC_FREE(tmp_ctx);
+ return WERR_GEN_FAILURE;
+ }
+
+ element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
+ if (element == NULL) {
+ DBG_ERR("dnsserver: zone %s has no properties.\n",
+ ldb_dn_get_linearized(z->zone_dn));
+ TALLOC_FREE(tmp_ctx);
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ for (i = 0; i < element->num_values; i++) {
+ prop = talloc_zero(element, struct dnsp_DnsProperty);
+ if (prop == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ err = ndr_pull_struct_blob(
+ &(element->values[i]),
+ tmp_ctx,
+ prop,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)){
+ /*
+ * If we can't pull it then try again parsing
+ * it again. A Windows server in the domain
+ * will permit the addition of an invalidly
+ * formed property with a 0 length and cause a
+ * failure here
+ */
+ struct dnsp_DnsProperty_short
+ *short_property
+ = talloc_zero(element,
+ struct dnsp_DnsProperty_short);
+ if (short_property == NULL) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ err = ndr_pull_struct_blob_all(
+ &(element->values[i]),
+ tmp_ctx,
+ short_property,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty_short);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ /*
+ * Unknown invalid data should be
+ * ignored and logged to match Windows
+ * behaviour
+ */
+ DBG_NOTICE("dnsserver: couldn't PULL "
+ "dnsProperty value#%d in "
+ "zone %s while trying to "
+ "reset id %d\n",
+ i,
+ ldb_dn_get_linearized(z->zone_dn),
+ prop_id);
+ continue;
+ }
+
+ /*
+ * Initialise the parts of the property not
+ * overwritten by value() in the IDL for
+ * re-push
+ */
+ *prop = (struct dnsp_DnsProperty){
+ .namelength = short_property->namelength,
+ .id = short_property->id,
+ .name = short_property->name
+ /* .data will be filled in below */
+ };
+ }
+
+ if (prop->id == prop_id) {
+ switch (prop_id) {
+ case DSPROPERTY_ZONE_AGING_STATE:
+ prop->data.aging_enabled = n_p->dwParam;
+ break;
+ case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
+ prop->data.norefresh_hours = n_p->dwParam;
+ break;
+ case DSPROPERTY_ZONE_REFRESH_INTERVAL:
+ prop->data.refresh_hours = n_p->dwParam;
+ break;
+ case DSPROPERTY_ZONE_ALLOW_UPDATE:
+ prop->data.allow_update_flag = n_p->dwParam;
+ break;
+ }
+
+ err = ndr_push_struct_blob(
+ &(element->values[i]),
+ tmp_ctx,
+ prop,
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)){
+ DBG_ERR("dnsserver: couldn't PUSH dns prop id "
+ "%d in zone %s\n",
+ prop->id,
+ ldb_dn_get_linearized(z->zone_dn));
+ TALLOC_FREE(tmp_ctx);
+ return WERR_INTERNAL_DB_ERROR;
+ }
+ }
+ }
+
+ element->flags = LDB_FLAG_MOD_REPLACE;
+ ret = ldb_modify(samdb, res->msgs[0]);
+ if (ret != LDB_SUCCESS) {
+ TALLOC_FREE(tmp_ctx);
+ DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
+ z->name,
+ n_p->pszNodeName,
+ ldb_errstring(samdb));
+ return WERR_INTERNAL_DB_ERROR;
+ }
+ TALLOC_FREE(tmp_ctx);
+
+ return WERR_OK;
+}
+
+/* Create dnsZone record to database and set security descriptor */
+static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
+ struct ldb_context *samdb,
+ struct ldb_dn *zone_dn,
+ struct dnsserver_zone *z)
+{
+ const char * const attrs[] = { "objectSID", NULL };
+ struct ldb_message *msg;
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+ const char sddl_template[] = "D:AI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;CC;;;AU)(A;;RPLCLORC;;;WD)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)(A;CIID;LC;;;RU)(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)S:AI";
+ char *sddl;
+ struct dom_sid dnsadmins_sid;
+ const struct dom_sid *domain_sid;
+ struct security_descriptor *secdesc;
+ struct dnsp_DnsProperty *prop;
+ DATA_BLOB *sd_encoded;
+ enum ndr_err_code ndr_err;
+ int ret;
+
+ /* Get DnsAdmins SID */
+ ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
+ LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ el = ldb_msg_find_element(res->msgs[0], "objectSID");
+ if (el == NULL || el->num_values != 1) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ /* create security descriptor with DnsAdmins GUID in sddl template */
+ sddl = talloc_asprintf(tmp_ctx, sddl_template,
+ dom_sid_string(tmp_ctx, &dnsadmins_sid));
+ if (sddl == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ talloc_free(res);
+
+ domain_sid = samdb_domain_sid(samdb);
+ if (domain_sid == NULL) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
+ if (secdesc == NULL) {
+ return WERR_GEN_FAILURE;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ W_ERROR_HAVE_NO_MEMORY(msg);
+
+ msg->dn = zone_dn;
+ ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
+ if (ret != LDB_SUCCESS) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
+ W_ERROR_HAVE_NO_MEMORY(sd_encoded);
+
+ ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_GEN_FAILURE;
+ }
+
+ ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
+ if (ret != LDB_SUCCESS) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* dns zone Properties */
+ prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
+ W_ERROR_HAVE_NO_MEMORY(prop);
+
+ prop->version = 1;
+
+ /* zone type */
+ prop->id = DSPROPERTY_ZONE_TYPE;
+ prop->data.zone_type = z->zoneinfo->dwZoneType;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* allow update */
+ prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
+ prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* secure time */
+ prop->id = DSPROPERTY_ZONE_SECURE_TIME;
+ prop->data.zone_secure_time = 0;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* norefresh interval */
+ prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
+ prop->data.norefresh_hours = 168;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* refresh interval */
+ prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
+ prop->data.refresh_hours = 168;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* aging state */
+ prop->id = DSPROPERTY_ZONE_AGING_STATE;
+ prop->data.aging_enabled = z->zoneinfo->fAging;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* aging enabled time */
+ prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
+ prop->data.next_scavenging_cycle_hours = 0;
+ if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ talloc_free(prop);
+
+ ret = ldb_add(samdb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
+ z->name, ldb_errstring(samdb)));
+
+ if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ return WERR_ACCESS_DENIED;
+ }
+
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ return WERR_OK;
+}
+
+
+/* Create new dnsZone record and @ record (SOA + NS) */
+WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
+ struct dnsserver_partition *partitions,
+ struct dnsserver_zone *zone,
+ struct loadparm_context *lp_ctx)
+{
+ struct dnsserver_partition *p;
+ bool in_forest = false;
+ WERROR status;
+ struct ldb_dn *dn;
+ TALLOC_CTX *tmp_ctx;
+ struct dnsp_DnssrvRpcRecord *dns_rec;
+ struct dnsp_soa soa;
+ char *tmpstr, *server_fqdn, *soa_email;
+ struct ldb_val name_val = data_blob_string_const(zone->name);
+
+ /* We only support primary zones for now */
+ if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
+ return WERR_CALL_NOT_IMPLEMENTED;
+ }
+
+ /* Get the correct partition */
+ if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
+ in_forest = true;
+ }
+ for (p = partitions; p; p = p->next) {
+ if (in_forest == p->is_forest) {
+ break;
+ }
+ }
+ if (p == NULL) {
+ return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+ dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
+
+ if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
+ talloc_free(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
+ talloc_free(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Add dnsZone record */
+ status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
+ if (!W_ERROR_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
+ talloc_free(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
+
+ tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
+ lpcfg_netbios_name(lp_ctx),
+ lpcfg_realm(lp_ctx));
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
+ server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
+ talloc_free(tmpstr);
+
+ tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
+ lpcfg_realm(lp_ctx));
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
+ soa_email = strlower_talloc(tmp_ctx, tmpstr);
+ W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
+ talloc_free(tmpstr);
+
+ /* SOA Record - values same as defined in provision/sambadns.py */
+ soa.serial = 1;
+ soa.refresh = 900;
+ soa.retry = 600;
+ soa.expire = 86400;
+ soa.minimum = 3600;
+ soa.mname = server_fqdn;
+ soa.rname = soa_email;
+
+ dns_rec[0].wType = DNS_TYPE_SOA;
+ dns_rec[0].rank = DNS_RANK_ZONE;
+ dns_rec[0].dwSerial = soa.serial;
+ dns_rec[0].dwTtlSeconds = 3600;
+ dns_rec[0].dwTimeStamp = 0;
+ dns_rec[0].data.soa = soa;
+
+ /* NS Record */
+ dns_rec[1].wType = DNS_TYPE_NS;
+ dns_rec[1].rank = DNS_RANK_ZONE;
+ dns_rec[1].dwSerial = soa.serial;
+ dns_rec[1].dwTtlSeconds = 3600;
+ dns_rec[1].dwTimeStamp = 0;
+ dns_rec[1].data.ns = server_fqdn;
+
+ /* Add @ Record */
+ status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
+
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+
+/* Delete dnsZone record and all DNS records in the zone */
+WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
+ struct dnsserver_zone *zone)
+{
+ int ret;
+
+ ret = ldb_transaction_start(samdb);
+ if (ret != LDB_SUCCESS) {
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
+ if (ret != LDB_SUCCESS) {
+ ldb_transaction_cancel(samdb);
+
+ if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ return WERR_ACCESS_DENIED;
+ }
+ return WERR_INTERNAL_DB_ERROR;
+ }
+
+ ret = ldb_transaction_commit(samdb);
+ 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
index 0000000..2e46e7c
--- /dev/null
+++ b/source4/rpc_server/dnsserver/dnsserver.h
@@ -0,0 +1,264 @@
+/*
+ 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 DNS_ADDR_ARRAY * aipServerAddrs;
+ struct DNS_ADDR_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;
+
+ 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_partition {
+ struct dnsserver_partition *prev, *next;
+ struct ldb_dn *partition_dn;
+ const char *pszDpFqdn;
+ uint32_t dwDpFlags;
+ bool is_forest;
+ int zones_count;
+};
+
+
+struct dnsserver_partition_info {
+ const char *pszCrDn;
+ uint32_t dwState;
+ uint32_t dwReplicaCount;
+ struct DNS_RPC_DP_REPLICA **ReplicaArray;
+};
+
+
+struct dnsserver_zone {
+ struct dnsserver_zone *prev, *next;
+ struct dnsserver_partition *partition;
+ const char *name;
+ struct ldb_dn *zone_dn;
+ struct dnsserver_zoneinfo *zoneinfo;
+ struct dnsp_DnsProperty *tmp_props;
+ int32_t num_props;
+};
+
+
+struct dns_tree {
+ const char *name;
+ int level;
+ unsigned int num_children;
+ struct dns_tree **children;
+ void *data;
+};
+
+/* 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 IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
+ struct DNS_ADDR_ARRAY *ip);
+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(struct ldb_message * const *m1, struct ldb_message * const *m2,
+ const char *search_name);
+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);
+WERROR dns_to_dnsp_convert(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns,
+ struct dnsp_DnssrvRpcRecord **out_dnsp,
+ bool check_name);
+
+struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res);
+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, int num_children,
+ 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);
+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_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
+ struct dnsserver_serverinfo *serverinfo,
+ struct ldb_context *samdb);
+struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
+ struct ldb_context *samdb,
+ struct dnsserver_partition *p);
+struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
+ struct ldb_context *samdb,
+ struct dnsserver_partition *p);
+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_do_reset_dword(struct ldb_context *samdb,
+ struct dnsserver_zone *z,
+ struct DNS_RPC_NAME_AND_PARAM *n_p);
+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);
+WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
+ struct dnsserver_partition *partitions,
+ struct dnsserver_zone *z,
+ struct loadparm_context *lp_ctx);
+WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
+ struct dnsserver_zone *z);
+
+#endif /* __DNSSERVER_H__ */
diff --git a/source4/rpc_server/dnsserver/dnsutils.c b/source4/rpc_server/dnsserver/dnsutils.c
new file mode 100644
index 0000000..2c56946
--- /dev/null
+++ b/source4/rpc_server/dnsserver/dnsutils.c
@@ -0,0 +1,414 @@
+/*
+ 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 "dns_server/dnsserver_common.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/socket/netif.h"
+#include "lib/util/util_net.h"
+#include "dnsserver_common.h"
+
+#undef strcasecmp
+
+static struct DNS_ADDR_ARRAY *fill_dns_addr_array(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ bool listen_only)
+{
+ struct interface *ifaces;
+ int num_interfaces, i;
+ struct DNS_ADDR_ARRAY *dns_addr_array;
+ const char *ipstr;
+ bool have_ipv4, have_ipv6;
+ uint16_t family;
+
+ have_ipv4 = have_ipv6 = false;
+
+ if (!listen_only) {
+ /*
+ Return all interfaces from kernel
+ Not implemented!
+ */
+ return NULL;
+ }
+
+ /* Only the used interfaces */
+ load_interface_list(mem_ctx, lp_ctx, &ifaces);
+ num_interfaces = iface_list_count(ifaces);
+
+ dns_addr_array = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
+ if (dns_addr_array == NULL) {
+ goto nomem;
+ }
+ dns_addr_array->MaxCount = num_interfaces;
+ dns_addr_array->AddrCount = num_interfaces;
+ if (num_interfaces == 0) {
+ goto nomem;
+ }
+
+ dns_addr_array->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR,
+ num_interfaces);
+ if (!dns_addr_array->AddrArray) {
+ TALLOC_FREE(dns_addr_array);
+ goto nomem;
+ }
+
+ for (i = 0; i < num_interfaces; i++) {
+ int ret;
+ ipstr = iface_list_n_ip(ifaces, i);
+ if (is_ipaddress_v4(ipstr)) {
+ have_ipv4 = true;
+ dns_addr_array->AddrArray[i].MaxSa[0] = 0x02;
+ ret = inet_pton(AF_INET, ipstr,
+ &dns_addr_array->AddrArray[i].MaxSa[4]);
+ } else {
+ have_ipv6 = true;
+ dns_addr_array->AddrArray[i].MaxSa[0] = 0x17;
+ ret = inet_pton(AF_INET6, ipstr,
+ &dns_addr_array->AddrArray[i].MaxSa[8]);
+ }
+ if (ret != 1) { /*yep, 1 means success for inet_pton */
+ DBG_ERR("Interface %d address (%s) is invalid\n",
+ i, ipstr);
+ goto nomem;
+ }
+ }
+
+ if (have_ipv4 && have_ipv6) {
+ family = 0; /* mixed: MS-DNSP */
+ } else if (have_ipv4 && !have_ipv6) {
+ family = AF_INET;
+ } else {
+ family = AF_INET6;
+ }
+ dns_addr_array->Family = family;
+
+nomem:
+ talloc_free(ifaces);
+ return dns_addr_array;
+}
+
+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;
+
+ 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 = dsdb_dc_functional_level(samdb);
+
+ 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));
+ /* IP addresses on which the DNS server listens for DNS requests */
+ serverinfo->aipListenAddrs = fill_dns_addr_array(mem_ctx, lp_ctx, true);
+
+ /* All IP addresses available on the server
+ * Not implemented!
+ * Use same as listen addresses
+ */
+ serverinfo->aipServerAddrs = serverinfo->aipListenAddrs;
+
+ 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 = lpcfg_parm_int(
+ lp_ctx, NULL, "dnsserver", "ScavengingInterval", 24 * 7);
+ serverinfo->dwDefaultRefreshInterval = lpcfg_parm_int(
+ lp_ctx, NULL, "dnsserver", "DefaultRefreshInterval", 24 * 3);
+ serverinfo->dwDefaultNoRefreshInterval = lpcfg_parm_int(
+ lp_ctx, NULL, "dnsserver", "DefaultNoRefreshInterval", 24 * 3);
+
+ 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)
+{
+ struct dnsserver_zoneinfo *zoneinfo;
+ uint32_t fReverse;
+ const char *revzone = "in-addr.arpa";
+ const char *revzone6 = "ip6.arpa";
+ int len1, len2;
+ unsigned int i = 0;
+
+ zoneinfo = talloc_zero(zone, struct dnsserver_zoneinfo);
+ if (zoneinfo == NULL) {
+ return NULL;
+ }
+
+ /* If the zone name ends with in-addr.arpa, it's reverse zone */
+ /* If the zone name ends with ip6.arpa, it's reverse zone (IPv6) */
+ fReverse = 0;
+ len1 = strlen(zone->name);
+ len2 = strlen(revzone);
+ if (len1 > len2 && strcasecmp(&zone->name[len1-len2], revzone) == 0) {
+ fReverse = 1;
+ } else {
+ len2 = strlen(revzone6);
+ if (len1 > len2 && strcasecmp(&zone->name[len1-len2], revzone6) == 0) {
+ fReverse = 1;
+ }
+ }
+
+ zoneinfo->Version = 0x32;
+ zoneinfo->Flags = DNS_RPC_ZONE_DSINTEGRATED;
+
+ if (strcmp(zone->name, ".") == 0) {
+ zoneinfo->dwZoneType = DNS_ZONE_TYPE_CACHE;
+ zoneinfo->fAllowUpdate = DNS_ZONE_UPDATE_OFF;
+ zoneinfo->fSecureSecondaries = DNS_ZONE_SECSECURE_NO_SECURITY;
+ zoneinfo->fNotifyLevel = DNS_ZONE_NOTIFY_OFF;
+ zoneinfo->dwNoRefreshInterval = 0;
+ zoneinfo->dwRefreshInterval = 0;
+ } else {
+ zoneinfo->Flags |= DNS_RPC_ZONE_UPDATE_SECURE;
+ zoneinfo->dwZoneType = DNS_ZONE_TYPE_PRIMARY;
+ zoneinfo->fAllowUpdate = DNS_ZONE_UPDATE_SECURE;
+ zoneinfo->fSecureSecondaries = DNS_ZONE_SECSECURE_NO_XFER;
+ zoneinfo->fNotifyLevel = DNS_ZONE_NOTIFY_LIST_ONLY;
+ zoneinfo->dwNoRefreshInterval = serverinfo->dwDefaultNoRefreshInterval;
+ zoneinfo->dwRefreshInterval = serverinfo->dwDefaultRefreshInterval;
+ }
+
+ zoneinfo->fReverse = fReverse;
+ zoneinfo->fPaused = 0;
+ zoneinfo->fShutdown = 0;
+ zoneinfo->fAutoCreated = 0;
+ zoneinfo->fUseDatabase = 1;
+ zoneinfo->pszDataFile = NULL;
+ zoneinfo->aipMasters = NULL;
+ zoneinfo->aipSecondaries = NULL;
+ zoneinfo->aipNotify = NULL;
+ zoneinfo->fUseWins = 0;
+ zoneinfo->fUseNbstat = 0;
+ zoneinfo->fAging = 0;
+ zoneinfo->dwAvailForScavengeTime = 0;
+ zoneinfo->aipScavengeServers = NULL;
+ zoneinfo->dwForwarderTimeout = 0;
+ zoneinfo->fForwarderSlave = 0;
+ zoneinfo->aipLocalMasters = NULL;
+ 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;
+
+ for(i=0; i<zone->num_props; i++){
+ bool valid_property;
+ valid_property = dns_zoneinfo_load_zone_property(
+ zoneinfo, &zone->tmp_props[i]);
+ if (!valid_property) {
+ TALLOC_FREE(zoneinfo);
+ return NULL;
+ }
+ }
+
+ 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 (samba_dns_name_equal(zone_name, z->name)) {
+ 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;
+ struct ldb_val name_val =
+ data_blob_string_const(name);
+
+ dn = ldb_dn_copy(mem_ctx, z->zone_dn);
+ if (dn == NULL) {
+ return NULL;
+ }
+ if (strcasecmp(name, z->name) == 0) {
+ ret = ldb_dn_add_child_fmt(dn, "DC=@");
+ if (!ret) {
+ talloc_free(dn);
+ return NULL;
+ }
+ return dn;
+ }
+
+ ret = ldb_dn_add_child_val(dn,
+ "DC",
+ name_val);
+
+ if (!ret) {
+ talloc_free(dn);
+ return NULL;
+ }
+
+ return dn;
+}
+
+uint32_t dnsserver_zone_to_request_filter(const char *zone_name)
+{
+ uint32_t request_filter = 0;
+
+ 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;
+}