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