root/source4/lib/registry/regf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hbin_by_offset
  2. regf_hdr_checksum
  3. hbin_get
  4. hbin_get_tdr
  5. hbin_alloc
  6. hbin_store
  7. hbin_store_tdr
  8. hbin_free
  9. hbin_store_resize
  10. hbin_store_tdr_resize
  11. regf_create_lh_hash
  12. regf_get_info
  13. regf_get_key
  14. regf_get_value
  15. regf_get_value_by_name
  16. regf_get_subkey_by_index
  17. regf_match_subkey_by_name
  18. regf_get_subkey_by_name
  19. regf_set_sec_desc
  20. regf_get_sec_desc
  21. regf_sl_add_entry
  22. regf_sl_del_entry
  23. regf_del_value
  24. regf_del_key
  25. regf_add_key
  26. regf_set_value
  27. regf_save_hbin
  28. reg_create_regf_file
  29. reg_open_regf_file

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

/* [<][>][^][v][top][bottom][index][help] */