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

Generated by: LCOV version 1.14