r10026: Move registry header file to lib/registry
[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 /*
28  * Read HBIN blocks into memory
29  */
30
31 struct regf_data {
32         DATA_BLOB data;
33         struct hbin_block **hbins;
34         struct regf_hdr *header;
35 };
36
37 static struct hbin_block *hbin_by_offset (const struct regf_data *data, uint32_t offset, uint32_t *rel_offset)
38 {
39         int i;
40
41         for (i = 0; data->hbins[i]; i++) {
42                 if (offset >= data->hbins[i]->offset_from_first && 
43                         offset < data->hbins[i]->offset_from_first+
44                                          data->hbins[i]->offset_to_next) {
45                         if (rel_offset)
46                                 *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
47                         return data->hbins[i];
48                 }
49         }
50
51         return NULL;
52 }
53
54 /*
55  * Validate a regf header
56  * For now, do nothing, but we should check the checksum
57  */
58 static uint32_t regf_hdr_checksum(const uint8_t *buffer)
59 {
60         uint32_t checksum = 0, x;
61         int i;
62         
63         for (i = 0; i < 0x01FB; i+= 4) {
64                 x = IVAL(buffer, i);
65                 checksum ^= x;
66         }
67
68         return checksum;
69 }
70
71 static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
72 {
73         DATA_BLOB ret;
74         struct hbin_block *hbin;
75         uint32_t rel_offset;
76         ret.data = NULL;
77         ret.length = 0;
78
79         hbin = hbin_by_offset(data, offset, &rel_offset);
80
81         if (hbin == NULL) {
82                 DEBUG(1, ("Can't find HBIN containing 0x%4x\n", offset));
83                 return ret;
84         }
85
86         ret.length = IVAL(hbin->data, rel_offset);
87         if (ret.length & 0x80000000) {
88                 /* absolute value */
89                 ret.length = (ret.length ^ 0xffffffff) + 1;
90         }
91         ret.length -= 4; /* 4 bytes for the length... */
92         ret.data = hbin->data + 
93                 (offset - hbin->offset_from_first - 0x20) + 4;
94         
95         return ret;
96 }
97
98 static BOOL hbin_get_tdr (struct regf_data *regf, uint32_t offset, tdr_pull_fn_t pull_fn, void *p)
99 {
100         DATA_BLOB data;
101         struct tdr_pull *pull;
102
103         data = hbin_get(regf, offset);
104         if (!data.data) {
105                 DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
106                 return False;
107         }
108         
109         pull = talloc_zero(regf, struct tdr_pull);
110         pull->data = data;
111
112         if (NT_STATUS_IS_ERR(pull_fn(pull, p))) {
113                 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
114                 talloc_free(pull);
115                 return False;
116         }
117
118         /* FIXME: Free pull ! */
119
120         return True;
121 }
122
123 /* Allocate some new data */
124 static DATA_BLOB hbin_alloc (struct regf_data *data, uint32_t size, uint32_t *offset)
125 {
126         DATA_BLOB ret;
127         uint32_t rel_offset = -1; /* Relative offset ! */
128         struct hbin_block *hbin = NULL;
129         int i;
130
131         size += 4; /* Need to include uint32 for the length */
132
133         /* Allocate as a multiple of 8 */
134         size = (size + 7) & ~7;
135
136         ret.data = NULL;
137         ret.length = 0;
138
139         if (size == 0)
140                 return ret;
141
142         for (i = 0; (hbin = data->hbins[i]); i++) {
143                 int j;
144                 uint32_t my_size;
145                 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
146                         my_size = IVAL(hbin->data, j);
147                         uint32_t header = IVAL(hbin->data, j + 4);
148
149                         if (my_size % 8 != 0) {
150                                 DEBUG(0, ("Encountered non-aligned block!\n"));
151                         }
152
153                         if (my_size & 0x80000000) { /* Used... */
154                                 my_size = (my_size ^ 0xffffffff) + 1;
155                         } else if (my_size == size) { /* exact match */
156                                 rel_offset = j;
157                                 break;
158                         } else if (my_size > size) { /* data will remain */
159                                 rel_offset = j;
160                                 SIVAL(hbin->data, rel_offset+size, my_size-size); 
161                                 break;
162                         }
163
164                         if (header == 0xffffffff &&
165                                 hbin->offset_to_next-rel_offset >= size)  {
166                                 rel_offset = j;
167                                 /* Mark new free block size */
168                                 SIVAL(hbin->data, rel_offset+size,hbin->offset_to_next - rel_offset - size - 0x20);
169                                 SIVAL(hbin->data, rel_offset+size+0x4, 0xffffffff);
170                                 break;
171                         }
172
173                         if (header == 0xffffffff)  {
174                                 break;
175                         }
176                 }
177
178                 if (rel_offset != -1)
179                         break;
180         }
181         
182         /* No space available in previous hbins, 
183          * allocate new one */
184         if (data->hbins[i] == NULL) { 
185                 data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
186                 hbin = talloc(data->hbins, struct hbin_block);
187                 data->hbins[i] = hbin;
188                 data->hbins[i+1] = NULL;
189
190                 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
191                 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
192                 hbin->offset_to_next = 0x1000;
193                 hbin->unknown[0] = 0;
194                 hbin->unknown[0] = 0;
195                 unix_to_nt_time(&hbin->last_change, time(NULL));
196                 hbin->block_size = hbin->offset_to_next;
197                 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
198
199                 rel_offset = 0x0;
200                 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
201                 SIVAL(hbin->data, size + 0x4, 0xffffffff);
202         }
203
204         /* Set size and mark as used */
205         SIVAL(hbin->data, rel_offset, size & 0x80000000);
206
207         ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
208         ret.length = size - 0x4;
209         if (offset)
210                 *offset = hbin->offset_from_first + rel_offset + 0x20;
211
212         return ret;
213 }
214
215 /* Store a data blob. Return the offset at which it was stored */
216 static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
217 {
218         uint32_t ret;
219         DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
220
221         memcpy(dest.data, blob.data, blob.length);
222
223         return ret;
224 }
225
226 static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
227 {
228         struct tdr_push *push = talloc_zero(data, struct tdr_push);
229         uint32_t ret;
230         
231         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
232                 DEBUG(0, ("Error during push\n"));
233                 return -1;
234         }
235
236         ret = hbin_store(data, push->data);
237
238         talloc_free(push);
239
240         return ret;
241 }
242
243
244 /* Free existing data */
245 static void hbin_free (struct regf_data *data, uint32_t offset)
246 {
247         uint32_t size;
248         uint32_t rel_offset;
249         struct hbin_block *hbin = hbin_by_offset(data, offset, &rel_offset);
250
251         if (hbin == NULL)
252                 return;
253         
254         /* Get original size */
255         size = IVAL(hbin->data, rel_offset);
256
257         if (!(size & 0x80000000)) {
258                 DEBUG(1, ("Trying to free already freed block\n"));
259                 return;
260         }
261
262         /* Mark block as free */
263         SIVAL(hbin->data, rel_offset, (size ^ 0xffffffff) + 1);
264 }
265
266 /* Store a data blob data was already stored, but hsa changed in size
267  * Will try to save it at the current location if possible, otherwise 
268  * does a free + store */
269 static uint32_t hbin_store_resize (struct regf_data *data, uint32_t orig_offset, DATA_BLOB blob)
270 {
271         uint32_t rel_offset;
272         struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
273         uint32_t orig_size;
274         uint32_t needed_size;
275         uint32_t possible_size;
276         int i;
277
278         if (!hbin)
279                 return hbin_store(data, blob);
280
281         /* Get original size */
282         orig_size = IVAL(hbin->data, rel_offset);
283
284         /* Fits into current allocated block */
285         if (orig_size - 4 >= blob.length) {
286                 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
287                 return orig_offset;
288         }
289
290         needed_size = blob.length + 4; /* Add uint32 containing length */
291         needed_size = (needed_size + 7) & ~7; /* Align */
292
293         possible_size = orig_size;
294
295         /* Check if it can be combined with the next few free records */
296         for (i = rel_offset; 
297                  i < hbin->offset_to_next - 0x20; 
298                  i = rel_offset + possible_size) {
299                 uint32_t header;
300                 if (IVAL(hbin->data, i) & 0x80000000) /* Used */
301                         break;
302
303                 header = IVAL(hbin->data, i + 4);
304                 if (header == 0xffffffff) {
305                         possible_size = hbin->offset_to_next - 0x20 - rel_offset;
306                 } else {
307                         possible_size += IVAL(hbin->data, i);
308                 }
309
310                 if (possible_size >= blob.length) {
311                         SIVAL(hbin->data, rel_offset, possible_size);
312                         memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
313                         return orig_offset;
314                 }
315
316                 if (header == 0xffffffff) 
317                         break;
318         }
319
320         hbin_free(data, orig_offset);
321         return hbin_store(data, blob);
322 }
323
324 static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn, uint32_t orig_offset, void *p)
325 {
326         struct tdr_push *push = talloc_zero(regf, struct tdr_push);
327         uint32_t ret;
328         
329         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
330                 DEBUG(0, ("Error during push\n"));
331                 return -1;
332         }
333
334         ret = hbin_store_resize(regf, orig_offset, push->data);
335
336         talloc_free(push);
337
338         return ret;
339 }
340
341 static WERROR regf_num_subkeys (struct registry_key *key, uint32_t *count)
342 {
343         struct nk_block *nk = key->backend_data;
344
345         *count = nk->num_subkeys;
346         
347         return WERR_OK;
348 }
349
350 static WERROR regf_num_values (struct registry_key *key, uint32_t *count)
351 {
352         struct nk_block *nk = key->backend_data;
353
354         *count = nk->num_values;
355
356         return WERR_OK;
357 }
358
359 static struct registry_key *regf_get_key (TALLOC_CTX *ctx, struct regf_data *regf, uint32_t offset)
360 {
361         struct registry_key *ret;
362         struct nk_block *nk;
363
364         ret = talloc_zero(ctx, struct registry_key);
365         nk = talloc(ret, struct nk_block);
366         if (!hbin_get_tdr(regf, offset, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
367                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
368                 return NULL;
369         }
370
371         if (strcmp(nk->header, "nk") != 0) {
372                 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
373                 talloc_free(ret);
374                 return NULL;
375         }
376
377         ret->name = talloc_steal(ret, nk->key_name);
378         ret->last_mod = nk->last_change;
379
380         if (nk->clsname_offset != -1) {
381                 DATA_BLOB data = hbin_get(regf, nk->clsname_offset);
382                 ret->class_name = talloc_strndup(ret, (char*)data.data, nk->clsname_length);
383         }
384         ret->backend_data = nk;
385
386         return ret;
387 }
388
389 static WERROR regf_get_value (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_value **ret)
390 {
391         struct nk_block *nk = key->backend_data;
392         struct vk_block *vk;
393         struct regf_data *regf = key->hive->backend_data;
394         uint32_t vk_offset;
395         DATA_BLOB data;
396
397         if (idx >= nk->num_values)
398                 return WERR_NO_MORE_ITEMS;
399
400         data = hbin_get(regf, nk->values_offset);
401         if (!data.data) {
402                 DEBUG(0, ("Unable to find value list\n"));
403                 return WERR_GENERAL_FAILURE;
404         }
405
406         if (data.length < nk->num_values * 4) {
407                 DEBUG(1, ("Value counts mismatch\n"));
408         }
409
410         vk_offset = IVAL(data.data, idx * 4);
411
412         *ret = talloc_zero(ctx, struct registry_value);
413         if (!(*ret)) 
414                 return WERR_NOMEM;
415
416         vk = talloc(*ret, struct vk_block);
417         if (!vk)
418                 return WERR_NOMEM;
419         
420         if (!hbin_get_tdr(regf, vk_offset, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
421                 DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
422                 return WERR_GENERAL_FAILURE;
423         }
424
425         (*ret)->name = talloc_steal(*ret, vk->data_name);
426         (*ret)->data_type = vk->data_type;
427         if (vk->data_length & 0x80000000) { 
428                 vk->data_length &= ~0x80000000;
429                 (*ret)->data.data = (uint8_t *)&vk->data_offset;
430                 (*ret)->data.length = vk->data_length;
431         } else {
432                 (*ret)->data = hbin_get(regf, vk->data_offset);
433         }
434
435         if ((*ret)->data.length < vk->data_length) {
436                 DEBUG(1, ("Read data less then indicated data length!\n"));
437         }
438         
439         return WERR_OK;
440 }
441
442 static WERROR regf_get_subkey (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_key **ret)
443 {
444         DATA_BLOB data;
445         struct nk_block *nk = key->backend_data;
446         uint32_t key_off;
447
448         if (idx >= nk->num_subkeys)
449                 return WERR_NO_MORE_ITEMS;
450
451         data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
452         if (!data.data) {
453                 DEBUG(0, ("Unable to find subkey list\n"));
454                 return WERR_GENERAL_FAILURE;
455         }
456
457         if (!strncmp((char *)data.data, "li", 2)) {
458                 DEBUG(4, ("Subkeys in LI list\n"));
459                 SMB_ASSERT(0);
460         } else if (!strncmp((char *)data.data, "lf", 2)) {
461                 struct lf_block lf;
462                 struct tdr_pull *pull = talloc_zero(ctx, struct tdr_pull);
463
464                 DEBUG(10, ("Subkeys in LF list\n"));
465                 pull->data = data;
466
467                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, &lf))) {
468                         DEBUG(0, ("Error parsing LF list\n"));
469                         return WERR_GENERAL_FAILURE;
470                 }
471
472                 if (lf.key_count != nk->num_subkeys) {
473                         DEBUG(0, ("Subkey counts don't match\n"));
474                         return WERR_GENERAL_FAILURE;
475                 }
476
477                 key_off = lf.hr[idx].nk_off;
478                 
479                 talloc_free(pull);
480         } else if (!strncmp((char *)data.data, "ri", 2)) {
481                 DEBUG(4, ("Subkeys in RI list\n"));
482                 SMB_ASSERT(0);
483         } else if (!strncmp((char *)data.data, "lh", 2)) {
484                 DEBUG(4, ("Subkeys in LH list\n"));
485                 SMB_ASSERT(0);
486         } else {
487                 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1]));
488                 return WERR_GENERAL_FAILURE;
489         }
490
491         *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
492
493         return WERR_OK;
494 }
495
496 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, struct registry_key *key, struct security_descriptor **sd)
497 {
498         struct nk_block *nk = key->backend_data;
499         struct sk_block sk;
500         struct regf_data *regf = key->hive->backend_data;
501         DATA_BLOB data;
502
503         if (!hbin_get_tdr(regf, nk->sk_offset, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
504                 DEBUG(0, ("Unable to find security descriptor\n"));
505                 return WERR_GENERAL_FAILURE;
506         }
507                 
508         if (strcmp(sk.header, "sk") != 0) {
509                 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
510                 return WERR_GENERAL_FAILURE;
511         }
512
513         *sd = talloc(ctx, struct security_descriptor);
514         if (!*sd)
515                 return WERR_NOMEM;
516
517         data.data = sk.sec_desc;
518         data.length = sk.rec_size;
519         if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
520                 DEBUG(0, ("Error parsing security descriptor\n"));
521                 return WERR_GENERAL_FAILURE;
522         }
523
524         return WERR_OK;
525 }
526
527 static uint32_t lf_add_entry (struct regf_data *regf, uint32_t list_offset, const char *name, uint32_t key_offset)
528 {
529         uint32_t ret;
530         struct lf_block lf;
531
532         /* Add to subkeys list */
533         if (list_offset == -1) { /* Need to create subkeys list */
534                 lf.header = "lf";
535                 lf.key_count = 0;
536                 lf.hr = NULL;
537         } else {
538                 if (!hbin_get_tdr(regf, list_offset, (tdr_pull_fn_t)tdr_pull_lf_block, &lf)) {
539                         DEBUG(0, ("Can't get subkeys list\n"));
540                         return -1;
541                 }
542         }
543
544         lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
545         lf.hr[lf.key_count].nk_off = key_offset;
546         lf.hr[lf.key_count].hash = name;
547
548         ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
549         
550         return ret;
551 }
552
553 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)
554 {
555         struct nk_block *parent_nk = parent->backend_data, nk;
556         uint32_t offset;
557
558         nk.header = "nk";
559         nk.type = REG_SUB_KEY;
560         unix_to_nt_time(&nk.last_change, time(NULL));
561         nk.uk1 = 0;
562         nk.parent_offset = 0; /* FIXME */
563         nk.num_subkeys = 0;
564         nk.uk2 = 0;
565         nk.subkeys_offset = -1;
566         nk.unknown_offset = -1;
567         nk.num_values = 0;
568         nk.sk_offset = 0;
569         memset(nk.unk3, 0, 5);
570         nk.clsname_offset = -1;
571         nk.clsname_length = 0;
572         nk.key_name = name;
573         
574         offset = hbin_store_tdr(parent->hive->backend_data, (tdr_push_fn_t) tdr_push_nk_block, &nk);
575
576         parent_nk->subkeys_offset = lf_add_entry(parent->hive->backend_data, parent_nk->subkeys_offset, name, nk.parent_offset);
577
578         parent_nk->num_subkeys++;
579
580         hbin_store_tdr_resize(parent->hive->backend_data, (tdr_push_fn_t) tdr_push_nk_block, nk.parent_offset, parent_nk);
581
582         /* FIXME: Set sec desc ! */
583
584         *ret = regf_get_key(ctx, parent->hive->backend_data, offset);
585         return WERR_OK;
586 }
587
588 static WERROR regf_set_value (struct registry_key *key, const char *name, uint32_t type, DATA_BLOB data)
589 {
590         /* FIXME */
591
592         return WERR_NOT_SUPPORTED;
593 }
594
595 static WERROR regf_save(struct registry_hive *hive, const char *location)
596 {
597         struct regf_data *regf = hive->backend_data;
598         struct tdr_push *push = talloc_zero(regf, struct tdr_push);
599         int i;
600
601         tdr_push_regf_hdr(push, regf->header);
602
603         for (i = 0; regf->hbins[i]; i++) {
604                 tdr_push_hbin_block(push, regf->hbins[i]);
605         }
606
607         file_save(location, push->data.data, push->data.length);
608
609         return WERR_OK;
610 }
611
612 static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
613 {
614         struct regf_data *regf;
615         struct regf_hdr *regf_hdr;
616         struct tdr_pull *pull;
617         int i;
618
619         regf = (struct regf_data *)talloc_zero(h, struct regf_data);
620         h->backend_data = regf;
621
622         DEBUG(5, ("Attempting to load registry file\n"));
623
624         /* Get the header */
625
626         regf->data.data = (uint8_t *)file_load(h->location, &regf->data.length, regf);
627         if (regf->data.data == NULL) {
628                 DEBUG(0,("Could not load file: %s, %s\n", h->location,
629                                  strerror(errno)));
630                 return WERR_GENERAL_FAILURE;
631         }
632
633         pull = talloc_zero(regf, struct tdr_pull);
634         if (!pull)
635                 return WERR_NOMEM;
636
637         pull->data = regf->data;
638
639         regf_hdr = talloc(regf, struct regf_hdr);
640         if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr))) {
641                 return WERR_GENERAL_FAILURE;
642         }
643
644         regf->header = regf_hdr;
645
646         if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
647                 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
648                                   regf_hdr->REGF_ID, h->location));
649         }
650
651         DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n", 
652                           regf_hdr->description, regf_hdr->version.major,
653                           regf_hdr->version.minor, regf_hdr->version.release,
654                           regf_hdr->version.build));
655
656         /*
657          * Validate the header ...
658          */
659         if (regf_hdr_checksum(regf->data.data) != regf_hdr->chksum) {
660                 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
661                                   h->location, regf_hdr->chksum, regf_hdr_checksum(regf->data.data)));
662                 return WERR_GENERAL_FAILURE;
663         }
664
665         pull->offset = 0x1000;
666
667         i = 0;
668         /* Read in all hbin blocks */
669         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
670         regf->hbins[0] = NULL;
671
672         while (pull->offset < pull->data.length) {
673                 struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
674
675                 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin))) {
676                         DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
677                         return WERR_FOOBAR;
678                 }
679
680                 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
681                         DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
682                         return WERR_FOOBAR;
683                 }
684
685                 regf->hbins[i] = hbin;
686                 i++;
687                 regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
688                 regf->hbins[i] = NULL;
689         } 
690
691         DEBUG(1, ("%d HBIN blocks read\n", i));
692
693         *key = regf_get_key(h, regf, 0x20);
694
695         return WERR_OK;
696 }
697
698 static struct hive_operations reg_backend_nt4 = {
699         .name = "nt4",
700         .open_hive = nt_open_hive,
701         .num_subkeys = regf_num_subkeys,
702         .num_values = regf_num_values,
703         .get_subkey_by_index = regf_get_subkey,
704         .get_value_by_index = regf_get_value,
705         .key_get_sec_desc = regf_get_sec_desc,
706         .add_key = regf_add_key,
707         .set_value = regf_set_value,
708         .save_hive = regf_save,
709 };
710
711 NTSTATUS registry_nt4_init(void)
712 {
713         return registry_register(&reg_backend_nt4);
714 }