4a3576f85eeed56af42e13cc32c1a413d4de1001
[bbaumbach/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
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19  
20 #include "includes.h"
21 #include "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, tdr_pull_fn_t pull_fn, void *p)
108 {
109         DATA_BLOB data;
110         struct tdr_pull *pull;
111
112         data = hbin_get(regf, offset);
113         if (!data.data) {
114                 DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
115                 return False;
116         }
117         
118         pull = talloc_zero(regf, struct tdr_pull);
119         pull->data = data;
120
121         if (NT_STATUS_IS_ERR(pull_fn(pull, p))) {
122                 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
123                 talloc_free(pull);
124                 return False;
125         }
126
127         /* FIXME: Free pull ! */
128
129         return True;
130 }
131
132 /* Allocate some new data */
133 static DATA_BLOB hbin_alloc (struct regf_data *data, uint32_t size, uint32_t *offset)
134 {
135         DATA_BLOB ret;
136         uint32_t rel_offset = -1; /* Relative offset ! */
137         struct hbin_block *hbin = NULL;
138         int i;
139
140         if (size == 0)
141                 return ret;
142
143         size += 4; /* Need to include uint32 for the length */
144
145         /* Allocate as a multiple of 8 */
146         size = (size + 7) & ~7;
147
148         ret.data = NULL;
149         ret.length = 0;
150
151         for (i = 0; (hbin = data->hbins[i]); i++) {
152                 int j;
153                 uint32_t my_size;
154                 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
155                         my_size = IVAL(hbin->data, j);
156                         uint32_t header = IVAL(hbin->data, j + 4);
157
158                         if (my_size == 0x0) {
159                                 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
160                                 return ret;
161                         }
162
163                         if (my_size % 8 != 0) {
164                                 DEBUG(0, ("Encountered non-aligned block!\n"));
165                         }
166
167                         if (my_size & 0x80000000) { /* Used... */
168                                 my_size = (my_size ^ 0xffffffff) + 1;
169                         } else if (my_size == size) { /* exact match */
170                                 rel_offset = j;
171                                 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", size));
172                                 break;
173                         } else if (my_size > size) { /* data will remain */
174                                 rel_offset = j;
175                                 SIVAL(hbin->data, rel_offset+size, my_size-size); 
176                                 DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", my_size, size));
177                                 break;
178                         }
179
180                         if (header == 0xffffffff &&
181                                 hbin->offset_to_next-rel_offset >= size)  {
182                                 rel_offset = j;
183
184                                 DEBUG(4, ("Found free block of size %d at end of HBIN\n", size));
185                                 /* Mark new free block size */
186                                 SIVAL(hbin->data, rel_offset+size,hbin->offset_to_next - rel_offset - size - 0x20);
187                                 SIVAL(hbin->data, rel_offset+size+0x4, 0xffffffff);
188                                 break;
189                         }
190
191                         if (header == 0xffffffff)  {
192                                 break;
193                         }
194                 }
195
196                 if (rel_offset != -1)
197                         break;
198         }
199         
200         /* No space available in previous hbins, 
201          * allocate new one */
202         if (data->hbins[i] == NULL) { 
203                 DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size));
204                 data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
205                 hbin = talloc(data->hbins, struct hbin_block);
206                 data->hbins[i] = hbin;
207                 data->hbins[i+1] = NULL;
208
209                 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
210                 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
211                 hbin->offset_to_next = 0x1000;
212                 hbin->unknown[0] = 0;
213                 hbin->unknown[0] = 0;
214                 unix_to_nt_time(&hbin->last_change, time(NULL));
215                 hbin->block_size = hbin->offset_to_next;
216                 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
217
218                 rel_offset = 0x0;
219                 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
220                 SIVAL(hbin->data, size + 0x4, 0xffffffff);
221         }
222
223         /* Set size and mark as used */
224         SIVAL(hbin->data, rel_offset, size | 0x80000000);
225
226         ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
227         ret.length = size - 0x4;
228         if (offset) {
229                 uint32_t new_rel_offset;
230                 *offset = hbin->offset_from_first + rel_offset + 0x20;
231                 SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
232                 SMB_ASSERT(new_rel_offset == rel_offset);
233         }
234
235         return ret;
236 }
237
238 /* Store a data blob. Return the offset at which it was stored */
239 static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
240 {
241         uint32_t ret;
242         DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
243
244         memcpy(dest.data, blob.data, blob.length);
245
246         return ret;
247 }
248
249 static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
250 {
251         struct tdr_push *push = talloc_zero(data, struct tdr_push);
252         uint32_t ret;
253         
254         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
255                 DEBUG(0, ("Error during push\n"));
256                 return -1;
257         }
258
259         ret = hbin_store(data, push->data);
260
261         talloc_free(push);
262
263         return ret;
264 }
265
266
267 /* Free existing data */
268 static void hbin_free (struct regf_data *data, uint32_t offset)
269 {
270         uint32_t size;
271         uint32_t rel_offset;
272         struct hbin_block *hbin;
273
274         SMB_ASSERT (offset > 0);
275         
276         hbin = hbin_by_offset(data, offset, &rel_offset);
277
278         if (hbin == NULL)
279                 return;
280         
281         /* Get original size */
282         size = IVAL(hbin->data, rel_offset);
283
284         if (!(size & 0x80000000)) {
285                 DEBUG(1, ("Trying to free already freed block at 0x%04x\n", offset));
286                 return;
287         }
288
289         /* Mark block as free */
290         SIVAL(hbin->data, rel_offset, size &~ 0x80000000);
291 }
292
293 /* Store a data blob data was already stored, but hsa changed in size
294  * Will try to save it at the current location if possible, otherwise 
295  * does a free + store */
296 static uint32_t hbin_store_resize (struct regf_data *data, uint32_t orig_offset, DATA_BLOB blob)
297 {
298         uint32_t rel_offset;
299         struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
300         uint32_t my_size;
301         uint32_t orig_size;
302         uint32_t needed_size;
303         uint32_t possible_size;
304         int i;
305
306         SMB_ASSERT(orig_offset > 0);
307
308         if (!hbin)
309                 return hbin_store(data, blob);
310
311         /* Get original size */
312         orig_size = IVAL(hbin->data, rel_offset);
313
314         needed_size = blob.length + 4; /* Add uint32 containing length */
315         needed_size = (needed_size + 7) & ~7; /* Align */
316
317         /* Fits into current allocated block */
318         if (orig_size >= needed_size) {
319                 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
320                 return orig_offset;
321         }
322
323         possible_size = orig_size;
324
325         /* Check if it can be combined with the next few free records */
326         for (i = rel_offset; 
327                  i < hbin->offset_to_next - 0x20; 
328                  i += my_size) {
329                 uint32_t header;
330                 if (IVAL(hbin->data, i) & 0x80000000) /* Used */
331                         break;
332
333                 my_size = IVAL(hbin->data, i);
334                 header = IVAL(hbin->data, i + 4);
335                 if (header == 0xffffffff) {
336                         possible_size = hbin->offset_to_next - 0x20 - rel_offset;
337                 } else if (my_size == 0x0) {
338                         DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
339                         break;
340                 } else {
341                         possible_size += my_size;
342                 }
343
344                 if (possible_size >= blob.length) {
345                         SIVAL(hbin->data, rel_offset, possible_size);
346                         memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
347                         return orig_offset;
348                 }
349
350                 if (header == 0xffffffff) 
351                         break;
352         }
353
354         hbin_free(data, orig_offset);
355         return hbin_store(data, blob);
356 }
357
358 static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn, uint32_t orig_offset, void *p)
359 {
360         struct tdr_push *push = talloc_zero(regf, struct tdr_push);
361         uint32_t ret;
362         
363         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
364                 DEBUG(0, ("Error during push\n"));
365                 return -1;
366         }
367
368         ret = hbin_store_resize(regf, orig_offset, push->data);
369
370         talloc_free(push);
371
372         return ret;
373 }
374
375 static WERROR regf_num_subkeys (struct registry_key *key, uint32_t *count)
376 {
377         struct nk_block *nk = key->backend_data;
378
379         *count = nk->num_subkeys;
380         
381         return WERR_OK;
382 }
383
384 static WERROR regf_num_values (struct registry_key *key, uint32_t *count)
385 {
386         struct nk_block *nk = key->backend_data;
387
388         *count = nk->num_values;
389
390         return WERR_OK;
391 }
392
393 static struct registry_key *regf_get_key (TALLOC_CTX *ctx, struct regf_data *regf, uint32_t offset)
394 {
395         struct registry_key *ret;
396         struct nk_block *nk;
397
398         ret = talloc_zero(ctx, struct registry_key);
399         nk = talloc(ret, struct nk_block);
400         if (!hbin_get_tdr(regf, offset, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
401                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
402                 return NULL;
403         }
404
405         if (strcmp(nk->header, "nk") != 0) {
406                 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
407                 talloc_free(ret);
408                 return NULL;
409         }
410
411         ret->name = talloc_steal(ret, nk->key_name);
412         ret->last_mod = nk->last_change;
413
414         if (nk->clsname_offset != -1) {
415                 DATA_BLOB data = hbin_get(regf, nk->clsname_offset);
416                 ret->class_name = talloc_strndup(ret, (char*)data.data, nk->clsname_length);
417         }
418         ret->backend_data = nk;
419
420         return ret;
421 }
422
423 static WERROR regf_get_value (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_value **ret)
424 {
425         struct nk_block *nk = key->backend_data;
426         struct vk_block *vk;
427         struct regf_data *regf = key->hive->backend_data;
428         uint32_t vk_offset;
429         DATA_BLOB data;
430
431         if (idx >= nk->num_values)
432                 return WERR_NO_MORE_ITEMS;
433
434         data = hbin_get(regf, nk->values_offset);
435         if (!data.data) {
436                 DEBUG(0, ("Unable to find value list\n"));
437                 return WERR_GENERAL_FAILURE;
438         }
439
440         if (data.length < nk->num_values * 4) {
441                 DEBUG(1, ("Value counts mismatch\n"));
442         }
443
444         vk_offset = IVAL(data.data, idx * 4);
445
446         *ret = talloc_zero(ctx, struct registry_value);
447         if (!(*ret)) 
448                 return WERR_NOMEM;
449
450         vk = talloc(*ret, struct vk_block);
451         if (!vk)
452                 return WERR_NOMEM;
453         
454         if (!hbin_get_tdr(regf, vk_offset, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
455                 DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
456                 return WERR_GENERAL_FAILURE;
457         }
458
459         (*ret)->name = talloc_steal(*ret, vk->data_name);
460         (*ret)->data_type = vk->data_type;
461         if (vk->data_length & 0x80000000) { 
462                 vk->data_length &=~0x80000000;
463                 (*ret)->data.data = (uint8_t *)&vk->data_offset;
464                 (*ret)->data.length = vk->data_length;
465         } else {
466                 (*ret)->data = hbin_get(regf, vk->data_offset);
467         }
468
469         if ((*ret)->data.length < vk->data_length) {
470                 DEBUG(1, ("Read data less then indicated data length!\n"));
471         }
472         
473         return WERR_OK;
474 }
475
476 static WERROR regf_get_subkey (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_key **ret)
477 {
478         DATA_BLOB data;
479         struct nk_block *nk = key->backend_data;
480         uint32_t key_off;
481
482         if (idx >= nk->num_subkeys)
483                 return WERR_NO_MORE_ITEMS;
484
485         data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
486         if (!data.data) {
487                 DEBUG(0, ("Unable to find subkey list\n"));
488                 return WERR_GENERAL_FAILURE;
489         }
490
491         if (!strncmp((char *)data.data, "li", 2)) {
492                 DEBUG(4, ("Subkeys in LI list\n"));
493                 SMB_ASSERT(0);
494         } else if (!strncmp((char *)data.data, "lf", 2)) {
495                 struct lf_block lf;
496                 struct tdr_pull *pull = talloc_zero(ctx, struct tdr_pull);
497
498                 DEBUG(10, ("Subkeys in LF list\n"));
499                 pull->data = data;
500
501                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, &lf))) {
502                         DEBUG(0, ("Error parsing LF list\n"));
503                         return WERR_GENERAL_FAILURE;
504                 }
505
506                 if (lf.key_count != nk->num_subkeys) {
507                         DEBUG(0, ("Subkey counts don't match\n"));
508                         return WERR_GENERAL_FAILURE;
509                 }
510
511                 key_off = lf.hr[idx].nk_off;
512                 
513                 talloc_free(pull);
514         } else if (!strncmp((char *)data.data, "ri", 2)) {
515                 DEBUG(4, ("Subkeys in RI list\n"));
516                 SMB_ASSERT(0);
517         } else if (!strncmp((char *)data.data, "lh", 2)) {
518                 DEBUG(4, ("Subkeys in LH list\n"));
519                 SMB_ASSERT(0);
520         } else {
521                 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1]));
522                 return WERR_GENERAL_FAILURE;
523         }
524
525         *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
526
527         return WERR_OK;
528 }
529
530
531 static WERROR regf_set_sec_desc (struct registry_key *key, struct security_descriptor *sec_desc)
532 {
533         /* FIXME */
534         return WERR_NOT_SUPPORTED;
535 }
536
537 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, struct registry_key *key, struct security_descriptor **sd)
538 {
539         struct nk_block *nk = key->backend_data;
540         struct sk_block sk;
541         struct regf_data *regf = key->hive->backend_data;
542         DATA_BLOB data;
543
544         if (!hbin_get_tdr(regf, nk->sk_offset, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
545                 DEBUG(0, ("Unable to find security descriptor\n"));
546                 return WERR_GENERAL_FAILURE;
547         }
548                 
549         if (strcmp(sk.header, "sk") != 0) {
550                 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
551                 return WERR_GENERAL_FAILURE;
552         }
553
554         *sd = talloc(ctx, struct security_descriptor);
555         if (!*sd)
556                 return WERR_NOMEM;
557
558         data.data = sk.sec_desc;
559         data.length = sk.rec_size;
560         if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
561                 DEBUG(0, ("Error parsing security descriptor\n"));
562                 return WERR_GENERAL_FAILURE;
563         }
564
565         return WERR_OK;
566 }
567
568 static uint32_t lf_add_entry (struct regf_data *regf, uint32_t list_offset, const char *name, uint32_t key_offset)
569 {
570         uint32_t ret;
571         struct lf_block lf;
572
573         /* Add to subkeys list */
574         if (list_offset == -1) { /* Need to create subkeys list */
575                 lf.header = "lf";
576                 lf.key_count = 0;
577                 lf.hr = NULL;
578         } else {
579                 if (!hbin_get_tdr(regf, list_offset, (tdr_pull_fn_t)tdr_pull_lf_block, &lf)) {
580                         DEBUG(0, ("Can't get subkeys list\n"));
581                         return -1;
582                 }
583         }
584
585         lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
586         lf.hr[lf.key_count].nk_off = key_offset;
587         lf.hr[lf.key_count].hash = talloc_strndup(regf, name, 4);
588         lf.key_count++;
589
590         ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
591         
592         return ret;
593 }
594
595 static WERROR regf_del_value (struct registry_key *parent, const char *name)
596 {
597         /* FIXME */
598         return WERR_NOT_SUPPORTED;
599 }
600
601
602 static WERROR regf_del_key (struct registry_key *parent, const char *name)
603 {
604         struct nk_block *nk = parent->backend_data;
605
606         SMB_ASSERT(nk);
607         
608         if (nk->subkeys_offset == -1) 
609                 return WERR_BADFILE;
610
611         /* FIXME */
612
613         return WERR_NOT_SUPPORTED;
614 }
615
616 static WERROR regf_add_key (TALLOC_CTX *ctx, struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **ret)
617 {
618         struct nk_block *parent_nk = parent->backend_data, nk;
619         struct regf_data *regf = parent->hive->backend_data;
620         uint32_t offset;
621
622         nk.header = "nk";
623         nk.type = REG_SUB_KEY;
624         unix_to_nt_time(&nk.last_change, time(NULL));
625         nk.uk1 = 0;
626         nk.parent_offset = 0; /* FIXME */
627         nk.num_subkeys = 0;
628         nk.uk2 = 0;
629         nk.subkeys_offset = -1;
630         nk.unknown_offset = -1;
631         nk.num_values = 0;
632         nk.sk_offset = 0;
633         memset(nk.unk3, 0, 5);
634         nk.clsname_offset = -1;
635         nk.clsname_length = 0;
636         nk.key_name = name;
637         
638         offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
639
640         parent_nk->subkeys_offset = lf_add_entry(regf, parent_nk->subkeys_offset, name, nk.parent_offset);
641
642         parent_nk->num_subkeys++;
643
644         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, nk.parent_offset, parent_nk);
645
646         *ret = regf_get_key(ctx, regf, offset);
647
648         /* FIXME: Set sec desc ! */
649         return WERR_OK;
650 }
651
652 static WERROR regf_set_value (struct registry_key *key, const char *name, uint32_t type, DATA_BLOB data)
653 {
654         /* FIXME */
655
656         return WERR_NOT_SUPPORTED;
657 }
658
659 static WERROR regf_save_hbin(struct registry_hive *hive, struct hbin_block *hbin)
660 {
661         struct regf_data *regf = hive->backend_data;
662
663         /* go to right offset */
664         if (lseek(regf->fd, SEEK_SET, regf->header->data_offset + hbin->offset_from_first) == -1) {
665                 DEBUG(0, ("Error lseeking in regf file\n"));
666                 return WERR_GENERAL_FAILURE;
667         }
668
669         if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, (tdr_push_fn_t)tdr_push_hbin_block, hbin))) {
670                 DEBUG(0, ("Error writing HBIN block\n"));       
671                 return WERR_GENERAL_FAILURE;
672         }
673
674         return WERR_OK;
675 }
676
677 static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
678 {
679         struct regf_data *regf;
680         struct regf_hdr *regf_hdr;
681         struct tdr_pull *pull;
682         int i;
683
684         regf = (struct regf_data *)talloc_zero(h, struct regf_data);
685         h->backend_data = regf;
686
687         DEBUG(5, ("Attempting to load registry file\n"));
688
689         /* Get the header */
690         regf->fd = open(h->location, O_RDWR);
691
692         if (regf->fd == -1) {
693                 DEBUG(0,("Could not load file: %s, %s\n", h->location,
694                                  strerror(errno)));
695                 return WERR_GENERAL_FAILURE;
696         }
697
698         pull = talloc_zero(regf, struct tdr_pull);
699         if (!pull)
700                 return WERR_NOMEM;
701
702         pull->data.data = (uint8_t*)fd_load(regf->fd, &pull->data.length, regf);
703
704         if (pull->data.data == NULL) {
705                 DEBUG(0, ("Error reading data\n"));
706                 return WERR_GENERAL_FAILURE;
707         }
708
709         regf_hdr = talloc(regf, struct regf_hdr);
710         if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr))) {
711                 return WERR_GENERAL_FAILURE;
712         }
713
714         regf->header = regf_hdr;
715
716         if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
717                 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
718                                   regf_hdr->REGF_ID, h->location));
719         }
720
721         DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n", 
722                           regf_hdr->description, regf_hdr->version.major,
723                           regf_hdr->version.minor, regf_hdr->version.release,
724                           regf_hdr->version.build));
725
726         /*
727          * Validate the header ...
728          */
729         if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) {
730                 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
731                                   h->location, regf_hdr->chksum, regf_hdr_checksum(pull->data.data)));
732                 return WERR_GENERAL_FAILURE;
733         }
734
735         pull->offset = 0x1000;
736
737         i = 0;
738         /* Read in all hbin blocks */
739         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
740         regf->hbins[0] = NULL;
741
742         while (pull->offset < pull->data.length) {
743                 struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
744
745                 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin))) {
746                         DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
747                         return WERR_FOOBAR;
748                 }
749
750                 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
751                         DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
752                         return WERR_FOOBAR;
753                 }
754
755                 regf->hbins[i] = hbin;
756                 i++;
757                 regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
758                 regf->hbins[i] = NULL;
759         } 
760
761         DEBUG(1, ("%d HBIN blocks read\n", i));
762
763         *key = regf_get_key(h, regf, 0x20);
764
765         return WERR_OK;
766 }
767
768 static struct hive_operations reg_backend_nt4 = {
769         .name = "nt4",
770         .open_hive = nt_open_hive,
771         .num_subkeys = regf_num_subkeys,
772         .num_values = regf_num_values,
773         .get_subkey_by_index = regf_get_subkey,
774         .get_value_by_index = regf_get_value,
775         .key_get_sec_desc = regf_get_sec_desc,
776         .key_set_sec_desc = regf_set_sec_desc,
777         .add_key = regf_add_key,
778         .set_value = regf_set_value,
779         .del_key = regf_del_key,
780         .del_value = regf_del_value,
781 };
782
783 NTSTATUS registry_nt4_init(void)
784 {
785         return registry_register(&reg_backend_nt4);
786 }