LCOV - code coverage report
Current view: top level - source4/rpc_server/dnsserver - dnsdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 420 672 62.5 %
Date: 2024-04-21 15:09:00 Functions: 13 15 86.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    DNS Server
       5             : 
       6             :    Copyright (C) Amitay Isaacs 2011
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "dnsserver.h"
      24             : #include "lib/util/dlinklist.h"
      25             : #include "librpc/gen_ndr/ndr_dnsp.h"
      26             : #include "librpc/gen_ndr/ndr_security.h"
      27             : #include "librpc/gen_ndr/ndr_misc.h"
      28             : #include "dsdb/samdb/samdb.h"
      29             : #include "libcli/security/security.h"
      30             : #include "dsdb/common/util.h"
      31             : 
      32             : #undef strcasecmp
      33             : 
      34             : /* There are only 2 fixed partitions for DNS */
      35        1531 : struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
      36             :                                                         struct dnsserver_serverinfo *serverinfo,
      37             :                                                         struct ldb_context *samdb)
      38             : {
      39           0 :         struct dnsserver_partition *partitions, *p;
      40             : 
      41        1531 :         partitions = NULL;
      42             : 
      43             :         /* Domain partition */
      44        1531 :         p = talloc_zero(mem_ctx, struct dnsserver_partition);
      45        1531 :         if (p == NULL) {
      46           0 :                 goto failed;
      47             :         }
      48             : 
      49        1531 :         p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszDomainDirectoryPartition);
      50        1531 :         if (p->partition_dn == NULL) {
      51           0 :                 goto failed;
      52             :         }
      53             : 
      54        1531 :         p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
      55        1531 :         p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_DOMAIN_DEFAULT | DNS_DP_ENLISTED;
      56        1531 :         p->is_forest = false;
      57             : 
      58        1531 :         DLIST_ADD_END(partitions, p);
      59             : 
      60             :         /* Forest Partition */
      61        1531 :         p = talloc_zero(mem_ctx, struct dnsserver_partition);
      62        1531 :         if (p == NULL) {
      63           0 :                 goto failed;
      64             :         }
      65             : 
      66        1531 :         p->partition_dn = ldb_dn_new(p, samdb, serverinfo->pszForestDirectoryPartition);
      67        1531 :         if (p->partition_dn == NULL) {
      68           0 :                 goto failed;
      69             :         }
      70             : 
      71        1531 :         p->pszDpFqdn = samdb_dn_to_dns_domain(p, p->partition_dn);
      72        1531 :         p->dwDpFlags = DNS_DP_AUTOCREATED | DNS_DP_FOREST_DEFAULT | DNS_DP_ENLISTED;
      73        1531 :         p->is_forest = true;
      74             : 
      75        1531 :         DLIST_ADD_END(partitions, p);
      76             : 
      77        1531 :         return partitions;
      78             : 
      79           0 : failed:
      80           0 :         return NULL;
      81             : 
      82             : }
      83             : 
      84             : 
      85             : /* Search for all dnsZone records */
      86        4674 : struct dnsserver_zone *dnsserver_db_enumerate_zones(TALLOC_CTX *mem_ctx,
      87             :                                                 struct ldb_context *samdb,
      88             :                                                 struct dnsserver_partition *p)
      89             : {
      90           0 :         TALLOC_CTX *tmp_ctx;
      91        4674 :         const char * const attrs[] = {"name", "dNSProperty", NULL};
      92           0 :         struct ldb_dn *dn;
      93           0 :         struct ldb_result *res;
      94           0 :         struct dnsserver_zone *zones, *z;
      95           0 :         int i, j, ret;
      96             : 
      97        4674 :         tmp_ctx = talloc_new(mem_ctx);
      98        4674 :         if (tmp_ctx == NULL) {
      99           0 :                 return NULL;
     100             :         }
     101             : 
     102        4674 :         dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
     103        4674 :         if (dn == NULL) {
     104           0 :                 goto failed;
     105             :         }
     106        4674 :         if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
     107           0 :                 goto failed;
     108             :         }
     109             : 
     110        4674 :         ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE,
     111             :                           attrs, "(objectClass=dnsZone)");
     112        4674 :         if (ret != LDB_SUCCESS) {
     113           0 :                 DEBUG(0, ("dnsserver: Failed to find DNS Zones in %s\n",
     114             :                         ldb_dn_get_linearized(dn)));
     115           0 :                 goto failed;
     116             :         }
     117             : 
     118        4674 :         zones = NULL;
     119       12930 :         for(i=0; i<res->count; i++) {
     120           0 :                 char *name;
     121        8256 :                 struct ldb_message_element *element = NULL;
     122        8256 :                 struct dnsp_DnsProperty *props = NULL;
     123           0 :                 enum ndr_err_code err;
     124        8256 :                 z = talloc_zero(mem_ctx, struct dnsserver_zone);
     125        8256 :                 if (z == NULL) {
     126           0 :                         goto failed;
     127             :                 }
     128             : 
     129        8256 :                 z->partition = p;
     130        8256 :                 name = talloc_strdup(z,
     131        8256 :                                 ldb_msg_find_attr_as_string(res->msgs[i],
     132             :                                                             "name", NULL));
     133        8256 :                 if (strcmp(name, "..TrustAnchors") == 0) {
     134           0 :                         talloc_free(z);
     135           0 :                         continue;
     136             :                 }
     137        8256 :                 if (strcmp(name, "RootDNSServers") == 0) {
     138        2337 :                         talloc_free(name);
     139        2337 :                         z->name = talloc_strdup(z, ".");
     140             :                 } else {
     141        5919 :                         z->name = name;
     142             :                 }
     143        8256 :                 z->zone_dn = talloc_steal(z, res->msgs[i]->dn);
     144             : 
     145        8256 :                 DLIST_ADD_END(zones, z);
     146        8256 :                 DEBUG(2, ("dnsserver: Found DNS zone %s\n", z->name));
     147             : 
     148        8256 :                 element = ldb_msg_find_element(res->msgs[i], "dNSProperty");
     149        8256 :                 if(element != NULL){
     150        5919 :                         props = talloc_zero_array(tmp_ctx,
     151             :                                                   struct dnsp_DnsProperty,
     152             :                                                   element->num_values);
     153       47352 :                         for (j = 0; j < element->num_values; j++ ) {
     154       41433 :                                 err = ndr_pull_struct_blob(
     155       41433 :                                         &(element->values[j]),
     156             :                                         mem_ctx,
     157       41433 :                                         &props[j],
     158             :                                         (ndr_pull_flags_fn_t)
     159             :                                                 ndr_pull_dnsp_DnsProperty);
     160       41433 :                                 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
     161             :                                         /*
     162             :                                          * Per Microsoft we must
     163             :                                          * ignore invalid data here
     164             :                                          * and continue as a Windows
     165             :                                          * server can put in a
     166             :                                          * structure with an invalid
     167             :                                          * length.
     168             :                                          *
     169             :                                          * We can safely fill in an
     170             :                                          * extra empty property here
     171             :                                          * because
     172             :                                          * dns_zoneinfo_load_zone_property()
     173             :                                          * just ignores
     174             :                                          * DSPROPERTY_ZONE_EMPTY
     175             :                                          */
     176           0 :                                         ZERO_STRUCT(props[j]);
     177           0 :                                         props[j].id = DSPROPERTY_ZONE_EMPTY;
     178           0 :                                         continue;
     179             :                                 }
     180             :                         }
     181        5919 :                         z->tmp_props = props;
     182        5919 :                         z->num_props = element->num_values;
     183             :                 }
     184             :         }
     185        4674 :         return zones;
     186             : 
     187           0 : failed:
     188           0 :         talloc_free(tmp_ctx);
     189           0 :         return NULL;
     190             : }
     191             : 
     192             : 
     193             : /* Find DNS partition information */
     194           0 : struct dnsserver_partition_info *dnsserver_db_partition_info(TALLOC_CTX *mem_ctx,
     195             :                                                         struct ldb_context *samdb,
     196             :                                                         struct dnsserver_partition *p)
     197             : {
     198           0 :         const char * const attrs[] = { "instanceType", "msDs-masteredBy", NULL };
     199           0 :         const char * const attrs_none[] = { NULL };
     200           0 :         struct ldb_result *res;
     201           0 :         struct ldb_message_element *el;
     202           0 :         struct ldb_dn *dn;
     203           0 :         struct dnsserver_partition_info *partinfo;
     204           0 :         int i, ret, instance_type;
     205           0 :         TALLOC_CTX *tmp_ctx;
     206             : 
     207           0 :         tmp_ctx = talloc_new(mem_ctx);
     208           0 :         if (tmp_ctx == NULL) {
     209           0 :                 return NULL;
     210             :         }
     211             : 
     212           0 :         partinfo = talloc_zero(mem_ctx, struct dnsserver_partition_info);
     213           0 :         if (partinfo == NULL) {
     214           0 :                 talloc_free(tmp_ctx);
     215           0 :                 return NULL;
     216             :         }
     217             : 
     218             :         /* Search for the active replica and state */
     219           0 :         ret = ldb_search(samdb, tmp_ctx, &res, p->partition_dn, LDB_SCOPE_BASE,
     220             :                         attrs, NULL);
     221           0 :         if (ret != LDB_SUCCESS || res->count != 1) {
     222           0 :                 goto failed;
     223             :         }
     224             : 
     225             :         /* Set the state of the partition */
     226           0 :         instance_type = ldb_msg_find_attr_as_int(res->msgs[0], "instanceType", -1);
     227           0 :         if (instance_type == -1) {
     228           0 :                 partinfo->dwState = DNS_DP_STATE_UNKNOWN;
     229           0 :         } else if (instance_type & INSTANCE_TYPE_NC_COMING) {
     230           0 :                 partinfo->dwState = DNS_DP_STATE_REPL_INCOMING;
     231           0 :         } else if (instance_type & INSTANCE_TYPE_NC_GOING) {
     232           0 :                 partinfo->dwState = DNS_DP_STATE_REPL_OUTGOING;
     233             :         } else {
     234           0 :                 partinfo->dwState = DNS_DP_OKAY;
     235             :         }
     236             : 
     237           0 :         el = ldb_msg_find_element(res->msgs[0], "msDs-masteredBy");
     238           0 :         if (el == NULL) {
     239           0 :                 partinfo->dwReplicaCount = 0;
     240           0 :                 partinfo->ReplicaArray = NULL;
     241             :         } else {
     242           0 :                 partinfo->dwReplicaCount = el->num_values;
     243           0 :                 partinfo->ReplicaArray = talloc_zero_array(partinfo,
     244             :                                                            struct DNS_RPC_DP_REPLICA *,
     245             :                                                            el->num_values);
     246           0 :                 if (partinfo->ReplicaArray == NULL) {
     247           0 :                         goto failed;
     248             :                 }
     249           0 :                 for (i=0; i<el->num_values; i++) {
     250           0 :                         partinfo->ReplicaArray[i] = talloc_zero(partinfo,
     251             :                                                         struct DNS_RPC_DP_REPLICA);
     252           0 :                         if (partinfo->ReplicaArray[i] == NULL) {
     253           0 :                                 goto failed;
     254             :                         }
     255           0 :                         partinfo->ReplicaArray[i]->pszReplicaDn = talloc_strdup(
     256             :                                                                         partinfo,
     257           0 :                                                                         (const char *)el->values[i].data);
     258           0 :                         if (partinfo->ReplicaArray[i]->pszReplicaDn == NULL) {
     259           0 :                                 goto failed;
     260             :                         }
     261             :                 }
     262             :         }
     263           0 :         talloc_free(res);
     264             : 
     265             :         /* Search for cross-reference object */
     266           0 :         dn = ldb_dn_copy(tmp_ctx, ldb_get_config_basedn(samdb));
     267           0 :         if (dn == NULL) {
     268           0 :                 goto failed;
     269             :         }
     270             : 
     271           0 :         ret = ldb_search(samdb, tmp_ctx, &res, dn, LDB_SCOPE_DEFAULT, attrs_none,
     272             :                         "(nCName=%s)", ldb_dn_get_linearized(p->partition_dn));
     273           0 :         if (ret != LDB_SUCCESS || res->count != 1) {
     274           0 :                 goto failed;
     275             :         }
     276           0 :         partinfo->pszCrDn = talloc_strdup(partinfo, ldb_dn_get_linearized(res->msgs[0]->dn));
     277           0 :         if (partinfo->pszCrDn == NULL) {
     278           0 :                 goto failed;
     279             :         }
     280           0 :         talloc_free(res);
     281             : 
     282           0 :         talloc_free(tmp_ctx);
     283           0 :         return partinfo;
     284             : 
     285           0 : failed:
     286           0 :         talloc_free(tmp_ctx);
     287           0 :         talloc_free(partinfo);
     288           0 :         return NULL;
     289             : }
     290             : 
     291             : 
     292             : /* Increment serial number and update timestamp */
     293        3693 : static unsigned int dnsserver_update_soa(TALLOC_CTX *mem_ctx,
     294             :                                 struct ldb_context *samdb,
     295             :                                 struct dnsserver_zone *z,
     296             :                                 WERROR *werr)
     297             : {
     298        3693 :         const char * const attrs[] = { "dnsRecord", NULL };
     299           0 :         struct ldb_result *res;
     300           0 :         struct dnsp_DnssrvRpcRecord rec;
     301           0 :         struct ldb_message_element *el;
     302           0 :         enum ndr_err_code ndr_err;
     303        3693 :         int ret, i, serial = -1;
     304             : 
     305        3693 :         *werr = WERR_INTERNAL_DB_ERROR;
     306             : 
     307        3693 :         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
     308             :                         "(&(objectClass=dnsNode)(name=@))");
     309        3693 :         if (ret != LDB_SUCCESS || res->count == 0) {
     310           0 :                 return -1;
     311             :         }
     312             : 
     313        3693 :         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
     314        3693 :         if (el == NULL) {
     315           0 :                 return -1;
     316             :         }
     317             : 
     318        3805 :         for (i=0; i<el->num_values; i++) {
     319        3805 :                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec,
     320             :                                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
     321        3805 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     322           0 :                         continue;
     323             :                 }
     324             : 
     325        3805 :                 if (rec.wType == DNS_TYPE_SOA) {
     326        3693 :                         serial = rec.data.soa.serial + 1;
     327        3693 :                         rec.dwSerial = serial;
     328        3693 :                         rec.dwTimeStamp = 0;
     329        3693 :                         rec.data.soa.serial = serial;
     330             : 
     331        3693 :                         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, &rec,
     332             :                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
     333        3693 :                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     334           0 :                                 *werr = WERR_NOT_ENOUGH_MEMORY;
     335           0 :                                 return -1;
     336             :                         }
     337        3693 :                         break;
     338             :                 }
     339             :         }
     340             : 
     341        3693 :         if (serial != -1) {
     342        3693 :                 el->flags = LDB_FLAG_MOD_REPLACE;
     343        3693 :                 ret = ldb_modify(samdb, res->msgs[0]);
     344        3693 :                 if (ret != LDB_SUCCESS) {
     345           8 :                         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     346           0 :                                 *werr = WERR_ACCESS_DENIED;
     347             :                         }
     348           8 :                         return -1;
     349             :                 }
     350             :         }
     351             : 
     352        3685 :         *werr = WERR_OK;
     353             : 
     354        3685 :         return serial;
     355             : }
     356             : 
     357             : 
     358             : /* Add DNS record to the database */
     359        1564 : static WERROR dnsserver_db_do_add_rec(TALLOC_CTX *mem_ctx,
     360             :                                 struct ldb_context *samdb,
     361             :                                 struct ldb_dn *dn,
     362             :                                 int num_rec,
     363             :                                 struct dnsp_DnssrvRpcRecord *rec)
     364             : {
     365           0 :         struct ldb_message *msg;
     366           0 :         struct ldb_val v;
     367           0 :         int ret;
     368           0 :         enum ndr_err_code ndr_err;
     369           0 :         int i;
     370             : 
     371        1564 :         msg = ldb_msg_new(mem_ctx);
     372        1564 :         W_ERROR_HAVE_NO_MEMORY(msg);
     373             : 
     374        1564 :         msg->dn = dn;
     375        1564 :         ret = ldb_msg_add_string(msg, "objectClass", "dnsNode");
     376        1564 :         if (ret != LDB_SUCCESS) {
     377           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     378             :         }
     379             : 
     380        1564 :         if (num_rec > 0 && rec) {
     381        3531 :                 for (i=0; i<num_rec; i++) {
     382        1967 :                         ndr_err = ndr_push_struct_blob(&v, mem_ctx, &rec[i],
     383             :                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
     384        1967 :                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     385           0 :                                 return WERR_GEN_FAILURE;
     386             :                         }
     387             : 
     388        1967 :                         ret = ldb_msg_add_value(msg, "dnsRecord", &v, NULL);
     389        1967 :                         if (ret != LDB_SUCCESS) {
     390           0 :                                 return WERR_NOT_ENOUGH_MEMORY;
     391             :                         }
     392             :                 }
     393             :         }
     394             : 
     395        1564 :         ret = ldb_add(samdb, msg);
     396        1564 :         if (ret != LDB_SUCCESS) {
     397           0 :                 return WERR_INTERNAL_DB_ERROR;
     398             :         }
     399             : 
     400        1564 :         return WERR_OK;
     401             : }
     402             : 
     403             : 
     404             : /* Add dnsNode record to the database with DNS record */
     405           0 : WERROR dnsserver_db_add_empty_node(TALLOC_CTX *mem_ctx,
     406             :                                         struct ldb_context *samdb,
     407             :                                         struct dnsserver_zone *z,
     408             :                                         const char *name)
     409             : {
     410           0 :         const char * const attrs[] = { "name", NULL };
     411           0 :         struct ldb_result *res;
     412           0 :         struct ldb_dn *dn;
     413           0 :         char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
     414           0 :         struct ldb_val name_val = data_blob_string_const(name);
     415           0 :         int ret;
     416             : 
     417           0 :         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_BASE, attrs,
     418             :                         "(&(objectClass=dnsNode)(name=%s))",
     419             :                          encoded_name);
     420           0 :         if (ret != LDB_SUCCESS) {
     421           0 :                 return WERR_INTERNAL_DB_ERROR;
     422             :         }
     423             : 
     424           0 :         if (res->count > 0) {
     425           0 :                 talloc_free(res);
     426           0 :                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
     427             :         }
     428             : 
     429           0 :         dn = ldb_dn_copy(mem_ctx, z->zone_dn);
     430           0 :         W_ERROR_HAVE_NO_MEMORY(dn);
     431             : 
     432           0 :         if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
     433           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     434             :         }
     435             : 
     436           0 :         return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 0, NULL);
     437             : }
     438             : 
     439        2159 : static void set_record_rank(struct dnsserver_zone *z,
     440             :                             const char *name,
     441             :                             struct dnsp_DnssrvRpcRecord *rec)
     442             : {
     443        2159 :         if (z->zoneinfo->dwZoneType == DNS_ZONE_TYPE_PRIMARY) {
     444        2159 :                 if (strcmp(name, "@") != 0 && rec->wType == DNS_TYPE_NS) {
     445         215 :                         rec->rank = DNS_RANK_NS_GLUE;
     446             :                 } else {
     447        1944 :                         rec->rank = DNS_RANK_ZONE;
     448             :                 }
     449           0 :         } else if (strcmp(z->name, ".") == 0) {
     450           0 :                 rec->rank = DNS_RANK_ROOT_HINT;
     451             :         }
     452        2159 : }
     453             : 
     454             : 
     455             : /* Add a DNS record */
     456        2230 : WERROR dnsserver_db_add_record(TALLOC_CTX *mem_ctx,
     457             :                                         struct ldb_context *samdb,
     458             :                                         struct dnsserver_zone *z,
     459             :                                         const char *name,
     460             :                                         struct DNS_RPC_RECORD *add_record)
     461             : {
     462        2230 :         const char * const attrs[] = { "dnsRecord", "dNSTombstoned", NULL };
     463           0 :         struct ldb_result *res;
     464        2230 :         struct dnsp_DnssrvRpcRecord *rec = NULL;
     465           0 :         struct ldb_message_element *el;
     466           0 :         struct ldb_dn *dn;
     467           0 :         enum ndr_err_code ndr_err;
     468           0 :         int ret, i;
     469           0 :         int serial;
     470           0 :         WERROR werr;
     471        2230 :         bool was_tombstoned = false;
     472        2230 :         char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
     473             : 
     474        2230 :         werr = dns_to_dnsp_convert(mem_ctx, add_record, &rec, true);
     475        2230 :         if (!W_ERROR_IS_OK(werr)) {
     476         173 :                 return werr;
     477             :         }
     478             : 
     479             :         /* Set the correct rank for the record. */
     480        2057 :         set_record_rank(z, name, rec);
     481             : 
     482        2057 :         serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
     483        2057 :         if (serial < 0) {
     484           7 :                 return werr;
     485             :         }
     486             : 
     487        2050 :         rec->dwSerial = serial;
     488        2050 :         rec->dwTimeStamp = 0;
     489             : 
     490        2050 :         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
     491             :                         "(&(objectClass=dnsNode)(name=%s))",
     492             :                          encoded_name);
     493        2050 :         if (ret != LDB_SUCCESS) {
     494           0 :                 return WERR_INTERNAL_DB_ERROR;
     495             :         }
     496             : 
     497        2050 :         if (res->count == 0) {
     498        1161 :                 dn = dnsserver_name_to_dn(mem_ctx, z, name);
     499        1161 :                 W_ERROR_HAVE_NO_MEMORY(dn);
     500             : 
     501        1161 :                 return dnsserver_db_do_add_rec(mem_ctx, samdb, dn, 1, rec);
     502             :         }
     503             : 
     504         889 :         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
     505         889 :         if (el == NULL) {
     506           0 :                 ret = ldb_msg_add_empty(res->msgs[0], "dnsRecord", 0, &el);
     507           0 :                 if (ret != LDB_SUCCESS) {
     508           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     509             :                 }
     510             :         }
     511             : 
     512         889 :         was_tombstoned = ldb_msg_find_attr_as_bool(res->msgs[0],
     513             :                                                    "dNSTombstoned", false);
     514         889 :         if (was_tombstoned) {
     515          33 :                 el->num_values = 0;
     516             :         }
     517             : 
     518        2608 :         for (i=0; i<el->num_values; i++) {
     519           0 :                 struct dnsp_DnssrvRpcRecord rec2;
     520             : 
     521        1836 :                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
     522             :                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
     523        1836 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     524           0 :                         return WERR_GEN_FAILURE;
     525             :                 }
     526             : 
     527        1836 :                 if (dns_record_match(rec, &rec2)) {
     528         117 :                         break;
     529             :                 }
     530             :         }
     531         889 :         if (i < el->num_values) {
     532         117 :                 return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
     533             :         }
     534         772 :         if (i == el->num_values) {
     535             :                 /* adding a new value */
     536         772 :                 el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1);
     537         772 :                 W_ERROR_HAVE_NO_MEMORY(el->values);
     538         772 :                 el->num_values++;
     539             :         }
     540             : 
     541         772 :         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, rec,
     542             :                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
     543         772 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     544           0 :                 return WERR_GEN_FAILURE;
     545             :         }
     546             : 
     547         772 :         el->flags = LDB_FLAG_MOD_REPLACE;
     548             : 
     549         772 :         el = ldb_msg_find_element(res->msgs[0], "dNSTombstoned");
     550         772 :         if (el != NULL) {
     551          33 :                 el->flags = LDB_FLAG_MOD_DELETE;
     552             :         }
     553             : 
     554         772 :         ret = ldb_modify(samdb, res->msgs[0]);
     555         772 :         if (ret != LDB_SUCCESS) {
     556           0 :                 return WERR_INTERNAL_DB_ERROR;
     557             :         }
     558             : 
     559         772 :         return WERR_OK;
     560             : }
     561             : 
     562             : 
     563             : /* Update a DNS record */
     564         141 : WERROR dnsserver_db_update_record(TALLOC_CTX *mem_ctx,
     565             :                                         struct ldb_context *samdb,
     566             :                                         struct dnsserver_zone *z,
     567             :                                         const char *name,
     568             :                                         struct DNS_RPC_RECORD *add_record,
     569             :                                         struct DNS_RPC_RECORD *del_record)
     570             : {
     571         141 :         const char * const attrs[] = { "dnsRecord", NULL };
     572           0 :         struct ldb_result *res;
     573           0 :         struct dnsp_DnssrvRpcRecord rec2;
     574         141 :         struct dnsp_DnssrvRpcRecord *arec = NULL, *drec = NULL;
     575           0 :         struct ldb_message_element *el;
     576           0 :         enum ndr_err_code ndr_err;
     577           0 :         int ret, i;
     578           0 :         int serial;
     579           0 :         WERROR werr;
     580         141 :         bool updating_ttl = false;
     581         141 :         char *encoded_name = ldb_binary_encode_string(mem_ctx, name);
     582             : 
     583         141 :         werr = dns_to_dnsp_convert(mem_ctx, add_record, &arec, true);
     584         141 :         if (!W_ERROR_IS_OK(werr)) {
     585          23 :                 return werr;
     586             :         }
     587             : 
     588         118 :         werr = dns_to_dnsp_convert(mem_ctx, del_record, &drec, true);
     589         118 :         if (!W_ERROR_IS_OK(werr)) {
     590           0 :                 return werr;
     591             :         }
     592             : 
     593         118 :         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
     594             :                         "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))",
     595             :                          encoded_name);
     596         118 :         if (ret != LDB_SUCCESS) {
     597           0 :                 return WERR_INTERNAL_DB_ERROR;
     598             :         }
     599             : 
     600         118 :         if (res->count == 0) {
     601          14 :                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
     602             :         }
     603             : 
     604         104 :         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
     605         104 :         if (el == NULL || el->num_values == 0) {
     606           0 :                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
     607             :         }
     608             : 
     609         244 :         for (i=0; i<el->num_values; i++) {
     610         227 :                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
     611             :                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
     612         227 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     613           0 :                         return WERR_GEN_FAILURE;
     614             :                 }
     615             : 
     616         227 :                 if (dns_record_match(arec, &rec2)) {
     617          87 :                         break;
     618             :                 }
     619             :         }
     620         104 :         if (i < el->num_values) {
     621             :                 /*
     622             :                  * The record already exists, which is an error UNLESS we are
     623             :                  * doing an in-place update.
     624             :                  *
     625             :                  * Therefore we need to see if drec also matches, in which
     626             :                  * case it's OK, though we can only update dwTtlSeconds and
     627             :                  * reset the timestamp to zero.
     628             :                  */
     629          87 :                 updating_ttl = dns_record_match(drec, &rec2);
     630          87 :                 if (! updating_ttl) {
     631           0 :                         return WERR_DNS_ERROR_RECORD_ALREADY_EXISTS;
     632             :                 }
     633             :                 /* In this case the next loop is redundant */
     634             :         }
     635             : 
     636         229 :         for (i=0; i<el->num_values; i++) {
     637         227 :                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
     638             :                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
     639         227 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     640           0 :                         return WERR_GEN_FAILURE;
     641             :                 }
     642             : 
     643         227 :                 if (dns_record_match(drec, &rec2)) {
     644             :                         /*
     645             :                          * we are replacing this one with arec, which is done
     646             :                          * by pushing arec into el->values[i] below, after the
     647             :                          * various manipulations.
     648             :                          */
     649         102 :                         break;
     650             :                 }
     651             :         }
     652         104 :         if (i == el->num_values) {
     653           2 :                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
     654             :         }
     655             : 
     656             :         /*
     657             :          * If we're updating a SOA record, use the specified serial.
     658             :          *
     659             :          * Otherwise, if we are updating ttl in place (i.e., not changing
     660             :          * .wType and .data on a record), we should increment the existing
     661             :          * serial, and save to the SOA.
     662             :          *
     663             :          * Outside of those two cases, we look for the zone's SOA record and
     664             :          * use its serial.
     665             :          */
     666         102 :         if (arec->wType != DNS_TYPE_SOA) {
     667         102 :                 if (updating_ttl) {
     668             :                         /*
     669             :                          * In this case, we keep some of the old values.
     670             :                          */
     671          87 :                         arec->dwSerial = rec2.dwSerial;
     672          87 :                         arec->dwReserved = rec2.dwReserved;
     673             :                         /*
     674             :                          * TODO: if the old TTL and the new TTL are
     675             :                          * different, the serial number is incremented.
     676             :                          */
     677             :                 } else {
     678          15 :                         arec->dwReserved = 0;
     679          15 :                         serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
     680          15 :                         if (serial < 0) {
     681           0 :                                 return werr;
     682             :                         }
     683          15 :                         arec->dwSerial = serial;
     684             :                 }
     685             :         }
     686             : 
     687             :         /* Set the correct rank for the record. */
     688         102 :         set_record_rank(z, name, arec);
     689             :         /*
     690             :          * Successful RPC updates *always* zero timestamp and flags and set
     691             :          * version.
     692             :          */
     693         102 :         arec->dwTimeStamp = 0;
     694         102 :         arec->version = 5;
     695         102 :         arec->flags = 0;
     696             : 
     697         102 :         ndr_err = ndr_push_struct_blob(&el->values[i], mem_ctx, arec,
     698             :                                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
     699         102 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     700           0 :                 return WERR_GEN_FAILURE;
     701             :         }
     702             : 
     703         102 :         el->flags = LDB_FLAG_MOD_REPLACE;
     704         102 :         ret = ldb_modify(samdb, res->msgs[0]);
     705         102 :         if (ret != LDB_SUCCESS) {
     706           0 :                 return WERR_INTERNAL_DB_ERROR;
     707             :         }
     708             : 
     709         102 :         return WERR_OK;
     710             : }
     711             : 
     712             : 
     713             : /* Delete a DNS record */
     714        1621 : WERROR dnsserver_db_delete_record(TALLOC_CTX *mem_ctx,
     715             :                                         struct ldb_context *samdb,
     716             :                                         struct dnsserver_zone *z,
     717             :                                         const char *name,
     718             :                                         struct DNS_RPC_RECORD *del_record)
     719             : {
     720        1621 :         const char * const attrs[] = { "dnsRecord", NULL };
     721           0 :         struct ldb_result *res;
     722        1621 :         struct dnsp_DnssrvRpcRecord *rec = NULL;
     723           0 :         struct ldb_message_element *el;
     724           0 :         enum ndr_err_code ndr_err;
     725           0 :         int ret, i;
     726           0 :         int serial;
     727           0 :         WERROR werr;
     728             : 
     729        1621 :         serial = dnsserver_update_soa(mem_ctx, samdb, z, &werr);
     730        1621 :         if (serial < 0) {
     731           1 :                 return werr;
     732             :         }
     733             : 
     734        1620 :         werr = dns_to_dnsp_convert(mem_ctx, del_record, &rec, false);
     735        1620 :         if (!W_ERROR_IS_OK(werr)) {
     736           0 :                 return werr;
     737             :         }
     738             : 
     739        1620 :         ret = ldb_search(samdb, mem_ctx, &res, z->zone_dn, LDB_SCOPE_ONELEVEL, attrs,
     740             :                         "(&(objectClass=dnsNode)(name=%s))",
     741             :                          ldb_binary_encode_string(mem_ctx, name));
     742        1620 :         if (ret != LDB_SUCCESS) {
     743           0 :                 return WERR_INTERNAL_DB_ERROR;
     744             :         }
     745             : 
     746        1620 :         if (res->count == 0) {
     747         103 :                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
     748             :         }
     749        1517 :         if (res->count > 1) {
     750           0 :                 return WERR_DNS_ERROR_RCODE_SERVER_FAILURE;
     751             :         }
     752             : 
     753        1517 :         el = ldb_msg_find_element(res->msgs[0], "dnsRecord");
     754        1517 :         if (el == NULL || el->num_values == 0) {
     755           0 :                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
     756             :         }
     757             : 
     758        1962 :         for (i=0; i<el->num_values; i++) {
     759           0 :                 struct dnsp_DnssrvRpcRecord rec2;
     760             : 
     761        1849 :                 ndr_err = ndr_pull_struct_blob(&el->values[i], mem_ctx, &rec2,
     762             :                                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
     763        1849 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     764           0 :                         return WERR_GEN_FAILURE;
     765             :                 }
     766             : 
     767        1849 :                 if (dns_record_match(rec, &rec2)) {
     768        1404 :                         break;
     769             :                 }
     770             :         }
     771        1517 :         if (i == el->num_values) {
     772         113 :                 return WERR_DNS_ERROR_RECORD_DOES_NOT_EXIST;
     773             :         }
     774        1404 :         if (i < el->num_values-1) {
     775         237 :                 memmove(&el->values[i], &el->values[i+1], sizeof(el->values[0])*((el->num_values-1)-i));
     776             :         }
     777        1404 :         el->num_values--;
     778             : 
     779        1404 :         if (el->num_values == 0) {
     780         932 :                 ret = ldb_delete(samdb, res->msgs[0]->dn);
     781             :         } else {
     782         472 :                 el->flags = LDB_FLAG_MOD_REPLACE;
     783         472 :                 ret = ldb_modify(samdb, res->msgs[0]);
     784             :         }
     785        1404 :         if (ret != LDB_SUCCESS) {
     786           0 :                 return WERR_INTERNAL_DB_ERROR;
     787             :         }
     788             : 
     789        1404 :         return WERR_OK;
     790             : }
     791             : 
     792             : 
     793        2947 : static bool dnsserver_db_msg_add_dnsproperty(TALLOC_CTX *mem_ctx,
     794             :                                              struct ldb_message *msg,
     795             :                                              struct dnsp_DnsProperty *prop)
     796             : {
     797           0 :         DATA_BLOB *prop_blob;
     798           0 :         enum ndr_err_code ndr_err;
     799           0 :         int ret;
     800             : 
     801        2947 :         prop_blob = talloc_zero(mem_ctx, DATA_BLOB);
     802        2947 :         if (prop_blob == NULL) return false;
     803             : 
     804        2947 :         ndr_err = ndr_push_struct_blob(prop_blob, mem_ctx, prop,
     805             :                         (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
     806        2947 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     807           0 :                 return false;
     808             :         }
     809        2947 :         ret = ldb_msg_add_steal_value(msg, "dNSProperty", prop_blob);
     810        2947 :         if (ret != LDB_SUCCESS) {
     811           0 :                 return false;
     812             :         }
     813        2947 :         return true;
     814             : }
     815             : 
     816         793 : WERROR dnsserver_db_do_reset_dword(struct ldb_context *samdb,
     817             :                                    struct dnsserver_zone *z,
     818             :                                    struct DNS_RPC_NAME_AND_PARAM *n_p)
     819             : {
     820         793 :         struct ldb_message_element *element = NULL;
     821         793 :         struct dnsp_DnsProperty *prop = NULL;
     822           0 :         enum ndr_err_code err;
     823         793 :         TALLOC_CTX *tmp_ctx = NULL;
     824         793 :         const char * const attrs[] = {"dNSProperty", NULL};
     825         793 :         struct ldb_result *res = NULL;
     826           0 :         int i, ret, prop_id;
     827             : 
     828         793 :         if (strcasecmp(n_p->pszNodeName, "Aging") == 0) {
     829         276 :                 z->zoneinfo->fAging = n_p->dwParam;
     830         276 :                 prop_id = DSPROPERTY_ZONE_AGING_STATE;
     831         517 :         } else if (strcasecmp(n_p->pszNodeName, "RefreshInterval") == 0) {
     832         104 :                 z->zoneinfo->dwRefreshInterval = n_p->dwParam;
     833         104 :                 prop_id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
     834         413 :         } else if (strcasecmp(n_p->pszNodeName, "NoRefreshInterval") == 0) {
     835         106 :                 z->zoneinfo->dwNoRefreshInterval = n_p->dwParam;
     836         106 :                 prop_id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
     837         307 :         } else if (strcasecmp(n_p->pszNodeName, "AllowUpdate") == 0) {
     838         307 :                 z->zoneinfo->fAllowUpdate = n_p->dwParam;
     839         307 :                 prop_id = DSPROPERTY_ZONE_ALLOW_UPDATE;
     840             :         } else {
     841           0 :                 return WERR_UNKNOWN_PROPERTY;
     842             :         }
     843             : 
     844         793 :         tmp_ctx = talloc_new(NULL);
     845         793 :         if (tmp_ctx == NULL) {
     846           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     847             :         }
     848             : 
     849         793 :         ret = ldb_search(samdb, tmp_ctx, &res, z->zone_dn, LDB_SCOPE_BASE,
     850             :                          attrs, "(objectClass=dnsZone)");
     851         793 :         if (ret != LDB_SUCCESS) {
     852           0 :                 DBG_ERR("dnsserver: no zone: %s\n",
     853             :                         ldb_dn_get_linearized(z->zone_dn));
     854           0 :                 TALLOC_FREE(tmp_ctx);
     855           0 :                 return WERR_INTERNAL_DB_ERROR;
     856             :         }
     857             : 
     858         793 :         if (res->count != 1) {
     859           0 :                 DBG_ERR("dnsserver: duplicate zone: %s\n",
     860             :                         ldb_dn_get_linearized(z->zone_dn));
     861           0 :                 TALLOC_FREE(tmp_ctx);
     862           0 :                 return WERR_GEN_FAILURE;
     863             :         }
     864             : 
     865         793 :         element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
     866         793 :         if (element == NULL) {
     867           0 :                 DBG_ERR("dnsserver: zone %s has no properties.\n",
     868             :                         ldb_dn_get_linearized(z->zone_dn));
     869           0 :                 TALLOC_FREE(tmp_ctx);
     870           0 :                 return WERR_INTERNAL_DB_ERROR;
     871             :         }
     872             : 
     873        6311 :         for (i = 0; i < element->num_values; i++) {
     874        5518 :                 prop = talloc_zero(element, struct dnsp_DnsProperty);
     875        5518 :                 if (prop == NULL) {
     876           0 :                         TALLOC_FREE(tmp_ctx);
     877           0 :                         return WERR_NOT_ENOUGH_MEMORY;
     878             :                 }
     879        5518 :                 err = ndr_pull_struct_blob(
     880        5518 :                         &(element->values[i]),
     881             :                         tmp_ctx,
     882             :                         prop,
     883             :                         (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
     884        5518 :                 if (!NDR_ERR_CODE_IS_SUCCESS(err)){
     885             :                         /*
     886             :                          * If we can't pull it then try again parsing
     887             :                          * it again.  A Windows server in the domain
     888             :                          * will permit the addition of an invalidly
     889             :                          * formed property with a 0 length and cause a
     890             :                          * failure here
     891             :                          */
     892           0 :                         struct dnsp_DnsProperty_short
     893             :                                 *short_property
     894           6 :                                 = talloc_zero(element,
     895             :                                               struct dnsp_DnsProperty_short);
     896           6 :                         if (short_property == NULL) {
     897           0 :                                 TALLOC_FREE(tmp_ctx);
     898           0 :                                 return WERR_NOT_ENOUGH_MEMORY;
     899             :                         }
     900           6 :                         err = ndr_pull_struct_blob_all(
     901           6 :                                 &(element->values[i]),
     902             :                                 tmp_ctx,
     903             :                                 short_property,
     904             :                                 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty_short);
     905           6 :                         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
     906             :                                 /*
     907             :                                  * Unknown invalid data should be
     908             :                                  * ignored and logged to match Windows
     909             :                                  * behaviour
     910             :                                  */
     911           0 :                                 DBG_NOTICE("dnsserver: couldn't PULL "
     912             :                                            "dnsProperty value#%d in "
     913             :                                            "zone %s while trying to "
     914             :                                            "reset id %d\n",
     915             :                                            i,
     916             :                                            ldb_dn_get_linearized(z->zone_dn),
     917             :                                            prop_id);
     918           0 :                                 continue;
     919             :                         }
     920             : 
     921             :                         /*
     922             :                          * Initialise the parts of the property not
     923             :                          * overwritten by value() in the IDL for
     924             :                          * re-push
     925             :                          */
     926           6 :                         *prop = (struct dnsp_DnsProperty){
     927           6 :                                 .namelength = short_property->namelength,
     928           6 :                                 .id = short_property->id,
     929           6 :                                 .name = short_property->name
     930             :                                 /* .data will be filled in below */
     931             :                         };
     932             :                 }
     933             : 
     934        5518 :                 if (prop->id == prop_id) {
     935         793 :                         switch (prop_id) {
     936         276 :                         case DSPROPERTY_ZONE_AGING_STATE:
     937         276 :                                 prop->data.aging_enabled = n_p->dwParam;
     938         276 :                                 break;
     939         106 :                         case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
     940         106 :                                 prop->data.norefresh_hours = n_p->dwParam;
     941         106 :                                 break;
     942         104 :                         case DSPROPERTY_ZONE_REFRESH_INTERVAL:
     943         104 :                                 prop->data.refresh_hours = n_p->dwParam;
     944         104 :                                 break;
     945         307 :                         case DSPROPERTY_ZONE_ALLOW_UPDATE:
     946         307 :                                 prop->data.allow_update_flag = n_p->dwParam;
     947         307 :                                 break;
     948             :                         }
     949             : 
     950         793 :                         err = ndr_push_struct_blob(
     951         793 :                                 &(element->values[i]),
     952             :                                 tmp_ctx,
     953             :                                 prop,
     954             :                                 (ndr_push_flags_fn_t)ndr_push_dnsp_DnsProperty);
     955         793 :                         if (!NDR_ERR_CODE_IS_SUCCESS(err)){
     956           0 :                                 DBG_ERR("dnsserver: couldn't PUSH dns prop id "
     957             :                                         "%d in zone %s\n",
     958             :                                         prop->id,
     959             :                                         ldb_dn_get_linearized(z->zone_dn));
     960           0 :                                 TALLOC_FREE(tmp_ctx);
     961           0 :                                 return WERR_INTERNAL_DB_ERROR;
     962             :                         }
     963             :                 }
     964             :         }
     965             : 
     966         793 :         element->flags = LDB_FLAG_MOD_REPLACE;
     967         793 :         ret = ldb_modify(samdb, res->msgs[0]);
     968         793 :         if (ret != LDB_SUCCESS) {
     969           0 :                 TALLOC_FREE(tmp_ctx);
     970           0 :                 DBG_ERR("dnsserver: Failed to modify zone %s prop %s: %s\n",
     971             :                         z->name,
     972             :                         n_p->pszNodeName,
     973             :                         ldb_errstring(samdb));
     974           0 :                 return WERR_INTERNAL_DB_ERROR;
     975             :         }
     976         793 :         TALLOC_FREE(tmp_ctx);
     977             : 
     978         793 :         return WERR_OK;
     979             : }
     980             : 
     981             : /* Create dnsZone record to database and set security descriptor */
     982         421 : static WERROR dnsserver_db_do_create_zone(TALLOC_CTX *tmp_ctx,
     983             :                                           struct ldb_context *samdb,
     984             :                                           struct ldb_dn *zone_dn,
     985             :                                           struct dnsserver_zone *z)
     986             : {
     987         421 :         const char * const attrs[] = { "objectSID", NULL };
     988           0 :         struct ldb_message *msg;
     989           0 :         struct ldb_result *res;
     990           0 :         struct ldb_message_element *el;
     991         421 :         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";
     992           0 :         char *sddl;
     993           0 :         struct dom_sid dnsadmins_sid;
     994           0 :         const struct dom_sid *domain_sid;
     995           0 :         struct security_descriptor *secdesc;
     996           0 :         struct dnsp_DnsProperty *prop;
     997           0 :         DATA_BLOB *sd_encoded;
     998           0 :         enum ndr_err_code ndr_err;
     999           0 :         int ret;
    1000             : 
    1001             :         /* Get DnsAdmins SID */
    1002         421 :         ret = ldb_search(samdb, tmp_ctx, &res, ldb_get_default_basedn(samdb),
    1003             :                          LDB_SCOPE_DEFAULT, attrs, "(sAMAccountName=DnsAdmins)");
    1004         421 :         if (ret != LDB_SUCCESS || res->count != 1) {
    1005           0 :                 return WERR_INTERNAL_DB_ERROR;
    1006             :         }
    1007             : 
    1008         421 :         el = ldb_msg_find_element(res->msgs[0], "objectSID");
    1009         421 :         if (el == NULL || el->num_values != 1) {
    1010           0 :                 return WERR_INTERNAL_DB_ERROR;
    1011             :         }
    1012             : 
    1013         421 :         ndr_err = ndr_pull_struct_blob(&el->values[0], tmp_ctx, &dnsadmins_sid,
    1014             :                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
    1015         421 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1016           0 :                 return WERR_INTERNAL_DB_ERROR;
    1017             :         }
    1018             : 
    1019             :         /* create security descriptor with DnsAdmins GUID in sddl template */
    1020         421 :         sddl = talloc_asprintf(tmp_ctx, sddl_template,
    1021             :                                dom_sid_string(tmp_ctx, &dnsadmins_sid));
    1022         421 :         if (sddl == NULL) {
    1023           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1024             :         }
    1025         421 :         talloc_free(res);
    1026             : 
    1027         421 :         domain_sid = samdb_domain_sid(samdb);
    1028         421 :         if (domain_sid == NULL) {
    1029           0 :                 return WERR_INTERNAL_DB_ERROR;
    1030             :         }
    1031             : 
    1032         421 :         secdesc = sddl_decode(tmp_ctx, sddl, domain_sid);
    1033         421 :         if (secdesc == NULL) {
    1034           0 :                 return WERR_GEN_FAILURE;
    1035             :         }
    1036             : 
    1037         421 :         msg = ldb_msg_new(tmp_ctx);
    1038         421 :         W_ERROR_HAVE_NO_MEMORY(msg);
    1039             : 
    1040         421 :         msg->dn = zone_dn;
    1041         421 :         ret = ldb_msg_add_string(msg, "objectClass", "dnsZone");
    1042         421 :         if (ret != LDB_SUCCESS) {
    1043           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1044             :         }
    1045             : 
    1046         421 :         sd_encoded = talloc_zero(tmp_ctx, DATA_BLOB);
    1047         421 :         W_ERROR_HAVE_NO_MEMORY(sd_encoded);
    1048             : 
    1049         421 :         ndr_err = ndr_push_struct_blob(sd_encoded, tmp_ctx, secdesc,
    1050             :                         (ndr_push_flags_fn_t)ndr_push_security_descriptor);
    1051         421 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1052           0 :                 return WERR_GEN_FAILURE;
    1053             :         }
    1054             : 
    1055         421 :         ret = ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd_encoded);
    1056         421 :         if (ret != LDB_SUCCESS) {
    1057           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1058             :         }
    1059             : 
    1060             :         /* dns zone Properties */
    1061         421 :         prop = talloc_zero(tmp_ctx, struct dnsp_DnsProperty);
    1062         421 :         W_ERROR_HAVE_NO_MEMORY(prop);
    1063             : 
    1064         421 :         prop->version = 1;
    1065             : 
    1066             :         /* zone type */
    1067         421 :         prop->id = DSPROPERTY_ZONE_TYPE;
    1068         421 :         prop->data.zone_type = z->zoneinfo->dwZoneType;
    1069         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1070           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1071             :         }
    1072             : 
    1073             :         /* allow update */
    1074         421 :         prop->id = DSPROPERTY_ZONE_ALLOW_UPDATE;
    1075         421 :         prop->data.allow_update_flag = z->zoneinfo->fAllowUpdate;
    1076         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1077           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1078             :         }
    1079             : 
    1080             :         /* secure time */
    1081         421 :         prop->id = DSPROPERTY_ZONE_SECURE_TIME;
    1082         421 :         prop->data.zone_secure_time = 0;
    1083         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1084           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1085             :         }
    1086             : 
    1087             :         /* norefresh interval */
    1088         421 :         prop->id = DSPROPERTY_ZONE_NOREFRESH_INTERVAL;
    1089         421 :         prop->data.norefresh_hours = 168;
    1090         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1091           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1092             :         }
    1093             : 
    1094             :         /* refresh interval */
    1095         421 :         prop->id = DSPROPERTY_ZONE_REFRESH_INTERVAL;
    1096         421 :         prop->data.refresh_hours = 168;
    1097         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1098           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1099             :         }
    1100             : 
    1101             :         /* aging state */
    1102         421 :         prop->id = DSPROPERTY_ZONE_AGING_STATE;
    1103         421 :         prop->data.aging_enabled = z->zoneinfo->fAging;
    1104         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1105           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1106             :         }
    1107             : 
    1108             :         /* aging enabled time */
    1109         421 :         prop->id = DSPROPERTY_ZONE_AGING_ENABLED_TIME;
    1110         421 :         prop->data.next_scavenging_cycle_hours = 0;
    1111         421 :         if (!dnsserver_db_msg_add_dnsproperty(tmp_ctx, msg, prop)) {
    1112           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1113             :         }
    1114             : 
    1115         421 :         talloc_free(prop);
    1116             : 
    1117         421 :         ret = ldb_add(samdb, msg);
    1118         421 :         if (ret != LDB_SUCCESS) {
    1119          18 :                 DEBUG(0, ("dnsserver: Failed to create zone (%s): %s\n",
    1120             :                       z->name, ldb_errstring(samdb)));
    1121             : 
    1122          18 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1123           0 :                         return WERR_ACCESS_DENIED;
    1124             :                 }
    1125             : 
    1126          18 :                 return WERR_INTERNAL_DB_ERROR;
    1127             :         }
    1128             : 
    1129         403 :         return WERR_OK;
    1130             : }
    1131             : 
    1132             : 
    1133             : /* Create new dnsZone record and @ record (SOA + NS) */
    1134         421 : WERROR dnsserver_db_create_zone(struct ldb_context *samdb,
    1135             :                                 struct dnsserver_partition *partitions,
    1136             :                                 struct dnsserver_zone *zone,
    1137             :                                 struct loadparm_context *lp_ctx)
    1138             : {
    1139           0 :         struct dnsserver_partition *p;
    1140         421 :         bool in_forest = false;
    1141           0 :         WERROR status;
    1142           0 :         struct ldb_dn *dn;
    1143           0 :         TALLOC_CTX *tmp_ctx;
    1144           0 :         struct dnsp_DnssrvRpcRecord *dns_rec;
    1145           0 :         struct dnsp_soa soa;
    1146           0 :         char *tmpstr, *server_fqdn, *soa_email;
    1147         421 :         struct ldb_val name_val = data_blob_string_const(zone->name);
    1148             : 
    1149             :         /* We only support primary zones for now */
    1150         421 :         if (zone->zoneinfo->dwZoneType != DNS_ZONE_TYPE_PRIMARY) {
    1151           0 :                 return WERR_CALL_NOT_IMPLEMENTED;
    1152             :         }
    1153             : 
    1154             :         /* Get the correct partition */
    1155         421 :         if (zone->partition->dwDpFlags & DNS_DP_FOREST_DEFAULT) {
    1156           4 :                 in_forest = true;
    1157             :         }
    1158         425 :         for (p = partitions; p; p = p->next) {
    1159         425 :                 if (in_forest == p->is_forest) {
    1160         421 :                         break;
    1161             :                 }
    1162             :         }
    1163         421 :         if (p == NULL) {
    1164           0 :                 return WERR_DNS_ERROR_DP_DOES_NOT_EXIST;
    1165             :         }
    1166             : 
    1167         421 :         tmp_ctx = talloc_new(NULL);
    1168         421 :         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
    1169             : 
    1170         421 :         dn = ldb_dn_copy(tmp_ctx, p->partition_dn);
    1171         421 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dn, tmp_ctx);
    1172             : 
    1173         421 :         if (!ldb_dn_add_child_fmt(dn, "CN=MicrosoftDNS")) {
    1174           0 :                 talloc_free(tmp_ctx);
    1175           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1176             :         }
    1177             : 
    1178         421 :         if (!ldb_dn_add_child_val(dn, "DC", name_val)) {
    1179           0 :                 talloc_free(tmp_ctx);
    1180           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1181             :         }
    1182             : 
    1183             :         /* Add dnsZone record */
    1184         421 :         status = dnsserver_db_do_create_zone(tmp_ctx, samdb, dn, zone);
    1185         421 :         if (!W_ERROR_IS_OK(status)) {
    1186          18 :                 talloc_free(tmp_ctx);
    1187          18 :                 return status;
    1188             :         }
    1189             : 
    1190         403 :         if (!ldb_dn_add_child_fmt(dn, "DC=@")) {
    1191           0 :                 talloc_free(tmp_ctx);
    1192           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    1193             :         }
    1194             : 
    1195         403 :         dns_rec = talloc_zero_array(tmp_ctx, struct dnsp_DnssrvRpcRecord, 2);
    1196         403 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(dns_rec, tmp_ctx);
    1197             : 
    1198         403 :         tmpstr = talloc_asprintf(tmp_ctx, "%s.%s",
    1199             :                                  lpcfg_netbios_name(lp_ctx),
    1200             :                                  lpcfg_realm(lp_ctx));
    1201         403 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
    1202         403 :         server_fqdn = strlower_talloc(tmp_ctx, tmpstr);
    1203         403 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(server_fqdn, tmp_ctx);
    1204         403 :         talloc_free(tmpstr);
    1205             : 
    1206         403 :         tmpstr = talloc_asprintf(tmp_ctx, "hostmaster.%s",
    1207             :                                   lpcfg_realm(lp_ctx));
    1208         403 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(tmpstr, tmp_ctx);
    1209         403 :         soa_email = strlower_talloc(tmp_ctx, tmpstr);
    1210         403 :         W_ERROR_HAVE_NO_MEMORY_AND_FREE(soa_email, tmp_ctx);
    1211         403 :         talloc_free(tmpstr);
    1212             : 
    1213             :         /* SOA Record - values same as defined in provision/sambadns.py */
    1214         403 :         soa.serial = 1;
    1215         403 :         soa.refresh = 900;
    1216         403 :         soa.retry = 600;
    1217         403 :         soa.expire = 86400;
    1218         403 :         soa.minimum = 3600;
    1219         403 :         soa.mname = server_fqdn;
    1220         403 :         soa.rname = soa_email;
    1221             : 
    1222         403 :         dns_rec[0].wType = DNS_TYPE_SOA;
    1223         403 :         dns_rec[0].rank = DNS_RANK_ZONE;
    1224         403 :         dns_rec[0].dwSerial = soa.serial;
    1225         403 :         dns_rec[0].dwTtlSeconds = 3600;
    1226         403 :         dns_rec[0].dwTimeStamp = 0;
    1227         403 :         dns_rec[0].data.soa = soa;
    1228             : 
    1229             :         /* NS Record */
    1230         403 :         dns_rec[1].wType = DNS_TYPE_NS;
    1231         403 :         dns_rec[1].rank = DNS_RANK_ZONE;
    1232         403 :         dns_rec[1].dwSerial = soa.serial;
    1233         403 :         dns_rec[1].dwTtlSeconds = 3600;
    1234         403 :         dns_rec[1].dwTimeStamp = 0;
    1235         403 :         dns_rec[1].data.ns = server_fqdn;
    1236             : 
    1237             :         /* Add @ Record */
    1238         403 :         status = dnsserver_db_do_add_rec(tmp_ctx, samdb, dn, 2, dns_rec);
    1239             : 
    1240         403 :         talloc_free(tmp_ctx);
    1241         403 :         return status;
    1242             : }
    1243             : 
    1244             : 
    1245             : /* Delete dnsZone record and all DNS records in the zone */
    1246         403 : WERROR dnsserver_db_delete_zone(struct ldb_context *samdb,
    1247             :                                 struct dnsserver_zone *zone)
    1248             : {
    1249           0 :         int ret;
    1250             : 
    1251         403 :         ret = ldb_transaction_start(samdb);
    1252         403 :         if (ret != LDB_SUCCESS) {
    1253           0 :                 return WERR_INTERNAL_DB_ERROR;
    1254             :         }
    1255             : 
    1256         403 :         ret = dsdb_delete(samdb, zone->zone_dn, DSDB_TREE_DELETE);
    1257         403 :         if (ret != LDB_SUCCESS) {
    1258           0 :                 ldb_transaction_cancel(samdb);
    1259             : 
    1260           0 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1261           0 :                         return WERR_ACCESS_DENIED;
    1262             :                 }
    1263           0 :                 return WERR_INTERNAL_DB_ERROR;
    1264             :         }
    1265             : 
    1266         403 :         ret = ldb_transaction_commit(samdb);
    1267         403 :         if (ret != LDB_SUCCESS) {
    1268           0 :                 return WERR_INTERNAL_DB_ERROR;
    1269             :         }
    1270             : 
    1271         403 :         return WERR_OK;
    1272             : }

Generated by: LCOV version 1.14