06c0d78c85d7f0effa86cfcd120d43ca962cb339
[bbaumbach/samba-autobuild/.git] / source4 / lib / registry / reg_backend_nt4.c
1 /*
2    Samba Unix/Linux SMB client utility libeditreg.c 
3    Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
4    Copyright (C) 2003-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 /*************************************************************************
21                                                        
22  A utility to edit a Windows NT/2K etc registry file.
23                                      
24  Many of the ideas in here come from other people and software. 
25  I first looked in Wine in misc/registry.c and was also influenced by
26  http://www.wednesday.demon.co.uk/dosreg.html
27
28  Which seems to contain comments from someone else. I reproduce them here
29  incase the site above disappears. It actually comes from 
30  http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt. 
31
32  The goal here is to read the registry into memory, manipulate it, and then
33  write it out if it was changed by any actions of the user.
34
35 The windows NT registry has 2 different blocks, where one can occur many
36 times...
37
38 the "regf"-Block
39 ================
40  
41 "regf" is obviously the abbreviation for "Registry file". "regf" is the
42 signature of the header-block which is always 4kb in size, although only
43 the first 64 bytes seem to be used and a checksum is calculated over
44 the first 0x200 bytes only!
45
46 Offset            Size      Contents
47 0x00000000      D-Word      ID: ASCII-"regf" = 0x66676572
48 0x00000004      D-Word      ???? //see struct REG_HANDLE
49 0x00000008      D-Word      ???? Always the same value as at 0x00000004
50 0x0000000C      Q-Word      last modify date in WinNT date-format
51 0x00000014      D-Word      1
52 0x00000018      D-Word      3
53 0x0000001C      D-Word      0
54 0x00000020      D-Word      1
55 0x00000024      D-Word      Offset of 1st key record
56 0x00000028      D-Word      Size of the data-blocks (Filesize-4kb)
57 0x0000002C      D-Word      1
58 0x000001FC      D-Word      Sum of all D-Words from 0x00000000 to
59 0x000001FB  //XOR of all words. Nigel
60
61 I have analyzed more registry files (from multiple machines running
62 NT 4.0 german version) and could not find an explanation for the values
63 marked with ???? the rest of the first 4kb page is not important...
64
65 the "hbin"-Block
66 ================
67 hbin probably means hive-bin (what bin stands for I don't know)
68 This block is always a multiple
69 of 4kb in size.
70
71 Inside these hbin-blocks the different records are placed. The memory-
72 management looks like a C-compiler heap management to me...
73
74 hbin-Header
75 ===========
76 Offset      Size      Contents
77 0x0000      D-Word      ID: ASCII-"hbin" = 0x6E696268
78 0x0004      D-Word      Offset from the 1st hbin-Block
79 0x0008      D-Word      Offset to the next hbin-Block
80 0x001C      D-Word      Block-size
81
82 The values in 0x0008 and 0x001C should be the same, so I don't know
83 if they are correct or swapped...
84
85 From offset 0x0020 inside a hbin-block data is stored with the following
86 format:
87
88 Offset      Size      Contents
89 0x0000      D-Word      Data-block size    //this size must be a
90 multiple of 8. Nigel
91 0x0004      ????      Data
92  
93 If the size field is negative (bit 31 set), the corresponding block
94 is free and has a size of -blocksize!
95
96 That does not seem to be true. All block lengths seem to be negative! 
97 (Richard Sharpe) 
98
99 The data is stored as one record per block. Block size is a multiple
100 of 4 and the last block reaches the next hbin-block, leaving no room.
101
102 (That also seems incorrect, in that the block size if a multiple of 8.
103 That is, the block, including the 4 byte header, is always a multiple of
104 8 bytes. Richard Sharpe.)
105
106 Records in the hbin-blocks
107 ==========================
108
109 nk-Record
110
111       The nk-record can be treated as a combination of tree-record and
112       key-record of the win 95 registry.
113
114 lf-Record
115
116       The lf-record is the counterpart to the RGKN-record (the
117       hash-function)
118
119 vk-Record
120
121       The vk-record consists information to a single value (value key).
122
123 sk-Record
124
125       sk (? Security Key ?) is the ACL of the registry.
126
127 Value-Lists
128
129       The value-lists contain information about which values are inside a
130       sub-key and don't have a header.
131
132 Datas
133
134       The datas of the registry are (like the value-list) stored without a
135       header.
136
137 All offset-values are relative to the first hbin-block and point to the
138 block-size field of the record-entry. to get the file offset, you have to add
139 the header size (4kb) and the size field (4 bytes)...
140
141 the nk-Record
142 =============
143 Offset      Size      Contents
144 0x0000      Word      ID: ASCII-"nk" = 0x6B6E
145 0x0002      Word      for the root-key: 0x2C, otherwise 0x20  //key symbolic links 0x10. Nigel
146 0x0004      Q-Word      write-date/time in windows nt notation
147 0x0010      D-Word      Offset of Owner/Parent key
148 0x0014      D-Word      number of sub-Keys
149 0x001C      D-Word      Offset of the sub-key lf-Records
150 0x0024      D-Word      number of values
151 0x0028      D-Word      Offset of the Value-List
152 0x002C      D-Word      Offset of the sk-Record
153
154 0x0030      D-Word      Offset of the Class-Name //see NK structure for the use of these fields. Nigel
155 0x0044      D-Word      Unused (data-trash)  //some kind of run time index. Does not appear to be important. Nigel
156 0x0048      Word      name-length
157 0x004A      Word      class-name length
158 0x004C      ????      key-name
159
160 the Value-List
161 ==============
162 Offset      Size      Contents
163 0x0000      D-Word      Offset 1st Value
164 0x0004      D-Word      Offset 2nd Value
165 0x????      D-Word      Offset nth Value
166
167 To determine the number of values, you have to look at the owner-nk-record!
168
169 The vk-Record
170 =============
171 Offset      Size      Contents
172 0x0000      Word      ID: ASCII-"vk" = 0x6B76
173 0x0002      Word      name length
174 0x0004      D-Word      length of the data   //if top bit is set when offset contains data. Nigel
175 0x0008      D-Word      Offset of Data
176 0x000C      D-Word      Type of value
177 0x0010      Word      Flag
178 0x0012      Word      Unused (data-trash)
179 0x0014      ????      Name
180
181 If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default)
182
183 If the data-size is lower 5, the data-offset value is used to store the data itself!
184
185 The data-types
186 ==============
187 Wert      Beteutung
188 0x0001      RegSZ:             character string (in UNICODE!)
189 0x0002      ExpandSZ:   string with "%var%" expanding (UNICODE!)
190 0x0003      RegBin:           raw-binary value
191 0x0004      RegDWord:   Dword
192 0x0007      RegMultiSZ:      multiple strings, seperated with 0
193                   (UNICODE!)
194
195 The "lf"-record
196 ===============
197 Offset      Size      Contents
198 0x0000      Word      ID: ASCII-"lf" = 0x666C
199 0x0002      Word      number of keys
200 0x0004      ????      Hash-Records
201
202 Hash-Record
203 ===========
204 Offset      Size      Contents
205 0x0000      D-Word      Offset of corresponding "nk"-Record
206 0x0004      D-Word      ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv!
207
208 Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the 
209 key-name you have to change the hash-value too!
210
211 //These hashrecords must be sorted low to high within the lf record. Nigel.
212
213 The "sk"-block
214 ==============
215 (due to the complexity of the SAM-info, not clear jet)
216 (This is just a self-relative security descriptor in the data. R Sharpe.) 
217
218
219 Offset      Size      Contents
220 0x0000      Word      ID: ASCII-"sk" = 0x6B73
221 0x0002      Word      Unused
222 0x0004      D-Word      Offset of previous "sk"-Record
223 0x0008      D-Word      Offset of next "sk"-Record
224 0x000C      D-Word      usage-counter
225 0x0010      D-Word      Size of "sk"-record in bytes
226 ????                                             //standard self
227 relative security desciptor. Nigel
228 ????  ????      Security and auditing settings...
229 ????
230
231 The usage counter counts the number of references to this
232 "sk"-record. You can use one "sk"-record for the entire registry!
233
234 Windows nt date/time format
235 ===========================
236 The time-format is a 64-bit integer which is incremented every
237 0,0000001 seconds by 1 (I don't know how accurate it realy is!)
238 It starts with 0 at the 1st of january 1601 0:00! All values are
239 stored in GMT time! The time-zone is important to get the real
240 time!
241
242 Common values for win95 and win-nt
243 ==================================
244 Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF).
245 If a value has no name (length=0, flag(bit 0)=0), it is treated as the
246 "Default" entry...
247 If a value has no data (length=0), it is displayed as empty.
248
249 simplyfied win-3.?? registry:
250 =============================
251
252 +-----------+
253 | next rec. |---+                      +----->+------------+
254 | first sub |   |                      |      | Usage cnt. |
255 | name      |   |  +-->+------------+  |      | length     |
256 | value     |   |  |   | next rec.  |  |      | text       |------->+-------+
257 +-----------+   |  |   | name rec.  |--+      +------------+        | xxxxx |
258    +------------+  |   | value rec. |-------->+------------+        +-------+
259    v               |   +------------+         | Usage cnt. |
260 +-----------+      |                          | length     |
261 | next rec. |      |                          | text       |------->+-------+
262 | first sub |------+                          +------------+        | xxxxx |
263 | name      |                                                       +-------+
264 | value     |
265 +-----------+    
266
267 Greatly simplyfied structure of the nt-registry:
268 ================================================
269    
270 +---------------------------------------------------------------+
271 |                                                               |
272 v                                                               |
273 +---------+     +---------->+-----------+  +----->+---------+   |
274 | "nk"    |     |           | lf-rec.   |  |      | nk-rec. |   |
275 | ID      |     |           | # of keys |  |      | parent  |---+
276 | Date    |     |           | 1st key   |--+      | ....    |
277 | parent  |     |           +-----------+         +---------+
278 | suk-keys|-----+
279 | values  |--------------------->+----------+
280 | SK-rec. |---------------+      | 1. value |--> +----------+
281 | class   |--+            |      +----------+    | vk-rec.  |
282 +---------+  |            |                      | ....     |
283              v            |                      | data     |--> +-------+
284       +------------+      |                      +----------+    | xxxxx |
285       | Class name |      |                                      +-------+
286       +------------+      |
287                           v
288           +---------+    +---------+
289    +----->| next sk |--->| Next sk |--+
290    |  +---| prev sk |<---| prev sk |  |
291    |  |   | ....    |    | ...     |  |
292    |  |   +---------+    +---------+  |
293    |  |                    ^          |
294    |  |                    |          |
295    |  +--------------------+          |
296    +----------------------------------+
297
298 ---------------------------------------------------------------------------
299
300 Hope this helps....  (Although it was "fun" for me to uncover this things,
301                   it took me several sleepless nights ;)
302
303             B.D.
304
305 *************************************************************************/
306
307 #include "includes.h"
308 #include "registry.h"
309 #include "system/filesys.h"
310 #include "system/shmem.h"
311
312 #define REG_KEY_LIST_SIZE 10
313 #define FLAG_HAS_NAME     0x01
314 /*FIXME*/
315
316 /*
317  * Structures for dealing with the on-disk format of the registry
318  */
319
320 const char *def_owner_sid_str = NULL;
321
322 /* 
323  * These definitions are for the in-memory registry structure.
324  * It is a tree structure that mimics what you see with tools like regedit
325  */
326
327
328 /*
329  * Definition of a Key. It has a name, classname, date/time last modified,
330  * sub-keys, values, and a security descriptor
331  */
332
333 #define REG_ROOT_KEY 1
334 #define REG_SUB_KEY  2
335 #define REG_SYM_LINK 3
336
337 /* 
338  * All of the structures below actually have a four-byte length before them
339  * which always seems to be negative. The following macro retrieves that
340  * size as an integer
341  */
342
343 #define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1))
344
345 typedef struct sk_struct SK_HDR;
346 /*
347  * This structure keeps track of the output format of the registry
348  */
349 #define REG_OUTBLK_HDR 1
350 #define REG_OUTBLK_HBIN 2
351
352 typedef struct regf_block {
353         uint32_t REGF_ID;     /* regf */
354         uint32_t update_counter1;
355         uint32_t update_counter2;
356         uint32_t tim1, tim2;
357         uint32_t uk3;             /* 1 */
358         uint32_t uk4;             /* 3 */
359         uint32_t uk5;             /* 0 */
360         uint32_t uk6;             /* 1 */
361         uint32_t first_key;       /* offset */
362         uint32_t dblk_size;
363     uint32_t uk7;        /* 1 */
364         wchar_t filename[64];
365         uint32_t unused[83];
366     uint32_t chksum;                    /* Checksum of first 0x200 bytes */
367 } REGF_HDR;
368
369 typedef struct hbin_sub_struct {
370         uint32_t dblocksize;
371         char data[1];
372 } HBIN_SUB_HDR;
373
374 typedef struct hbin_struct {
375         uint32_t HBIN_ID; /* hbin */
376         uint32_t off_from_first;
377         uint32_t off_to_next;
378         uint32_t uk1;
379         uint32_t uk2;
380         uint32_t uk3;
381         uint32_t uk4;
382         uint32_t blk_size;
383         HBIN_SUB_HDR hbin_sub_hdr;
384 } HBIN_HDR;
385
386 typedef struct nk_struct {
387         uint16_t NK_ID;
388         uint16_t type;
389         uint32_t t1, t2;
390         uint32_t uk1;
391         uint32_t own_off;
392         uint32_t subk_num;
393         uint32_t uk2;
394         uint32_t lf_off;
395         uint32_t uk3;
396         uint32_t val_cnt;
397         uint32_t val_off;
398         uint32_t sk_off;
399         uint32_t clsnam_off;
400         uint32_t unk4[4];
401         uint32_t unk5;
402         uint16_t nam_len;
403         uint16_t clsnam_len;
404         char key_nam[1];  /* Actual length determined by nam_len */
405 } NK_HDR;
406
407 struct sk_struct {
408         uint16_t SK_ID;
409         uint16_t uk1;
410         uint32_t prev_off;
411         uint32_t next_off;
412         uint32_t ref_cnt;
413         uint32_t rec_size;
414         char sec_desc[1];
415 };
416
417 typedef struct key_sec_desc_s {
418         struct key_sec_desc_s *prev, *next;
419         int ref_cnt;
420         int state;
421         int offset;
422         SK_HDR *sk_hdr;     /* This means we must keep the registry in memory */
423         struct security_descriptor *sec_desc;
424 } KEY_SEC_DESC; 
425
426 /* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */
427 typedef struct sk_map_s {
428   int sk_off;
429   KEY_SEC_DESC *key_sec_desc;
430 } SK_MAP;
431
432 typedef struct vk_struct {
433   uint16_t VK_ID;
434   uint16_t nam_len;
435   uint32_t dat_len;    /* If top-bit set, offset contains the data */
436   uint32_t dat_off;
437   uint32_t dat_type;
438   uint16_t flag;        /* =1, has name, else no name (=Default). */
439   uint16_t unk1;
440   char dat_name[1]; /* Name starts here ... */
441 } VK_HDR;
442
443 typedef uint32_t VL_TYPE[1];  /* Value list is an array of vk rec offsets */
444                                                                                 
445 typedef struct hash_struct {
446   uint32_t nk_off;
447   char hash[4];
448 } HASH_REC;
449
450
451 typedef struct lf_struct {
452   uint16_t LF_ID;
453   uint16_t key_count;
454   struct hash_struct hr[1];  /* Array of hash records, depending on key_count */} LF_HDR;
455
456
457
458 /*
459  * This structure keeps track of the output format of the registry
460  */
461 #define REG_OUTBLK_HDR 1
462 #define REG_OUTBLK_HBIN 2
463
464 typedef struct hbin_blk_s {
465   int type, size;
466   struct hbin_blk_s *next;
467   char *data;                /* The data block                */
468   uint_t file_offset;  /* Offset in file                */
469   uint_t free_space;   /* Amount of free space in block */
470   uint_t fsp_off;      /* Start of free space in block  */
471   int complete, stored;
472 } HBIN_BLK;
473
474 typedef struct regf_struct_s {
475         int reg_type;
476         int fd;
477         struct stat sbuf;
478         char *base;
479         BOOL modified;
480         NTTIME last_mod_time;
481         NK_HDR *first_key;
482         int sk_count, sk_map_size;
483         SK_MAP *sk_map;
484         const char *owner_sid_str;
485         struct security_descriptor *def_sec_desc;
486         /*
487          * These next pointers point to the blocks used to contain the 
488          * keys when we are preparing to write them to a file
489          */
490         HBIN_BLK *blk_head, *blk_tail, *free_space;
491 } REGF;
492
493 static uint32_t str_to_dword(const char *a) {
494         int i;
495         unsigned long ret = 0;
496         for(i = strlen(a)-1; i >= 0; i--) {
497                 ret = ret * 0x100 + a[i];
498         }
499         return ret;
500 }
501
502 #if 0
503
504 /*
505  * Create an ACE
506  */
507 static BOOL nt_create_ace(SEC_ACE *ace, int type, int flags, uint32_t perms, const char *sid)
508 {
509   DOM_SID s;
510   SEC_ACCESS access;
511   access.mask = perms;
512   if(!string_to_sid(&s, sid))return False;
513   init_sec_ace(ace, &s, type, access, flags);
514   return True;
515 }
516
517 /*
518  * Create a default ACL
519  */
520 static SEC_ACL *nt_create_default_acl(struct registry_hive *regf)
521 {
522   SEC_ACE aces[8];
523
524   if(!nt_create_ace(&aces[0], 0x00, 0x0, 0xF003F, regf->owner_sid_str)) return NULL;
525   if(!nt_create_ace(&aces[1], 0x00, 0x0, 0xF003F, "S-1-5-18")) return NULL;
526   if(!nt_create_ace(&aces[2], 0x00, 0x0, 0xF003F, "S-1-5-32-544")) return NULL;
527   if(!nt_create_ace(&aces[3], 0x00, 0x0, 0x20019, "S-1-5-12")) return NULL;
528   if(!nt_create_ace(&aces[4], 0x00, 0x0B, GENERIC_RIGHT_ALL_ACCESS, regf->owner_sid_str)) return NULL;
529   if(!nt_create_ace(&aces[5], 0x00, 0x0B, 0x10000000, "S-1-5-18")) return NULL;
530   if(!nt_create_ace(&aces[6], 0x00, 0x0B, 0x10000000, "S-1-5-32-544")) return NULL;
531   if(!nt_create_ace(&aces[7], 0x00, 0x0B, 0x80000000, "S-1-5-12")) return NULL;
532
533   return make_sec_acl(regf->mem_ctx, 2, 8, aces);
534 }
535
536 /*
537  * Create a default security descriptor. We pull in things from env
538  * if need be 
539  */
540 static SEC_DESC *nt_create_def_sec_desc(struct registry_hive *regf)
541 {
542   SEC_DESC *tmp;
543
544   tmp = malloc_p(SEC_DESC);
545
546   tmp->revision = 1;
547   tmp->type = SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT;
548   if (!string_to_sid(tmp->owner_sid, "S-1-5-32-544")) goto error;
549   if (!string_to_sid(tmp->grp_sid, "S-1-5-18")) goto error;
550   tmp->sacl = NULL;
551   tmp->dacl = nt_create_default_acl(regf);
552
553   return tmp;
554
555  error:
556   if (tmp) nt_delete_sec_desc(tmp);
557   return NULL;
558 }
559
560 /*
561  * We will implement inheritence that is based on what the parent's SEC_DESC
562  * says, but the Owner and Group SIDs can be overwridden from the command line
563  * and additional ACEs can be applied from the command line etc.
564  */
565 static KEY_SEC_DESC *nt_inherit_security(struct registry_key *key)
566 {
567
568   if (!key) return NULL;
569   return key->security;
570 }
571
572 /*
573  * Create an initial security descriptor and init other structures, if needed
574  * We assume that the initial security stuff is empty ...
575  */
576 static KEY_SEC_DESC *nt_create_init_sec(struct registry_hive *h)
577 {
578         REGF *regf = h->backend_data;
579         KEY_SEC_DESC *tsec = NULL;
580
581         tsec = malloc_p(KEY_SEC_DESC);
582
583         tsec->ref_cnt = 1;
584         tsec->state = SEC_DESC_NBK;
585         tsec->offset = 0;
586
587         tsec->sec_desc = regf->def_sec_desc;
588
589         return tsec;
590 }
591 #endif
592
593 /*
594  * Get the starting record for NT Registry file 
595  */
596
597 /* 
598  * Where we keep all the regf stuff for one registry.
599  * This is the structure that we use to tie the in memory tree etc 
600  * together. By keeping separate structs, we can operate on different
601  * registries at the same time.
602  * Currently, the SK_MAP is an array of mapping structure.
603  * Since we only need this on input and output, we fill in the structure
604  * as we go on input. On output, we know how many SK items we have, so
605  * we can allocate the structure as we need to.
606  * If you add stuff here that is dynamically allocated, add the 
607  * appropriate free statements below.
608  */
609
610 #define REG_HANDLE_REGTYPE_NONE 0
611 #define REG_HANDLE_REGTYPE_NT   1
612 #define REG_HANDLE_REGTYPE_W9X  2
613
614 #define TTTONTTIME(r, t1, t2) (r)->last_mod_time = (t1) | (((uint64_t)(t2)) << 32)
615
616 #define REGF_HDR_BLKSIZ 0x1000 
617
618 #define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4) 
619 #define LOCN(base, f) ((base) + OFF(f))
620
621 /* Get the header of the registry. Return a pointer to the structure 
622  * If the mmap'd area has not been allocated, then mmap the input file
623  */
624 static REGF_HDR *nt_get_regf_hdr(struct registry_hive *h)
625 {
626         REGF *regf = h->backend_data;
627         SMB_ASSERT(regf);
628
629         if (!regf->base) { /* Try to mmap etc the file */
630
631                 if ((regf->fd = open(h->location, O_RDONLY, 0000)) <0) {
632                         return NULL; /* What about errors? */
633                 }
634
635                 if (fstat(regf->fd, &regf->sbuf) < 0) {
636                         return NULL;
637                 }
638
639                 regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0);
640
641                 if ((int)regf->base == 1) {
642                         DEBUG(0,("Could not mmap file: %s, %s\n", h->location,
643                                          strerror(errno)));
644                         return NULL;
645                 }
646         }
647
648         /* 
649          * At this point, regf->base != NULL, and we should be able to read the 
650          * header 
651          */
652
653         SMB_ASSERT(regf->base != NULL);
654
655         return (REGF_HDR *)regf->base;
656 }
657
658 /*
659  * Validate a regf header
660  * For now, do nothing, but we should check the checksum
661  */
662 static int valid_regf_hdr(REGF_HDR *regf_hdr)
663 {
664         if (!regf_hdr) return 0;
665
666         return 1;
667 }
668
669 #if 0
670
671 /*
672  * Process an SK header ...
673  * Every time we see a new one, add it to the map. Otherwise, just look it up.
674  * We will do a simple linear search for the moment, since many KEYs have the 
675  * same security descriptor. 
676  * We allocate the map in increments of 10 entries.
677  */
678
679 /*
680  * Create a new entry in the map, and increase the size of the map if needed
681  */
682 static SK_MAP *alloc_sk_map_entry(struct registry_hive *h, KEY_SEC_DESC *tmp, int sk_off)
683 {
684         REGF *regf = h->backend_data;
685         if (!regf->sk_map) { /* Allocate a block of 10 */
686                 regf->sk_map = malloc_array_p(SK_MAP, 10);
687                 regf->sk_map_size = 10;
688                 regf->sk_count = 1;
689                 (regf->sk_map)[0].sk_off = sk_off;
690                 (regf->sk_map)[0].key_sec_desc = tmp;
691         }
692         else { /* Simply allocate a new slot, unless we have to expand the list */ 
693                 int ndx = regf->sk_count;
694                 if (regf->sk_count >= regf->sk_map_size) {
695                         regf->sk_map = (SK_MAP *)realloc(regf->sk_map, 
696                                                                                          (regf->sk_map_size + 10)*sizeof(SK_MAP));
697                         if (!regf->sk_map) {
698                                 free(tmp);
699                                 return NULL;
700                         }
701                         /*
702                          * ndx already points at the first entry of the new block
703                          */
704                         regf->sk_map_size += 10;
705                 }
706                 (regf->sk_map)[ndx].sk_off = sk_off;
707                 (regf->sk_map)[ndx].key_sec_desc = tmp;
708                 regf->sk_count++;
709         }
710         return regf->sk_map;
711 }
712
713 /*
714  * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not
715  * found
716  */
717 KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off)
718 {
719         int i;
720
721         if (!sk_map) return NULL;
722
723         for (i = 0; i < count; i++) {
724
725                 if (sk_map[i].sk_off == sk_off)
726                         return sk_map[i].key_sec_desc;
727
728         }
729
730         return NULL;
731
732 }
733
734 /*
735  * Allocate a KEY_SEC_DESC if we can't find one in the map
736  */
737 static KEY_SEC_DESC *lookup_create_sec_key(struct registry_hive *h, SK_MAP *sk_map, int sk_off)
738 {
739         REGF *regf = h->backend_data;
740         KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off);
741
742         if (tmp) {
743                 return tmp;
744         }
745         else { /* Allocate a new one */
746                 tmp = malloc_p(KEY_SEC_DESC);
747                 memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */
748                 tmp->state = SEC_DESC_RES;
749                 if (!alloc_sk_map_entry(h, tmp, sk_off)) {
750                         return NULL;
751                 }
752                 return tmp;
753         }
754 }
755
756 static SEC_DESC *process_sec_desc(struct registry_hive *regf, SEC_DESC *sec_desc)
757 {
758         SEC_DESC *tmp = NULL;
759
760         tmp = malloc_p(SEC_DESC);
761
762         tmp->revision = SVAL(&sec_desc->revision,0);
763         tmp->type = SVAL(&sec_desc->type,0);
764         DEBUG(2, ("SEC_DESC Rev: %0X, Type: %0X\n", tmp->revision, tmp->type));
765         DEBUGADD(2, ("SEC_DESC Owner Off: %0X\n", IVAL(&sec_desc->off_owner_sid,0)));
766         DEBUGADD(2, ("SEC_DESC Group Off: %0X\n", IVAL(&sec_desc->off_grp_sid,0)));
767         DEBUGADD(2, ("SEC_DESC DACL Off: %0X\n", IVAL(&sec_desc->off_dacl,0)));
768         tmp->owner_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_owner_sid,0)));
769         if (!tmp->owner_sid) {
770                 free(tmp);
771                 return NULL;
772         }
773         tmp->grp_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_grp_sid,0)));
774         if (!tmp->grp_sid) {
775                 free(tmp);
776                 return NULL;
777         }
778
779         /* Now pick up the SACL and DACL */
780
781         DEBUG(0, ("%d, %d\n", IVAL(&sec_desc->off_sacl,0), IVAL(&sec_desc->off_dacl,0)));
782
783         if (sec_desc->off_sacl)
784                 tmp->sacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_sacl,0)));
785         else
786                 tmp->sacl = NULL;
787
788         if (sec_desc->off_dacl)
789                 tmp->dacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_dacl,0)));
790         else
791                 tmp->dacl = NULL;
792
793         return tmp;
794 }
795
796 static KEY_SEC_DESC *process_sk(struct registry_hive *regf, SK_HDR *sk_hdr, int sk_off, int size)
797 {
798         KEY_SEC_DESC *tmp = NULL;
799         int sk_next_off, sk_prev_off, sk_size;
800         SEC_DESC *sec_desc;
801
802         if (!sk_hdr) return NULL;
803
804         if (SVAL(&sk_hdr->SK_ID,0) != str_to_dword("sk")) {
805                 DEBUG(0, ("Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr,
806                                   regf->regfile_name));
807                 return NULL;
808         }
809
810         if (-size < (sk_size = IVAL(&sk_hdr->rec_size,0))) {
811                 DEBUG(0, ("Incorrect SK record size: %d vs %d. %s\n",
812                                   -size, sk_size, regf->regfile_name));
813                 return NULL;
814         }
815
816         /* 
817          * Now, we need to look up the SK Record in the map, and return it
818          * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can
819          * use that
820          */
821
822         if (regf->sk_map &&
823                 ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL)
824                 && (tmp->state == SEC_DESC_OCU)) {
825                 tmp->ref_cnt++;
826                 return tmp;
827         }
828
829         /* Here, we have an item in the map that has been reserved, or tmp==NULL. */
830
831         SMB_ASSERT(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON));
832
833         /*
834          * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the
835          * new KEY_SEC_DESC to the mapping structure, since the offset supplied is 
836          * the actual offset of structure. The same offset will be used by
837          * all future references to this structure
838          * We could put all this unpleasantness in a function.
839          */
840
841         if (!tmp) {
842                 tmp = malloc_p(KEY_SEC_DESC);
843                 memset(tmp, 0, sizeof(KEY_SEC_DESC));
844
845                 /*
846                  * Allocate an entry in the SK_MAP ...
847                  * We don't need to free tmp, because that is done for us if the
848                  * sm_map entry can't be expanded when we need more space in the map.
849                  */
850
851                 if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
852                         return NULL;
853                 }
854         }
855
856         tmp->ref_cnt++;
857         tmp->state = SEC_DESC_OCU;
858
859         /*
860          * Now, process the actual sec desc and plug the values in
861          */
862
863         sec_desc = (SEC_DESC *)&sk_hdr->sec_desc[0];
864         tmp->sec_desc = process_sec_desc(regf, sec_desc);
865
866         /*
867          * Now forward and back links. Here we allocate an entry in the sk_map
868          * if it does not exist, and mark it reserved
869          */
870
871         sk_prev_off = IVAL(&sk_hdr->prev_off,0);
872         tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off);
873         SMB_ASSERT(tmp->prev != NULL);
874         sk_next_off = IVAL(&sk_hdr->next_off,0);
875         tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off);
876         SMB_ASSERT(tmp->next != NULL);
877
878         return tmp;
879 }
880 #endif
881
882 /*
883  * Process a VK header and return a value
884  */
885 static WERROR vk_to_val(TALLOC_CTX *mem_ctx, struct registry_key *parent, VK_HDR *vk_hdr, int size, struct registry_value **value)
886 {
887         REGF *regf = parent->hive->backend_data;
888         int nam_len, dat_len, flag, dat_type, dat_off, vk_id;
889         struct registry_value *tmp = NULL; 
890
891         if (!vk_hdr) return WERR_INVALID_PARAM;
892
893         if ((vk_id = SVAL(&vk_hdr->VK_ID,0)) != str_to_dword("vk")) {
894                 DEBUG(0, ("Unrecognized VK header ID: %0X, block: %0X, %s\n",
895                                   vk_id, (int)vk_hdr, parent->hive->location));
896                 return WERR_GENERAL_FAILURE;
897         }
898
899         nam_len = SVAL(&vk_hdr->nam_len,0);
900         flag = SVAL(&vk_hdr->flag,0);
901         dat_type = IVAL(&vk_hdr->dat_type,0);
902         dat_len = IVAL(&vk_hdr->dat_len,0);  /* If top bit, offset contains data */
903         dat_off = IVAL(&vk_hdr->dat_off,0);
904
905         tmp = talloc(mem_ctx, struct registry_value);
906         tmp->data_type = dat_type;
907
908         if (flag & FLAG_HAS_NAME) {
909                 tmp->name = talloc_strndup(mem_ctx, vk_hdr->dat_name, nam_len);
910         } else {
911                 tmp->name = NULL;
912         }
913
914         /*
915          * Allocate space and copy the data as a BLOB
916          */
917
918         if (dat_len&0x7FFFFFFF) {
919
920                 char *dtmp = talloc_size(mem_ctx, dat_len&0x7FFFFFFF);
921
922                 if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */
923                         char *dat_ptr = LOCN(regf->base, dat_off);
924                         memcpy(dtmp, dat_ptr, dat_len);
925                 }
926                 else { /* The data is in the offset or type */
927                         /*
928                          * FIXME.
929                          * Some registry files seem to have weird fields. If top bit is set,
930                          * but len is 0, the type seems to be the value ...
931                          * Not sure how to handle this last type for the moment ...
932                          */
933                         dat_len = dat_len & 0x7FFFFFFF;
934                         memcpy(dtmp, &dat_off, dat_len);
935                 }
936
937                 tmp->data = data_blob_talloc(mem_ctx, dtmp, dat_len);
938         }
939
940         *value = tmp;
941         return WERR_OK;
942 }
943
944 #if 0 /* unused */
945
946 static BOOL vl_verify(VL_TYPE vl, int count, int size)
947 {
948         if(!vl) return False;
949         if (-size < (count+1)*sizeof(int)){
950                 DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size));
951                 return False;
952         }
953         return True;
954 }
955
956 #endif
957
958 static WERROR lf_verify(struct registry_hive *h, LF_HDR *lf_hdr, int size)
959 {
960         int lf_id;
961         if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) {
962                 DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n",
963                                   lf_id, (int)lf_hdr, h->location));
964                 return WERR_INVALID_PARAM;
965         }
966         return WERR_OK;
967 }
968
969 static WERROR lf_num_entries(struct registry_hive *h, LF_HDR *lf_hdr, int size, uint32_t *count)
970 {
971         WERROR error;
972
973         error = lf_verify(h, lf_hdr, size);
974         if(!W_ERROR_IS_OK(error)) return error;
975
976         SMB_ASSERT(size < 0);
977
978         *count = SVAL(&lf_hdr->key_count,0);
979         DEBUG(2, ("Key Count: %u\n", *count));
980         if (*count <= 0) return WERR_INVALID_PARAM;
981
982         return WERR_OK;
983 }
984
985
986 static WERROR nk_to_key(TALLOC_CTX *, struct registry_hive *regf, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **);
987
988
989
990 /*
991  * Process an LF Header and return a list of sub-keys
992  */
993 static WERROR lf_get_entry(TALLOC_CTX *mem_ctx, struct registry_key *parent, LF_HDR *lf_hdr, int size, int n, struct registry_key **key)
994 {
995         REGF *regf = parent->hive->backend_data;
996         int count, nk_off;
997         NK_HDR *nk_hdr;
998         WERROR error;
999
1000         if (!lf_hdr) return WERR_INVALID_PARAM;
1001
1002         error = lf_verify(parent->hive, lf_hdr, size);
1003         if(!W_ERROR_IS_OK(error)) return error;
1004
1005         SMB_ASSERT(size < 0);
1006
1007         count = SVAL(&lf_hdr->key_count,0);
1008         DEBUG(2, ("Key Count: %u\n", count));
1009         if (count <= 0) return WERR_GENERAL_FAILURE;
1010         if (n >= count) return WERR_NO_MORE_ITEMS;
1011
1012         nk_off = IVAL(&lf_hdr->hr[n].nk_off,0);
1013         DEBUG(2, ("NK Offset: %0X\n", nk_off));
1014         nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off);
1015         return nk_to_key(mem_ctx, parent->hive, nk_hdr, BLK_SIZE(nk_hdr), parent, key);
1016 }
1017
1018 static WERROR nk_to_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **key)
1019 {
1020         REGF *regf = h->backend_data;
1021         struct registry_key *tmp = NULL, *own;
1022         int namlen, clsname_len, sk_off, own_off;
1023         uint_t nk_id;
1024         SK_HDR *sk_hdr;
1025         int type;
1026         char key_name[1024];
1027
1028         if (!nk_hdr) return WERR_INVALID_PARAM;
1029
1030         if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) {
1031                 DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n", 
1032                                   nk_id, (int)nk_hdr, parent->hive->location));
1033                 return WERR_INVALID_PARAM;
1034         }
1035
1036         SMB_ASSERT(size < 0);
1037
1038         namlen = SVAL(&nk_hdr->nam_len,0);
1039         clsname_len = SVAL(&nk_hdr->clsnam_len,0);
1040
1041         /*
1042          * The value of -size should be ge 
1043          * (sizeof(NK_HDR) - 1 + namlen)
1044          * The -1 accounts for the fact that we included the first byte of 
1045          * the name in the structure. clsname_len is the length of the thing 
1046          * pointed to by clsnam_off
1047          */
1048
1049         if (-size < (sizeof(NK_HDR) - 1 + namlen)) {
1050                 DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr));
1051                 DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n",
1052                           (int)sizeof(NK_HDR), namlen, clsname_len));
1053                 return WERR_GENERAL_FAILURE;
1054         }
1055
1056         DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", namlen, clsname_len));
1057
1058         /* Fish out the key name and process the LF list */
1059
1060         SMB_ASSERT(namlen < sizeof(key_name));
1061
1062         strncpy(key_name, nk_hdr->key_nam, namlen);
1063         key_name[namlen] = '\0';
1064
1065         type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY);
1066         if(type == REG_ROOT_KEY && parent) {
1067                 DEBUG(0,("Root key encountered below root level!\n"));
1068                 return WERR_GENERAL_FAILURE;
1069         }
1070
1071         tmp = talloc(mem_ctx, struct registry_key);
1072         tmp->name = talloc_strdup(mem_ctx, key_name);
1073         tmp->backend_data = nk_hdr;
1074
1075         DEBUG(2, ("Key name: %s\n", key_name));
1076
1077         /*
1078          * Fish out the class name, it is in UNICODE, while the key name is 
1079          * ASCII :-)
1080          */
1081
1082         if (clsname_len) { /* Just print in Ascii for now */
1083                 void *clsnamep;
1084                 int clsnam_off;
1085
1086                 clsnam_off = IVAL(&nk_hdr->clsnam_off,0);
1087                 clsnamep = LOCN(regf->base, clsnam_off);
1088                 DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off));
1089
1090                 pull_ucs2_talloc(mem_ctx, &tmp->class_name, clsnamep);
1091
1092                 DEBUGADD(2,("  Class Name: %s\n", tmp->class_name));
1093
1094         }
1095
1096         /*
1097          * Process the owner offset ...
1098          */
1099
1100         own_off = IVAL(&nk_hdr->own_off,0);
1101         own = (struct registry_key *)LOCN(regf->base, own_off);
1102         DEBUG(2, ("Owner Offset: %0X\n", own_off));
1103
1104         DEBUGADD(2, ("  Owner locn: %0X, Our locn: %0X\n", 
1105                                  (uint_t)own, (uint_t)nk_hdr));
1106
1107         /* 
1108          * We should verify that the owner field is correct ...
1109          * for now, we don't worry ...
1110          */
1111
1112         /* 
1113          * Also handle the SK header ...
1114          */
1115
1116         sk_off = IVAL(&nk_hdr->sk_off,0);
1117         sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off);
1118         DEBUG(2, ("SK Offset: %0X\n", sk_off));
1119
1120         if (sk_off != -1) {
1121
1122 #if 0
1123                 tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr));
1124 #endif
1125
1126         } 
1127
1128         *key = tmp;
1129         return WERR_OK;
1130 }
1131
1132 #if 0 /* unused */
1133
1134 /*
1135  * Allocate a new hbin block, set up the header for the block etc 
1136  */
1137 static HBIN_BLK *nt_create_hbin_blk(struct registry_hive *h, int size)
1138 {
1139         REGF *regf = h->backend_data;
1140         HBIN_BLK *tmp;
1141         HBIN_HDR *hdr;
1142
1143         if (!regf || !size) return NULL;
1144
1145         /* Round size up to multiple of REGF_HDR_BLKSIZ */
1146
1147         size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1);
1148
1149         tmp = malloc_p(HBIN_BLK);
1150         memset(tmp, 0, sizeof(HBIN_BLK));
1151
1152         tmp->data = malloc(size);
1153
1154         memset(tmp->data, 0, size);  /* Make it pristine */
1155
1156         tmp->size = size;
1157         /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/
1158
1159         tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR));
1160         tmp->fsp_off = size - tmp->free_space;
1161
1162         /* 
1163          * Now, build the header in the data block 
1164          */
1165         hdr = (HBIN_HDR *)tmp->data;
1166         hdr->HBIN_ID = str_to_dword("hbin");
1167         hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ;
1168         hdr->off_to_next = tmp->size;
1169         hdr->blk_size = tmp->size;
1170
1171         /*
1172          * Now link it in
1173          */
1174
1175         regf->blk_tail->next = tmp;
1176         regf->blk_tail = tmp;
1177         if (!regf->free_space) regf->free_space = tmp;
1178
1179         return tmp;
1180 }
1181
1182 /*
1183  * Allocate a unit of space ... and return a pointer as function param
1184  * and the block's offset as a side effect
1185  */
1186 static void *nt_alloc_regf_space(struct registry_hive *h, int size, uint_t *off)
1187 {
1188         REGF *regf = h->backend_data;
1189         int tmp = 0;
1190         void *ret = NULL;
1191         HBIN_BLK *blk;
1192
1193         if (!regf || !size || !off) return NULL;
1194
1195         SMB_ASSERT(regf->blk_head != NULL);
1196
1197         /*
1198          * round up size to include header and then to 8-byte boundary
1199          */
1200         size = (size + 4 + 7) & ~7;
1201
1202         /*
1203          * Check if there is space, if none, grab a block
1204          */
1205         if (!regf->free_space) {
1206                 if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ))
1207                         return NULL;
1208         }
1209
1210         /*
1211          * Now, chain down the list of blocks looking for free space
1212          */
1213
1214         for (blk = regf->free_space; blk != NULL; blk = blk->next) {
1215                 if (blk->free_space <= size) {
1216                         tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
1217                         ret = blk->data + blk->fsp_off;
1218                         blk->free_space -= size;
1219                         blk->fsp_off += size;
1220
1221                         /* Insert the header */
1222                         ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
1223
1224                         /*
1225                          * Fix up the free space ptr
1226                          * If it is NULL, we fix it up next time
1227                          */
1228
1229                         if (!blk->free_space) 
1230                                 regf->free_space = blk->next;
1231
1232                         *off = tmp;
1233                         return (((char *)ret)+4);/* The pointer needs to be to the data struct */
1234                 }
1235         }
1236
1237         /*
1238          * If we got here, we need to add another block, which might be 
1239          * larger than one block -- deal with that later
1240          */
1241         if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) {
1242                 blk = regf->free_space;
1243                 tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
1244                 ret = blk->data + blk->fsp_off;
1245                 blk->free_space -= size;
1246                 blk->fsp_off += size;
1247
1248                 /* Insert the header */
1249                 ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
1250
1251                 /*
1252                  * Fix up the free space ptr
1253                  * If it is NULL, we fix it up next time
1254                  */
1255
1256                 if (!blk->free_space) 
1257                         regf->free_space = blk->next;
1258
1259                 *off = tmp;
1260                 return (((char *)ret) + 4);/* The pointer needs to be to the data struct */
1261         }
1262
1263         return NULL;
1264 }
1265
1266 /*
1267  * Store a SID at the location provided
1268  */
1269 static int nt_store_SID(struct registry_hive *regf, DOM_SID *sid, uint8_t *locn)
1270 {
1271         int i;
1272         uint8_t *p = locn;
1273
1274         if (!regf || !sid || !locn) return 0;
1275
1276         *p = sid->sid_rev_num; p++;
1277         *p = sid->num_auths; p++;
1278
1279         for (i=0; i < 6; i++) {
1280                 *p = sid->id_auth[i]; p++;
1281         }
1282
1283         for (i=0; i < sid->num_auths; i++) {
1284                 SIVAL(p, 0, sid->sub_auths[i]); p+=4;
1285         }
1286
1287         return p - locn;
1288
1289 }
1290
1291 static int nt_store_ace(struct registry_hive *regf, SEC_ACE *ace, uint8_t *locn)
1292 {
1293         int size = 0;
1294         SEC_ACE *reg_ace = (SEC_ACE *)locn;
1295         uint8_t *p;
1296
1297         if (!regf || !ace || !locn) return 0;
1298
1299         reg_ace->type = ace->type;
1300         reg_ace->flags = ace->flags;
1301
1302         /* Deal with the length when we have stored the SID */
1303
1304         p = (uint8_t *)&reg_ace->info.mask;
1305
1306         SIVAL(p, 0, ace->info.mask); p += 4;
1307
1308         size = nt_store_SID(regf, &ace->trustee, p);
1309
1310         size += 8; /* Size of the fixed header */
1311
1312         p = (uint8_t *)&reg_ace->size;
1313
1314         SSVAL(p, 0, size);
1315
1316         return size;
1317 }
1318
1319 /*
1320  * Store an ACL at the location provided
1321  */
1322 static int nt_store_acl(struct registry_hive *regf, SEC_ACL *acl, uint8_t *locn) {
1323         int size = 0, i;
1324         uint8_t *p = locn, *s;
1325
1326         if (!regf || !acl || !locn) return 0;
1327
1328         /*
1329          * Now store the header and then the ACEs ...
1330          */
1331
1332         SSVAL(p, 0, acl->revision);
1333
1334         p += 2; s = p; /* Save this for the size field */
1335
1336         p += 2;
1337
1338         SIVAL(p, 0, acl->num_aces);
1339
1340         p += 4;
1341
1342         for (i = 0; i < acl->num_aces; i++) {
1343                 size = nt_store_ace(regf, &acl->ace[i], p);
1344                 p += size;
1345         }
1346
1347         size = s - locn;
1348         SSVAL(s, 0, size);
1349         return size;
1350 }
1351
1352 /*
1353  * Flatten and store the Sec Desc 
1354  * Windows lays out the DACL first, but since there is no SACL, it might be
1355  * that first, then the owner, then the group SID. So, we do it that way
1356  * too.
1357  */
1358 static uint_t nt_store_sec_desc(struct registry_hive *regf, SEC_DESC *sd, char *locn)
1359 {
1360         SEC_DESC *rsd = (SEC_DESC *)locn;
1361         uint_t size = 0, off = 0;
1362
1363         if (!regf || !sd || !locn) return 0;
1364
1365         /* 
1366          * Now, fill in the first two fields, then lay out the various fields
1367          * as needed
1368          */
1369
1370         rsd->revision = SEC_DESC_REVISION;
1371         rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE;  
1372
1373         off = 4 * sizeof(uint32_t) + 4;
1374
1375         if (sd->sacl){
1376                 size = nt_store_acl(regf, sd->sacl, (char *)(locn + off));
1377                 rsd->off_sacl = off;
1378         }
1379         else
1380                 rsd->off_sacl = 0;
1381
1382         off += size;
1383
1384         if (sd->dacl) {
1385                 rsd->off_dacl = off;
1386                 size = nt_store_acl(regf, sd->dacl, (char *)(locn + off));
1387         }
1388         else {
1389                 rsd->off_dacl = 0;
1390         }
1391
1392         off += size;
1393
1394         /* Now the owner and group SIDs */
1395
1396         if (sd->owner_sid) {
1397                 rsd->off_owner_sid = off;
1398                 size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off));
1399         }
1400         else {
1401                 rsd->off_owner_sid = 0;
1402         }
1403
1404         off += size;
1405
1406         if (sd->grp_sid) {
1407                 rsd->off_grp_sid = off;
1408                 size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off));
1409         }
1410         else {
1411                 rsd->off_grp_sid = 0;
1412         }
1413
1414         off += size;
1415
1416         return size;
1417 }
1418
1419 /*
1420  * Store the security information
1421  *
1422  * If it has already been stored, just get its offset from record
1423  * otherwise, store it and record its offset
1424  */
1425 static uint_t nt_store_security(struct registry_hive *regf, KEY_SEC_DESC *sec)
1426 {
1427         int size = 0;
1428         uint_t sk_off;
1429         SK_HDR *sk_hdr;
1430
1431         if (sec->offset) return sec->offset;
1432
1433         /*
1434          * OK, we don't have this one in the file yet. We must compute the 
1435          * size taken by the security descriptor as a self-relative SD, which
1436          * means making one pass over each structure and figuring it out
1437          */
1438
1439 /* FIXME        size = sec_desc_size(sec->sec_desc); */
1440
1441         /* Allocate that much space */
1442
1443         sk_hdr = nt_alloc_regf_space(regf, size, &sk_off);
1444         sec->sk_hdr = sk_hdr;
1445
1446         if (!sk_hdr) return 0;
1447
1448         /* Now, lay out the sec_desc in the space provided */
1449
1450         sk_hdr->SK_ID = str_to_dword("sk");
1451
1452         /* 
1453          * We can't deal with the next and prev offset in the SK_HDRs until the
1454          * whole tree has been stored, then we can go and deal with them
1455          */
1456
1457         sk_hdr->ref_cnt = sec->ref_cnt;
1458         sk_hdr->rec_size = size;       /* Is this correct */
1459
1460         /* Now, lay out the sec_desc */
1461
1462         if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc))
1463                 return 0;
1464
1465         return sk_off;
1466
1467 }
1468
1469 /*
1470  * Store a KEY in the file ...
1471  *
1472  * We store this depth first, and defer storing the lf struct until
1473  * all the sub-keys have been stored.
1474  * 
1475  * We store the NK hdr, any SK header, class name, and VK structure, then
1476  * recurse down the LF structures ... 
1477  * 
1478  * We return the offset of the NK struct
1479  * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ...
1480  */
1481 static int nt_store_reg_key(struct registry_hive *regf, struct registry_key *key)
1482 {
1483         NK_HDR *nk_hdr; 
1484         uint_t nk_off, sk_off, size;
1485
1486         if (!regf || !key) return 0;
1487
1488         size = sizeof(NK_HDR) + strlen(key->name) - 1;
1489         nk_hdr = nt_alloc_regf_space(regf, size, &nk_off);
1490         if (!nk_hdr) goto error;
1491
1492         key->offset = nk_off;  /* We will need this later */
1493
1494         /*
1495          * Now fill in each field etc ...
1496          */
1497
1498         nk_hdr->NK_ID = str_to_dword("nk"); 
1499         if (key->type == REG_ROOT_KEY)
1500                 nk_hdr->type = 0x2C;
1501         else
1502                 nk_hdr->type = 0x20;
1503
1504         /* FIXME: Fill in the time of last update */
1505
1506         if (key->type != REG_ROOT_KEY)
1507                 nk_hdr->own_off = key->owner->offset;
1508
1509         if (key->sub_keys)
1510                 nk_hdr->subk_num = key->sub_keys->key_count;
1511
1512         /*
1513          * Now, process the Sec Desc and then store its offset
1514          */
1515
1516         sk_off = nt_store_security(regf, key->security);
1517         nk_hdr->sk_off = sk_off;
1518
1519         /*
1520          * Then, store the val list and store its offset
1521          */
1522         if (key->values) {
1523                 nk_hdr->val_cnt = key->values->val_count;
1524                 nk_hdr->val_off = nt_store_val_list(regf, key->values);
1525         }
1526         else {
1527                 nk_hdr->val_off = -1;
1528                 nk_hdr->val_cnt = 0;
1529         }
1530
1531         /*
1532          * Finally, store the subkeys, and their offsets
1533          */
1534
1535 error:
1536         return 0;
1537 }
1538
1539 /*
1540  * Store the registry header ...
1541  * We actually create the registry header block and link it to the chain
1542  * of output blocks.
1543  */
1544 static REGF_HDR *nt_get_reg_header(struct registry_hive *h) {
1545         REGF *regf = h->backend_data;
1546         HBIN_BLK *tmp = NULL;
1547
1548         tmp = malloc_p(HBIN_BLK);
1549
1550         memset(tmp, 0, sizeof(HBIN_BLK));
1551         tmp->type = REG_OUTBLK_HDR;
1552         tmp->size = REGF_HDR_BLKSIZ;
1553         tmp->data = malloc(REGF_HDR_BLKSIZ);
1554         if (!tmp->data) goto error;
1555
1556         memset(tmp->data, 0, REGF_HDR_BLKSIZ);  /* Make it pristine, unlike Windows */
1557         regf->blk_head = regf->blk_tail = tmp;
1558
1559         return (REGF_HDR *)tmp->data;
1560
1561 error:
1562         if (tmp) free(tmp);
1563         return NULL;
1564 }
1565
1566 #endif
1567
1568 static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
1569 {
1570         REGF *regf;
1571         REGF_HDR *regf_hdr;
1572         uint_t regf_id, hbin_id;
1573         HBIN_HDR *hbin_hdr;
1574
1575         regf = (REGF *)talloc(h, REGF);
1576         memset(regf, 0, sizeof(REGF));
1577         regf->owner_sid_str = NULL; /* FIXME: Fill in */
1578         h->backend_data = regf;
1579
1580         DEBUG(5, ("Attempting to load registry file\n"));
1581
1582         /* Get the header */
1583
1584         if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) {
1585                 DEBUG(0, ("Unable to get header\n"));
1586                 return WERR_GENERAL_FAILURE;
1587         }
1588
1589         /* Now process that header and start to read the rest in */
1590
1591         if ((regf_id = IVAL(&regf_hdr->REGF_ID,0)) != str_to_dword("regf")) {
1592                 DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n",
1593                                   regf_id, h->location));
1594                 return WERR_GENERAL_FAILURE;
1595         }
1596
1597         /*
1598          * Validate the header ...
1599          */
1600         if (!valid_regf_hdr(regf_hdr)) {
1601                 DEBUG(0, ("Registry file header does not validate: %s\n",
1602                                   h->location));
1603                 return WERR_GENERAL_FAILURE;
1604         }
1605
1606         /* Update the last mod date, and then go get the first NK record and on */
1607
1608         TTTONTTIME(regf, IVAL(&regf_hdr->tim1,0), IVAL(&regf_hdr->tim2,0));
1609
1610         /* 
1611          * The hbin hdr seems to be just uninteresting garbage. Check that
1612          * it is there, but that is all.
1613          */
1614
1615         hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ);
1616
1617         if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) {
1618                 DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", 
1619                                   hbin_id, h->location));
1620                 return WERR_GENERAL_FAILURE;
1621         } 
1622
1623         /*
1624          * Get a pointer to the first key from the hreg_hdr
1625          */
1626
1627         DEBUG(2, ("First Key: %0X\n",
1628                           IVAL(&regf_hdr->first_key, 0)));
1629
1630         regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(&regf_hdr->first_key,0));
1631         DEBUGADD(2, ("First Key Offset: %0X\n", 
1632                                  IVAL(&regf_hdr->first_key, 0)));
1633
1634         DEBUGADD(2, ("Data Block Size: %d\n",
1635                                  IVAL(&regf_hdr->dblk_size, 0)));
1636
1637         DEBUGADD(2, ("Offset to next hbin block: %0X\n",
1638                                  IVAL(&hbin_hdr->off_to_next, 0)));
1639
1640         DEBUGADD(2, ("HBIN block size: %0X\n",
1641                                  IVAL(&hbin_hdr->blk_size, 0)));
1642
1643         /*
1644          * Unmap the registry file, as we might want to read in another
1645          * tree etc.
1646          */
1647
1648         h->backend_data = regf;
1649
1650         return nk_to_key(h, h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key);
1651 }
1652
1653
1654 static WERROR nt_num_subkeys(struct registry_key *k, uint32_t *num) 
1655 {
1656         REGF *regf = k->hive->backend_data;
1657         LF_HDR *lf_hdr;
1658         int lf_off;
1659         NK_HDR *nk_hdr = k->backend_data;
1660         lf_off = IVAL(&nk_hdr->lf_off,0);
1661         DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
1662         if(lf_off == -1) {
1663                 *num = 0;
1664                 return WERR_OK;
1665         }
1666         lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1667
1668         return lf_num_entries(k->hive, lf_hdr, BLK_SIZE(lf_hdr), num);
1669 }
1670
1671 static WERROR nt_num_values(struct registry_key *k, uint32_t *count)
1672 {
1673         NK_HDR *nk_hdr = k->backend_data;
1674         *count = IVAL(&nk_hdr->val_cnt,0);
1675         return WERR_OK;
1676 }
1677
1678 static WERROR nt_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_value **value)
1679 {
1680         VL_TYPE *vl;
1681         int val_off, vk_off;
1682         int val_count;
1683         VK_HDR *vk_hdr;
1684         REGF *regf = k->hive->backend_data;
1685         NK_HDR *nk_hdr = k->backend_data;
1686         val_count = IVAL(&nk_hdr->val_cnt,0);
1687         val_off = IVAL(&nk_hdr->val_off,0);
1688         vl = (VL_TYPE *)LOCN(regf->base, val_off);
1689         DEBUG(2, ("Val List Offset: %0X\n", val_off));
1690         if(n < 0) return WERR_INVALID_PARAM;
1691         if(n >= val_count) return WERR_NO_MORE_ITEMS;
1692
1693         vk_off = IVAL(&vl[n],0);
1694         vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off);
1695         return vk_to_val(mem_ctx, k, vk_hdr, BLK_SIZE(vk_hdr), value);
1696 }
1697
1698 static WERROR nt_key_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_key **subkey)
1699 {
1700         REGF *regf = k->hive->backend_data;
1701         int lf_off;
1702         NK_HDR *nk_hdr = k->backend_data;
1703         LF_HDR *lf_hdr;
1704         lf_off = IVAL(&nk_hdr->lf_off,0);
1705         DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
1706
1707         /*
1708          * No more subkeys if lf_off == -1
1709          */
1710
1711         if (lf_off != -1) {
1712                 lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1713                 return lf_get_entry(mem_ctx, k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey);
1714         }
1715
1716         return WERR_NO_MORE_ITEMS;
1717 }
1718
1719 static struct hive_operations reg_backend_nt4 = {
1720         .name = "nt4",
1721         .open_hive = nt_open_hive,
1722         .num_subkeys = nt_num_subkeys,
1723         .num_values = nt_num_values,
1724         .get_subkey_by_index = nt_key_by_index,
1725         .get_value_by_index = nt_value_by_index,
1726
1727         /* TODO: 
1728         .add_key
1729         .add_value
1730         .del_key
1731         .del_value
1732         .update_value
1733         */
1734 };
1735
1736 NTSTATUS registry_nt4_init(void)
1737 {
1738         return registry_register(&reg_backend_nt4);
1739 }