LCOV - code coverage report
Current view: top level - source4/lib/registry - regf.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 536 1139 47.1 %
Date: 2021-09-23 10:06:22 Functions: 28 31 90.3 %

          Line data    Source code
       1             : /*
       2             :    Samba CIFS implementation
       3             :    Registry backend for REGF files
       4             :    Copyright (C) 2005-2007 Jelmer Vernooij, jelmer@samba.org
       5             :    Copyright (C) 2006-2010 Wilco Baan Hofman, wilco@baanhofman.nl
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/filesys.h"
      22             : #include "system/time.h"
      23             : #include "lib/registry/tdr_regf.h"
      24             : #include "librpc/gen_ndr/ndr_security.h"
      25             : #include "librpc/gen_ndr/winreg.h"
      26             : #include "lib/registry/registry.h"
      27             : #include "libcli/security/security.h"
      28             : 
      29             : #undef strcasecmp
      30             : 
      31             : static struct hive_operations reg_backend_regf;
      32             : 
      33             : /**
      34             :  * There are several places on the web where the REGF format is explained;
      35             :  *
      36             :  * TODO: Links
      37             :  */
      38             : 
      39             : /* TODO:
      40             :  *  - Return error codes that make more sense
      41             :  *  - Locking
      42             :  *  - do more things in-memory
      43             :  */
      44             : 
      45             : /*
      46             :  * Read HBIN blocks into memory
      47             :  */
      48             : 
      49             : struct regf_data {
      50             :         int fd;
      51             :         struct hbin_block **hbins;
      52             :         struct regf_hdr *header;
      53             :         time_t last_write;
      54             : };
      55             : 
      56             : static WERROR regf_save_hbin(struct regf_data *data, bool flush);
      57             : 
      58             : struct regf_key_data {
      59             :         struct hive_key key;
      60             :         struct regf_data *hive;
      61             :         uint32_t offset;
      62             :         struct nk_block *nk;
      63             : };
      64             : 
      65           0 : static struct hbin_block *hbin_by_offset(const struct regf_data *data,
      66             :                                          uint32_t offset, uint32_t *rel_offset)
      67             : {
      68             :         unsigned int i;
      69             : 
      70           0 :         for (i = 0; data->hbins[i]; i++) {
      71         308 :                 if (offset >= data->hbins[i]->offset_from_first &&
      72         154 :                         offset < data->hbins[i]->offset_from_first+
      73         154 :                                          data->hbins[i]->offset_to_next) {
      74           0 :                         if (rel_offset != NULL)
      75         154 :                                 *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
      76           0 :                         return data->hbins[i];
      77             :                 }
      78             :         }
      79             : 
      80           0 :         return NULL;
      81             : }
      82             : 
      83             : /**
      84             :  * Validate a regf header
      85             :  * For now, do nothing, but we should check the checksum
      86             :  */
      87           2 : static uint32_t regf_hdr_checksum(const uint8_t *buffer)
      88             : {
      89           2 :         uint32_t checksum = 0, x;
      90             :         unsigned int i;
      91             : 
      92         256 :         for (i = 0; i < 0x01FB; i+= 4) {
      93         254 :                 x = IVAL(buffer, i);
      94         254 :                 checksum ^= x;
      95             :         }
      96             : 
      97           2 :         return checksum;
      98             : }
      99             : 
     100             : /**
     101             :  * Obtain the contents of a HBIN block
     102             :  */
     103          73 : static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
     104             : {
     105             :         DATA_BLOB ret;
     106             :         struct hbin_block *hbin;
     107             :         uint32_t rel_offset;
     108             : 
     109          73 :         ret.data = NULL;
     110          73 :         ret.length = 0;
     111             : 
     112         146 :         hbin = hbin_by_offset(data, offset, &rel_offset);
     113             : 
     114          73 :         if (hbin == NULL) {
     115           0 :                 DEBUG(1, ("Can't find HBIN at 0x%04x\n", offset));
     116           0 :                 return ret;
     117             :         }
     118             : 
     119          73 :         ret.length = IVAL(hbin->data, rel_offset);
     120          73 :         if (!(ret.length & 0x80000000)) {
     121           0 :                 DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
     122           0 :                 return ret;
     123             :         }
     124             : 
     125             :         /* remove high bit */
     126          73 :         ret.length = (ret.length ^ 0xffffffff) + 1;
     127             : 
     128          73 :         ret.length -= 4; /* 4 bytes for the length... */
     129          73 :         ret.data = hbin->data +
     130          73 :                 (offset - hbin->offset_from_first - 0x20) + 4;
     131             : 
     132          73 :         return ret;
     133             : }
     134             : 
     135          48 : static bool hbin_get_tdr(struct regf_data *regf, uint32_t offset,
     136             :                          TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
     137             : {
     138          48 :         struct tdr_pull *pull = tdr_pull_init(regf);
     139             : 
     140          48 :         pull->data = hbin_get(regf, offset);
     141          48 :         if (!pull->data.data) {
     142           0 :                 DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
     143           0 :                 talloc_free(pull);
     144           0 :                 return false;
     145             :         }
     146             : 
     147          48 :         if (NT_STATUS_IS_ERR(pull_fn(pull, ctx, p))) {
     148           0 :                 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n",
     149             :                         offset));
     150           0 :                 talloc_free(pull);
     151           0 :                 return false;
     152             :         }
     153          48 :         talloc_free(pull);
     154             : 
     155          48 :         return true;
     156             : }
     157             : 
     158             : /* Allocate some new data */
     159          34 : static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size,
     160             :                             uint32_t *offset)
     161             : {
     162             :         DATA_BLOB ret;
     163          34 :         uint32_t rel_offset = (uint32_t) -1; /* Relative offset ! */
     164          34 :         struct hbin_block *hbin = NULL;
     165             :         unsigned int i;
     166             : 
     167          34 :         if (offset != NULL) {
     168          34 :                 *offset = 0;
     169             :         }
     170             : 
     171          34 :         if (size == 0)
     172           0 :                 return data_blob(NULL, 0);
     173             : 
     174          34 :         size += 4; /* Need to include int32 for the length */
     175             : 
     176             :         /* Allocate as a multiple of 8 */
     177          34 :         size = (size + 7) & ~7;
     178             : 
     179          34 :         ret.data = NULL;
     180          34 :         ret.length = 0;
     181             : 
     182          34 :         for (i = 0; (hbin = data->hbins[i]); i++) {
     183             :                 int j;
     184             :                 int32_t my_size;
     185         294 :                 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
     186         327 :                         my_size = IVALS(hbin->data, j);
     187             : 
     188         327 :                         if (my_size == 0x0) {
     189           0 :                                 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
     190           0 :                                 return ret;
     191             :                         }
     192             : 
     193         327 :                         if (my_size % 8 != 0) {
     194           0 :                                 DEBUG(0, ("Encountered non-aligned block!\n"));
     195             :                         }
     196             : 
     197         327 :                         if (my_size < 0) { /* Used... */
     198         257 :                                 my_size = -my_size;
     199          70 :                         } else if (my_size == size) { /* exact match */
     200           4 :                                 rel_offset = j;
     201           4 :                                 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n",
     202             :                                         size));
     203           0 :                                 break;
     204          66 :                         } else if (my_size > size) { /* data will remain */
     205          29 :                                 rel_offset = j;
     206             :                                 /* Split this block and mark the next block as free */
     207          29 :                                 SIVAL(hbin->data, rel_offset+size, my_size-size);
     208          29 :                                 DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n",
     209             :                                         my_size, size));
     210           0 :                                 break;
     211             :                         }
     212             :                 }
     213             : 
     214          33 :                 if (rel_offset != -1)
     215           0 :                         break;
     216             :         }
     217             : 
     218             :         /* No space available in previous hbins,
     219             :          * allocate new one */
     220          34 :         if (data->hbins[i] == NULL) {
     221           1 :                 DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n",
     222             :                         size));
     223             : 
     224             :                 /* Add extra hbin block */
     225           1 :                 data->hbins = talloc_realloc(data, data->hbins,
     226             :                                              struct hbin_block *, i+2);
     227           1 :                 hbin = talloc(data->hbins, struct hbin_block);
     228           1 :                 SMB_ASSERT(hbin != NULL);
     229             : 
     230           1 :                 data->hbins[i] = hbin;
     231           1 :                 data->hbins[i+1] = NULL;
     232             : 
     233             :                 /* Set hbin data */
     234           1 :                 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
     235           1 :                 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
     236           1 :                 hbin->offset_to_next = 0x1000;
     237           1 :                 hbin->unknown[0] = 0;
     238           1 :                 hbin->unknown[1] = 0;
     239           1 :                 unix_to_nt_time(&hbin->last_change, time(NULL));
     240           1 :                 hbin->block_size = hbin->offset_to_next;
     241           1 :                 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
     242             :                 /* Update the regf header */
     243           1 :                 data->header->last_block += hbin->offset_to_next;
     244             : 
     245             :                 /* Set the next block to it's proper size and set the
     246             :                  * rel_offset for this block */
     247           1 :                 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
     248           1 :                 rel_offset = 0x0;
     249             :         }
     250             : 
     251             :         /* Set size and mark as used */
     252          34 :         SIVAL(hbin->data, rel_offset, -size);
     253             : 
     254          34 :         ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
     255          34 :         ret.length = size - 0x4;
     256          34 :         if (offset) {
     257          34 :                 uint32_t new_rel_offset = 0;
     258          34 :                 *offset = hbin->offset_from_first + rel_offset + 0x20;
     259          68 :                 SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
     260          34 :                 SMB_ASSERT(new_rel_offset == rel_offset);
     261             :         }
     262             : 
     263          34 :         return ret;
     264             : }
     265             : 
     266             : /* Store a data blob. Return the offset at which it was stored */
     267          34 : static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
     268             : {
     269             :         uint32_t ret;
     270          34 :         DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
     271             : 
     272          68 :         memcpy(dest.data, blob.data, blob.length);
     273             : 
     274             :         /* Make sure that we have no tailing garbage in the block */
     275          34 :         if (dest.length > blob.length) {
     276          15 :                 memset(dest.data + blob.length, 0, dest.length - blob.length);
     277             :         }
     278             : 
     279          34 :         return ret;
     280             : }
     281             : 
     282          28 : static uint32_t hbin_store_tdr(struct regf_data *data,
     283             :                                tdr_push_fn_t push_fn, void *p)
     284             : {
     285          28 :         struct tdr_push *push = tdr_push_init(data);
     286             :         uint32_t ret;
     287             : 
     288          28 :         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
     289           0 :                 DEBUG(0, ("Error during push\n"));
     290           0 :                 return -1;
     291             :         }
     292             : 
     293          28 :         ret = hbin_store(data, push->data);
     294             : 
     295          28 :         talloc_free(push);
     296             : 
     297          28 :         return ret;
     298             : }
     299             : 
     300             : 
     301             : /* Free existing data */
     302          18 : static void hbin_free (struct regf_data *data, uint32_t offset)
     303             : {
     304             :         int32_t size;
     305             :         uint32_t rel_offset;
     306             :         int32_t next_size;
     307             :         struct hbin_block *hbin;
     308             : 
     309          18 :         SMB_ASSERT (offset > 0);
     310             : 
     311          36 :         hbin = hbin_by_offset(data, offset, &rel_offset);
     312             : 
     313          18 :         if (hbin == NULL)
     314           0 :                 return;
     315             : 
     316             :         /* Get original size */
     317          18 :         size = IVALS(hbin->data, rel_offset);
     318             : 
     319          18 :         if (size > 0) {
     320           0 :                 DEBUG(1, ("Trying to free already freed block at 0x%04x\n",
     321             :                         offset));
     322           0 :                 return;
     323             :         }
     324             :         /* Mark as unused */
     325          18 :         size = -size;
     326             : 
     327             :         /* If the next block is free, merge into big free block */
     328          18 :         if (rel_offset + size < hbin->offset_to_next - 0x20) {
     329          18 :                 next_size = IVALS(hbin->data, rel_offset+size);
     330          18 :                 if (next_size > 0) {
     331          11 :                         size += next_size;
     332             :                 }
     333             :         }
     334             : 
     335             :         /* Write block size */
     336          18 :         SIVALS(hbin->data, rel_offset, size);
     337             : }
     338             : 
     339             : /**
     340             :  * Store a data blob data was already stored, but has changed in size
     341             :  * Will try to save it at the current location if possible, otherwise
     342             :  * does a free + store */
     343          29 : static uint32_t hbin_store_resize(struct regf_data *data,
     344             :                                   uint32_t orig_offset, DATA_BLOB blob)
     345             : {
     346             :         uint32_t rel_offset;
     347          58 :         struct hbin_block *hbin = hbin_by_offset(data, orig_offset,
     348             :                                                  &rel_offset);
     349             :         int32_t my_size;
     350             :         int32_t orig_size;
     351             :         int32_t needed_size;
     352             :         int32_t possible_size;
     353             :         unsigned int i;
     354             : 
     355          29 :         SMB_ASSERT(orig_offset > 0);
     356             : 
     357          29 :         if (!hbin)
     358           0 :                 return hbin_store(data, blob);
     359             : 
     360             :         /* Get original size */
     361          29 :         orig_size = -IVALS(hbin->data, rel_offset);
     362             : 
     363          29 :         needed_size = blob.length + 4; /* Add int32 containing length */
     364          29 :         needed_size = (needed_size + 7) & ~7; /* Align */
     365             : 
     366             :         /* Fits into current allocated block */
     367          29 :         if (orig_size >= needed_size) {
     368          46 :                 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
     369             :                 /* If the difference in size is greater than 0x4, split the block
     370             :                  * and free/merge it */
     371          23 :                 if (orig_size - needed_size > 0x4) {
     372           1 :                         SIVALS(hbin->data, rel_offset, -needed_size);
     373           1 :                         SIVALS(hbin->data, rel_offset + needed_size,
     374             :                                needed_size-orig_size);
     375           1 :                         hbin_free(data, orig_offset + needed_size);
     376             :                 }
     377           0 :                 return orig_offset;
     378             :         }
     379             : 
     380           0 :         possible_size = orig_size;
     381             : 
     382             :         /* Check if it can be combined with the next few free records */
     383           0 :         for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {
     384           6 :                 if (IVALS(hbin->data, i) < 0) /* Used */
     385           0 :                         break;
     386             : 
     387           0 :                 my_size = IVALS(hbin->data, i);
     388             : 
     389           0 :                 if (my_size == 0x0) {
     390           0 :                         DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
     391           0 :                         break;
     392             :                 } else {
     393           0 :                         possible_size += my_size;
     394             :                 }
     395             : 
     396           0 :                 if (possible_size >= blob.length) {
     397           0 :                         SIVAL(hbin->data, rel_offset, -possible_size);
     398           0 :                         memcpy(hbin->data + rel_offset + 0x4,
     399           0 :                                blob.data, blob.length);
     400           0 :                         return orig_offset;
     401             :                 }
     402             :         }
     403             : 
     404           6 :         hbin_free(data, orig_offset);
     405           6 :         return hbin_store(data, blob);
     406             : }
     407             : 
     408          29 : static uint32_t hbin_store_tdr_resize(struct regf_data *regf,
     409             :                                       tdr_push_fn_t push_fn,
     410             :                                       uint32_t orig_offset, void *p)
     411             : {
     412          29 :         struct tdr_push *push = tdr_push_init(regf);
     413             :         uint32_t ret;
     414             : 
     415          29 :         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
     416           0 :                 DEBUG(0, ("Error during push\n"));
     417           0 :                 return -1;
     418             :         }
     419             : 
     420          29 :         ret = hbin_store_resize(regf, orig_offset, push->data);
     421             : 
     422          29 :         talloc_free(push);
     423             : 
     424          29 :         return ret;
     425             : }
     426             : 
     427          15 : static uint32_t regf_create_lh_hash(const char *name)
     428             : {
     429             :         char *hash_name;
     430          15 :         uint32_t ret = 0;
     431             :         uint16_t i;
     432             : 
     433          15 :         hash_name = strupper_talloc(NULL, name);
     434         184 :         for (i = 0; *(hash_name + i) != 0; i++) {
     435         169 :                 ret *= 37;
     436         169 :                 ret += *(hash_name + i);
     437             :         }
     438          15 :         talloc_free(hash_name);
     439          15 :         return ret;
     440             : }
     441             : 
     442           2 : static WERROR regf_get_info(TALLOC_CTX *mem_ctx,
     443             :                             const struct hive_key *key,
     444             :                             const char **classname,
     445             :                             uint32_t *num_subkeys,
     446             :                             uint32_t *num_values,
     447             :                             NTTIME *last_mod_time,
     448             :                             uint32_t *max_subkeynamelen,
     449             :                             uint32_t *max_valnamelen,
     450             :                             uint32_t *max_valbufsize)
     451             : {
     452           2 :         const struct regf_key_data *private_data =
     453             :                 (const struct regf_key_data *)key;
     454             : 
     455           2 :         if (num_subkeys != NULL)
     456           2 :                 *num_subkeys = private_data->nk->num_subkeys;
     457             : 
     458           2 :         if (num_values != NULL)
     459           2 :                 *num_values = private_data->nk->num_values;
     460             : 
     461           2 :         if (classname != NULL) {
     462           0 :                 if (private_data->nk->clsname_offset != -1) {
     463           0 :                         DATA_BLOB data = hbin_get(private_data->hive,
     464           0 :                                                   private_data->nk->clsname_offset);
     465           0 :                         *classname = talloc_strndup(mem_ctx,
     466           0 :                                                     (char*)data.data,
     467           0 :                                                     private_data->nk->clsname_length);
     468           0 :                         W_ERROR_HAVE_NO_MEMORY(*classname);
     469             :                 } else
     470           0 :                         *classname = NULL;
     471             :         }
     472             : 
     473             :         /* TODO: Last mod time */
     474             : 
     475             :         /* TODO: max valnamelen */
     476             :         
     477             :         /* TODO: max valbufsize */
     478             : 
     479             :         /* TODO: max subkeynamelen */
     480             : 
     481           2 :         return WERR_OK;
     482             : }
     483             : 
     484          16 : static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,
     485             :                                           struct regf_data *regf,
     486             :                                           uint32_t offset)
     487             : {
     488             :         struct nk_block *nk;
     489             :         struct regf_key_data *ret;
     490             : 
     491          16 :         ret = talloc_zero(ctx, struct regf_key_data);
     492          16 :         ret->key.ops = &reg_backend_regf;
     493          16 :         ret->hive = talloc_reference(ret, regf);
     494          16 :         ret->offset = offset;
     495          16 :         nk = talloc(ret, struct nk_block);
     496          16 :         if (nk == NULL)
     497           0 :                 return NULL;
     498             : 
     499          16 :         ret->nk = nk;
     500             : 
     501          16 :         if (!hbin_get_tdr(regf, offset, nk,
     502             :                           (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
     503           0 :                 DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n", offset));
     504           0 :                 return NULL;
     505             :         }
     506             : 
     507          16 :         if (strcmp(nk->header, "nk") != 0) {
     508           0 :                 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
     509           0 :                 talloc_free(ret);
     510           0 :                 return NULL;
     511             :         }
     512             : 
     513           0 :         return ret;
     514             : }
     515             : 
     516             : 
     517           6 : static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key,
     518             :                              uint32_t idx, const char **name,
     519             :                              uint32_t *data_type, DATA_BLOB *data)
     520             : {
     521           6 :         const struct regf_key_data *private_data =
     522             :                         (const struct regf_key_data *)key;
     523             :         struct vk_block *vk;
     524           6 :         struct regf_data *regf = private_data->hive;
     525             :         uint32_t vk_offset;
     526             :         DATA_BLOB tmp;
     527             : 
     528           6 :         if (idx >= private_data->nk->num_values)
     529           3 :                 return WERR_NO_MORE_ITEMS;
     530             : 
     531           3 :         tmp = hbin_get(regf, private_data->nk->values_offset);
     532           3 :         if (!tmp.data) {
     533           0 :                 DEBUG(0, ("Unable to find value list at 0x%x\n",
     534             :                                 private_data->nk->values_offset));
     535           0 :                 return WERR_GEN_FAILURE;
     536             :         }
     537             : 
     538           3 :         if (tmp.length < private_data->nk->num_values * 4) {
     539           0 :                 DEBUG(1, ("Value counts mismatch\n"));
     540             :         }
     541             : 
     542           3 :         vk_offset = IVAL(tmp.data, idx * 4);
     543             : 
     544           3 :         vk = talloc(NULL, struct vk_block);
     545           3 :         W_ERROR_HAVE_NO_MEMORY(vk);
     546             : 
     547           3 :         if (!hbin_get_tdr(regf, vk_offset, vk,
     548             :                           (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
     549           0 :                 DEBUG(0, ("Unable to get VK block at 0x%x\n", vk_offset));
     550           0 :                 talloc_free(vk);
     551           0 :                 return WERR_GEN_FAILURE;
     552             :         }
     553             : 
     554             :         /* FIXME: name character set ?*/
     555           3 :         if (name != NULL) {
     556           3 :                 *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
     557           3 :                 W_ERROR_HAVE_NO_MEMORY(*name);
     558             :         }
     559             : 
     560           3 :         if (data_type != NULL)
     561           2 :                 *data_type = vk->data_type;
     562             : 
     563           3 :         if (vk->data_length & 0x80000000) {
     564             :                 /* this is data of type "REG_DWORD" or "REG_DWORD_BIG_ENDIAN" */
     565           3 :                 data->data = talloc_size(ctx, sizeof(uint32_t));
     566           3 :                 W_ERROR_HAVE_NO_MEMORY(data->data);
     567           3 :                 SIVAL(data->data, 0, vk->data_offset);
     568           3 :                 data->length = sizeof(uint32_t);
     569             :         } else {
     570           0 :                 *data = hbin_get(regf, vk->data_offset);
     571             :         }
     572             : 
     573           3 :         if (data->length < vk->data_length) {
     574           3 :                 DEBUG(1, ("Read data less than indicated data length!\n"));
     575             :         }
     576             : 
     577           3 :         talloc_free(vk);
     578             : 
     579           3 :         return WERR_OK;
     580             : }
     581             : 
     582           3 : static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx,
     583             :                                      struct hive_key *key, const char *name,
     584             :                                      uint32_t *type, DATA_BLOB *data)
     585             : {
     586             :         unsigned int i;
     587             :         const char *vname;
     588             :         WERROR error;
     589             : 
     590             :         /* FIXME: Do binary search? Is this list sorted at all? */
     591             : 
     592           6 :         for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i,
     593             :                                                          &vname, type, data));
     594           0 :                                                          i++) {
     595           1 :                 if (!strcmp(vname, name))
     596           1 :                         return WERR_OK;
     597             :         }
     598             : 
     599           2 :         if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
     600           2 :                 return WERR_FILE_NOT_FOUND;
     601             : 
     602           0 :         return error;
     603             : }
     604             : 
     605             : 
     606           1 : static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx,
     607             :                                        const struct hive_key *key,
     608             :                                        uint32_t idx, const char **name,
     609             :                                        const char **classname,
     610             :                                        NTTIME *last_mod_time)
     611             : {
     612             :         DATA_BLOB data;
     613             :         struct regf_key_data *ret;
     614           1 :         const struct regf_key_data *private_data = (const struct regf_key_data *)key;
     615           1 :         struct nk_block *nk = private_data->nk;
     616           1 :         uint32_t key_off=0;
     617             : 
     618           1 :         if (idx >= nk->num_subkeys)
     619           0 :                 return WERR_NO_MORE_ITEMS;
     620             : 
     621             :         /* Make sure that we don't crash if the key is empty */
     622           1 :         if (nk->subkeys_offset == -1) {
     623           0 :                 return WERR_NO_MORE_ITEMS;
     624             :         }
     625             : 
     626           1 :         data = hbin_get(private_data->hive, nk->subkeys_offset);
     627           1 :         if (!data.data) {
     628           0 :                 DEBUG(0, ("Unable to find subkey list at 0x%x\n",
     629             :                         nk->subkeys_offset));
     630           0 :                 return WERR_GEN_FAILURE;
     631             :         }
     632             : 
     633           1 :         if (!strncmp((char *)data.data, "li", 2)) {
     634             :                 struct li_block li;
     635           0 :                 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
     636             : 
     637           0 :                 DEBUG(10, ("Subkeys in LI list\n"));
     638           0 :                 pull->data = data;
     639             : 
     640           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
     641           0 :                         DEBUG(0, ("Error parsing LI list\n"));
     642           0 :                         talloc_free(pull);
     643           0 :                         return WERR_GEN_FAILURE;
     644             :                 }
     645           0 :                 talloc_free(pull);
     646           0 :                 SMB_ASSERT(!strncmp(li.header, "li", 2));
     647             : 
     648           0 :                 if (li.key_count != nk->num_subkeys) {
     649           0 :                         DEBUG(0, ("Subkey counts don't match\n"));
     650           0 :                         return WERR_GEN_FAILURE;
     651             :                 }
     652           0 :                 key_off = li.nk_offset[idx];
     653             : 
     654           1 :         } else if (!strncmp((char *)data.data, "lf", 2)) {
     655             :                 struct lf_block lf;
     656           0 :                 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
     657             : 
     658           0 :                 DEBUG(10, ("Subkeys in LF list\n"));
     659           0 :                 pull->data = data;
     660             : 
     661           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
     662           0 :                         DEBUG(0, ("Error parsing LF list\n"));
     663           0 :                         talloc_free(pull);
     664           0 :                         return WERR_GEN_FAILURE;
     665             :                 }
     666           0 :                 talloc_free(pull);
     667           0 :                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
     668             : 
     669           0 :                 if (lf.key_count != nk->num_subkeys) {
     670           0 :                         DEBUG(0, ("Subkey counts don't match\n"));
     671           0 :                         return WERR_GEN_FAILURE;
     672             :                 }
     673             : 
     674           0 :                 key_off = lf.hr[idx].nk_offset;
     675           1 :         } else if (!strncmp((char *)data.data, "lh", 2)) {
     676             :                 struct lh_block lh;
     677           1 :                 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
     678             : 
     679           1 :                 DEBUG(10, ("Subkeys in LH list\n"));
     680           1 :                 pull->data = data;
     681             : 
     682           1 :                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
     683           0 :                         DEBUG(0, ("Error parsing LH list\n"));
     684           0 :                         talloc_free(pull);
     685           0 :                         return WERR_GEN_FAILURE;
     686             :                 }
     687           1 :                 talloc_free(pull);
     688           1 :                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
     689             : 
     690           1 :                 if (lh.key_count != nk->num_subkeys) {
     691           0 :                         DEBUG(0, ("Subkey counts don't match\n"));
     692           0 :                         return WERR_GEN_FAILURE;
     693             :                 }
     694           1 :                 key_off = lh.hr[idx].nk_offset;
     695           0 :         } else if (!strncmp((char *)data.data, "ri", 2)) {
     696             :                 struct ri_block ri;
     697           0 :                 struct tdr_pull *pull = tdr_pull_init(ctx);
     698             :                 uint16_t i;
     699           0 :                 uint16_t sublist_count = 0;
     700             : 
     701           0 :                 DEBUG(10, ("Subkeys in RI list\n"));
     702           0 :                 pull->data = data;
     703             : 
     704           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
     705           0 :                         DEBUG(0, ("Error parsing RI list\n"));
     706           0 :                         talloc_free(pull);
     707           0 :                         return WERR_GEN_FAILURE;
     708             :                 }
     709           0 :                 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
     710             : 
     711           0 :                 for (i = 0; i < ri.key_count; i++) {
     712             :                         DATA_BLOB list_data;
     713             : 
     714             :                         /* Get sublist data blob */
     715           0 :                         list_data = hbin_get(private_data->hive, ri.offset[i]);
     716           0 :                         if (!list_data.data) {
     717           0 :                                 DEBUG(0, ("Error getting RI list."));
     718           0 :                                 talloc_free(pull);
     719           0 :                                 return WERR_GEN_FAILURE;
     720             :                         }
     721             : 
     722           0 :                         pull->data = list_data;
     723             : 
     724           0 :                         if (!strncmp((char *)list_data.data, "li", 2)) {
     725             :                                 struct li_block li;
     726             : 
     727           0 :                                 DEBUG(10, ("Subkeys in RI->LI list\n"));
     728             : 
     729           0 :                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
     730             :                                                                        nk,
     731             :                                                                        &li))) {
     732           0 :                                         DEBUG(0, ("Error parsing LI list from RI\n"));
     733           0 :                                         talloc_free(pull);
     734           0 :                                         return WERR_GEN_FAILURE;
     735             :                                 }
     736           0 :                                 SMB_ASSERT(!strncmp(li.header, "li", 2));
     737             : 
     738             :                                 /* Advance to next sublist if necessary */
     739           0 :                                 if (idx >= sublist_count + li.key_count) {
     740           0 :                                         sublist_count += li.key_count;
     741           0 :                                         continue;
     742             :                                 }
     743           0 :                                 key_off = li.nk_offset[idx - sublist_count];
     744           0 :                                 sublist_count += li.key_count;
     745           0 :                                 break;
     746           0 :                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
     747             :                                 struct lh_block lh;
     748             : 
     749           0 :                                 DEBUG(10, ("Subkeys in RI->LH list\n"));
     750             : 
     751           0 :                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
     752             :                                                                        nk,
     753             :                                                                        &lh))) {
     754           0 :                                         DEBUG(0, ("Error parsing LH list from RI\n"));
     755           0 :                                         talloc_free(pull);
     756           0 :                                         return WERR_GEN_FAILURE;
     757             :                                 }
     758           0 :                                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
     759             : 
     760             :                                 /* Advance to next sublist if necessary */
     761           0 :                                 if (idx >= sublist_count + lh.key_count) {
     762           0 :                                         sublist_count += lh.key_count;
     763           0 :                                         continue;
     764             :                                 }
     765           0 :                                 key_off = lh.hr[idx - sublist_count].nk_offset;
     766           0 :                                 sublist_count += lh.key_count;
     767           0 :                                 break;
     768             :                         } else {
     769           0 :                                 DEBUG(0,("Unknown sublist in ri block\n"));
     770           0 :                                 talloc_free(pull);
     771             : 
     772           0 :                                 return WERR_GEN_FAILURE;
     773             :                         }
     774             : 
     775             :                 }
     776           0 :                 talloc_free(pull);
     777             : 
     778             : 
     779           0 :                 if (idx > sublist_count) {
     780           0 :                         return WERR_NO_MORE_ITEMS;
     781             :                 }
     782             : 
     783             :         } else {
     784           0 :                 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n",
     785             :                                   nk->subkeys_offset, data.data[0], data.data[1]));
     786           0 :                 return WERR_GEN_FAILURE;
     787             :         }
     788             : 
     789           1 :         ret = regf_get_key (ctx, private_data->hive, key_off);
     790             : 
     791           1 :         if (classname != NULL) {
     792           0 :                 if (ret->nk->clsname_offset != -1) {
     793           0 :                         DATA_BLOB db = hbin_get(ret->hive,
     794           0 :                                                 ret->nk->clsname_offset);
     795           0 :                         *classname = talloc_strndup(ctx,
     796           0 :                                                     (char*)db.data,
     797           0 :                                                     ret->nk->clsname_length);
     798           0 :                         W_ERROR_HAVE_NO_MEMORY(*classname);
     799             :                 } else
     800           0 :                         *classname = NULL;
     801             :         }
     802             : 
     803           1 :         if (last_mod_time != NULL)
     804           0 :                 *last_mod_time = ret->nk->last_change;
     805             : 
     806           1 :         if (name != NULL)
     807           1 :                 *name = talloc_steal(ctx, ret->nk->key_name);
     808             : 
     809           1 :         talloc_free(ret);
     810             : 
     811           1 :         return WERR_OK;
     812             : }
     813             : 
     814           4 : static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx,
     815             :                                         const struct hive_key *key,
     816             :                                         uint32_t offset,
     817             :                                         const char *name, uint32_t *ret)
     818             : {
     819             :         DATA_BLOB subkey_data;
     820             :         struct nk_block subkey;
     821             :         struct tdr_pull *pull;
     822           4 :         const struct regf_key_data *private_data =
     823             :                 (const struct regf_key_data *)key;
     824             : 
     825           4 :         subkey_data = hbin_get(private_data->hive, offset);
     826           4 :         if (!subkey_data.data) {
     827           0 :                 DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
     828           0 :                 return WERR_GEN_FAILURE;
     829             :         }
     830             : 
     831           4 :         pull = tdr_pull_init(ctx);
     832             : 
     833           4 :         pull->data = subkey_data;
     834             : 
     835           4 :         if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, ctx, &subkey))) {
     836           0 :                 DEBUG(0, ("Error parsing NK structure.\n"));
     837           0 :                 talloc_free(pull);
     838           0 :                 return WERR_GEN_FAILURE;
     839             :         }
     840           4 :         talloc_free(pull);
     841             : 
     842           4 :         if (strncmp(subkey.header, "nk", 2)) {
     843           0 :                 DEBUG(0, ("Not an NK structure.\n"));
     844           0 :                 return WERR_GEN_FAILURE;
     845             :         }
     846             : 
     847           4 :         if (!strcasecmp(subkey.key_name, name)) {
     848           4 :                 *ret = offset;
     849             :         } else {
     850           0 :                 *ret = 0;
     851             :         }
     852           4 :         return WERR_OK;
     853             : }
     854             : 
     855           5 : static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
     856             :                                       const struct hive_key *key,
     857             :                                       const char *name,
     858             :                                       struct hive_key **ret)
     859             : {
     860             :         DATA_BLOB data;
     861           5 :         const struct regf_key_data *private_data =
     862             :                 (const struct regf_key_data *)key;
     863           5 :         struct nk_block *nk = private_data->nk;
     864           5 :         uint32_t key_off = 0;
     865             : 
     866             :         /* Make sure that we don't crash if the key is empty */
     867           5 :         if (nk->subkeys_offset == -1) {
     868           0 :                 return WERR_FILE_NOT_FOUND;
     869             :         }
     870             : 
     871           5 :         data = hbin_get(private_data->hive, nk->subkeys_offset);
     872           5 :         if (!data.data) {
     873           0 :                 DEBUG(0, ("Unable to find subkey list\n"));
     874           0 :                 return WERR_GEN_FAILURE;
     875             :         }
     876             : 
     877           5 :         if (!strncmp((char *)data.data, "li", 2)) {
     878             :                 struct li_block li;
     879           0 :                 struct tdr_pull *pull = tdr_pull_init(ctx);
     880             :                 uint16_t i;
     881             : 
     882           0 :                 DEBUG(10, ("Subkeys in LI list\n"));
     883           0 :                 pull->data = data;
     884             : 
     885           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
     886           0 :                         DEBUG(0, ("Error parsing LI list\n"));
     887           0 :                         talloc_free(pull);
     888           0 :                         return WERR_GEN_FAILURE;
     889             :                 }
     890           0 :                 talloc_free(pull);
     891           0 :                 SMB_ASSERT(!strncmp(li.header, "li", 2));
     892             : 
     893           0 :                 if (li.key_count != nk->num_subkeys) {
     894           0 :                         DEBUG(0, ("Subkey counts don't match\n"));
     895           0 :                         return WERR_GEN_FAILURE;
     896             :                 }
     897             : 
     898           0 :                 for (i = 0; i < li.key_count; i++) {
     899           0 :                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
     900             :                                                                         li.nk_offset[i],
     901             :                                                                         name,
     902             :                                                                         &key_off));
     903           0 :                         if (key_off != 0)
     904           0 :                                 break;
     905             :                 }
     906           0 :                 if (key_off == 0)
     907           0 :                         return WERR_FILE_NOT_FOUND;
     908           5 :         } else if (!strncmp((char *)data.data, "lf", 2)) {
     909             :                 struct lf_block lf;
     910           0 :                 struct tdr_pull *pull = tdr_pull_init(ctx);
     911             :                 uint16_t i;
     912             : 
     913           0 :                 DEBUG(10, ("Subkeys in LF list\n"));
     914           0 :                 pull->data = data;
     915             : 
     916           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
     917           0 :                         DEBUG(0, ("Error parsing LF list\n"));
     918           0 :                         talloc_free(pull);
     919           0 :                         return WERR_GEN_FAILURE;
     920             :                 }
     921           0 :                 talloc_free(pull);
     922           0 :                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
     923             : 
     924           0 :                 if (lf.key_count != nk->num_subkeys) {
     925           0 :                         DEBUG(0, ("Subkey counts don't match\n"));
     926           0 :                         return WERR_GEN_FAILURE;
     927             :                 }
     928             : 
     929           0 :                 for (i = 0; i < lf.key_count; i++) {
     930           0 :                         if (strncmp(lf.hr[i].hash, name, 4)) {
     931           0 :                                 continue;
     932             :                         }
     933           0 :                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
     934             :                                                                         key,
     935             :                                                                         lf.hr[i].nk_offset,
     936             :                                                                         name,
     937             :                                                                         &key_off));
     938           0 :                         if (key_off != 0)
     939           0 :                                 break;
     940             :                 }
     941           0 :                 if (key_off == 0)
     942           0 :                         return WERR_FILE_NOT_FOUND;
     943           5 :         } else if (!strncmp((char *)data.data, "lh", 2)) {
     944             :                 struct lh_block lh;
     945           5 :                 struct tdr_pull *pull = tdr_pull_init(ctx);
     946             :                 uint16_t i;
     947             :                 uint32_t hash;
     948             : 
     949           5 :                 DEBUG(10, ("Subkeys in LH list\n"));
     950           5 :                 pull->data = data;
     951             : 
     952           5 :                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
     953           0 :                         DEBUG(0, ("Error parsing LH list\n"));
     954           0 :                         talloc_free(pull);
     955           1 :                         return WERR_GEN_FAILURE;
     956             :                 }
     957           5 :                 talloc_free(pull);
     958           5 :                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
     959             : 
     960           5 :                 if (lh.key_count != nk->num_subkeys) {
     961           0 :                         DEBUG(0, ("Subkey counts don't match\n"));
     962           0 :                         return WERR_GEN_FAILURE;
     963             :                 }
     964             : 
     965           5 :                 hash = regf_create_lh_hash(name);
     966          11 :                 for (i = 0; i < lh.key_count; i++) {
     967          10 :                         if (lh.hr[i].base37 != hash) {
     968           6 :                                 continue;
     969             :                         }
     970           4 :                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
     971             :                                                                         key,
     972             :                                                                         lh.hr[i].nk_offset,
     973             :                                                                         name,
     974             :                                                                         &key_off));
     975           4 :                         if (key_off != 0)
     976           0 :                                 break;
     977             :                 }
     978           5 :                 if (key_off == 0)
     979           1 :                         return WERR_FILE_NOT_FOUND;
     980           0 :         } else if (!strncmp((char *)data.data, "ri", 2)) {
     981             :                 struct ri_block ri;
     982           0 :                 struct tdr_pull *pull = tdr_pull_init(ctx);
     983             :                 uint16_t i, j;
     984             : 
     985           0 :                 DEBUG(10, ("Subkeys in RI list\n"));
     986           0 :                 pull->data = data;
     987             : 
     988           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
     989           0 :                         DEBUG(0, ("Error parsing RI list\n"));
     990           0 :                         talloc_free(pull);
     991           0 :                         return WERR_GEN_FAILURE;
     992             :                 }
     993           0 :                 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
     994             : 
     995           0 :                 for (i = 0; i < ri.key_count; i++) {
     996             :                         DATA_BLOB list_data;
     997             : 
     998             :                         /* Get sublist data blob */
     999           0 :                         list_data = hbin_get(private_data->hive, ri.offset[i]);
    1000           0 :                         if (list_data.data == NULL) {
    1001           0 :                                 DEBUG(0, ("Error getting RI list."));
    1002           0 :                                 talloc_free(pull);
    1003           0 :                                 return WERR_GEN_FAILURE;
    1004             :                         }
    1005             : 
    1006           0 :                         pull->data = list_data;
    1007             : 
    1008           0 :                         if (!strncmp((char *)list_data.data, "li", 2)) {
    1009             :                                 struct li_block li;
    1010             : 
    1011           0 :                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
    1012             :                                                                        nk,
    1013             :                                                                        &li))) {
    1014           0 :                                         DEBUG(0, ("Error parsing LI list from RI\n"));
    1015           0 :                                         talloc_free(pull);
    1016           0 :                                         return WERR_GEN_FAILURE;
    1017             :                                 }
    1018           0 :                                 SMB_ASSERT(!strncmp(li.header, "li", 2));
    1019             : 
    1020           0 :                                 for (j = 0; j < li.key_count; j++) {
    1021           0 :                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
    1022             :                                                                                         li.nk_offset[j],
    1023             :                                                                                         name,
    1024             :                                                                                         &key_off));
    1025           0 :                                         if (key_off)
    1026           0 :                                                 break;
    1027             :                                 }
    1028           0 :                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
    1029             :                                 struct lh_block lh;
    1030             :                                 uint32_t hash;
    1031             : 
    1032           0 :                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
    1033             :                                                                        nk,
    1034             :                                                                        &lh))) {
    1035           0 :                                         DEBUG(0, ("Error parsing LH list from RI\n"));
    1036           0 :                                         talloc_free(pull);
    1037           0 :                                         return WERR_GEN_FAILURE;
    1038             :                                 }
    1039           0 :                                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
    1040             : 
    1041           0 :                                 hash = regf_create_lh_hash(name);
    1042           0 :                                 for (j = 0; j < lh.key_count; j++) {
    1043           0 :                                         if (lh.hr[j].base37 != hash) {
    1044           0 :                                                 continue;
    1045             :                                         }
    1046           0 :                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
    1047             :                                                                                         lh.hr[j].nk_offset,
    1048             :                                                                                         name,
    1049             :                                                                                         &key_off));
    1050           0 :                                         if (key_off)
    1051           0 :                                                 break;
    1052             :                                 }
    1053             :                         }
    1054           0 :                         if (key_off)
    1055           0 :                                 break;
    1056             :                 }
    1057           0 :                 talloc_free(pull);
    1058           0 :                 if (!key_off)
    1059           0 :                         return WERR_FILE_NOT_FOUND;
    1060             :         } else {
    1061           0 :                 DEBUG(0, ("Unknown subkey list type.\n"));
    1062           0 :                 return WERR_GEN_FAILURE;
    1063             :         }
    1064             : 
    1065           4 :         *ret = (struct hive_key *)regf_get_key(ctx, private_data->hive,
    1066             :                                                key_off);
    1067           4 :         return WERR_OK;
    1068             : }
    1069             : 
    1070           1 : static WERROR regf_set_sec_desc(struct hive_key *key,
    1071             :                                 const struct security_descriptor *sec_desc)
    1072             : {
    1073           1 :         const struct regf_key_data *private_data =
    1074             :                 (const struct regf_key_data *)key;
    1075             :         struct sk_block cur_sk, sk, new_sk;
    1076           1 :         struct regf_data *regf = private_data->hive;
    1077             :         struct nk_block root;
    1078             :         DATA_BLOB data;
    1079             :         uint32_t sk_offset, cur_sk_offset;
    1080           1 :         bool update_cur_sk = false;
    1081             : 
    1082             :         /* Get the root nk */
    1083           1 :         hbin_get_tdr(regf, regf->header->data_offset, regf,
    1084             :                      (tdr_pull_fn_t) tdr_pull_nk_block, &root);
    1085             : 
    1086             :         /* Push the security descriptor to a blob */
    1087           1 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf, 
    1088             :                                                           sec_desc, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
    1089           0 :                 DEBUG(0, ("Unable to push security descriptor\n"));
    1090           0 :                 return WERR_GEN_FAILURE;
    1091             :         }
    1092             : 
    1093             :         /* Get the current security descriptor for the key */
    1094           1 :         if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf,
    1095             :                           (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
    1096           0 :                 DEBUG(0, ("Unable to find security descriptor for current key\n"));
    1097           0 :                 return WERR_FILE_NOT_FOUND;
    1098             :         }
    1099             :         /* If there's no change, change nothing. */
    1100           1 :         if (memcmp(data.data, cur_sk.sec_desc,
    1101           1 :                    MIN(data.length, cur_sk.rec_size)) == 0) {
    1102           1 :                 return WERR_OK;
    1103             :         }
    1104             : 
    1105             :         /* Delete the current sk if only this key is using it */
    1106           0 :         if (cur_sk.ref_cnt == 1) {
    1107             :                 /* Get the previous security descriptor for the key */
    1108           0 :                 if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf,
    1109             :                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
    1110           0 :                         DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
    1111           0 :                         return WERR_FILE_NOT_FOUND;
    1112             :                 }
    1113             :                 /* Change and store the previous security descriptor */
    1114           0 :                 sk.next_offset = cur_sk.next_offset;
    1115           0 :                 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
    1116             :                                       cur_sk.prev_offset, &sk);
    1117             : 
    1118             :                 /* Get the next security descriptor for the key */
    1119           0 :                 if (!hbin_get_tdr(regf, cur_sk.next_offset, regf,
    1120             :                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
    1121           0 :                         DEBUG(0, ("Unable to find next security descriptor for current key\n"));
    1122           0 :                         return WERR_FILE_NOT_FOUND;
    1123             :                 }
    1124             :                 /* Change and store the next security descriptor */
    1125           0 :                 sk.prev_offset = cur_sk.prev_offset;
    1126           0 :                 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
    1127             :                                       cur_sk.next_offset, &sk);
    1128             : 
    1129           0 :                 hbin_free(regf, private_data->nk->sk_offset);
    1130             :         } else {
    1131             :                 /* This key will no longer be referring to this sk */
    1132           0 :                 cur_sk.ref_cnt--;
    1133           0 :                 update_cur_sk = true;
    1134             :         }
    1135             : 
    1136           0 :         sk_offset = root.sk_offset;
    1137             : 
    1138             :         do {
    1139           0 :                 cur_sk_offset = sk_offset;
    1140           0 :                 if (!hbin_get_tdr(regf, sk_offset, regf,
    1141             :                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
    1142           0 :                         DEBUG(0, ("Unable to find security descriptor\n"));
    1143           0 :                         return WERR_FILE_NOT_FOUND;
    1144             :                 }
    1145           0 :                 if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
    1146           0 :                         private_data->nk->sk_offset = sk_offset;
    1147           0 :                         sk.ref_cnt++;
    1148           0 :                         hbin_store_tdr_resize(regf,
    1149             :                                               (tdr_push_fn_t) tdr_push_sk_block,
    1150             :                                               sk_offset, &sk);
    1151           0 :                         hbin_store_tdr_resize(regf,
    1152             :                                               (tdr_push_fn_t) tdr_push_nk_block,
    1153           0 :                                               private_data->offset,
    1154           0 :                                               private_data->nk);
    1155           0 :                         return WERR_OK;
    1156             :                 }
    1157           0 :                 sk_offset = sk.next_offset;
    1158           0 :         } while (sk_offset != root.sk_offset);
    1159             : 
    1160           0 :         ZERO_STRUCT(new_sk);
    1161           0 :         new_sk.header = "sk";
    1162           0 :         new_sk.prev_offset = cur_sk_offset;
    1163           0 :         new_sk.next_offset = root.sk_offset;
    1164           0 :         new_sk.ref_cnt = 1;
    1165           0 :         new_sk.rec_size = data.length;
    1166           0 :         new_sk.sec_desc = data.data;
    1167             : 
    1168           0 :         sk_offset = hbin_store_tdr(regf,
    1169             :                                    (tdr_push_fn_t) tdr_push_sk_block,
    1170             :                                    &new_sk);
    1171           0 :         if (sk_offset == -1) {
    1172           0 :                 DEBUG(0, ("Error storing sk block\n"));
    1173           0 :                 return WERR_GEN_FAILURE;
    1174             :         }
    1175           0 :         private_data->nk->sk_offset = sk_offset;
    1176             : 
    1177           0 :         if (update_cur_sk) {
    1178           0 :                 hbin_store_tdr_resize(regf,
    1179             :                                       (tdr_push_fn_t) tdr_push_sk_block,
    1180           0 :                                       private_data->nk->sk_offset, &cur_sk);
    1181             :         }
    1182             : 
    1183             :         /* Get the previous security descriptor for the key */
    1184           0 :         if (!hbin_get_tdr(regf, new_sk.prev_offset, regf,
    1185             :                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
    1186           0 :                 DEBUG(0, ("Unable to find security descriptor for previous key\n"));
    1187           0 :                 return WERR_FILE_NOT_FOUND;
    1188             :         }
    1189             :         /* Change and store the previous security descriptor */
    1190           0 :         sk.next_offset = sk_offset;
    1191           0 :         hbin_store_tdr_resize(regf,
    1192             :                               (tdr_push_fn_t) tdr_push_sk_block,
    1193             :                               cur_sk.prev_offset, &sk);
    1194             : 
    1195             :         /* Get the next security descriptor for the key (always root, as we append) */
    1196           0 :         if (!hbin_get_tdr(regf, new_sk.next_offset, regf,
    1197             :                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
    1198           0 :                 DEBUG(0, ("Unable to find security descriptor for current key\n"));
    1199           0 :                 return WERR_FILE_NOT_FOUND;
    1200             :         }
    1201             :         /* Change and store the next security descriptor (always root, as we append) */
    1202           0 :         sk.prev_offset = sk_offset;
    1203           0 :         hbin_store_tdr_resize(regf,
    1204             :                               (tdr_push_fn_t) tdr_push_sk_block,
    1205             :                               root.sk_offset, &sk);
    1206             : 
    1207             : 
    1208             :         /* Store the nk. */
    1209           0 :         hbin_store_tdr_resize(regf,
    1210             :                               (tdr_push_fn_t) tdr_push_sk_block,
    1211           0 :                               private_data->offset, private_data->nk);
    1212           0 :         return WERR_OK;
    1213             : }
    1214             : 
    1215           2 : static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key,
    1216             :                                 struct security_descriptor **sd)
    1217             : {
    1218           2 :         const struct regf_key_data *private_data =
    1219             :                 (const struct regf_key_data *)key;
    1220             :         struct sk_block sk;
    1221           2 :         struct regf_data *regf = private_data->hive;
    1222             :         DATA_BLOB data;
    1223             : 
    1224           2 :         if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx,
    1225             :                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
    1226           0 :                 DEBUG(0, ("Unable to find security descriptor\n"));
    1227           0 :                 return WERR_GEN_FAILURE;
    1228             :         }
    1229             : 
    1230           2 :         if (strcmp(sk.header, "sk") != 0) {
    1231           0 :                 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
    1232           0 :                 return WERR_GEN_FAILURE;
    1233             :         }
    1234             : 
    1235           2 :         *sd = talloc(ctx, struct security_descriptor);
    1236           2 :         W_ERROR_HAVE_NO_MEMORY(*sd);
    1237             : 
    1238           2 :         data.data = sk.sec_desc;
    1239           2 :         data.length = sk.rec_size;
    1240           2 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&data, ctx, *sd,
    1241             :                                                   (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
    1242           0 :                 DEBUG(0, ("Error parsing security descriptor\n"));
    1243           0 :                 return WERR_GEN_FAILURE;
    1244             :         }
    1245             : 
    1246           2 :         return WERR_OK;
    1247             : }
    1248             : 
    1249          10 : static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset,
    1250             :                                 const char *name,
    1251             :                                 uint32_t key_offset, uint32_t *ret)
    1252             : {
    1253             :         DATA_BLOB data;
    1254             : 
    1255             :         /* Create a new key if necessary */
    1256          10 :         if (list_offset == -1) {
    1257           4 :                 if (regf->header->version.major != 1) {
    1258           0 :                         DEBUG(0, ("Can't store keys in unknown registry format\n"));
    1259           0 :                         return WERR_NOT_SUPPORTED;
    1260             :                 }
    1261           4 :                 if (regf->header->version.minor < 3) {
    1262             :                         /* Store LI */
    1263             :                         struct li_block li;
    1264           0 :                         ZERO_STRUCT(li);
    1265           0 :                         li.header = "li";
    1266           0 :                         li.key_count = 1;
    1267             : 
    1268           0 :                         li.nk_offset = talloc_array(regf, uint32_t, 1);
    1269           0 :                         W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
    1270           0 :                         li.nk_offset[0] = key_offset;
    1271             : 
    1272           0 :                         *ret = hbin_store_tdr(regf,
    1273             :                                               (tdr_push_fn_t) tdr_push_li_block,
    1274             :                                               &li);
    1275             : 
    1276           0 :                         talloc_free(li.nk_offset);
    1277           4 :                 } else if (regf->header->version.minor == 3 ||
    1278           0 :                            regf->header->version.minor == 4) {
    1279             :                         /* Store LF */
    1280             :                         struct lf_block lf;
    1281           0 :                         ZERO_STRUCT(lf);
    1282           0 :                         lf.header = "lf";
    1283           0 :                         lf.key_count = 1;
    1284             : 
    1285           0 :                         lf.hr = talloc_array(regf, struct hash_record, 1);
    1286           0 :                         W_ERROR_HAVE_NO_MEMORY(lf.hr);
    1287           0 :                         lf.hr[0].nk_offset = key_offset;
    1288           0 :                         lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
    1289           0 :                         W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
    1290             : 
    1291           0 :                         *ret = hbin_store_tdr(regf,
    1292             :                                               (tdr_push_fn_t) tdr_push_lf_block,
    1293             :                                               &lf);
    1294             : 
    1295           0 :                         talloc_free(lf.hr);
    1296           4 :                 } else if (regf->header->version.minor == 5) {
    1297             :                         /* Store LH */
    1298             :                         struct lh_block lh;
    1299           4 :                         ZERO_STRUCT(lh);
    1300           4 :                         lh.header = "lh";
    1301           4 :                         lh.key_count = 1;
    1302             : 
    1303           4 :                         lh.hr = talloc_array(regf, struct lh_hash, 1);
    1304           4 :                         W_ERROR_HAVE_NO_MEMORY(lh.hr);
    1305           4 :                         lh.hr[0].nk_offset = key_offset;
    1306           4 :                         lh.hr[0].base37 = regf_create_lh_hash(name);
    1307             : 
    1308           4 :                         *ret = hbin_store_tdr(regf,
    1309             :                                               (tdr_push_fn_t) tdr_push_lh_block,
    1310             :                                               &lh);
    1311             : 
    1312           4 :                         talloc_free(lh.hr);
    1313             :                 }
    1314           4 :                 return WERR_OK;
    1315             :         }
    1316             : 
    1317           6 :         data = hbin_get(regf, list_offset);
    1318           6 :         if (!data.data) {
    1319           0 :                 DEBUG(0, ("Unable to find subkey list\n"));
    1320           0 :                 return WERR_FILE_NOT_FOUND;
    1321             :         }
    1322             : 
    1323           6 :         if (!strncmp((char *)data.data, "li", 2)) {
    1324           0 :                 struct tdr_pull *pull = tdr_pull_init(regf);
    1325             :                 struct li_block li;
    1326             :                 struct nk_block sub_nk;
    1327             :                 int32_t i, j;
    1328             : 
    1329           0 :                 pull->data = data;
    1330             : 
    1331           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
    1332           0 :                         DEBUG(0, ("Error parsing LI list\n"));
    1333           0 :                         talloc_free(pull);
    1334           0 :                         return WERR_FILE_NOT_FOUND;
    1335             :                 }
    1336           0 :                 talloc_free(pull);
    1337             : 
    1338           0 :                 if (strncmp(li.header, "li", 2) != 0) {
    1339           0 :                         abort();
    1340             :                         DEBUG(0, ("LI header corrupt\n"));
    1341             :                         return WERR_FILE_NOT_FOUND;
    1342             :                 }
    1343             : 
    1344             :                 /* 
    1345             :                  * Find the position to store the pointer
    1346             :                  * Extensive testing reveils that at least on windows 7 subkeys 
    1347             :                  * *MUST* be stored in alphabetical order
    1348             :                  */
    1349           0 :                 for (i = 0; i < li.key_count; i++) {
    1350             :                         /* Get the nk */
    1351           0 :                         hbin_get_tdr(regf, li.nk_offset[i], regf,
    1352             :                                         (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
    1353           0 :                         if (strcasecmp(name, sub_nk.key_name) < 0) {
    1354           0 :                                 break;
    1355             :                         }
    1356             :                 }
    1357             : 
    1358           0 :                 li.nk_offset = talloc_realloc(regf, li.nk_offset,
    1359             :                                               uint32_t, li.key_count+1);
    1360           0 :                 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
    1361             : 
    1362             :                 /* Move everything behind this offset */
    1363           0 :                 for (j = li.key_count - 1; j >= i; j--) {
    1364           0 :                         li.nk_offset[j+1] = li.nk_offset[j];
    1365             :                 }
    1366             :                         
    1367           0 :                 li.nk_offset[i] = key_offset;
    1368           0 :                 li.key_count++;
    1369           0 :                 *ret = hbin_store_tdr_resize(regf,
    1370             :                                              (tdr_push_fn_t)tdr_push_li_block,
    1371             :                                              list_offset, &li);
    1372             : 
    1373           0 :                 talloc_free(li.nk_offset);
    1374           6 :         } else if (!strncmp((char *)data.data, "lf", 2)) {
    1375           0 :                 struct tdr_pull *pull = tdr_pull_init(regf);
    1376             :                 struct lf_block lf;
    1377             :                 struct nk_block sub_nk;
    1378             :                 int32_t i, j;
    1379             : 
    1380           0 :                 pull->data = data;
    1381             : 
    1382           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
    1383           0 :                         DEBUG(0, ("Error parsing LF list\n"));
    1384           0 :                         talloc_free(pull);
    1385           0 :                         return WERR_FILE_NOT_FOUND;
    1386             :                 }
    1387           0 :                 talloc_free(pull);
    1388           0 :                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
    1389             : 
    1390             :                 /* 
    1391             :                  * Find the position to store the hash record
    1392             :                  * Extensive testing reveils that at least on windows 7 subkeys 
    1393             :                  * *MUST* be stored in alphabetical order
    1394             :                  */
    1395           0 :                 for (i = 0; i < lf.key_count; i++) {
    1396             :                         /* Get the nk */
    1397           0 :                         hbin_get_tdr(regf, lf.hr[i].nk_offset, regf,
    1398             :                                         (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
    1399           0 :                         if (strcasecmp(name, sub_nk.key_name) < 0) {
    1400           0 :                                 break;
    1401             :                         }
    1402             :                 }
    1403             : 
    1404           0 :                 lf.hr = talloc_realloc(regf, lf.hr, struct hash_record,
    1405             :                                        lf.key_count+1);
    1406           0 :                 W_ERROR_HAVE_NO_MEMORY(lf.hr);
    1407             : 
    1408             :                 /* Move everything behind this hash record */
    1409           0 :                 for (j = lf.key_count - 1; j >= i; j--) {
    1410           0 :                         lf.hr[j+1] = lf.hr[j];
    1411             :                 }
    1412             : 
    1413           0 :                 lf.hr[i].nk_offset = key_offset;
    1414           0 :                 lf.hr[i].hash = talloc_strndup(lf.hr, name, 4);
    1415           0 :                 W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
    1416           0 :                 lf.key_count++;
    1417           0 :                 *ret = hbin_store_tdr_resize(regf,
    1418             :                                              (tdr_push_fn_t)tdr_push_lf_block,
    1419             :                                              list_offset, &lf);
    1420             : 
    1421           0 :                 talloc_free(lf.hr);
    1422           6 :         } else if (!strncmp((char *)data.data, "lh", 2)) {
    1423           6 :                 struct tdr_pull *pull = tdr_pull_init(regf);
    1424             :                 struct lh_block lh;
    1425             :                 struct nk_block sub_nk;
    1426             :                 int32_t i, j;
    1427             : 
    1428           6 :                 pull->data = data;
    1429             : 
    1430           6 :                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
    1431           0 :                         DEBUG(0, ("Error parsing LH list\n"));
    1432           0 :                         talloc_free(pull);
    1433           0 :                         return WERR_FILE_NOT_FOUND;
    1434             :                 }
    1435           6 :                 talloc_free(pull);
    1436           6 :                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
    1437             : 
    1438             :                 /* 
    1439             :                  * Find the position to store the hash record
    1440             :                  * Extensive testing reveils that at least on windows 7 subkeys 
    1441             :                  * *MUST* be stored in alphabetical order
    1442             :                  */
    1443           8 :                 for (i = 0; i < lh.key_count; i++) {
    1444             :                         /* Get the nk */
    1445          13 :                         hbin_get_tdr(regf, lh.hr[i].nk_offset, regf,
    1446             :                                         (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
    1447          13 :                         if (strcasecmp(name, sub_nk.key_name) < 0) {
    1448           0 :                                 break;
    1449             :                         }
    1450             :                 }
    1451             : 
    1452           6 :                 lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash,
    1453             :                                        lh.key_count+1);
    1454           6 :                 W_ERROR_HAVE_NO_MEMORY(lh.hr);
    1455             : 
    1456             :                 /* Move everything behind this hash record */
    1457          17 :                 for (j = lh.key_count - 1; j >= i; j--) {
    1458          11 :                         lh.hr[j+1] = lh.hr[j];
    1459             :                 }
    1460             : 
    1461           6 :                 lh.hr[i].nk_offset = key_offset;
    1462           6 :                 lh.hr[i].base37 = regf_create_lh_hash(name);
    1463           6 :                 lh.key_count++;
    1464           6 :                 *ret = hbin_store_tdr_resize(regf,
    1465             :                                              (tdr_push_fn_t)tdr_push_lh_block,
    1466             :                                              list_offset, &lh);
    1467             : 
    1468           6 :                 talloc_free(lh.hr);
    1469           0 :         } else if (!strncmp((char *)data.data, "ri", 2)) {
    1470             :                 /* FIXME */
    1471           0 :                 DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
    1472           0 :                 return WERR_NOT_SUPPORTED;
    1473             :         } else {
    1474           0 :                 DEBUG(0, ("Cannot add to unknown subkey list\n"));
    1475           0 :                 return WERR_FILE_NOT_FOUND;
    1476             :         }
    1477             : 
    1478           6 :         return WERR_OK;
    1479             : }
    1480             : 
    1481           4 : static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
    1482             :                                 uint32_t key_offset, uint32_t *ret)
    1483             : {
    1484             :         DATA_BLOB data;
    1485             : 
    1486           4 :         data = hbin_get(regf, list_offset);
    1487           4 :         if (!data.data) {
    1488           0 :                 DEBUG(0, ("Unable to find subkey list\n"));
    1489           0 :                 return WERR_FILE_NOT_FOUND;
    1490             :         }
    1491             : 
    1492           4 :         if (strncmp((char *)data.data, "li", 2) == 0) {
    1493             :                 struct li_block li;
    1494           0 :                 struct tdr_pull *pull = tdr_pull_init(regf);
    1495             :                 uint16_t i;
    1496           0 :                 bool found_offset = false;
    1497             : 
    1498           0 :                 DEBUG(10, ("Subkeys in LI list\n"));
    1499             : 
    1500           0 :                 pull->data = data;
    1501             : 
    1502           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
    1503           0 :                         DEBUG(0, ("Error parsing LI list\n"));
    1504           0 :                         talloc_free(pull);
    1505           0 :                         return WERR_FILE_NOT_FOUND;
    1506             :                 }
    1507           0 :                 talloc_free(pull);
    1508             : 
    1509           0 :                 SMB_ASSERT(!strncmp(li.header, "li", 2));
    1510             : 
    1511           0 :                 for (i = 0; i < li.key_count; i++) {
    1512           0 :                         if (found_offset) {
    1513           0 :                                 li.nk_offset[i-1] = li.nk_offset[i];
    1514             :                         }
    1515           0 :                         if (li.nk_offset[i] == key_offset) {
    1516           0 :                                 found_offset = true;
    1517           0 :                                 continue;
    1518             :                         }
    1519             :                 }
    1520           0 :                 if (!found_offset) {
    1521           0 :                         DEBUG(2, ("Subkey not found\n"));
    1522           0 :                         return WERR_FILE_NOT_FOUND;
    1523             :                 }
    1524           0 :                 li.key_count--;
    1525             : 
    1526             :                 /* If the there are no entries left, free the subkey list */
    1527           0 :                 if (li.key_count == 0) {
    1528           0 :                         hbin_free(regf, list_offset);
    1529           0 :                         *ret = -1;
    1530             :                 }
    1531             : 
    1532             :                 /* Store li block */
    1533           0 :                 *ret = hbin_store_tdr_resize(regf,
    1534             :                                              (tdr_push_fn_t) tdr_push_li_block,
    1535             :                                              list_offset, &li);
    1536           4 :         } else if (strncmp((char *)data.data, "lf", 2) == 0) {
    1537             :                 struct lf_block lf;
    1538           0 :                 struct tdr_pull *pull = tdr_pull_init(regf);
    1539             :                 uint16_t i;
    1540           0 :                 bool found_offset = false;
    1541             : 
    1542           0 :                 DEBUG(10, ("Subkeys in LF list\n"));
    1543             : 
    1544           0 :                 pull->data = data;
    1545             : 
    1546           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
    1547           0 :                         DEBUG(0, ("Error parsing LF list\n"));
    1548           0 :                         talloc_free(pull);
    1549           0 :                         return WERR_FILE_NOT_FOUND;
    1550             :                 }
    1551           0 :                 talloc_free(pull);
    1552             : 
    1553           0 :                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
    1554             : 
    1555           0 :                 for (i = 0; i < lf.key_count; i++) {
    1556           0 :                         if (found_offset) {
    1557           0 :                                 lf.hr[i-1] = lf.hr[i];
    1558           0 :                                 continue;
    1559             :                         }
    1560           0 :                         if (lf.hr[i].nk_offset == key_offset) {
    1561           0 :                                 found_offset = 1;
    1562           0 :                                 continue;
    1563             :                         }
    1564             :                 }
    1565           0 :                 if (!found_offset) {
    1566           0 :                         DEBUG(2, ("Subkey not found\n"));
    1567           0 :                         return WERR_FILE_NOT_FOUND;
    1568             :                 }
    1569           0 :                 lf.key_count--;
    1570             : 
    1571             :                 /* If the there are no entries left, free the subkey list */
    1572           0 :                 if (lf.key_count == 0) {
    1573           0 :                         hbin_free(regf, list_offset);
    1574           0 :                         *ret = -1;
    1575           0 :                         return WERR_OK;
    1576             :                 }
    1577             : 
    1578             :                 /* Store lf block */
    1579           0 :                 *ret = hbin_store_tdr_resize(regf,
    1580             :                                              (tdr_push_fn_t) tdr_push_lf_block,
    1581             :                                              list_offset, &lf);
    1582           4 :         } else if (strncmp((char *)data.data, "lh", 2) == 0) {
    1583             :                 struct lh_block lh;
    1584           4 :                 struct tdr_pull *pull = tdr_pull_init(regf);
    1585             :                 uint16_t i;
    1586           4 :                 bool found_offset = false;
    1587             : 
    1588           4 :                 DEBUG(10, ("Subkeys in LH list\n"));
    1589             : 
    1590           4 :                 pull->data = data;
    1591             : 
    1592           4 :                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
    1593           0 :                         DEBUG(0, ("Error parsing LF list\n"));
    1594           0 :                         talloc_free(pull);
    1595           3 :                         return WERR_FILE_NOT_FOUND;
    1596             :                 }
    1597           4 :                 talloc_free(pull);
    1598             : 
    1599           4 :                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
    1600             : 
    1601           8 :                 for (i = 0; i < lh.key_count; i++) {
    1602           8 :                         if (found_offset) {
    1603           2 :                                 lh.hr[i-1] = lh.hr[i];
    1604           2 :                                 continue;
    1605             :                         }
    1606           6 :                         if (lh.hr[i].nk_offset == key_offset) {
    1607           4 :                                 found_offset = 1;
    1608           4 :                                 continue;
    1609             :                         }
    1610             :                 }
    1611           4 :                 if (!found_offset) {
    1612           0 :                         DEBUG(0, ("Subkey not found\n"));
    1613           0 :                         return WERR_FILE_NOT_FOUND;
    1614             :                 }
    1615           4 :                 lh.key_count--;
    1616             : 
    1617             :                 /* If the there are no entries left, free the subkey list */
    1618           4 :                 if (lh.key_count == 0) {
    1619           3 :                         hbin_free(regf, list_offset);
    1620           3 :                         *ret = -1;
    1621           3 :                         return WERR_OK;
    1622             :                 }
    1623             : 
    1624             :                 /* Store lh block */
    1625           1 :                 *ret = hbin_store_tdr_resize(regf,
    1626             :                                              (tdr_push_fn_t) tdr_push_lh_block,
    1627             :                                              list_offset, &lh);
    1628           0 :         } else if (strncmp((char *)data.data, "ri", 2) == 0) {
    1629             :                 /* FIXME */
    1630           0 :                 DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
    1631           0 :                 return WERR_NOT_SUPPORTED;
    1632             :         } else {
    1633           0 :                 DEBUG (0, ("Unknown header found in subkey list.\n"));
    1634           0 :                 return WERR_FILE_NOT_FOUND;
    1635             :         }
    1636           1 :         return WERR_OK;
    1637             : }
    1638             : 
    1639           3 : static WERROR regf_del_value(TALLOC_CTX *mem_ctx, struct hive_key *key,
    1640             :                              const char *name)
    1641             : {
    1642           3 :         struct regf_key_data *private_data = (struct regf_key_data *)key;
    1643           3 :         struct regf_data *regf = private_data->hive;
    1644           3 :         struct nk_block *nk = private_data->nk;
    1645             :         struct vk_block vk;
    1646             :         uint32_t vk_offset;
    1647           3 :         bool found_offset = false;
    1648             :         DATA_BLOB values;
    1649             :         unsigned int i;
    1650             : 
    1651           3 :         if (nk->values_offset == -1) {
    1652           1 :                 return WERR_FILE_NOT_FOUND;
    1653             :         }
    1654             : 
    1655           2 :         values = hbin_get(regf, nk->values_offset);
    1656             : 
    1657           4 :         for (i = 0; i < nk->num_values; i++) {
    1658           2 :                 if (found_offset) {
    1659           0 :                         ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
    1660             :                 } else {
    1661           2 :                         vk_offset = IVAL(values.data, i * 4);
    1662           2 :                         if (!hbin_get_tdr(regf, vk_offset, private_data,
    1663             :                                           (tdr_pull_fn_t)tdr_pull_vk_block,
    1664             :                                           &vk)) {
    1665           0 :                                 DEBUG(0, ("Unable to get VK block at %d\n",
    1666             :                                         vk_offset));
    1667           0 :                                 return WERR_FILE_NOT_FOUND;
    1668             :                         }
    1669           2 :                         if (strcmp(vk.data_name, name) == 0) {
    1670           2 :                                 hbin_free(regf, vk_offset);
    1671           2 :                                 found_offset = true;
    1672             :                         }
    1673             :                 }
    1674             :         }
    1675           2 :         if (!found_offset) {
    1676           0 :                 return WERR_FILE_NOT_FOUND;
    1677             :         } else {
    1678           2 :                 nk->num_values--;
    1679           2 :                 values.length = (nk->num_values)*4;
    1680             :         }
    1681             : 
    1682             :         /* Store values list and nk */
    1683           2 :         if (nk->num_values == 0) {
    1684           2 :                 hbin_free(regf, nk->values_offset);
    1685           2 :                 nk->values_offset = -1;
    1686             :         } else {
    1687           0 :                 nk->values_offset = hbin_store_resize(regf,
    1688             :                                                       nk->values_offset,
    1689             :                                                       values);
    1690             :         }
    1691           2 :         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
    1692             :                               private_data->offset, nk);
    1693             : 
    1694           2 :         return regf_save_hbin(private_data->hive, 0);
    1695             : }
    1696             : 
    1697             : 
    1698           6 : static WERROR regf_del_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
    1699             :                            const char *name)
    1700             : {
    1701           6 :         const struct regf_key_data *private_data =
    1702             :                 (const struct regf_key_data *)parent;
    1703             :         struct regf_key_data *key;
    1704             :         struct nk_block *parent_nk;
    1705             :         WERROR error;
    1706             : 
    1707           6 :         SMB_ASSERT(private_data);
    1708             : 
    1709           6 :         parent_nk = private_data->nk;
    1710             : 
    1711           6 :         if (parent_nk->subkeys_offset == -1) {
    1712           1 :                 DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
    1713           1 :                 return WERR_FILE_NOT_FOUND;
    1714             :         }
    1715             : 
    1716             :         /* Find the key */
    1717           5 :         if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
    1718             :                                                    (struct hive_key **)&key))) {
    1719           1 :                 DEBUG(2, ("Key '%s' not found\n", name));
    1720           1 :                 return WERR_FILE_NOT_FOUND;
    1721             :         }
    1722             : 
    1723           4 :         if (key->nk->subkeys_offset != -1) {
    1724           1 :                 struct hive_key *sk = (struct hive_key *)key;
    1725           1 :                 unsigned int i = key->nk->num_subkeys;
    1726           3 :                 while (i--) {
    1727             :                         char *sk_name;
    1728           1 :                         const char *p = NULL;
    1729             : 
    1730             :                         /* Get subkey information. */
    1731           1 :                         error = regf_get_subkey_by_index(parent_nk, sk, 0,
    1732             :                                                          &p,
    1733             :                                                          NULL, NULL);
    1734           1 :                         if (!W_ERROR_IS_OK(error)) {
    1735           0 :                                 DEBUG(0, ("Can't retrieve subkey by index.\n"));
    1736           0 :                                 return error;
    1737             :                         }
    1738           1 :                         sk_name = discard_const_p(char, p);
    1739             : 
    1740             :                         /* Delete subkey. */
    1741           1 :                         error = regf_del_key(NULL, sk, sk_name);
    1742           1 :                         if (!W_ERROR_IS_OK(error)) {
    1743           0 :                                 DEBUG(0, ("Can't delete key '%s'.\n", sk_name));
    1744           0 :                                 return error;
    1745             :                         }
    1746             : 
    1747           1 :                         talloc_free(sk_name);
    1748             :                 }
    1749             :         }
    1750             : 
    1751           4 :         if (key->nk->values_offset != -1) {
    1752           1 :                 struct hive_key *sk = (struct hive_key *)key;
    1753             :                 DATA_BLOB data;
    1754           1 :                 unsigned int i = key->nk->num_values;
    1755           3 :                 while (i--) {
    1756             :                         char *val_name;
    1757           1 :                         const char *p = NULL;
    1758             : 
    1759             :                         /* Get value information. */
    1760           1 :                         error = regf_get_value(parent_nk, sk, 0,
    1761             :                                                &p,
    1762             :                                                NULL, &data);
    1763           1 :                         if (!W_ERROR_IS_OK(error)) {
    1764           0 :                                 DEBUG(0, ("Can't retrieve value by index.\n"));
    1765           0 :                                 return error;
    1766             :                         }
    1767           1 :                         val_name = discard_const_p(char, p);
    1768             : 
    1769             :                         /* Delete value. */
    1770           1 :                         error = regf_del_value(NULL, sk, val_name);
    1771           1 :                         if (!W_ERROR_IS_OK(error)) {
    1772           0 :                                 DEBUG(0, ("Can't delete value '%s'.\n", val_name));
    1773           0 :                                 return error;
    1774             :                         }
    1775             : 
    1776           1 :                         talloc_free(val_name);
    1777             :                 }
    1778             :         }
    1779             : 
    1780             :         /* Delete it from the subkey list. */
    1781           8 :         error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset,
    1782           4 :                                   key->offset, &parent_nk->subkeys_offset);
    1783           4 :         if (!W_ERROR_IS_OK(error)) {
    1784           0 :                 DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
    1785           0 :                 return error;
    1786             :         }
    1787             : 
    1788             :         /* Re-store parent key */
    1789           4 :         parent_nk->num_subkeys--;
    1790           4 :         hbin_store_tdr_resize(private_data->hive,
    1791             :                               (tdr_push_fn_t) tdr_push_nk_block,
    1792           0 :                               private_data->offset, parent_nk);
    1793             : 
    1794           4 :         if (key->nk->clsname_offset != -1) {
    1795           0 :                 hbin_free(private_data->hive, key->nk->clsname_offset);
    1796             :         }
    1797           4 :         hbin_free(private_data->hive, key->offset);
    1798             : 
    1799           4 :         return regf_save_hbin(private_data->hive, 0);
    1800             : }
    1801             : 
    1802          10 : static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent,
    1803             :                            const char *name, const char *classname,
    1804             :                            struct security_descriptor *sec_desc,
    1805             :                            struct hive_key **ret)
    1806             : {
    1807          10 :         const struct regf_key_data *private_data =
    1808             :                 (const struct regf_key_data *)parent;
    1809          10 :         struct nk_block *parent_nk = private_data->nk, nk;
    1810             :         struct nk_block *root;
    1811          10 :         struct regf_data *regf = private_data->hive;
    1812             :         uint32_t offset;
    1813             :         WERROR error;
    1814             : 
    1815          10 :         nk.header = "nk";
    1816          10 :         nk.type = REG_SUB_KEY;
    1817          10 :         unix_to_nt_time(&nk.last_change, time(NULL));
    1818          10 :         nk.uk1 = 0;
    1819          10 :         nk.parent_offset = private_data->offset;
    1820          10 :         nk.num_subkeys = 0;
    1821          10 :         nk.uk2 = 0;
    1822          10 :         nk.subkeys_offset = -1;
    1823          10 :         nk.unknown_offset = -1;
    1824          10 :         nk.num_values = 0;
    1825          10 :         nk.values_offset = -1;
    1826          10 :         memset(nk.unk3, 0, sizeof(nk.unk3));
    1827          10 :         nk.clsname_offset = -1; /* FIXME: fill in */
    1828          10 :         nk.clsname_length = 0;
    1829          10 :         nk.key_name = name;
    1830             : 
    1831             :         /* Get the security descriptor of the root key */
    1832          10 :         root = talloc_zero(ctx, struct nk_block);
    1833          10 :         W_ERROR_HAVE_NO_MEMORY(root);
    1834             : 
    1835          10 :         if (!hbin_get_tdr(regf, regf->header->data_offset, root,
    1836             :                           (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
    1837           0 :                 DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n",
    1838             :                         regf->header->data_offset));
    1839           0 :                 return WERR_GEN_FAILURE;
    1840             :         }
    1841          10 :         nk.sk_offset = root->sk_offset;
    1842          10 :         talloc_free(root);
    1843             : 
    1844             :         /* Store the new nk key */
    1845          10 :         offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
    1846             : 
    1847          10 :         error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset,
    1848             :                                   &parent_nk->subkeys_offset);
    1849          10 :         if (!W_ERROR_IS_OK(error)) {
    1850           0 :                 hbin_free(regf, offset);
    1851           0 :                 return error;
    1852             :         }
    1853             : 
    1854          10 :         parent_nk->num_subkeys++;
    1855             : 
    1856             :         /* Since the subkey offset of the parent can change, store it again */
    1857          10 :         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
    1858             :                                                   nk.parent_offset, parent_nk);
    1859             : 
    1860          10 :         *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
    1861             : 
    1862          10 :         DEBUG(9, ("Storing key %s\n", name));
    1863          10 :         return regf_save_hbin(private_data->hive, 0);
    1864             : }
    1865             : 
    1866           6 : static WERROR regf_set_value(struct hive_key *key, const char *name,
    1867             :                              uint32_t type, const DATA_BLOB data)
    1868             : {
    1869           6 :         struct regf_key_data *private_data = (struct regf_key_data *)key;
    1870           6 :         struct regf_data *regf = private_data->hive;
    1871           6 :         struct nk_block *nk = private_data->nk;
    1872             :         struct vk_block vk;
    1873             :         uint32_t i;
    1874           6 :         uint32_t tmp_vk_offset, vk_offset, old_vk_offset = (uint32_t) -1;
    1875           6 :         DATA_BLOB values = {0};
    1876             : 
    1877           6 :         ZERO_STRUCT(vk);
    1878             : 
    1879             :         /* find the value offset, if it exists */
    1880           6 :         if (nk->values_offset != -1) {
    1881           0 :                 values = hbin_get(regf, nk->values_offset);
    1882             : 
    1883           0 :                 for (i = 0; i < nk->num_values; i++) {
    1884           0 :                         tmp_vk_offset = IVAL(values.data, i * 4);
    1885           0 :                         if (!hbin_get_tdr(regf, tmp_vk_offset, private_data,
    1886             :                                           (tdr_pull_fn_t)tdr_pull_vk_block,
    1887             :                                           &vk)) {
    1888           0 :                                 DEBUG(0, ("Unable to get VK block at 0x%x\n",
    1889             :                                         tmp_vk_offset));
    1890           0 :                                 return WERR_GEN_FAILURE;
    1891             :                         }
    1892           0 :                         if (strcmp(vk.data_name, name) == 0) {
    1893           0 :                                 old_vk_offset = tmp_vk_offset;
    1894           0 :                                 break;
    1895             :                         }
    1896             :                 }
    1897             :         }
    1898             : 
    1899             :         /* If it's new, create the vk struct, if it's old, free the old data. */
    1900           0 :         if (old_vk_offset == -1) {
    1901           6 :                 vk.header = "vk";
    1902           6 :                 if (name != NULL && name[0] != '\0') {
    1903           6 :                         vk.flag = 1;
    1904           6 :                         vk.data_name = name;
    1905           6 :                         vk.name_length = strlen(name);
    1906             :                 } else {
    1907           0 :                         vk.flag = 0;
    1908           0 :                         vk.data_name = NULL;
    1909           0 :                         vk.name_length = 0;
    1910             :                 }
    1911             :         } else {
    1912             :                 /* Free data, if any */
    1913           0 :                 if (!(vk.data_length & 0x80000000)) {
    1914           0 :                         hbin_free(regf, vk.data_offset);
    1915             :                 }
    1916             :         }
    1917             : 
    1918             :         /* Set the type and data */
    1919           6 :         vk.data_length = data.length;
    1920           6 :         vk.data_type = type;
    1921           6 :         if ((type == REG_DWORD) || (type == REG_DWORD_BIG_ENDIAN)) {
    1922           6 :                 if (vk.data_length != sizeof(uint32_t)) {
    1923           0 :                         DEBUG(0, ("DWORD or DWORD_BIG_ENDIAN value with size other than 4 byte!\n"));
    1924           0 :                         return WERR_NOT_SUPPORTED;
    1925             :                 }
    1926           6 :                 vk.data_length |= 0x80000000;
    1927           6 :                 vk.data_offset = IVAL(data.data, 0);
    1928             :         } else {
    1929             :                 /* Store data somewhere */
    1930           0 :                 vk.data_offset = hbin_store(regf, data);
    1931             :         }
    1932           6 :         if (old_vk_offset == -1) {
    1933             :                 /* Store new vk */
    1934           6 :                 vk_offset = hbin_store_tdr(regf,
    1935             :                                            (tdr_push_fn_t) tdr_push_vk_block,
    1936             :                                            &vk);
    1937             :         } else {
    1938             :                 /* Store vk at offset */
    1939           0 :                 vk_offset = hbin_store_tdr_resize(regf,
    1940             :                                                   (tdr_push_fn_t) tdr_push_vk_block,
    1941             :                                                   old_vk_offset ,&vk);
    1942             :         }
    1943             : 
    1944             :         /* Re-allocate the value list */
    1945           6 :         if (nk->values_offset == -1) {
    1946           6 :                 nk->values_offset = hbin_store_tdr(regf,
    1947             :                                                    (tdr_push_fn_t) tdr_push_uint32,
    1948             :                                                    &vk_offset);
    1949           6 :                 nk->num_values = 1;
    1950             :         } else {
    1951             : 
    1952             :                 /* Change if we're changing, otherwise we're adding the value */
    1953           0 :                 if (old_vk_offset != -1) {
    1954             :                         /* Find and overwrite the offset. */
    1955           0 :                         for (i = 0; i < nk->num_values; i++) {
    1956           0 :                                 if (IVAL(values.data, i * 4) == old_vk_offset) {
    1957           0 :                                         SIVAL(values.data, i * 4, vk_offset);
    1958           0 :                                         break;
    1959             :                                 }
    1960             :                         }
    1961             :                 } else {
    1962             :                         /* Create a new value list */
    1963             :                         DATA_BLOB value_list;
    1964             : 
    1965           0 :                         value_list.length = (nk->num_values+1)*4;
    1966           0 :                         value_list.data = (uint8_t *)talloc_array(private_data,
    1967             :                                                                   uint32_t,
    1968             :                                                                   nk->num_values+1);
    1969           0 :                         W_ERROR_HAVE_NO_MEMORY(value_list.data);
    1970           0 :                         memcpy(value_list.data, values.data, nk->num_values * 4);
    1971             : 
    1972           0 :                         SIVAL(value_list.data, nk->num_values * 4, vk_offset);
    1973           0 :                         nk->num_values++;
    1974           0 :                         nk->values_offset = hbin_store_resize(regf,
    1975             :                                                               nk->values_offset,
    1976             :                                                               value_list);
    1977             :                 }
    1978             : 
    1979             :         }
    1980           6 :         hbin_store_tdr_resize(regf,
    1981             :                               (tdr_push_fn_t) tdr_push_nk_block,
    1982             :                               private_data->offset, nk);
    1983           6 :         return regf_save_hbin(private_data->hive, 0);
    1984             : }
    1985             : 
    1986          24 : static WERROR regf_save_hbin(struct regf_data *regf, bool flush)
    1987             : {
    1988          24 :         struct tdr_push *push = tdr_push_init(regf);
    1989             :         unsigned int i;
    1990             : 
    1991          24 :         W_ERROR_HAVE_NO_MEMORY(push);
    1992             : 
    1993             :         /* Only write once every 5 seconds, or when flush is set */
    1994          24 :         if (!flush && regf->last_write + 5 >= time(NULL)) {
    1995          22 :                 return WERR_OK;
    1996             :         }
    1997             : 
    1998           2 :         regf->last_write = time(NULL);
    1999             : 
    2000           2 :         if (lseek(regf->fd, 0, SEEK_SET) == -1) {
    2001           0 :                 DEBUG(0, ("Error lseeking in regf file\n"));
    2002           0 :                 return WERR_GEN_FAILURE;
    2003             :         }
    2004             : 
    2005             :         /* Recompute checksum */
    2006           2 :         if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
    2007           0 :                 DEBUG(0, ("Failed to push regf header\n"));
    2008           0 :                 return WERR_GEN_FAILURE;
    2009             :         }
    2010           2 :         regf->header->chksum = regf_hdr_checksum(push->data.data);
    2011           2 :         talloc_free(push);
    2012             : 
    2013           2 :         if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
    2014             :                                             (tdr_push_fn_t)tdr_push_regf_hdr,
    2015             :                                             regf->header))) {
    2016           0 :                 DEBUG(0, ("Error writing registry file header\n"));
    2017           0 :                 return WERR_GEN_FAILURE;
    2018             :         }
    2019             : 
    2020           2 :         if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
    2021           0 :                 DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
    2022           0 :                 return WERR_GEN_FAILURE;
    2023             :         }
    2024             : 
    2025           2 :         for (i = 0; regf->hbins[i]; i++) {
    2026           2 :                 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, 
    2027             :                                                     (tdr_push_fn_t)tdr_push_hbin_block,
    2028             :                                                     regf->hbins[i]))) {
    2029           0 :                         DEBUG(0, ("Error writing HBIN block\n"));
    2030           0 :                         return WERR_GEN_FAILURE;
    2031             :                 }
    2032             :         }
    2033             : 
    2034           2 :         return WERR_OK;
    2035             : }
    2036             : 
    2037           1 : WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, 
    2038             :                             const char *location,
    2039             :                             int minor_version, struct hive_key **key)
    2040             : {
    2041             :         struct regf_data *regf;
    2042             :         struct regf_hdr *regf_hdr;
    2043             :         struct nk_block nk;
    2044             :         struct sk_block sk;
    2045             :         WERROR error;
    2046             :         DATA_BLOB data;
    2047             :         struct security_descriptor *sd;
    2048             :         uint32_t sk_offset;
    2049             : 
    2050           1 :         regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
    2051             : 
    2052           1 :         W_ERROR_HAVE_NO_MEMORY(regf);
    2053             : 
    2054           1 :         DEBUG(5, ("Attempting to create registry file\n"));
    2055             : 
    2056             :         /* Get the header */
    2057           1 :         regf->fd = creat(location, 0644);
    2058             : 
    2059           1 :         if (regf->fd == -1) {
    2060           0 :                 DEBUG(0,("Could not create file: %s, %s\n", location,
    2061             :                                  strerror(errno)));
    2062           0 :                 talloc_free(regf);
    2063           0 :                 return WERR_GEN_FAILURE;
    2064             :         }
    2065             : 
    2066           1 :         regf_hdr = talloc_zero(regf, struct regf_hdr);
    2067           1 :         W_ERROR_HAVE_NO_MEMORY(regf_hdr);
    2068           1 :         regf_hdr->REGF_ID = "regf";
    2069           1 :         unix_to_nt_time(&regf_hdr->modtime, time(NULL));
    2070           1 :         regf_hdr->version.major = 1;
    2071           1 :         regf_hdr->version.minor = minor_version;
    2072           1 :         regf_hdr->last_block = 0x1000; /* Block size */
    2073           1 :         regf_hdr->description = talloc_strdup(regf_hdr,
    2074             :                                               "Registry created by Samba 4");
    2075           1 :         W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
    2076           1 :         regf_hdr->chksum = 0;
    2077             : 
    2078           1 :         regf->header = regf_hdr;
    2079             : 
    2080             :         /* Create all hbin blocks */
    2081           1 :         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
    2082           1 :         W_ERROR_HAVE_NO_MEMORY(regf->hbins);
    2083           1 :         regf->hbins[0] = NULL;
    2084             : 
    2085           1 :         nk.header = "nk";
    2086           1 :         nk.type = REG_ROOT_KEY;
    2087           1 :         unix_to_nt_time(&nk.last_change, time(NULL));
    2088           1 :         nk.uk1 = 0;
    2089           1 :         nk.parent_offset = -1;
    2090           1 :         nk.num_subkeys = 0;
    2091           1 :         nk.uk2 = 0;
    2092           1 :         nk.subkeys_offset = -1;
    2093           1 :         nk.unknown_offset = -1;
    2094           1 :         nk.num_values = 0;
    2095           1 :         nk.values_offset = -1;
    2096           1 :         memset(nk.unk3, 0, 5 * sizeof(uint32_t));
    2097           1 :         nk.clsname_offset = -1;
    2098           1 :         nk.clsname_length = 0;
    2099           1 :         nk.sk_offset = 0x80;
    2100           1 :         nk.key_name = "SambaRootKey";
    2101             : 
    2102             :         /*
    2103             :          * It should be noted that changing the key_name to something shorter
    2104             :          * creates a shorter nk block, which makes the position of the sk block
    2105             :          * change. All Windows registries I've seen have the sk at 0x80. 
    2106             :          * I therefore recommend that our regf files share that offset -- Wilco
    2107             :          */
    2108             : 
    2109             :         /* Create a security descriptor. */
    2110           1 :         sd = security_descriptor_dacl_create(regf,
    2111             :                                          0,
    2112             :                                          NULL, NULL,
    2113             :                                          SID_NT_AUTHENTICATED_USERS,
    2114             :                                          SEC_ACE_TYPE_ACCESS_ALLOWED,
    2115             :                                          SEC_GENERIC_ALL,
    2116             :                                          SEC_ACE_FLAG_OBJECT_INHERIT,
    2117             :                                          NULL);
    2118             :         
    2119             :         /* Push the security descriptor to a blob */
    2120           1 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf, 
    2121             :                                      sd, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
    2122           0 :                 DEBUG(0, ("Unable to push security descriptor\n"));
    2123           0 :                 return WERR_GEN_FAILURE;
    2124             :         }
    2125             : 
    2126           1 :         ZERO_STRUCT(sk);
    2127           1 :         sk.header = "sk";
    2128           1 :         sk.prev_offset = 0x80;
    2129           1 :         sk.next_offset = 0x80;
    2130           1 :         sk.ref_cnt = 1;
    2131           1 :         sk.rec_size = data.length;
    2132           1 :         sk.sec_desc = data.data;
    2133             : 
    2134             :         /* Store the new nk key */
    2135           1 :         regf->header->data_offset = hbin_store_tdr(regf,
    2136             :                                                    (tdr_push_fn_t)tdr_push_nk_block,
    2137             :                                                    &nk);
    2138             :         /* Store the sk block */
    2139           1 :         sk_offset = hbin_store_tdr(regf,
    2140             :                                    (tdr_push_fn_t) tdr_push_sk_block,
    2141             :                                    &sk);
    2142           1 :         if (sk_offset != 0x80) {
    2143           0 :                 DEBUG(0, ("Error storing sk block, should be at 0x80, stored at 0x%x\n", nk.sk_offset));
    2144           0 :                 return WERR_GEN_FAILURE;
    2145             :         }
    2146             : 
    2147             : 
    2148           1 :         *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
    2149           1 :                                                regf->header->data_offset);
    2150             : 
    2151           1 :         error = regf_save_hbin(regf, 1);
    2152           1 :         if (!W_ERROR_IS_OK(error)) {
    2153           0 :                 return error;
    2154             :         }
    2155             :         
    2156             :         /* We can drop our own reference now that *key will have created one */
    2157           1 :         talloc_unlink(NULL, regf);
    2158             : 
    2159           1 :         return WERR_OK;
    2160             : }
    2161             : 
    2162           1 : static WERROR regf_flush_key(struct hive_key *key)
    2163             : {
    2164           1 :         struct regf_key_data *private_data = (struct regf_key_data *)key;
    2165           1 :         struct regf_data *regf = private_data->hive;
    2166             :         WERROR error;
    2167             : 
    2168           1 :         error = regf_save_hbin(regf, 1);
    2169           1 :         if (!W_ERROR_IS_OK(error)) {
    2170           0 :                 DEBUG(0, ("Failed to flush regf to disk\n"));
    2171           0 :                 return error;
    2172             :         }
    2173             : 
    2174           1 :         return WERR_OK;
    2175             : }
    2176             : 
    2177           0 : static int regf_destruct(struct regf_data *regf)
    2178             : {
    2179             :         WERROR error;
    2180             : 
    2181             :         /* Write to disk */
    2182           0 :         error = regf_save_hbin(regf, 1);
    2183           0 :         if (!W_ERROR_IS_OK(error)) {
    2184           0 :                 DEBUG(0, ("Failed to flush registry to disk\n"));
    2185           0 :                 return -1;
    2186             :         }
    2187             : 
    2188             :         /* Close file descriptor */
    2189           0 :         close(regf->fd);
    2190             : 
    2191           0 :         return 0;
    2192             : }
    2193             : 
    2194           0 : WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, const char *location, 
    2195             :                           struct hive_key **key)
    2196             : {
    2197             :         struct regf_data *regf;
    2198             :         struct regf_hdr *regf_hdr;
    2199             :         struct tdr_pull *pull;
    2200             :         unsigned int i;
    2201             : 
    2202           0 :         regf = (struct regf_data *)talloc_zero(parent_ctx, struct regf_data);
    2203           0 :         W_ERROR_HAVE_NO_MEMORY(regf);
    2204             : 
    2205           0 :         talloc_set_destructor(regf, regf_destruct);
    2206             : 
    2207           0 :         DEBUG(5, ("Attempting to load registry file\n"));
    2208             : 
    2209             :         /* Get the header */
    2210           0 :         regf->fd = open(location, O_RDWR);
    2211             : 
    2212           0 :         if (regf->fd == -1) {
    2213           0 :                 DEBUG(0,("Could not load file: %s, %s\n", location,
    2214             :                                  strerror(errno)));
    2215           0 :                 talloc_free(regf);
    2216           0 :                 return WERR_GEN_FAILURE;
    2217             :         }
    2218             : 
    2219           0 :         pull = tdr_pull_init(regf);
    2220             : 
    2221           0 :         pull->data.data = (uint8_t*)fd_load(regf->fd, &pull->data.length, 0, regf);
    2222             : 
    2223           0 :         if (pull->data.data == NULL) {
    2224           0 :                 DEBUG(0, ("Error reading data from file: %s\n", location));
    2225           0 :                 talloc_free(regf);
    2226           0 :                 return WERR_GEN_FAILURE;
    2227             :         }
    2228             : 
    2229           0 :         regf_hdr = talloc(regf, struct regf_hdr);
    2230           0 :         W_ERROR_HAVE_NO_MEMORY(regf_hdr);
    2231             : 
    2232           0 :         if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr, regf_hdr))) {
    2233           0 :                 DEBUG(0, ("Failed to pull regf header from file: %s\n", location));
    2234           0 :                 talloc_free(regf);
    2235           0 :                 return WERR_GEN_FAILURE;
    2236             :         }
    2237             : 
    2238           0 :         regf->header = regf_hdr;
    2239             : 
    2240           0 :         if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
    2241           0 :                 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
    2242             :                         regf_hdr->REGF_ID, location));
    2243           0 :                 talloc_free(regf);
    2244           0 :                 return WERR_GEN_FAILURE;
    2245             :         }
    2246             : 
    2247             :         /* Validate the header ... */
    2248           0 :         if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) {
    2249           0 :                 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
    2250             :                         location, regf_hdr->chksum,
    2251             :                         regf_hdr_checksum(pull->data.data)));
    2252           0 :                 talloc_free(regf);
    2253           0 :                 return WERR_GEN_FAILURE;
    2254             :         }
    2255             : 
    2256           0 :         pull->offset = 0x1000;
    2257             : 
    2258           0 :         i = 0;
    2259             :         /* Read in all hbin blocks */
    2260           0 :         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
    2261           0 :         W_ERROR_HAVE_NO_MEMORY(regf->hbins);
    2262             : 
    2263           0 :         regf->hbins[0] = NULL;
    2264             : 
    2265           0 :         while (pull->offset < pull->data.length &&
    2266           0 :                pull->offset <= regf->header->last_block) {
    2267           0 :                 struct hbin_block *hbin = talloc(regf->hbins,
    2268             :                                                  struct hbin_block);
    2269             : 
    2270           0 :                 W_ERROR_HAVE_NO_MEMORY(hbin);
    2271             : 
    2272           0 :                 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin, hbin))) {
    2273           0 :                         DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
    2274           0 :                         talloc_free(regf);
    2275           0 :                         return WERR_FOOBAR;
    2276             :                 }
    2277             : 
    2278           0 :                 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
    2279           0 :                         DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n",
    2280             :                                 i, hbin->HBIN_ID));
    2281           0 :                         talloc_free(regf);
    2282           0 :                         return WERR_FOOBAR;
    2283             :                 }
    2284             : 
    2285           0 :                 regf->hbins[i] = hbin;
    2286           0 :                 i++;
    2287           0 :                 regf->hbins = talloc_realloc(regf, regf->hbins,
    2288             :                                              struct hbin_block *, i+2);
    2289           0 :                 regf->hbins[i] = NULL;
    2290             :         }
    2291             : 
    2292           0 :         talloc_free(pull);
    2293             : 
    2294           0 :         DEBUG(1, ("%d HBIN blocks read\n", i));
    2295             : 
    2296           0 :         *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
    2297           0 :                                                regf->header->data_offset);
    2298             : 
    2299             :         /* We can drop our own reference now that *key will have created one */
    2300           0 :         talloc_unlink(parent_ctx, regf);
    2301             : 
    2302           0 :         return WERR_OK;
    2303             : }
    2304             : 
    2305             : static struct hive_operations reg_backend_regf = {
    2306             :         .name = "regf",
    2307             :         .get_key_info = regf_get_info,
    2308             :         .enum_key = regf_get_subkey_by_index,
    2309             :         .get_key_by_name = regf_get_subkey_by_name,
    2310             :         .get_value_by_name = regf_get_value_by_name,
    2311             :         .enum_value = regf_get_value,
    2312             :         .get_sec_desc = regf_get_sec_desc,
    2313             :         .set_sec_desc = regf_set_sec_desc,
    2314             :         .add_key = regf_add_key,
    2315             :         .set_value = regf_set_value,
    2316             :         .del_key = regf_del_key,
    2317             :         .delete_value = regf_del_value,
    2318             :         .flush_key = regf_flush_key
    2319             : };

Generated by: LCOV version 1.13