r5037: got rid of all of the TALLOC_DEPRECATED stuff. My apologies for the
[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-2004 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/shmem.h"
310
311 #define REG_KEY_LIST_SIZE 10
312 #define FLAG_HAS_NAME     0x01
313 /*FIXME*/
314
315 /*
316  * Structures for dealing with the on-disk format of the registry
317  */
318
319 const char *def_owner_sid_str = NULL;
320
321 /* 
322  * These definitions are for the in-memory registry structure.
323  * It is a tree structure that mimics what you see with tools like regedit
324  */
325
326
327 /*
328  * Definition of a Key. It has a name, classname, date/time last modified,
329  * sub-keys, values, and a security descriptor
330  */
331
332 #define REG_ROOT_KEY 1
333 #define REG_SUB_KEY  2
334 #define REG_SYM_LINK 3
335
336 /* 
337  * All of the structures below actually have a four-byte length before them
338  * which always seems to be negative. The following macro retrieves that
339  * size as an integer
340  */
341
342 #define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1))
343
344 typedef uint_t DWORD;
345 typedef unsigned short WORD;
346
347 typedef struct sk_struct SK_HDR;
348 /*
349  * This structure keeps track of the output format of the registry
350  */
351 #define REG_OUTBLK_HDR 1
352 #define REG_OUTBLK_HBIN 2
353
354 typedef struct regf_block {
355         DWORD REGF_ID;     /* regf */
356         DWORD uk1;
357         DWORD uk2;
358         DWORD tim1, tim2;
359         DWORD uk3;             /* 1 */
360         DWORD uk4;             /* 3 */
361         DWORD uk5;             /* 0 */
362         DWORD uk6;             /* 1 */
363         DWORD first_key;       /* offset */
364         uint_t dblk_size;
365     DWORD uk7[116];        /* 1 */
366     DWORD chksum;
367 } REGF_HDR;
368
369 typedef struct hbin_sub_struct {
370         DWORD dblocksize;
371         char data[1];
372 } HBIN_SUB_HDR;
373
374 typedef struct hbin_struct {
375         DWORD HBIN_ID; /* hbin */
376         DWORD off_from_first;
377         DWORD off_to_next;
378         DWORD uk1;
379         DWORD uk2;
380         DWORD uk3;
381         DWORD uk4;
382         DWORD blk_size;
383         HBIN_SUB_HDR hbin_sub_hdr;
384 } HBIN_HDR;
385
386 typedef struct nk_struct {
387         WORD NK_ID;
388         WORD type;
389         DWORD t1, t2;
390         DWORD uk1;
391         DWORD own_off;
392         DWORD subk_num;
393         DWORD uk2;
394         DWORD lf_off;
395         DWORD uk3;
396         DWORD val_cnt;
397         DWORD val_off;
398         DWORD sk_off;
399         DWORD clsnam_off;
400         DWORD unk4[4];
401         DWORD unk5;
402         WORD nam_len;
403         WORD clsnam_len;
404         char key_nam[1];  /* Actual length determined by nam_len */
405 } NK_HDR;
406
407 struct sk_struct {
408         WORD SK_ID;
409         WORD uk1;
410         DWORD prev_off;
411         DWORD next_off;
412         DWORD ref_cnt;
413         DWORD 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   WORD VK_ID;
434   WORD nam_len;
435   DWORD dat_len;    /* If top-bit set, offset contains the data */
436   DWORD dat_off;
437   DWORD dat_type;
438   WORD flag;        /* =1, has name, else no name (=Default). */
439   WORD unk1;
440   char dat_name[1]; /* Name starts here ... */
441 } VK_HDR;
442
443 typedef DWORD VL_TYPE[1];  /* Value list is an array of vk rec offsets */
444                                                                                 
445 typedef struct hash_struct {
446   DWORD nk_off;
447   char hash[4];
448 } HASH_REC;
449
450
451 typedef struct lf_struct {
452   WORD LF_ID;
453   WORD 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 DWORD 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_REG_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_REG_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_REG_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_REG_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_REG_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
938                 tmp->data_blk = dtmp;
939                 tmp->data_len = dat_len;
940         }
941
942         *value = tmp;
943         return WERR_OK;
944 }
945
946 #if 0 /* unused */
947
948 static BOOL vl_verify(VL_TYPE vl, int count, int size)
949 {
950         if(!vl) return False;
951         if (-size < (count+1)*sizeof(int)){
952                 DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size));
953                 return False;
954         }
955         return True;
956 }
957
958 #endif
959
960 static WERROR lf_verify(struct registry_hive *h, LF_HDR *lf_hdr, int size)
961 {
962         int lf_id;
963         if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) {
964                 DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n",
965                                   lf_id, (int)lf_hdr, h->location));
966                 return WERR_INVALID_PARAM;
967         }
968         return WERR_OK;
969 }
970
971 static WERROR lf_num_entries(struct registry_hive *h, LF_HDR *lf_hdr, int size, int *count)
972 {
973         WERROR error;
974
975         error = lf_verify(h, lf_hdr, size);
976         if(!W_ERROR_IS_OK(error)) return error;
977
978         SMB_REG_ASSERT(size < 0);
979
980         *count = SVAL(&lf_hdr->key_count,0);
981         DEBUG(2, ("Key Count: %u\n", *count));
982         if (*count <= 0) return WERR_INVALID_PARAM;
983
984         return WERR_OK;
985 }
986
987
988 static WERROR nk_to_key(TALLOC_CTX *, struct registry_hive *regf, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **);
989
990
991
992 /*
993  * Process an LF Header and return a list of sub-keys
994  */
995 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)
996 {
997         REGF *regf = parent->hive->backend_data;
998         int count, nk_off;
999         NK_HDR *nk_hdr;
1000         WERROR error;
1001
1002         if (!lf_hdr) return WERR_INVALID_PARAM;
1003
1004         error = lf_verify(parent->hive, lf_hdr, size);
1005         if(!W_ERROR_IS_OK(error)) return error;
1006
1007         SMB_REG_ASSERT(size < 0);
1008
1009         count = SVAL(&lf_hdr->key_count,0);
1010         DEBUG(2, ("Key Count: %u\n", count));
1011         if (count <= 0) return WERR_GENERAL_FAILURE;
1012         if (n >= count) return WERR_NO_MORE_ITEMS;
1013
1014         nk_off = IVAL(&lf_hdr->hr[n].nk_off,0);
1015         DEBUG(2, ("NK Offset: %0X\n", nk_off));
1016         nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off);
1017         return nk_to_key(mem_ctx, parent->hive, nk_hdr, BLK_SIZE(nk_hdr), parent, key);
1018 }
1019
1020 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)
1021 {
1022         REGF *regf = h->backend_data;
1023         struct registry_key *tmp = NULL, *own;
1024         int namlen, clsname_len, sk_off, own_off;
1025         uint_t nk_id;
1026         SK_HDR *sk_hdr;
1027         int type;
1028         char key_name[1024];
1029
1030         if (!nk_hdr) return WERR_INVALID_PARAM;
1031
1032         if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) {
1033                 DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n", 
1034                                   nk_id, (int)nk_hdr, parent->hive->location));
1035                 return WERR_INVALID_PARAM;
1036         }
1037
1038         SMB_REG_ASSERT(size < 0);
1039
1040         namlen = SVAL(&nk_hdr->nam_len,0);
1041         clsname_len = SVAL(&nk_hdr->clsnam_len,0);
1042
1043         /*
1044          * The value of -size should be ge 
1045          * (sizeof(NK_HDR) - 1 + namlen)
1046          * The -1 accounts for the fact that we included the first byte of 
1047          * the name in the structure. clsname_len is the length of the thing 
1048          * pointed to by clsnam_off
1049          */
1050
1051         if (-size < (sizeof(NK_HDR) - 1 + namlen)) {
1052                 DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr));
1053                 DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n",
1054                                   sizeof(NK_HDR), namlen, clsname_len));
1055                 return WERR_GENERAL_FAILURE;
1056         }
1057
1058         DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", namlen, clsname_len));
1059
1060         /* Fish out the key name and process the LF list */
1061
1062         SMB_REG_ASSERT(namlen < sizeof(key_name));
1063
1064         strncpy(key_name, nk_hdr->key_nam, namlen);
1065         key_name[namlen] = '\0';
1066
1067         type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY);
1068         if(type == REG_ROOT_KEY && parent) {
1069                 DEBUG(0,("Root key encountered below root level!\n"));
1070                 return WERR_GENERAL_FAILURE;
1071         }
1072
1073         tmp = talloc(mem_ctx, struct registry_key);
1074         tmp->name = talloc_strdup(mem_ctx, key_name);
1075         tmp->backend_data = nk_hdr;
1076
1077         DEBUG(2, ("Key name: %s\n", key_name));
1078
1079         /*
1080          * Fish out the class name, it is in UNICODE, while the key name is 
1081          * ASCII :-)
1082          */
1083
1084         if (clsname_len) { /* Just print in Ascii for now */
1085                 void *clsnamep;
1086                 int clsnam_off;
1087
1088                 clsnam_off = IVAL(&nk_hdr->clsnam_off,0);
1089                 clsnamep = LOCN(regf->base, clsnam_off);
1090                 DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off));
1091
1092                 pull_ucs2_talloc(mem_ctx, &tmp->class_name, clsnamep);
1093
1094                 DEBUGADD(2,("  Class Name: %s\n", tmp->class_name));
1095
1096         }
1097
1098         /*
1099          * Process the owner offset ...
1100          */
1101
1102         own_off = IVAL(&nk_hdr->own_off,0);
1103         own = (struct registry_key *)LOCN(regf->base, own_off);
1104         DEBUG(2, ("Owner Offset: %0X\n", own_off));
1105
1106         DEBUGADD(2, ("  Owner locn: %0X, Our locn: %0X\n", 
1107                                  (uint_t)own, (uint_t)nk_hdr));
1108
1109         /* 
1110          * We should verify that the owner field is correct ...
1111          * for now, we don't worry ...
1112          */
1113
1114         /* 
1115          * Also handle the SK header ...
1116          */
1117
1118         sk_off = IVAL(&nk_hdr->sk_off,0);
1119         sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off);
1120         DEBUG(2, ("SK Offset: %0X\n", sk_off));
1121
1122         if (sk_off != -1) {
1123
1124 #if 0
1125                 tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr));
1126 #endif
1127
1128         } 
1129
1130         *key = tmp;
1131         return WERR_OK;
1132 }
1133
1134 #if 0 /* unused */
1135
1136 /*
1137  * Allocate a new hbin block, set up the header for the block etc 
1138  */
1139 static HBIN_BLK *nt_create_hbin_blk(struct registry_hive *h, int size)
1140 {
1141         REGF *regf = h->backend_data;
1142         HBIN_BLK *tmp;
1143         HBIN_HDR *hdr;
1144
1145         if (!regf || !size) return NULL;
1146
1147         /* Round size up to multiple of REGF_HDR_BLKSIZ */
1148
1149         size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1);
1150
1151         tmp = malloc_p(HBIN_BLK);
1152         memset(tmp, 0, sizeof(HBIN_BLK));
1153
1154         tmp->data = malloc(size);
1155
1156         memset(tmp->data, 0, size);  /* Make it pristine */
1157
1158         tmp->size = size;
1159         /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/
1160
1161         tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR));
1162         tmp->fsp_off = size - tmp->free_space;
1163
1164         /* 
1165          * Now, build the header in the data block 
1166          */
1167         hdr = (HBIN_HDR *)tmp->data;
1168         hdr->HBIN_ID = str_to_dword("hbin");
1169         hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ;
1170         hdr->off_to_next = tmp->size;
1171         hdr->blk_size = tmp->size;
1172
1173         /*
1174          * Now link it in
1175          */
1176
1177         regf->blk_tail->next = tmp;
1178         regf->blk_tail = tmp;
1179         if (!regf->free_space) regf->free_space = tmp;
1180
1181         return tmp;
1182 }
1183
1184 /*
1185  * Allocate a unit of space ... and return a pointer as function param
1186  * and the block's offset as a side effect
1187  */
1188 static void *nt_alloc_regf_space(struct registry_hive *h, int size, uint_t *off)
1189 {
1190         REGF *regf = h->backend_data;
1191         int tmp = 0;
1192         void *ret = NULL;
1193         HBIN_BLK *blk;
1194
1195         if (!regf || !size || !off) return NULL;
1196
1197         SMB_REG_ASSERT(regf->blk_head != NULL);
1198
1199         /*
1200          * round up size to include header and then to 8-byte boundary
1201          */
1202         size = (size + 4 + 7) & ~7;
1203
1204         /*
1205          * Check if there is space, if none, grab a block
1206          */
1207         if (!regf->free_space) {
1208                 if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ))
1209                         return NULL;
1210         }
1211
1212         /*
1213          * Now, chain down the list of blocks looking for free space
1214          */
1215
1216         for (blk = regf->free_space; blk != NULL; blk = blk->next) {
1217                 if (blk->free_space <= size) {
1218                         tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
1219                         ret = blk->data + blk->fsp_off;
1220                         blk->free_space -= size;
1221                         blk->fsp_off += size;
1222
1223                         /* Insert the header */
1224                         ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
1225
1226                         /*
1227                          * Fix up the free space ptr
1228                          * If it is NULL, we fix it up next time
1229                          */
1230
1231                         if (!blk->free_space) 
1232                                 regf->free_space = blk->next;
1233
1234                         *off = tmp;
1235                         return (((char *)ret)+4);/* The pointer needs to be to the data struct */
1236                 }
1237         }
1238
1239         /*
1240          * If we got here, we need to add another block, which might be 
1241          * larger than one block -- deal with that later
1242          */
1243         if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) {
1244                 blk = regf->free_space;
1245                 tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
1246                 ret = blk->data + blk->fsp_off;
1247                 blk->free_space -= size;
1248                 blk->fsp_off += size;
1249
1250                 /* Insert the header */
1251                 ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
1252
1253                 /*
1254                  * Fix up the free space ptr
1255                  * If it is NULL, we fix it up next time
1256                  */
1257
1258                 if (!blk->free_space) 
1259                         regf->free_space = blk->next;
1260
1261                 *off = tmp;
1262                 return (((char *)ret) + 4);/* The pointer needs to be to the data struct */
1263         }
1264
1265         return NULL;
1266 }
1267
1268 /*
1269  * Store a SID at the location provided
1270  */
1271 static int nt_store_SID(struct registry_hive *regf, DOM_SID *sid, uint8_t *locn)
1272 {
1273         int i;
1274         uint8_t *p = locn;
1275
1276         if (!regf || !sid || !locn) return 0;
1277
1278         *p = sid->sid_rev_num; p++;
1279         *p = sid->num_auths; p++;
1280
1281         for (i=0; i < 6; i++) {
1282                 *p = sid->id_auth[i]; p++;
1283         }
1284
1285         for (i=0; i < sid->num_auths; i++) {
1286                 SIVAL(p, 0, sid->sub_auths[i]); p+=4;
1287         }
1288
1289         return p - locn;
1290
1291 }
1292
1293 static int nt_store_ace(struct registry_hive *regf, SEC_ACE *ace, uint8_t *locn)
1294 {
1295         int size = 0;
1296         SEC_ACE *reg_ace = (SEC_ACE *)locn;
1297         uint8_t *p;
1298
1299         if (!regf || !ace || !locn) return 0;
1300
1301         reg_ace->type = ace->type;
1302         reg_ace->flags = ace->flags;
1303
1304         /* Deal with the length when we have stored the SID */
1305
1306         p = (uint8_t *)&reg_ace->info.mask;
1307
1308         SIVAL(p, 0, ace->info.mask); p += 4;
1309
1310         size = nt_store_SID(regf, &ace->trustee, p);
1311
1312         size += 8; /* Size of the fixed header */
1313
1314         p = (uint8_t *)&reg_ace->size;
1315
1316         SSVAL(p, 0, size);
1317
1318         return size;
1319 }
1320
1321 /*
1322  * Store an ACL at the location provided
1323  */
1324 static int nt_store_acl(struct registry_hive *regf, SEC_ACL *acl, uint8_t *locn) {
1325         int size = 0, i;
1326         uint8_t *p = locn, *s;
1327
1328         if (!regf || !acl || !locn) return 0;
1329
1330         /*
1331          * Now store the header and then the ACEs ...
1332          */
1333
1334         SSVAL(p, 0, acl->revision);
1335
1336         p += 2; s = p; /* Save this for the size field */
1337
1338         p += 2;
1339
1340         SIVAL(p, 0, acl->num_aces);
1341
1342         p += 4;
1343
1344         for (i = 0; i < acl->num_aces; i++) {
1345                 size = nt_store_ace(regf, &acl->ace[i], p);
1346                 p += size;
1347         }
1348
1349         size = s - locn;
1350         SSVAL(s, 0, size);
1351         return size;
1352 }
1353
1354 /*
1355  * Flatten and store the Sec Desc 
1356  * Windows lays out the DACL first, but since there is no SACL, it might be
1357  * that first, then the owner, then the group SID. So, we do it that way
1358  * too.
1359  */
1360 static uint_t nt_store_sec_desc(struct registry_hive *regf, SEC_DESC *sd, char *locn)
1361 {
1362         SEC_DESC *rsd = (SEC_DESC *)locn;
1363         uint_t size = 0, off = 0;
1364
1365         if (!regf || !sd || !locn) return 0;
1366
1367         /* 
1368          * Now, fill in the first two fields, then lay out the various fields
1369          * as needed
1370          */
1371
1372         rsd->revision = SEC_DESC_REVISION;
1373         rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE;  
1374
1375         off = 4 * sizeof(DWORD) + 4;
1376
1377         if (sd->sacl){
1378                 size = nt_store_acl(regf, sd->sacl, (char *)(locn + off));
1379                 rsd->off_sacl = off;
1380         }
1381         else
1382                 rsd->off_sacl = 0;
1383
1384         off += size;
1385
1386         if (sd->dacl) {
1387                 rsd->off_dacl = off;
1388                 size = nt_store_acl(regf, sd->dacl, (char *)(locn + off));
1389         }
1390         else {
1391                 rsd->off_dacl = 0;
1392         }
1393
1394         off += size;
1395
1396         /* Now the owner and group SIDs */
1397
1398         if (sd->owner_sid) {
1399                 rsd->off_owner_sid = off;
1400                 size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off));
1401         }
1402         else {
1403                 rsd->off_owner_sid = 0;
1404         }
1405
1406         off += size;
1407
1408         if (sd->grp_sid) {
1409                 rsd->off_grp_sid = off;
1410                 size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off));
1411         }
1412         else {
1413                 rsd->off_grp_sid = 0;
1414         }
1415
1416         off += size;
1417
1418         return size;
1419 }
1420
1421 /*
1422  * Store the security information
1423  *
1424  * If it has already been stored, just get its offset from record
1425  * otherwise, store it and record its offset
1426  */
1427 static uint_t nt_store_security(struct registry_hive *regf, KEY_SEC_DESC *sec)
1428 {
1429         int size = 0;
1430         uint_t sk_off;
1431         SK_HDR *sk_hdr;
1432
1433         if (sec->offset) return sec->offset;
1434
1435         /*
1436          * OK, we don't have this one in the file yet. We must compute the 
1437          * size taken by the security descriptor as a self-relative SD, which
1438          * means making one pass over each structure and figuring it out
1439          */
1440
1441 /* FIXME        size = sec_desc_size(sec->sec_desc); */
1442
1443         /* Allocate that much space */
1444
1445         sk_hdr = nt_alloc_regf_space(regf, size, &sk_off);
1446         sec->sk_hdr = sk_hdr;
1447
1448         if (!sk_hdr) return 0;
1449
1450         /* Now, lay out the sec_desc in the space provided */
1451
1452         sk_hdr->SK_ID = str_to_dword("sk");
1453
1454         /* 
1455          * We can't deal with the next and prev offset in the SK_HDRs until the
1456          * whole tree has been stored, then we can go and deal with them
1457          */
1458
1459         sk_hdr->ref_cnt = sec->ref_cnt;
1460         sk_hdr->rec_size = size;       /* Is this correct */
1461
1462         /* Now, lay out the sec_desc */
1463
1464         if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc))
1465                 return 0;
1466
1467         return sk_off;
1468
1469 }
1470
1471 /*
1472  * Store a KEY in the file ...
1473  *
1474  * We store this depth first, and defer storing the lf struct until
1475  * all the sub-keys have been stored.
1476  * 
1477  * We store the NK hdr, any SK header, class name, and VK structure, then
1478  * recurse down the LF structures ... 
1479  * 
1480  * We return the offset of the NK struct
1481  * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ...
1482  */
1483 static int nt_store_reg_key(struct registry_hive *regf, struct registry_key *key)
1484 {
1485         NK_HDR *nk_hdr; 
1486         uint_t nk_off, sk_off, size;
1487
1488         if (!regf || !key) return 0;
1489
1490         size = sizeof(NK_HDR) + strlen(key->name) - 1;
1491         nk_hdr = nt_alloc_regf_space(regf, size, &nk_off);
1492         if (!nk_hdr) goto error;
1493
1494         key->offset = nk_off;  /* We will need this later */
1495
1496         /*
1497          * Now fill in each field etc ...
1498          */
1499
1500         nk_hdr->NK_ID = str_to_dword("nk"); 
1501         if (key->type == REG_ROOT_KEY)
1502                 nk_hdr->type = 0x2C;
1503         else
1504                 nk_hdr->type = 0x20;
1505
1506         /* FIXME: Fill in the time of last update */
1507
1508         if (key->type != REG_ROOT_KEY)
1509                 nk_hdr->own_off = key->owner->offset;
1510
1511         if (key->sub_keys)
1512                 nk_hdr->subk_num = key->sub_keys->key_count;
1513
1514         /*
1515          * Now, process the Sec Desc and then store its offset
1516          */
1517
1518         sk_off = nt_store_security(regf, key->security);
1519         nk_hdr->sk_off = sk_off;
1520
1521         /*
1522          * Then, store the val list and store its offset
1523          */
1524         if (key->values) {
1525                 nk_hdr->val_cnt = key->values->val_count;
1526                 nk_hdr->val_off = nt_store_val_list(regf, key->values);
1527         }
1528         else {
1529                 nk_hdr->val_off = -1;
1530                 nk_hdr->val_cnt = 0;
1531         }
1532
1533         /*
1534          * Finally, store the subkeys, and their offsets
1535          */
1536
1537 error:
1538         return 0;
1539 }
1540
1541 /*
1542  * Store the registry header ...
1543  * We actually create the registry header block and link it to the chain
1544  * of output blocks.
1545  */
1546 static REGF_HDR *nt_get_reg_header(struct registry_hive *h) {
1547         REGF *regf = h->backend_data;
1548         HBIN_BLK *tmp = NULL;
1549
1550         tmp = malloc_p(HBIN_BLK);
1551
1552         memset(tmp, 0, sizeof(HBIN_BLK));
1553         tmp->type = REG_OUTBLK_HDR;
1554         tmp->size = REGF_HDR_BLKSIZ;
1555         tmp->data = malloc(REGF_HDR_BLKSIZ);
1556         if (!tmp->data) goto error;
1557
1558         memset(tmp->data, 0, REGF_HDR_BLKSIZ);  /* Make it pristine, unlike Windows */
1559         regf->blk_head = regf->blk_tail = tmp;
1560
1561         return (REGF_HDR *)tmp->data;
1562
1563 error:
1564         if (tmp) free(tmp);
1565         return NULL;
1566 }
1567
1568 #endif
1569
1570 static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
1571 {
1572         REGF *regf;
1573         REGF_HDR *regf_hdr;
1574         uint_t regf_id, hbin_id;
1575         HBIN_HDR *hbin_hdr;
1576
1577         regf = (REGF *)talloc(h, REGF);
1578         memset(regf, 0, sizeof(REGF));
1579         regf->owner_sid_str = NULL; /* FIXME: Fill in */
1580         h->backend_data = regf;
1581
1582         DEBUG(5, ("Attempting to load registry file\n"));
1583
1584         /* Get the header */
1585
1586         if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) {
1587                 DEBUG(0, ("Unable to get header\n"));
1588                 return WERR_GENERAL_FAILURE;
1589         }
1590
1591         /* Now process that header and start to read the rest in */
1592
1593         if ((regf_id = IVAL(&regf_hdr->REGF_ID,0)) != str_to_dword("regf")) {
1594                 DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n",
1595                                   regf_id, h->location));
1596                 return WERR_GENERAL_FAILURE;
1597         }
1598
1599         /*
1600          * Validate the header ...
1601          */
1602         if (!valid_regf_hdr(regf_hdr)) {
1603                 DEBUG(0, ("Registry file header does not validate: %s\n",
1604                                   h->location));
1605                 return WERR_GENERAL_FAILURE;
1606         }
1607
1608         /* Update the last mod date, and then go get the first NK record and on */
1609
1610         TTTONTTIME(regf, IVAL(&regf_hdr->tim1,0), IVAL(&regf_hdr->tim2,0));
1611
1612         /* 
1613          * The hbin hdr seems to be just uninteresting garbage. Check that
1614          * it is there, but that is all.
1615          */
1616
1617         hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ);
1618
1619         if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) {
1620                 DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", 
1621                                   hbin_id, h->location));
1622                 return WERR_GENERAL_FAILURE;
1623         } 
1624
1625         /*
1626          * Get a pointer to the first key from the hreg_hdr
1627          */
1628
1629         DEBUG(2, ("First Key: %0X\n",
1630                           IVAL(&regf_hdr->first_key, 0)));
1631
1632         regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(&regf_hdr->first_key,0));
1633         DEBUGADD(2, ("First Key Offset: %0X\n", 
1634                                  IVAL(&regf_hdr->first_key, 0)));
1635
1636         DEBUGADD(2, ("Data Block Size: %d\n",
1637                                  IVAL(&regf_hdr->dblk_size, 0)));
1638
1639         DEBUGADD(2, ("Offset to next hbin block: %0X\n",
1640                                  IVAL(&hbin_hdr->off_to_next, 0)));
1641
1642         DEBUGADD(2, ("HBIN block size: %0X\n",
1643                                  IVAL(&hbin_hdr->blk_size, 0)));
1644
1645         /*
1646          * Unmap the registry file, as we might want to read in another
1647          * tree etc.
1648          */
1649
1650         h->backend_data = regf;
1651
1652         return nk_to_key(h, h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key);
1653 }
1654
1655
1656 static WERROR nt_num_subkeys(struct registry_key *k, int *num) 
1657 {
1658         REGF *regf = k->hive->backend_data;
1659         LF_HDR *lf_hdr;
1660         int lf_off;
1661         NK_HDR *nk_hdr = k->backend_data;
1662         lf_off = IVAL(&nk_hdr->lf_off,0);
1663         DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
1664         if(lf_off == -1) {
1665                 *num = 0;
1666                 return WERR_OK;
1667         }
1668         lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1669
1670         return lf_num_entries(k->hive, lf_hdr, BLK_SIZE(lf_hdr), num);
1671 }
1672
1673 static WERROR nt_num_values(struct registry_key *k, int *count)
1674 {
1675         NK_HDR *nk_hdr = k->backend_data;
1676         *count = IVAL(&nk_hdr->val_cnt,0);
1677         return WERR_OK;
1678 }
1679
1680 static WERROR nt_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_value **value)
1681 {
1682         VL_TYPE *vl;
1683         int val_off, vk_off;
1684         int val_count;
1685         VK_HDR *vk_hdr;
1686         REGF *regf = k->hive->backend_data;
1687         NK_HDR *nk_hdr = k->backend_data;
1688         val_count = IVAL(&nk_hdr->val_cnt,0);
1689         val_off = IVAL(&nk_hdr->val_off,0);
1690         vl = (VL_TYPE *)LOCN(regf->base, val_off);
1691         DEBUG(2, ("Val List Offset: %0X\n", val_off));
1692         if(n < 0) return WERR_INVALID_PARAM;
1693         if(n >= val_count) return WERR_NO_MORE_ITEMS;
1694
1695         vk_off = IVAL(&vl[n],0);
1696         vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off);
1697         return vk_to_val(mem_ctx, k, vk_hdr, BLK_SIZE(vk_hdr), value);
1698 }
1699
1700 static WERROR nt_key_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_key **subkey)
1701 {
1702         REGF *regf = k->hive->backend_data;
1703         int lf_off;
1704         NK_HDR *nk_hdr = k->backend_data;
1705         LF_HDR *lf_hdr;
1706         lf_off = IVAL(&nk_hdr->lf_off,0);
1707         DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
1708
1709         /*
1710          * No more subkeys if lf_off == -1
1711          */
1712
1713         if (lf_off != -1) {
1714                 lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1715                 return lf_get_entry(mem_ctx, k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey);
1716         }
1717
1718         return WERR_NO_MORE_ITEMS;
1719 }
1720
1721 static struct hive_operations reg_backend_nt4 = {
1722         .name = "nt4",
1723         .open_hive = nt_open_hive,
1724         .num_subkeys = nt_num_subkeys,
1725         .num_values = nt_num_values,
1726         .get_subkey_by_index = nt_key_by_index,
1727         .get_value_by_index = nt_value_by_index,
1728
1729         /* TODO: 
1730         .add_key
1731         .add_value
1732         .del_key
1733         .del_value
1734         .update_value
1735         */
1736 };
1737
1738 NTSTATUS registry_nt4_init(void)
1739 {
1740         return registry_register(&reg_backend_nt4);
1741 }