r24665: Close file handles properly.
[sfrench/samba-autobuild/.git] / source4 / lib / registry / reg_backend_nt4.c
1 /*
2    Samba CIFS implementation
3    Registry backend for REGF files
4    Copyright (C) 2005 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 "lib/registry/registry.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "lib/registry/tdr_regf.h"
25 #include "librpc/gen_ndr/ndr_security.h"
26
27 /* TODO:
28  *  - Return error codes that make more sense
29  *  - Locking
30  */
31
32 /*
33  * Read HBIN blocks into memory
34  */
35
36 struct regf_data {
37         int fd;
38         struct hbin_block **hbins;
39         struct regf_hdr *header;
40 };
41
42 static struct hbin_block *hbin_by_offset (const struct regf_data *data, uint32_t offset, uint32_t *rel_offset)
43 {
44         int i;
45
46         for (i = 0; data->hbins[i]; i++) {
47                 if (offset >= data->hbins[i]->offset_from_first && 
48                         offset < data->hbins[i]->offset_from_first+
49                                          data->hbins[i]->offset_to_next) {
50                         if (rel_offset)
51                                 *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
52                         return data->hbins[i];
53                 }
54         }
55
56         return NULL;
57 }
58
59 /*
60  * Validate a regf header
61  * For now, do nothing, but we should check the checksum
62  */
63 static uint32_t regf_hdr_checksum(const uint8_t *buffer)
64 {
65         uint32_t checksum = 0, x;
66         int i;
67         
68         for (i = 0; i < 0x01FB; i+= 4) {
69                 x = IVAL(buffer, i);
70                 checksum ^= x;
71         }
72
73         return checksum;
74 }
75
76 static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
77 {
78         DATA_BLOB ret;
79         struct hbin_block *hbin;
80         uint32_t rel_offset;
81         ret.data = NULL;
82         ret.length = 0;
83
84         hbin = hbin_by_offset(data, offset, &rel_offset);
85
86         if (hbin == NULL) {
87                 DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));
88                 return ret;
89         }
90
91         ret.length = IVAL(hbin->data, rel_offset);
92         if (!(ret.length & 0x80000000)) {
93                 DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
94                 return ret;
95         }
96
97         /* remove high bit */
98         ret.length = (ret.length ^ 0xffffffff) + 1;
99
100         ret.length -= 4; /* 4 bytes for the length... */
101         ret.data = hbin->data + 
102                 (offset - hbin->offset_from_first - 0x20) + 4;
103         
104         return ret;
105 }
106
107 static BOOL hbin_get_tdr (struct regf_data *regf, uint32_t offset, TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
108 {
109         struct tdr_pull pull;
110
111         ZERO_STRUCT(pull);
112
113         pull.data = hbin_get(regf, offset);
114         if (!pull.data.data) {
115                 DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
116                 return False;
117         }
118         
119         if (NT_STATUS_IS_ERR(pull_fn(&pull, ctx, p))) {
120                 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
121                 return False;
122         }
123
124         return True;
125 }
126
127 /* Allocate some new data */
128 static DATA_BLOB hbin_alloc (struct regf_data *data, uint32_t size, uint32_t *offset)
129 {
130         DATA_BLOB ret;
131         uint32_t rel_offset = -1; /* Relative offset ! */
132         struct hbin_block *hbin = NULL;
133         int i;
134
135         *offset = 0;
136
137         if (size == 0)
138                 return data_blob(NULL, 0);
139
140         size += 4; /* Need to include uint32 for the length */
141
142         /* Allocate as a multiple of 8 */
143         size = (size + 7) & ~7;
144
145         ret.data = NULL;
146         ret.length = 0;
147
148         for (i = 0; (hbin = data->hbins[i]); i++) {
149                 int j;
150                 uint32_t my_size;
151                 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
152                         uint32_t header = IVAL(hbin->data, j + 4);
153                         my_size = IVAL(hbin->data, j);
154
155                         if (my_size == 0x0) {
156                                 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
157                                 return ret;
158                         }
159
160                         if (my_size % 8 != 0) {
161                                 DEBUG(0, ("Encountered non-aligned block!\n"));
162                         }
163
164                         if (my_size & 0x80000000) { /* Used... */
165                                 my_size = (my_size ^ 0xffffffff) + 1;
166                         } else if (my_size == size) { /* exact match */
167                                 rel_offset = j;
168                                 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", size));
169                                 break;
170                         } else if (my_size > size) { /* data will remain */
171                                 rel_offset = j;
172                                 SIVAL(hbin->data, rel_offset+size, my_size-size); 
173                                 DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", my_size, size));
174                                 break;
175                         }
176
177                         if (header == 0xffffffff &&
178                                 hbin->offset_to_next-rel_offset >= size)  {
179                                 rel_offset = j;
180
181                                 DEBUG(4, ("Found free block of size %d at end of HBIN\n", size));
182                                 /* Mark new free block size */
183                                 SIVAL(hbin->data, rel_offset+size,hbin->offset_to_next - rel_offset - size - 0x20);
184                                 SIVAL(hbin->data, rel_offset+size+0x4, 0xffffffff);
185                                 break;
186                         }
187
188                         if (header == 0xffffffff)  {
189                                 break;
190                         }
191                 }
192
193                 if (rel_offset != -1)
194                         break;
195         }
196         
197         /* No space available in previous hbins, 
198          * allocate new one */
199         if (data->hbins[i] == NULL) { 
200                 DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size));
201                 data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
202                 hbin = talloc(data->hbins, struct hbin_block);
203                 data->hbins[i] = hbin;
204                 data->hbins[i+1] = NULL;
205
206                 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
207                 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
208                 hbin->offset_to_next = 0x1000;
209                 hbin->unknown[0] = 0;
210                 hbin->unknown[0] = 0;
211                 unix_to_nt_time(&hbin->last_change, time(NULL));
212                 hbin->block_size = hbin->offset_to_next;
213                 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
214
215                 rel_offset = 0x0;
216                 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
217                 SIVAL(hbin->data, size + 0x4, 0xffffffff);
218         }
219
220         /* Set size and mark as used */
221         SIVAL(hbin->data, rel_offset, size | 0x80000000);
222
223         ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
224         ret.length = size - 0x4;
225         if (offset) {
226                 uint32_t new_rel_offset;
227                 *offset = hbin->offset_from_first + rel_offset + 0x20;
228                 SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
229                 SMB_ASSERT(new_rel_offset == rel_offset);
230         }
231
232         return ret;
233 }
234
235 /* Store a data blob. Return the offset at which it was stored */
236 static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
237 {
238         uint32_t ret;
239         DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
240
241         memcpy(dest.data, blob.data, blob.length);
242
243         return ret;
244 }
245
246 static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
247 {
248         struct tdr_push *push = talloc_zero(data, struct tdr_push);
249         uint32_t ret;
250         
251         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
252                 DEBUG(0, ("Error during push\n"));
253                 return -1;
254         }
255
256         ret = hbin_store(data, push->data);
257
258         talloc_free(push);
259
260         return ret;
261 }
262
263
264 /* Free existing data */
265 static void hbin_free (struct regf_data *data, uint32_t offset)
266 {
267         uint32_t size;
268         uint32_t rel_offset;
269         struct hbin_block *hbin;
270
271         SMB_ASSERT (offset > 0);
272         
273         hbin = hbin_by_offset(data, offset, &rel_offset);
274
275         if (hbin == NULL)
276                 return;
277         
278         /* Get original size */
279         size = IVAL(hbin->data, rel_offset);
280
281         if (!(size & 0x80000000)) {
282                 DEBUG(1, ("Trying to free already freed block at 0x%04x\n", offset));
283                 return;
284         }
285
286         /* Mark block as free */
287         SIVAL(hbin->data, rel_offset, size &~ 0x80000000);
288 }
289
290 /* Store a data blob data was already stored, but hsa changed in size
291  * Will try to save it at the current location if possible, otherwise 
292  * does a free + store */
293 static uint32_t hbin_store_resize (struct regf_data *data, uint32_t orig_offset, DATA_BLOB blob)
294 {
295         uint32_t rel_offset;
296         struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
297         uint32_t my_size;
298         uint32_t orig_size;
299         uint32_t needed_size;
300         uint32_t possible_size;
301         int i;
302
303         SMB_ASSERT(orig_offset > 0);
304
305         if (!hbin)
306                 return hbin_store(data, blob);
307
308         /* Get original size */
309         orig_size = IVAL(hbin->data, rel_offset);
310
311         needed_size = blob.length + 4; /* Add uint32 containing length */
312         needed_size = (needed_size + 7) & ~7; /* Align */
313
314         /* Fits into current allocated block */
315         if (orig_size >= needed_size) {
316                 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
317                 return orig_offset;
318         }
319
320         possible_size = orig_size;
321
322         /* Check if it can be combined with the next few free records */
323         for (i = rel_offset; 
324                  i < hbin->offset_to_next - 0x20; 
325                  i += my_size) {
326                 uint32_t header;
327                 if (IVAL(hbin->data, i) & 0x80000000) /* Used */
328                         break;
329
330                 my_size = IVAL(hbin->data, i);
331                 header = IVAL(hbin->data, i + 4);
332                 if (header == 0xffffffff) {
333                         possible_size = hbin->offset_to_next - 0x20 - rel_offset;
334                 } else if (my_size == 0x0) {
335                         DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
336                         break;
337                 } else {
338                         possible_size += my_size;
339                 }
340
341                 if (possible_size >= blob.length) {
342                         SIVAL(hbin->data, rel_offset, possible_size);
343                         memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
344                         return orig_offset;
345                 }
346
347                 if (header == 0xffffffff) 
348                         break;
349         }
350
351         hbin_free(data, orig_offset);
352         return hbin_store(data, blob);
353 }
354
355 static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn, uint32_t orig_offset, void *p)
356 {
357         struct tdr_push *push = talloc_zero(regf, struct tdr_push);
358         uint32_t ret;
359         
360         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
361                 DEBUG(0, ("Error during push\n"));
362                 return -1;
363         }
364
365         ret = hbin_store_resize(regf, orig_offset, push->data);
366
367         talloc_free(push);
368
369         return ret;
370 }
371
372 static WERROR regf_num_subkeys (const struct registry_key *key, uint32_t *count)
373 {
374         struct nk_block *nk = key->backend_data;
375
376         *count = nk->num_subkeys;
377         
378         return WERR_OK;
379 }
380
381 static WERROR regf_num_values (const struct registry_key *key, uint32_t *count)
382 {
383         struct nk_block *nk = key->backend_data;
384
385         *count = nk->num_values;
386
387         return WERR_OK;
388 }
389
390 static struct registry_key *regf_get_key (TALLOC_CTX *ctx, struct regf_data *regf, uint32_t offset)
391 {
392         struct registry_key *ret;
393         struct nk_block *nk;
394
395         ret = talloc_zero(ctx, struct registry_key);
396         nk = talloc(ret, struct nk_block);
397         if (!hbin_get_tdr(regf, offset, nk, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
398                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
399                 return NULL;
400         }
401
402         if (strcmp(nk->header, "nk") != 0) {
403                 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
404                 talloc_free(ret);
405                 return NULL;
406         }
407
408         ret->name = talloc_steal(ret, nk->key_name);
409         ret->last_mod = nk->last_change;
410
411         if (nk->clsname_offset != -1) {
412                 DATA_BLOB data = hbin_get(regf, nk->clsname_offset);
413                 ret->class_name = talloc_strndup(ret, (char*)data.data, nk->clsname_length);
414         }
415         ret->backend_data = nk;
416
417         return ret;
418 }
419
420 static WERROR regf_get_value (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_value **ret)
421 {
422         struct nk_block *nk = key->backend_data;
423         struct vk_block *vk;
424         struct regf_data *regf = key->hive->backend_data;
425         uint32_t vk_offset;
426         DATA_BLOB data;
427
428         if (idx >= nk->num_values)
429                 return WERR_NO_MORE_ITEMS;
430
431         data = hbin_get(regf, nk->values_offset);
432         if (!data.data) {
433                 DEBUG(0, ("Unable to find value list\n"));
434                 return WERR_GENERAL_FAILURE;
435         }
436
437         if (data.length < nk->num_values * 4) {
438                 DEBUG(1, ("Value counts mismatch\n"));
439         }
440
441         vk_offset = IVAL(data.data, idx * 4);
442
443         *ret = talloc_zero(ctx, struct registry_value);
444         if (!(*ret)) 
445                 return WERR_NOMEM;
446
447         vk = talloc(*ret, struct vk_block);
448         if (!vk)
449                 return WERR_NOMEM;
450         
451         if (!hbin_get_tdr(regf, vk_offset, vk, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
452                 DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
453                 return WERR_GENERAL_FAILURE;
454         }
455
456         (*ret)->name = talloc_steal(*ret, vk->data_name);
457         (*ret)->data_type = vk->data_type;
458         if (vk->data_length & 0x80000000) { 
459                 vk->data_length &=~0x80000000;
460                 (*ret)->data.data = (uint8_t *)&vk->data_offset;
461                 (*ret)->data.length = vk->data_length;
462         } else {
463                 (*ret)->data = hbin_get(regf, vk->data_offset);
464         }
465
466         if ((*ret)->data.length < vk->data_length) {
467                 DEBUG(1, ("Read data less than indicated data length!\n"));
468         }
469         
470         return WERR_OK;
471 }
472
473 static WERROR regf_get_subkey_by_index (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_key **ret)
474 {
475         DATA_BLOB data;
476         struct nk_block *nk = key->backend_data;
477         uint32_t key_off=0;
478
479         if (idx >= nk->num_subkeys)
480                 return WERR_NO_MORE_ITEMS;
481
482         data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
483         if (!data.data) {
484                 DEBUG(0, ("Unable to find subkey list\n"));
485                 return WERR_GENERAL_FAILURE;
486         }
487
488         if (!strncmp((char *)data.data, "li", 2)) {
489                 struct li_block li;
490                 struct tdr_pull pull;
491
492                 DEBUG(10, ("Subkeys in LI list\n"));
493                 ZERO_STRUCT(pull);
494                 pull.data = data;
495
496                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
497                         DEBUG(0, ("Error parsing LI list\n"));
498                         return WERR_GENERAL_FAILURE;
499                 }
500                 SMB_ASSERT(!strncmp(li.header, "li",2));
501
502                 if (li.key_count != nk->num_subkeys) {
503                         DEBUG(0, ("Subkey counts don't match\n"));
504                         return WERR_GENERAL_FAILURE;
505                 }
506                 key_off = li.nk_offset[idx];
507         
508         } else if (!strncmp((char *)data.data, "lf", 2)) {
509                 struct lf_block lf;
510                 struct tdr_pull pull;
511
512                 DEBUG(10, ("Subkeys in LF list\n"));
513                 ZERO_STRUCT(pull);
514                 pull.data = data;
515
516                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
517                         DEBUG(0, ("Error parsing LF list\n"));
518                         return WERR_GENERAL_FAILURE;
519                 }
520                 SMB_ASSERT(!strncmp(lf.header, "lf",2));
521
522                 if (lf.key_count != nk->num_subkeys) {
523                         DEBUG(0, ("Subkey counts don't match\n"));
524                         return WERR_GENERAL_FAILURE;
525                 }
526
527                 key_off = lf.hr[idx].nk_offset;
528         } else if (!strncmp((char *)data.data, "lh", 2)) {
529                 struct lh_block lh;
530                 struct tdr_pull pull;
531                 
532                 DEBUG(10, ("Subkeys in LH list"));
533                 ZERO_STRUCT(pull);
534                 pull.data = data;
535                 
536                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
537                         DEBUG(0, ("Error parsing LH list\n"));
538                         return WERR_GENERAL_FAILURE;
539                 }
540                 SMB_ASSERT(!strncmp(lh.header, "lh",2));
541                 
542                 if (lh.key_count != nk->num_subkeys) {
543                         DEBUG(0, ("Subkey counts don't match\n"));
544                         return WERR_GENERAL_FAILURE;
545                 }
546                 key_off = lh.hr[idx].nk_offset;
547         } else if (!strncmp((char *)data.data, "ri", 2)) {
548                 struct ri_block ri;
549                 struct tdr_pull pull;
550                 uint16_t i;
551                 uint16_t sublist_count = 0;
552                 
553                 ZERO_STRUCT(pull);
554                 pull.data = data;
555                 
556                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
557                         DEBUG(0, ("Error parsing RI list\n"));
558                         return WERR_GENERAL_FAILURE;
559                 }
560                 SMB_ASSERT(!strncmp(ri.header, "ri",2));
561                 
562                 for (i = 0; i < ri.key_count; i++) {
563                         DATA_BLOB list_data;
564                         
565                         /* Get sublist data blob */
566                         list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
567                         if (!list_data.data) {
568                                 DEBUG(0, ("Error getting RI list."));
569                                 return WERR_GENERAL_FAILURE;
570                         }
571                         
572                         ZERO_STRUCT(pull);
573                         pull.data = list_data;
574                         
575                         if (!strncmp((char *)list_data.data, "li", 2)) {
576                                 struct li_block li;
577
578                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
579                                         DEBUG(0, ("Error parsing LI list from RI\n"));
580                                         return WERR_GENERAL_FAILURE;
581                                 }
582                                 SMB_ASSERT(!strncmp(li.header, "li",2));
583                                 
584                                 /* Advance to next sublist if necessary */
585                                 if (idx >= sublist_count + li.key_count) {
586                                         sublist_count += li.key_count;
587                                         continue;
588                                 }
589                                 key_off = li.nk_offset[idx - sublist_count];
590                                 sublist_count += li.key_count;
591                                 break;
592                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
593                                 struct lh_block lh;
594                                 
595                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
596                                         DEBUG(0, ("Error parsing LH list from RI\n"));
597                                         return WERR_GENERAL_FAILURE;
598                                 }
599                                 SMB_ASSERT(!strncmp(lh.header, "lh",2));
600
601                                 
602                                 /* Advance to next sublist if necessary */
603                                 if (idx >= sublist_count + lh.key_count) {
604                                         sublist_count += lh.key_count;
605                                         continue;
606                                 }
607                                 key_off = lh.hr[idx - sublist_count].nk_offset;
608                                 sublist_count += lh.key_count;
609                                 break;
610                         } else {
611                                 DEBUG(0,("Unknown sublist in ri block\n"));
612                                 SMB_ASSERT(0);
613                         }
614                         
615                 }
616         
617                 if (idx > sublist_count) {
618                         return WERR_NO_MORE_ITEMS;
619                 }
620
621         } else {
622                 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1]));
623                 return WERR_GENERAL_FAILURE;
624         }
625
626         *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
627
628         return WERR_OK;
629 }
630
631 static WERROR regf_match_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, uint32_t offset, const char *name, uint32_t *ret) 
632 {
633         DATA_BLOB subkey_data;
634         struct nk_block subkey;
635         struct tdr_pull pull;
636         
637         subkey_data = hbin_get(key->hive->backend_data, offset);
638         if (!subkey_data.data) {
639                 DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
640                 return WERR_GENERAL_FAILURE;
641         }
642
643         ZERO_STRUCT(pull);
644         pull.data = subkey_data;
645         
646         if (NT_STATUS_IS_ERR(tdr_pull_nk_block(&pull, ctx, &subkey))) {
647                 DEBUG(0, ("Error parsing NK structure.\n"));
648                 return WERR_GENERAL_FAILURE;
649         }
650         if (strncmp(subkey.header, "nk", 2)) {
651                 DEBUG(0, ("Not an NK structure.\n"));
652                 return WERR_GENERAL_FAILURE;
653         }
654         if (!strcasecmp(subkey.key_name, name)) {
655                 *ret = offset;
656         } else {
657                 *ret = 0;
658         }
659         return WERR_OK;
660 }
661         
662 static WERROR regf_get_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, const char *name, struct registry_key **ret)
663 {
664         DATA_BLOB data;
665         struct nk_block *nk = key->backend_data;
666         uint32_t key_off = 0;
667
668         data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
669         if (!data.data) {
670                 DEBUG(0, ("Unable to find subkey list\n"));
671                 return WERR_GENERAL_FAILURE;
672         }
673
674         if (!strncmp((char *)data.data, "li",2)) {
675                 struct li_block li;
676                 struct tdr_pull pull;
677                 uint16_t i;
678
679                 DEBUG(10, ("Subkeys in LI list\n"));
680                 ZERO_STRUCT(pull);
681                 pull.data = data;
682                 
683                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
684                         DEBUG(0, ("Error parsing LI list\n"));
685                         return WERR_GENERAL_FAILURE;
686                 }
687                 SMB_ASSERT(!strncmp(li.header, "li",2));
688
689                 if (li.key_count != nk->num_subkeys) {
690                         DEBUG(0, ("Subkey counts don't match\n"));
691                         return WERR_GENERAL_FAILURE;
692                 }
693                 
694                 for (i = 0; i < li.key_count; i++) {
695                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, li.nk_offset[i], name, &key_off));
696                         if (key_off) {
697                                 break;
698                         }
699                 }
700                 if (!key_off) {
701                         return WERR_DEST_NOT_FOUND;
702                 }
703         } else if (!strncmp((char *)data.data, "lf",2)) {
704                 struct lf_block lf;
705                 struct tdr_pull pull;
706                 uint16_t i;
707
708                 DEBUG(10, ("Subkeys in LF list\n"));
709                 ZERO_STRUCT(pull);
710                 pull.data = data;
711                 
712                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
713                         DEBUG(0, ("Error parsing LF list\n"));
714                         return WERR_GENERAL_FAILURE;
715                 }
716                 SMB_ASSERT(!strncmp(lf.header, "lf",2));
717
718                 if (lf.key_count != nk->num_subkeys) {
719                         DEBUG(0, ("Subkey counts don't match\n"));
720                         return WERR_GENERAL_FAILURE;
721                 }
722                 
723                 for (i = 0; i < lf.key_count; i++) {
724                         if (strncmp(lf.hr[i].hash, name, 4)) {
725                                 continue;
726                         }
727                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lf.hr[i].nk_offset, name, &key_off));
728                         if (key_off) {
729                                 break;
730                         }
731                 }
732                 if (!key_off) {
733                         return WERR_DEST_NOT_FOUND;
734                 }
735         } else if (!strncmp((char *)data.data, "lh",2)) {
736                 struct lh_block lh;
737                 struct tdr_pull pull;
738                 uint16_t i;
739                 uint32_t hash = 0;
740                 char *hash_name;
741
742                 DEBUG(10, ("Subkeys in LH list\n"));
743                 ZERO_STRUCT(pull);
744                 pull.data = data;
745                 
746                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
747                         DEBUG(0, ("Error parsing LH list\n"));
748                         return WERR_GENERAL_FAILURE;
749                 }
750                 SMB_ASSERT(!strncmp(lh.header, "lh",2));
751
752                 if (lh.key_count != nk->num_subkeys) {
753                         DEBUG(0, ("Subkey counts don't match\n"));
754                         return WERR_GENERAL_FAILURE;
755                 }
756                 
757                 /* Compute hash for the name */
758                 hash_name = strupper_talloc(nk, name);          
759                 for (i = 0; *(hash_name + i) != 0; i++) {
760                         hash *= 37;
761                         hash += *(hash_name + i);
762                 }
763                 for (i = 0; i < lh.key_count; i++) {
764                         if (lh.hr[i].base37 != hash) {
765                                 continue;
766                         }
767                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lh.hr[i].nk_offset, name, &key_off));
768                         if (key_off) {
769                                 break;
770                         }
771                 }       
772                 if (!key_off) {
773                         return WERR_DEST_NOT_FOUND;
774                 }
775         } else if (!strncmp((char *)data.data, "ri", 2)) {
776                 struct ri_block ri;
777                 struct tdr_pull pull;
778                 uint16_t i, j;
779
780                 DEBUG(10, ("Subkeys in RI list\n"));
781                 ZERO_STRUCT(pull);
782                 pull.data = data;
783                 
784                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
785                         DEBUG(0, ("Error parsing RI list\n"));
786                         return WERR_GENERAL_FAILURE;
787                 }
788                 SMB_ASSERT(!strncmp(ri.header, "ri",2));
789
790                         
791                 for (i = 0; i < ri.key_count; i++) {
792                         DATA_BLOB list_data;
793                         
794                         /* Get sublist data blob */
795                         list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
796                         if (!list_data.data) {
797                                 DEBUG(0, ("Error getting RI list."));
798                                 return WERR_GENERAL_FAILURE;
799                         }
800                                 
801                         ZERO_STRUCT(pull);
802                         pull.data = list_data;
803                         
804                         if (!strncmp((char *)list_data.data, "li", 2)) {
805                                 struct li_block li;
806         
807                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
808                                         DEBUG(0, ("Error parsing LI list from RI\n"));
809                                         return WERR_GENERAL_FAILURE;
810                                 }
811                                 SMB_ASSERT(!strncmp(li.header, "li",2));
812                                 
813                                 for (j = 0; j < li.key_count; j++) {
814                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, 
815                                                                 li.nk_offset[j], name, &key_off));
816                                         if (key_off) {
817                                                 break;
818                                         }
819                                 }
820                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
821                                 struct lh_block lh;
822                                 uint32_t hash = 0;
823                                 char *hash_name;
824                                 
825                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
826                                         DEBUG(0, ("Error parsing LH list from RI\n"));
827                                         return WERR_GENERAL_FAILURE;
828                                 }
829                                 SMB_ASSERT(!strncmp(lh.header, "lh",2));
830
831                                 /* Compute hash for the name */
832                                 hash_name = strupper_talloc(nk, name);          
833                                 for (j = 0; *(hash_name + j) != 0; j++) {
834                                         hash *= 37;
835                                         hash += *(hash_name + j);
836                                 }
837                                 for (j = 0; j < lh.key_count; j++) {
838                                         if (lh.hr[j].base37 != hash) {
839                                                 continue;
840                                         }
841                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, 
842                                                                 lh.hr[j].nk_offset, name, &key_off));
843                                         if (key_off) {
844                                                 break;
845                                         }
846                                 }
847                         }
848                         if (key_off) {
849                                 break;
850                         }
851                                 
852                 }
853                 if (!key_off) {
854                         return WERR_DEST_NOT_FOUND;
855                 }
856         } else {
857                 DEBUG(0, ("Unknown subkey list type.\n"));
858                 return WERR_GENERAL_FAILURE;
859         }
860
861         *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
862         return WERR_OK;
863 }
864
865 static WERROR regf_set_sec_desc (const struct registry_key *key, const struct security_descriptor *sec_desc)
866 {
867         /* FIXME */
868         return WERR_NOT_SUPPORTED;
869 }
870
871 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **sd)
872 {
873         struct nk_block *nk = key->backend_data;
874         struct sk_block sk;
875         struct regf_data *regf = key->hive->backend_data;
876         DATA_BLOB data;
877
878         if (!hbin_get_tdr(regf, nk->sk_offset, ctx, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
879                 DEBUG(0, ("Unable to find security descriptor\n"));
880                 return WERR_GENERAL_FAILURE;
881         }
882                 
883         if (strcmp(sk.header, "sk") != 0) {
884                 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
885                 return WERR_GENERAL_FAILURE;
886         }
887
888         *sd = talloc(ctx, struct security_descriptor);
889         if (!*sd)
890                 return WERR_NOMEM;
891
892         data.data = sk.sec_desc;
893         data.length = sk.rec_size;
894         if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
895                 DEBUG(0, ("Error parsing security descriptor\n"));
896                 return WERR_GENERAL_FAILURE;
897         }
898
899         return WERR_OK;
900 }
901
902 static uint32_t lf_add_entry (struct regf_data *regf, uint32_t list_offset, const char *name, uint32_t key_offset)
903 {
904         uint32_t ret;
905         struct lf_block lf;
906
907         ZERO_STRUCT(lf);
908
909         /* Add to subkeys list */
910         if (list_offset == -1) { /* Need to create subkeys list */
911                 lf.header = "lf";
912         } else {
913                 if (!hbin_get_tdr(regf, list_offset, regf, (tdr_pull_fn_t)tdr_pull_lf_block, &lf)) {
914                         DEBUG(0, ("Can't get subkeys list\n"));
915                         return -1;
916                 }
917         }
918
919         lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
920         lf.hr[lf.key_count].nk_offset = key_offset;
921         lf.hr[lf.key_count].hash = talloc_strndup(regf, name, 4);
922         lf.key_count++;
923
924         ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
925
926         talloc_free(lf.hr);
927         
928         return ret;
929 }
930
931 static WERROR regf_del_value (const struct registry_key *parent, const char *name)
932 {
933         /* FIXME */
934         return WERR_NOT_SUPPORTED;
935 }
936
937
938 static WERROR regf_del_key (const struct registry_key *parent, const char *name)
939 {
940         struct nk_block *nk = parent->backend_data;
941
942         SMB_ASSERT(nk);
943         
944         if (nk->subkeys_offset == -1) 
945                 return WERR_BADFILE;
946
947         /* FIXME */
948
949         return WERR_NOT_SUPPORTED;
950 }
951
952 static WERROR regf_add_key (TALLOC_CTX *ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **ret)
953 {
954         struct nk_block *parent_nk = parent->backend_data, nk;
955         struct regf_data *regf = parent->hive->backend_data;
956         uint32_t offset;
957
958         nk.header = "nk";
959         nk.type = REG_SUB_KEY;
960         unix_to_nt_time(&nk.last_change, time(NULL));
961         nk.uk1 = 0;
962         nk.parent_offset = 0; /* FIXME */
963         nk.num_subkeys = 0;
964         nk.uk2 = 0;
965         nk.subkeys_offset = -1;
966         nk.unknown_offset = -1;
967         nk.num_values = 0;
968         nk.sk_offset = 0;
969         memset(nk.unk3, 0, 5);
970         nk.clsname_offset = -1;
971         nk.clsname_length = 0;
972         nk.key_name = name;
973         
974         offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
975
976         parent_nk->subkeys_offset = lf_add_entry(regf, parent_nk->subkeys_offset, name, nk.parent_offset);
977
978         parent_nk->num_subkeys++;
979
980         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, nk.parent_offset, parent_nk);
981
982         *ret = regf_get_key(ctx, regf, offset);
983
984         /* FIXME: Set sec desc ! */
985         return WERR_OK;
986 }
987
988 static WERROR regf_set_value (const struct registry_key *key, const char *name, uint32_t type, const DATA_BLOB data)
989 {
990         /* FIXME */
991
992         return WERR_NOT_SUPPORTED;
993 }
994
995 #if 0 /* Unused */
996
997 static WERROR regf_save_hbin(struct registry_hive *hive, struct hbin_block *hbin)
998 {
999         struct regf_data *regf = hive->backend_data;
1000
1001         /* go to right offset */
1002         if (lseek(regf->fd, SEEK_SET, regf->header->data_offset + hbin->offset_from_first) == -1) {
1003                 DEBUG(0, ("Error lseeking in regf file\n"));
1004                 return WERR_GENERAL_FAILURE;
1005         }
1006
1007         if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, (tdr_push_fn_t)tdr_push_hbin_block, hbin))) {
1008                 DEBUG(0, ("Error writing HBIN block\n"));       
1009                 return WERR_GENERAL_FAILURE;
1010         }
1011
1012         return WERR_OK;
1013 }
1014
1015 #endif
1016
1017 static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
1018 {
1019         struct regf_data *regf;
1020         struct regf_hdr *regf_hdr;
1021         struct tdr_pull pull;
1022         int i;
1023
1024         regf = (struct regf_data *)talloc_zero(h, struct regf_data);
1025         h->backend_data = regf;
1026
1027         DEBUG(5, ("Attempting to load registry file\n"));
1028
1029         /* Get the header */
1030         regf->fd = open(h->location, O_RDWR);
1031
1032         if (regf->fd == -1) {
1033                 DEBUG(0,("Could not load file: %s, %s\n", h->location,
1034                                  strerror(errno)));
1035                 return WERR_GENERAL_FAILURE;
1036         }
1037
1038         ZERO_STRUCT(pull);
1039         pull.data.data = (uint8_t*)fd_load(regf->fd, &pull.data.length, regf);
1040
1041         if (pull.data.data == NULL) {
1042                 DEBUG(0, ("Error reading data\n"));
1043                 return WERR_GENERAL_FAILURE;
1044         }
1045
1046         regf_hdr = talloc(regf, struct regf_hdr);
1047         if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(&pull, regf_hdr, regf_hdr))) {
1048                 return WERR_GENERAL_FAILURE;
1049         }
1050
1051         regf->header = regf_hdr;
1052
1053         if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
1054                 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
1055                                   regf_hdr->REGF_ID, h->location));
1056         }
1057
1058         DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n", 
1059                           regf_hdr->description, regf_hdr->version.major,
1060                           regf_hdr->version.minor, regf_hdr->version.release,
1061                           regf_hdr->version.build));
1062
1063         /*
1064          * Validate the header ...
1065          */
1066         if (regf_hdr_checksum(pull.data.data) != regf_hdr->chksum) {
1067                 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
1068                                   h->location, regf_hdr->chksum, regf_hdr_checksum(pull.data.data)));
1069                 return WERR_GENERAL_FAILURE;
1070         }
1071
1072         pull.offset = 0x1000;
1073
1074         i = 0;
1075         /* Read in all hbin blocks */
1076         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
1077         regf->hbins[0] = NULL;
1078
1079         while (pull.offset < pull.data.length && pull.offset < regf->header->last_block) {
1080                 struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
1081
1082                 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(&pull, hbin, hbin))) {
1083                         DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
1084                         return WERR_FOOBAR;
1085                 }
1086
1087                 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
1088                         DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
1089                         return WERR_FOOBAR;
1090                 }
1091
1092                 regf->hbins[i] = hbin;
1093                 i++;
1094                 regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
1095                 regf->hbins[i] = NULL;
1096         } 
1097
1098         DEBUG(1, ("%d HBIN blocks read\n", i));
1099
1100         *key = regf_get_key(h, regf, 0x20);
1101
1102         return WERR_OK;
1103 }
1104
1105 static struct hive_operations reg_backend_nt4 = {
1106         .name = "nt4",
1107         .open_hive = nt_open_hive,
1108         .num_subkeys = regf_num_subkeys,
1109         .num_values = regf_num_values,
1110         .get_subkey_by_index = regf_get_subkey_by_index,
1111         .get_subkey_by_name = regf_get_subkey_by_name,
1112         .get_value_by_index = regf_get_value,
1113         .key_get_sec_desc = regf_get_sec_desc,
1114         .key_set_sec_desc = regf_set_sec_desc,
1115         .add_key = regf_add_key,
1116         .set_value = regf_set_value,
1117         .del_key = regf_del_key,
1118         .del_value = regf_del_value,
1119 };
1120
1121 NTSTATUS registry_nt4_init(void)
1122 {
1123         return registry_register(&reg_backend_nt4);
1124 }