s4:rpc_server: only use context within op_bind() hooks and dcesrv_interface_bind_...
[gd/samba-autobuild/.git] / source4 / rpc_server / dnsserver / dcerpc_dnsserver.c
index 5733a51177ae3a824272198880ce6abaa1285ba2..7c2ca8e4d5283553506a8db69a4934d3b827f0fb 100644 (file)
 #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;
@@ -63,14 +73,14 @@ static void dnsserver_reload_zones(struct dnsserver_state *dsstate)
                                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;
                }
@@ -95,16 +105,21 @@ static void dnsserver_reload_zones(struct dnsserver_state *dsstate)
 
 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;
        }
@@ -112,8 +127,12 @@ static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_c
        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;
@@ -142,18 +161,29 @@ static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_c
                }
                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;
 
@@ -196,8 +226,10 @@ static WERROR dnsserver_query_server(struct dnsserver_state *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;
@@ -238,8 +270,10 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                        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);
@@ -293,8 +327,8 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                        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);
@@ -694,9 +728,9 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                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) {
@@ -1095,6 +1129,7 @@ static WERROR dnsserver_operate_server(struct dnsserver_state *dsstate,
        } 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);
@@ -1104,20 +1139,32 @@ static WERROR dnsserver_operate_server(struct dnsserver_state *dsstate,
                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;
@@ -1206,9 +1253,9 @@ static WERROR dnsserver_complex_operate_server(struct dnsserver_state *dsstate,
 {
        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) {
@@ -1491,15 +1538,14 @@ static WERROR dnsserver_operate_zone(struct dnsserver_state *dsstate,
        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) {
@@ -1625,7 +1671,8 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
        }
 
        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;
@@ -1656,9 +1703,13 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
        /* 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;
@@ -1722,12 +1773,15 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
        /* 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);
@@ -1798,10 +1852,15 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
 
                        /* 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;
@@ -1835,6 +1894,37 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate,
        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,
@@ -1853,13 +1943,22 @@ 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 */