#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"
-#include "lib/ldb/include/ldb_private.h"
+#define DCESRV_INTERFACE_DNSSERVER_BIND(call, iface) \
+ dcesrv_interface_dnsserver_bind(call, iface)
+static NTSTATUS dcesrv_interface_dnsserver_bind(struct dcesrv_call_state *dce_call,
+ const struct dcesrv_interface *iface)
+{
+ struct dcesrv_connection_context *context = dce_call->context;
+ 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;
if (z->zoneinfo == NULL) {
continue;
}
- DLIST_ADD_END(new_list, z, NULL);
+ 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, NULL);
+ DLIST_ADD_END(new_list, zmatch);
}
z = znext;
}
static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_call)
{
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(dce_call);
struct dnsserver_state *dsstate;
struct dnsserver_zone *zones, *z, *znext;
struct dnsserver_partition *partitions, *p;
+ NTSTATUS status;
- dsstate = talloc_get_type(dce_call->context->private_data, struct dnsserver_state);
+ dsstate = dcesrv_iface_state_find_conn(dce_call,
+ DNSSERVER_STATE_MAGIC,
+ struct dnsserver_state);
if (dsstate != NULL) {
return dsstate;
}
- dsstate = talloc_zero(dce_call->context, struct dnsserver_state);
+ dsstate = talloc_zero(dce_call, struct dnsserver_state);
if (dsstate == NULL) {
return NULL;
}
dsstate->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
/* FIXME: create correct auth_session_info for connecting user */
- dsstate->samdb = samdb_connect(dsstate, dce_call->event_ctx, dsstate->lp_ctx,
- dce_call->conn->auth_state.session_info, 0);
+ dsstate->samdb = samdb_connect(dsstate,
+ dce_call->event_ctx,
+ dsstate->lp_ctx,
+ session_info,
+ dce_call->conn->remote_address,
+ 0);
if (dsstate->samdb == NULL) {
DEBUG(0,("dnsserver: Failed to open samdb"));
goto failed;
}
for (z = zones; z; ) {
znext = z->next;
- z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo);
- if (z->zoneinfo == NULL) {
- goto failed;
+ 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'",
+ z->name, ldb_dn_get_linearized(z->zone_dn)));
}
- DLIST_ADD_END(dsstate->zones, z, NULL);
- p->zones_count++;
- dsstate->zones_count++;
z = znext;
}
}
- dce_call->context->private_data = dsstate;
+ status = dcesrv_iface_state_store_conn(dce_call,
+ DNSSERVER_STATE_MAGIC,
+ dsstate);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
return dsstate;
r->ServerInfoW2K->fDsAvailable = serverinfo->fDsAvailable;
r->ServerInfoW2K->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
r->ServerInfoW2K->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
- r->ServerInfoW2K->aipServerAddrs = ip4_array_copy(mem_ctx, serverinfo->aipServerAddrs);
- r->ServerInfoW2K->aipListenAddrs = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+ r->ServerInfoW2K->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->ServerInfoDotNet->fDsAvailable = serverinfo->fDsAvailable;
r->ServerInfoDotNet->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
r->ServerInfoDotNet->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
- r->ServerInfoDotNet->aipServerAddrs = ip4_array_copy(mem_ctx, serverinfo->aipServerAddrs);
- r->ServerInfoDotNet->aipListenAddrs = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+ r->ServerInfoDotNet->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->ServerInfo->fDsAvailable = serverinfo->fDsAvailable;
r->ServerInfo->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
r->ServerInfo->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
- r->ServerInfo->aipServerAddrs = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipServerAddrs);
- r->ServerInfo->aipListenAddrs = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipListenAddrs);
+ r->ServerInfo->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);
is_addresses = 1;
} else if (strcasecmp(operation, "ListenAddresses") == 0) {
if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
- answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipListenAddrs);
+ answer_addrarray = serverinfo->aipListenAddrs;
} else {
- answer_iparray = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+ answer_iparray = dns_addr_array_to_ip4_array(mem_ctx, serverinfo->aipListenAddrs);
}
is_addresses = 1;
} else if (strcasecmp(operation, "BreakOnReceiveFrom") == 0) {
} else if (strcasecmp(operation, "ZoneCreate") == 0) {
struct dnsserver_zone *z, *z2;
WERROR status;
+ int len;
z = talloc_zero(mem_ctx, struct dnsserver_zone);
W_ERROR_HAVE_NO_MEMORY(z);
W_ERROR_HAVE_NO_MEMORY_AND_FREE(z->zoneinfo, z);
if (typeid == DNSSRV_TYPEID_ZONE_CREATE_W2K) {
- z->name = talloc_strdup(z, r->ZoneCreateW2K->pszZoneName);
+ len = strlen(r->ZoneCreateW2K->pszZoneName);
+ if (r->ZoneCreateW2K->pszZoneName[len-1] == '.') {
+ len -= 1;
+ }
+ z->name = talloc_strndup(z, r->ZoneCreateW2K->pszZoneName, len);
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) {
- z->name = talloc_strdup(z, r->ZoneCreateDotNet->pszZoneName);
+ len = strlen(r->ZoneCreateDotNet->pszZoneName);
+ if (r->ZoneCreateDotNet->pszZoneName[len-1] == '.') {
+ len -= 1;
+ }
+ z->name = talloc_strndup(z, r->ZoneCreateDotNet->pszZoneName, len);
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) {
- z->name = talloc_strdup(z, r->ZoneCreate->pszZoneName);
+ len = strlen(r->ZoneCreate->pszZoneName);
+ if (r->ZoneCreate->pszZoneName[len-1] == '.') {
+ len -= 1;
+ }
+ z->name = talloc_strndup(z, r->ZoneCreate->pszZoneName, len);
z->zoneinfo->dwZoneType = r->ZoneCreate->dwZoneType;
z->zoneinfo->fAllowUpdate = r->ZoneCreate->fAllowUpdate;
z->zoneinfo->fAging = r->ZoneCreate->fAging;
{
int valid_operation = 0;
struct dnsserver_zone *z, **zlist;
- int zcount;
+ size_t zcount;
bool found1, found2, found3, found4;
- int i;
+ size_t i;
if (strcasecmp(operation, "QueryDwordProperty") == 0) {
if (typeid_in == DNSSRV_TYPEID_LPSTR) {
bool valid_operation = false;
if (strcasecmp(operation, "ResetDwordProperty") == 0) {
+
if (typeid != DNSSRV_TYPEID_NAME_AND_PARAM) {
return WERR_DNS_ERROR_INVALID_PROPERTY;
}
- /* Ignore property resets */
- if (strcasecmp(r->NameAndParam->pszNodeName, "AllowUpdate") == 0) {
- return WERR_OK;
- }
- valid_operation = true;
+ 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) {
}
ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
- LDB_SCOPE_ONELEVEL, attrs, "(&(objectClass=dnsNode)(name=@))");
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=@)(!(dNSTombstoned=TRUE)))");
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return WERR_INTERNAL_DB_ERROR;
/* 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))", add_names[i]);
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ encoded_name);
if (ret != LDB_SUCCESS || res->count == 0) {
talloc_free(res);
continue;
/* 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)");
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))");
} 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)))",
- name, name);
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s))(!(dNSTombstoned=TRUE)))",
+ encoded_name, encoded_name);
}
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
/* 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))", name);
+ "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
+ encoded_name);
talloc_free(name);
if (ret != LDB_SUCCESS) {
continue;
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,
W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
/* If node_name is @ or zone name, dns record is @ */
- if (strcmp(node_name, "@") == 0 || strcasecmp(node_name, z->name) == 0) {
+ 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 */