s4:rpc-dnsserver: Use cached zone information to get rootservers
[ddiss/samba.git] / source4 / rpc_server / dnsserver / dcerpc_dnsserver.c
index fd0c97795a7d4bff735997d2cf52f65f51194cc4..345cfb814e859c54774e6f9baf9b61ffb404df0e 100644 (file)
@@ -31,6 +31,7 @@
 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;
@@ -42,7 +43,8 @@ struct dnsserver_state {
 static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_call)
 {
        struct dnsserver_state *dsstate;
-       struct dnsserver_zone *zones, *z;
+       struct dnsserver_zone *zones, *z, *znext;
+       struct dnsserver_partition *partitions, *p;
 
        dsstate = talloc_get_type(dce_call->context->private_data, struct dnsserver_state);
        if (dsstate != NULL) {
@@ -72,31 +74,30 @@ static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_c
                goto failed;
        }
 
-       /* Search for DNS zones */
-       zones = dnsserver_db_enumerate_zones(dsstate, dsstate->samdb, true);
-       if (zones == NULL) {
+       /* Search for DNS partitions */
+       partitions = dnsserver_db_enumerate_partitions(dsstate, dsstate->serverinfo, dsstate->samdb);
+       if (partitions == NULL) {
                goto failed;
        }
-       for (z = zones; z; z = z->next) {
-               z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo, true);
-               if (z->zoneinfo == NULL) {
-                       goto failed;
-               }
-               DLIST_ADD_END(dsstate->zones, z, NULL);
-               dsstate->zones_count++;
-       }
+       dsstate->partitions = partitions;
 
-       zones = dnsserver_db_enumerate_zones(dsstate, dsstate->samdb, false);
-       if (zones == NULL) {
-               goto failed;
-       }
-       for (z = zones; z; z = z->next) {
-               z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo, false);
-               if (z->zoneinfo == NULL) {
+       /* 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;
                }
-               DLIST_ADD_END(dsstate->zones, z, NULL);
-               dsstate->zones_count++;
+               for (z = zones; z; ) {
+                       znext = z->next;
+                       z->zoneinfo = dnsserver_init_zoneinfo(z, dsstate->serverinfo);
+                       if (z->zoneinfo == NULL) {
+                               goto failed;
+                       }
+                       DLIST_ADD_END(dsstate->zones, z, NULL);
+                       p->zones_count++;
+                       dsstate->zones_count++;
+                       z = znext;
+               }
        }
 
        dce_call->context->private_data = dsstate;
@@ -773,8 +774,8 @@ static WERROR dnsserver_query_zone(struct dnsserver_state *dsstate,
                        r->Zone->Flags = zoneinfo->Flags;
                        r->Zone->ZoneType = zoneinfo->dwZoneType;
                        r->Zone->Version = zoneinfo->Version;
-                       r->Zone->dwDpFlags = zoneinfo->dwDpFlags;
-                       r->Zone->pszDpFqdn = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+                       r->Zone->dwDpFlags = z->partition->dwDpFlags;
+                       r->Zone->pszDpFqdn = talloc_strdup(mem_ctx, z->partition->pszDpFqdn);
                }
                return WERR_OK;
        }
@@ -835,8 +836,8 @@ static WERROR dnsserver_query_zone(struct dnsserver_state *dsstate,
                        r->ZoneInfoDotNet->dwForwarderTimeout = zoneinfo->dwForwarderTimeout;
                        r->ZoneInfoDotNet->fForwarderSlave = zoneinfo->fForwarderSlave;
                        r->ZoneInfoDotNet->aipLocalMasters = ip4_array_copy(mem_ctx, zoneinfo->aipLocalMasters);
-                       r->ZoneInfoDotNet->dwDpFlags = zoneinfo->dwDpFlags;
-                       r->ZoneInfoDotNet->pszDpFqdn = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+                       r->ZoneInfoDotNet->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;
@@ -870,8 +871,8 @@ static WERROR dnsserver_query_zone(struct dnsserver_state *dsstate,
                        r->ZoneInfo->dwForwarderTimeout = zoneinfo->dwForwarderTimeout;
                        r->ZoneInfo->fForwarderSlave = zoneinfo->fForwarderSlave;
                        r->ZoneInfo->aipLocalMasters = ip4_array_to_dns_addr_array(mem_ctx, zoneinfo->aipLocalMasters);
-                       r->ZoneInfo->dwDpFlags = zoneinfo->dwDpFlags;
-                       r->ZoneInfo->pszDpFqdn = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+                       r->ZoneInfo->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;
@@ -998,7 +999,7 @@ static WERROR dnsserver_query_zone(struct dnsserver_state *dsstate,
                answer_string = talloc_strdup(mem_ctx, zoneinfo->pszDataFile);
                is_string = 1;
        } else if (strcasecmp(operation, "ApplicationDirectoryPartition") == 0) {
-               answer_string = talloc_strdup(mem_ctx, zoneinfo->pszDpFqdn);
+               answer_string = talloc_strdup(mem_ctx, z->partition->pszDpFqdn);
                is_string = 1;
        } else if (strcasecmp(operation, "BreakOnNameUpdate") == 0) {
                answer_string = NULL;
@@ -1105,7 +1106,7 @@ static WERROR dnsserver_complex_operate_server(struct dnsserver_state *dsstate,
        int valid_operation = 0;
        struct dnsserver_zone *z, **zlist;
        int zcount;
-       bool found;
+       bool found1, found2, found3, found4;
        int i;
 
        if (strcasecmp(operation, "QueryDwordProperty") == 0) {
@@ -1124,74 +1125,109 @@ static WERROR dnsserver_complex_operate_server(struct dnsserver_state *dsstate,
                zcount = 0;
                zlist = talloc_zero_array(mem_ctx, struct dnsserver_zone *, 0);
                for (z = dsstate->zones; z; z = z->next) {
-                       found = false;
-                       if (rin->Dword & DNS_ZONE_REQUEST_PRIMARY) {
-                               if (z->zoneinfo->dwZoneType & DNS_ZONE_TYPE_PRIMARY) {
-                                       found = true;
+
+                       /* 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) {
-                                       found = 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) {
-                                       found = 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->zoneinfo->dwDpFlags & DNS_DP_AUTOCREATED) {
-                                       found = true;
+                               if (rin->Dword & DNS_ZONE_REQUEST_AUTO) {
+                                       if (z->zoneinfo->fAutoCreated 
+                                               || z->partition->dwDpFlags & DNS_DP_AUTOCREATED) {
+                                               found1 = true;
+                                       }
                                }
+                       } else {
+                               found1 = true;
                        }
-                       if (rin->Dword & DNS_ZONE_REQUEST_FORWARD) {
-                               if (!(z->zoneinfo->Flags & DNS_RPC_ZONE_REVERSE)) {
-                                       found = 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->Flags & DNS_RPC_ZONE_REVERSE) {
-                                       found = 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) {
-                                       found = 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) {
-                                       found = true;
+                               if (rin->Dword & DNS_ZONE_REQUEST_STUB) {
+                                       if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_STUB) {
+                                               found2 = true;
+                                       }
                                }
+                       } else {
+                               found2 = true;
                        }
-                       if (rin->Dword & DNS_ZONE_REQUEST_DS) {
-                               if (z->zoneinfo->Flags & DNS_RPC_ZONE_DSINTEGRATED) {
-                                       found = 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)) {
-                                       found = 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->zoneinfo->dwDpFlags & DNS_DP_DOMAIN_DEFAULT) {
-                                       found = 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->zoneinfo->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
-                                       found = 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 (found) {
+                       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) {
@@ -1247,8 +1283,8 @@ static WERROR dnsserver_complex_operate_server(struct dnsserver_state *dsstate,
                                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]->zoneinfo->dwDpFlags;
-                               rout->ZoneList->ZoneArray[i]->pszDpFqdn = talloc_strdup(mem_ctx, zlist[i]->zoneinfo->pszDpFqdn);
+                               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;
@@ -1258,7 +1294,40 @@ static WERROR dnsserver_complex_operate_server(struct dnsserver_state *dsstate,
        } else if (strcasecmp(operation, "EnumZones2") == 0) {
                valid_operation = true;
        } else if (strcasecmp(operation, "EnumDirectoryPartitions") == 0) {
-               valid_operation = true;
+               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);
+                       if (dplist == NULL) {
+                               return WERR_NOMEM;
+                       }
+
+                       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) {
                valid_operation = true;
        } else if (strcasecmp(operation, "Statistics") == 0) {
@@ -1388,9 +1457,9 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
                                        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 ldb_dn *dn;
        struct DNS_RPC_RECORDS_ARRAY *recs;
        char **add_names;
        char *rname;
@@ -1401,15 +1470,12 @@ static WERROR dnsserver_enumerate_root_records(struct dnsserver_state *dsstate,
        tmp_ctx = talloc_new(mem_ctx);
        W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
 
-       dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(dsstate->samdb));
-       W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
-
-       if (!ldb_dn_add_child_fmt(dn, "DC=RootDNSServers,CN=MicrosoftDNS,DC=DomainDnsZones")) {
-               talloc_free(tmp_ctx);
-               return WERR_NOMEM;
+       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, dn,
+       ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
                                LDB_SCOPE_ONELEVEL, attrs, "(&(objectClass=dnsNode)(name=@))");
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -1441,7 +1507,7 @@ 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++) {
-                       ret = ldb_search(dsstate->samdb, tmp_ctx, &res, dn,
+                       ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn,
                                        LDB_SCOPE_ONELEVEL, attrs,
                                        "(&(objectClass=dnsNode)(name=%s))", add_names[i]);
                        if (ret != LDB_SUCCESS || res->count == 0) {