r3737: - Get rid of the register_subsystem() and register_backend() functions.
[Samba/aatanasov.git] / source / lib / registry / reg_backend_nt4 / reg_backend_nt4.c
blobaac6e548a855ea79db010f8463329f30492e08b2
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
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.
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.
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. */
20 /*************************************************************************
22 A utility to edit a Windows NT/2K etc registry file.
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
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.
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.
35 The windows NT registry has 2 different blocks, where one can occur many
36 times...
38 the "regf"-Block
39 ================
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!
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
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...
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.
70 Inside these hbin-blocks the different records are placed. The memory-
71 management looks like a C-compiler heap management to me...
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
81 The values in 0x0008 and 0x001C should be the same, so I don't know
82 if they are correct or swapped...
84 From offset 0x0020 inside a hbin-block data is stored with the following
85 format:
87 Offset Size Contents
88 0x0000 D-Word Data-block size //this size must be a
89 multiple of 8. Nigel
90 0x0004 ???? Data
92 If the size field is negative (bit 31 set), the corresponding block
93 is free and has a size of -blocksize!
95 That does not seem to be true. All block lengths seem to be negative!
96 (Richard Sharpe)
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.
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.)
105 Records in the hbin-blocks
106 ==========================
108 nk-Record
110 The nk-record can be treated as a combination of tree-record and
111 key-record of the win 95 registry.
113 lf-Record
115 The lf-record is the counterpart to the RGKN-record (the
116 hash-function)
118 vk-Record
120 The vk-record consists information to a single value (value key).
122 sk-Record
124 sk (? Security Key ?) is the ACL of the registry.
126 Value-Lists
128 The value-lists contain information about which values are inside a
129 sub-key and don't have a header.
131 Datas
133 The datas of the registry are (like the value-list) stored without a
134 header.
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)...
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
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
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
166 To determine the number of values, you have to look at the owner-nk-record!
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
180 If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default)
182 If the data-size is lower 5, the data-offset value is used to store the data itself!
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!)
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
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!
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!
210 //These hashrecords must be sorted low to high within the lf record. Nigel.
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.)
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 ????
230 The usage counter counts the number of references to this
231 "sk"-record. You can use one "sk"-record for the entire registry!
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!
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.
248 simplyfied win-3.?? registry:
249 =============================
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 +-----------+
266 Greatly simplyfied structure of the nt-registry:
267 ================================================
269 +---------------------------------------------------------------+
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 +------------+ |
287 +---------+ +---------+
288 +----->| next sk |--->| Next sk |--+
289 | +---| prev sk |<---| prev sk | |
290 | | | .... | | ... | |
291 | | +---------+ +---------+ |
292 | | ^ |
293 | | | |
294 | +--------------------+ |
295 +----------------------------------+
297 ---------------------------------------------------------------------------
299 Hope this helps.... (Although it was "fun" for me to uncover this things,
300 it took me several sleepless nights ;)
302 B.D.
304 *************************************************************************/
306 #include "includes.h"
307 #include "registry.h"
308 #include "system/shmem.h"
310 #define REG_KEY_LIST_SIZE 10
311 #define FLAG_HAS_NAME 0x01
312 /*FIXME*/
315 * Structures for dealing with the on-disk format of the registry
318 const char *def_owner_sid_str = NULL;
321 * These definitions are for the in-memory registry structure.
322 * It is a tree structure that mimics what you see with tools like regedit
327 * Definition of a Key. It has a name, classname, date/time last modified,
328 * sub-keys, values, and a security descriptor
331 #define REG_ROOT_KEY 1
332 #define REG_SUB_KEY 2
333 #define REG_SYM_LINK 3
336 * All of the structures below actually have a four-byte length before them
337 * which always seems to be negative. The following macro retrieves that
338 * size as an integer
341 #define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1))
343 typedef uint_t DWORD;
344 typedef unsigned short WORD;
346 typedef struct sk_struct SK_HDR;
348 * This structure keeps track of the output format of the registry
350 #define REG_OUTBLK_HDR 1
351 #define REG_OUTBLK_HBIN 2
353 typedef struct regf_block {
354 DWORD REGF_ID; /* regf */
355 DWORD uk1;
356 DWORD uk2;
357 DWORD tim1, tim2;
358 DWORD uk3; /* 1 */
359 DWORD uk4; /* 3 */
360 DWORD uk5; /* 0 */
361 DWORD uk6; /* 1 */
362 DWORD first_key; /* offset */
363 uint_t dblk_size;
364 DWORD uk7[116]; /* 1 */
365 DWORD chksum;
366 } REGF_HDR;
368 typedef struct hbin_sub_struct {
369 DWORD dblocksize;
370 char data[1];
371 } HBIN_SUB_HDR;
373 typedef struct hbin_struct {
374 DWORD HBIN_ID; /* hbin */
375 DWORD off_from_first;
376 DWORD off_to_next;
377 DWORD uk1;
378 DWORD uk2;
379 DWORD uk3;
380 DWORD uk4;
381 DWORD blk_size;
382 HBIN_SUB_HDR hbin_sub_hdr;
383 } HBIN_HDR;
385 typedef struct nk_struct {
386 WORD NK_ID;
387 WORD type;
388 DWORD t1, t2;
389 DWORD uk1;
390 DWORD own_off;
391 DWORD subk_num;
392 DWORD uk2;
393 DWORD lf_off;
394 DWORD uk3;
395 DWORD val_cnt;
396 DWORD val_off;
397 DWORD sk_off;
398 DWORD clsnam_off;
399 DWORD unk4[4];
400 DWORD unk5;
401 WORD nam_len;
402 WORD clsnam_len;
403 char key_nam[1]; /* Actual length determined by nam_len */
404 } NK_HDR;
406 struct sk_struct {
407 WORD SK_ID;
408 WORD uk1;
409 DWORD prev_off;
410 DWORD next_off;
411 DWORD ref_cnt;
412 DWORD rec_size;
413 char sec_desc[1];
416 typedef struct key_sec_desc_s {
417 struct key_sec_desc_s *prev, *next;
418 int ref_cnt;
419 int state;
420 int offset;
421 SK_HDR *sk_hdr; /* This means we must keep the registry in memory */
422 SEC_DESC *sec_desc;
423 } KEY_SEC_DESC;
425 /* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */
426 typedef struct sk_map_s {
427 int sk_off;
428 KEY_SEC_DESC *key_sec_desc;
429 } SK_MAP;
431 typedef struct vk_struct {
432 WORD VK_ID;
433 WORD nam_len;
434 DWORD dat_len; /* If top-bit set, offset contains the data */
435 DWORD dat_off;
436 DWORD dat_type;
437 WORD flag; /* =1, has name, else no name (=Default). */
438 WORD unk1;
439 char dat_name[1]; /* Name starts here ... */
440 } VK_HDR;
442 typedef DWORD VL_TYPE[1]; /* Value list is an array of vk rec offsets */
444 typedef struct hash_struct {
445 DWORD nk_off;
446 char hash[4];
447 } HASH_REC;
450 typedef struct lf_struct {
451 WORD LF_ID;
452 WORD key_count;
453 struct hash_struct hr[1]; /* Array of hash records, depending on key_count */} LF_HDR;
458 * This structure keeps track of the output format of the registry
460 #define REG_OUTBLK_HDR 1
461 #define REG_OUTBLK_HBIN 2
463 typedef struct hbin_blk_s {
464 int type, size;
465 struct hbin_blk_s *next;
466 char *data; /* The data block */
467 uint_t file_offset; /* Offset in file */
468 uint_t free_space; /* Amount of free space in block */
469 uint_t fsp_off; /* Start of free space in block */
470 int complete, stored;
471 } HBIN_BLK;
473 typedef struct regf_struct_s {
474 int reg_type;
475 int fd;
476 struct stat sbuf;
477 char *base;
478 BOOL modified;
479 NTTIME last_mod_time;
480 NK_HDR *first_key;
481 int sk_count, sk_map_size;
482 SK_MAP *sk_map;
483 const char *owner_sid_str;
484 SEC_DESC *def_sec_desc;
486 * These next pointers point to the blocks used to contain the
487 * keys when we are preparing to write them to a file
489 HBIN_BLK *blk_head, *blk_tail, *free_space;
490 } REGF;
492 static DWORD str_to_dword(const char *a) {
493 int i;
494 unsigned long ret = 0;
495 for(i = strlen(a)-1; i >= 0; i--) {
496 ret = ret * 0x100 + a[i];
498 return ret;
501 #if 0
504 * Create an ACE
506 static BOOL nt_create_ace(SEC_ACE *ace, int type, int flags, uint32_t perms, const char *sid)
508 DOM_SID s;
509 SEC_ACCESS access;
510 access.mask = perms;
511 if(!string_to_sid(&s, sid))return False;
512 init_sec_ace(ace, &s, type, access, flags);
513 return True;
517 * Create a default ACL
519 static SEC_ACL *nt_create_default_acl(struct registry_hive *regf)
521 SEC_ACE aces[8];
523 if(!nt_create_ace(&aces[0], 0x00, 0x0, 0xF003F, regf->owner_sid_str)) return NULL;
524 if(!nt_create_ace(&aces[1], 0x00, 0x0, 0xF003F, "S-1-5-18")) return NULL;
525 if(!nt_create_ace(&aces[2], 0x00, 0x0, 0xF003F, "S-1-5-32-544")) return NULL;
526 if(!nt_create_ace(&aces[3], 0x00, 0x0, 0x20019, "S-1-5-12")) return NULL;
527 if(!nt_create_ace(&aces[4], 0x00, 0x0B, GENERIC_RIGHT_ALL_ACCESS, regf->owner_sid_str)) return NULL;
528 if(!nt_create_ace(&aces[5], 0x00, 0x0B, 0x10000000, "S-1-5-18")) return NULL;
529 if(!nt_create_ace(&aces[6], 0x00, 0x0B, 0x10000000, "S-1-5-32-544")) return NULL;
530 if(!nt_create_ace(&aces[7], 0x00, 0x0B, 0x80000000, "S-1-5-12")) return NULL;
532 return make_sec_acl(regf->mem_ctx, 2, 8, aces);
536 * Create a default security descriptor. We pull in things from env
537 * if need be
539 static SEC_DESC *nt_create_def_sec_desc(struct registry_hive *regf)
541 SEC_DESC *tmp;
543 tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC));
545 tmp->revision = 1;
546 tmp->type = SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT;
547 if (!string_to_sid(tmp->owner_sid, "S-1-5-32-544")) goto error;
548 if (!string_to_sid(tmp->grp_sid, "S-1-5-18")) goto error;
549 tmp->sacl = NULL;
550 tmp->dacl = nt_create_default_acl(regf);
552 return tmp;
554 error:
555 if (tmp) nt_delete_sec_desc(tmp);
556 return NULL;
560 * We will implement inheritence that is based on what the parent's SEC_DESC
561 * says, but the Owner and Group SIDs can be overwridden from the command line
562 * and additional ACEs can be applied from the command line etc.
564 static KEY_SEC_DESC *nt_inherit_security(struct registry_key *key)
567 if (!key) return NULL;
568 return key->security;
572 * Create an initial security descriptor and init other structures, if needed
573 * We assume that the initial security stuff is empty ...
575 static KEY_SEC_DESC *nt_create_init_sec(struct registry_hive *h)
577 REGF *regf = h->backend_data;
578 KEY_SEC_DESC *tsec = NULL;
580 tsec = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
582 tsec->ref_cnt = 1;
583 tsec->state = SEC_DESC_NBK;
584 tsec->offset = 0;
586 tsec->sec_desc = regf->def_sec_desc;
588 return tsec;
590 #endif
593 * Get the starting record for NT Registry file
597 * Where we keep all the regf stuff for one registry.
598 * This is the structure that we use to tie the in memory tree etc
599 * together. By keeping separate structs, we can operate on different
600 * registries at the same time.
601 * Currently, the SK_MAP is an array of mapping structure.
602 * Since we only need this on input and output, we fill in the structure
603 * as we go on input. On output, we know how many SK items we have, so
604 * we can allocate the structure as we need to.
605 * If you add stuff here that is dynamically allocated, add the
606 * appropriate free statements below.
609 #define REG_HANDLE_REGTYPE_NONE 0
610 #define REG_HANDLE_REGTYPE_NT 1
611 #define REG_HANDLE_REGTYPE_W9X 2
613 #define TTTONTTIME(r, t1, t2) (r)->last_mod_time = (t1) | (((uint64_t)(t2)) << 32)
615 #define REGF_HDR_BLKSIZ 0x1000
617 #define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4)
618 #define LOCN(base, f) ((base) + OFF(f))
620 /* Get the header of the registry. Return a pointer to the structure
621 * If the mmap'd area has not been allocated, then mmap the input file
623 static REGF_HDR *nt_get_regf_hdr(struct registry_hive *h)
625 REGF *regf = h->backend_data;
626 SMB_REG_ASSERT(regf);
628 if (!regf->base) { /* Try to mmap etc the file */
630 if ((regf->fd = open(h->location, O_RDONLY, 0000)) <0) {
631 return NULL; /* What about errors? */
634 if (fstat(regf->fd, &regf->sbuf) < 0) {
635 return NULL;
638 regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0);
640 if ((int)regf->base == 1) {
641 DEBUG(0,("Could not mmap file: %s, %s\n", h->location,
642 strerror(errno)));
643 return NULL;
648 * At this point, regf->base != NULL, and we should be able to read the
649 * header
652 SMB_REG_ASSERT(regf->base != NULL);
654 return (REGF_HDR *)regf->base;
658 * Validate a regf header
659 * For now, do nothing, but we should check the checksum
661 static int valid_regf_hdr(REGF_HDR *regf_hdr)
663 if (!regf_hdr) return 0;
665 return 1;
668 #if 0
671 * Process an SK header ...
672 * Every time we see a new one, add it to the map. Otherwise, just look it up.
673 * We will do a simple linear search for the moment, since many KEYs have the
674 * same security descriptor.
675 * We allocate the map in increments of 10 entries.
679 * Create a new entry in the map, and increase the size of the map if needed
681 static SK_MAP *alloc_sk_map_entry(struct registry_hive *h, KEY_SEC_DESC *tmp, int sk_off)
683 REGF *regf = h->backend_data;
684 if (!regf->sk_map) { /* Allocate a block of 10 */
685 regf->sk_map = (SK_MAP *)malloc(sizeof(SK_MAP) * 10);
686 regf->sk_map_size = 10;
687 regf->sk_count = 1;
688 (regf->sk_map)[0].sk_off = sk_off;
689 (regf->sk_map)[0].key_sec_desc = tmp;
691 else { /* Simply allocate a new slot, unless we have to expand the list */
692 int ndx = regf->sk_count;
693 if (regf->sk_count >= regf->sk_map_size) {
694 regf->sk_map = (SK_MAP *)realloc(regf->sk_map,
695 (regf->sk_map_size + 10)*sizeof(SK_MAP));
696 if (!regf->sk_map) {
697 free(tmp);
698 return NULL;
701 * ndx already points at the first entry of the new block
703 regf->sk_map_size += 10;
705 (regf->sk_map)[ndx].sk_off = sk_off;
706 (regf->sk_map)[ndx].key_sec_desc = tmp;
707 regf->sk_count++;
709 return regf->sk_map;
713 * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not
714 * found
716 KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off)
718 int i;
720 if (!sk_map) return NULL;
722 for (i = 0; i < count; i++) {
724 if (sk_map[i].sk_off == sk_off)
725 return sk_map[i].key_sec_desc;
729 return NULL;
734 * Allocate a KEY_SEC_DESC if we can't find one in the map
736 static KEY_SEC_DESC *lookup_create_sec_key(struct registry_hive *h, SK_MAP *sk_map, int sk_off)
738 REGF *regf = h->backend_data;
739 KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off);
741 if (tmp) {
742 return tmp;
744 else { /* Allocate a new one */
745 tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
746 memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */
747 tmp->state = SEC_DESC_RES;
748 if (!alloc_sk_map_entry(h, tmp, sk_off)) {
749 return NULL;
751 return tmp;
755 static SEC_DESC *process_sec_desc(struct registry_hive *regf, SEC_DESC *sec_desc)
757 SEC_DESC *tmp = NULL;
759 tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC));
761 tmp->revision = SVAL(&sec_desc->revision,0);
762 tmp->type = SVAL(&sec_desc->type,0);
763 DEBUG(2, ("SEC_DESC Rev: %0X, Type: %0X\n", tmp->revision, tmp->type));
764 DEBUGADD(2, ("SEC_DESC Owner Off: %0X\n", IVAL(&sec_desc->off_owner_sid,0)));
765 DEBUGADD(2, ("SEC_DESC Group Off: %0X\n", IVAL(&sec_desc->off_grp_sid,0)));
766 DEBUGADD(2, ("SEC_DESC DACL Off: %0X\n", IVAL(&sec_desc->off_dacl,0)));
767 tmp->owner_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_owner_sid,0)));
768 if (!tmp->owner_sid) {
769 free(tmp);
770 return NULL;
772 tmp->grp_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_grp_sid,0)));
773 if (!tmp->grp_sid) {
774 free(tmp);
775 return NULL;
778 /* Now pick up the SACL and DACL */
780 DEBUG(0, ("%d, %d\n", IVAL(&sec_desc->off_sacl,0), IVAL(&sec_desc->off_dacl,0)));
782 if (sec_desc->off_sacl)
783 tmp->sacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_sacl,0)));
784 else
785 tmp->sacl = NULL;
787 if (sec_desc->off_dacl)
788 tmp->dacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_dacl,0)));
789 else
790 tmp->dacl = NULL;
792 return tmp;
795 static KEY_SEC_DESC *process_sk(struct registry_hive *regf, SK_HDR *sk_hdr, int sk_off, int size)
797 KEY_SEC_DESC *tmp = NULL;
798 int sk_next_off, sk_prev_off, sk_size;
799 SEC_DESC *sec_desc;
801 if (!sk_hdr) return NULL;
803 if (SVAL(&sk_hdr->SK_ID,0) != str_to_dword("sk")) {
804 DEBUG(0, ("Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr,
805 regf->regfile_name));
806 return NULL;
809 if (-size < (sk_size = IVAL(&sk_hdr->rec_size,0))) {
810 DEBUG(0, ("Incorrect SK record size: %d vs %d. %s\n",
811 -size, sk_size, regf->regfile_name));
812 return NULL;
816 * Now, we need to look up the SK Record in the map, and return it
817 * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can
818 * use that
821 if (regf->sk_map &&
822 ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL)
823 && (tmp->state == SEC_DESC_OCU)) {
824 tmp->ref_cnt++;
825 return tmp;
828 /* Here, we have an item in the map that has been reserved, or tmp==NULL. */
830 SMB_REG_ASSERT(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON));
833 * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the
834 * new KEY_SEC_DESC to the mapping structure, since the offset supplied is
835 * the actual offset of structure. The same offset will be used by
836 * all future references to this structure
837 * We could put all this unpleasantness in a function.
840 if (!tmp) {
841 tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
842 memset(tmp, 0, sizeof(KEY_SEC_DESC));
845 * Allocate an entry in the SK_MAP ...
846 * We don't need to free tmp, because that is done for us if the
847 * sm_map entry can't be expanded when we need more space in the map.
850 if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
851 return NULL;
855 tmp->ref_cnt++;
856 tmp->state = SEC_DESC_OCU;
859 * Now, process the actual sec desc and plug the values in
862 sec_desc = (SEC_DESC *)&sk_hdr->sec_desc[0];
863 tmp->sec_desc = process_sec_desc(regf, sec_desc);
866 * Now forward and back links. Here we allocate an entry in the sk_map
867 * if it does not exist, and mark it reserved
870 sk_prev_off = IVAL(&sk_hdr->prev_off,0);
871 tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off);
872 SMB_REG_ASSERT(tmp->prev != NULL);
873 sk_next_off = IVAL(&sk_hdr->next_off,0);
874 tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off);
875 SMB_REG_ASSERT(tmp->next != NULL);
877 return tmp;
879 #endif
882 * Process a VK header and return a value
884 static WERROR vk_to_val(TALLOC_CTX *mem_ctx, struct registry_key *parent, VK_HDR *vk_hdr, int size, struct registry_value **value)
886 REGF *regf = parent->hive->backend_data;
887 int nam_len, dat_len, flag, dat_type, dat_off, vk_id;
888 struct registry_value *tmp = NULL;
890 if (!vk_hdr) return WERR_INVALID_PARAM;
892 if ((vk_id = SVAL(&vk_hdr->VK_ID,0)) != str_to_dword("vk")) {
893 DEBUG(0, ("Unrecognized VK header ID: %0X, block: %0X, %s\n",
894 vk_id, (int)vk_hdr, parent->hive->location));
895 return WERR_GENERAL_FAILURE;
898 nam_len = SVAL(&vk_hdr->nam_len,0);
899 flag = SVAL(&vk_hdr->flag,0);
900 dat_type = IVAL(&vk_hdr->dat_type,0);
901 dat_len = IVAL(&vk_hdr->dat_len,0); /* If top bit, offset contains data */
902 dat_off = IVAL(&vk_hdr->dat_off,0);
904 tmp = talloc_p(mem_ctx, struct registry_value);
905 tmp->data_type = dat_type;
907 if (flag & FLAG_HAS_NAME) {
908 tmp->name = talloc_strndup(mem_ctx, vk_hdr->dat_name, nam_len);
909 } else {
910 tmp->name = NULL;
914 * Allocate space and copy the data as a BLOB
917 if (dat_len&0x7FFFFFFF) {
919 char *dtmp = (char *)talloc(mem_ctx, dat_len&0x7FFFFFFF);
921 if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */
922 char *dat_ptr = LOCN(regf->base, dat_off);
923 memcpy(dtmp, dat_ptr, dat_len);
925 else { /* The data is in the offset or type */
927 * FIXME.
928 * Some registry files seem to have weird fields. If top bit is set,
929 * but len is 0, the type seems to be the value ...
930 * Not sure how to handle this last type for the moment ...
932 dat_len = dat_len & 0x7FFFFFFF;
933 memcpy(dtmp, &dat_off, dat_len);
937 if(tmp->data_type == REG_SZ) {
938 char *ret;
939 dat_len = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, dtmp, dat_len, (void **)&ret);
940 dtmp = ret;
944 tmp->data_blk = dtmp;
945 tmp->data_len = dat_len;
948 *value = tmp;
949 return WERR_OK;
952 #if 0 /* unused */
954 static BOOL vl_verify(VL_TYPE vl, int count, int size)
956 if(!vl) return False;
957 if (-size < (count+1)*sizeof(int)){
958 DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size));
959 return False;
961 return True;
964 #endif
966 static WERROR lf_verify(struct registry_hive *h, LF_HDR *lf_hdr, int size)
968 int lf_id;
969 if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) {
970 DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n",
971 lf_id, (int)lf_hdr, h->location));
972 return WERR_INVALID_PARAM;
974 return WERR_OK;
977 static WERROR lf_num_entries(struct registry_hive *h, LF_HDR *lf_hdr, int size, int *count)
979 WERROR error;
981 error = lf_verify(h, lf_hdr, size);
982 if(!W_ERROR_IS_OK(error)) return error;
984 SMB_REG_ASSERT(size < 0);
986 *count = SVAL(&lf_hdr->key_count,0);
987 DEBUG(2, ("Key Count: %u\n", *count));
988 if (*count <= 0) return WERR_INVALID_PARAM;
990 return WERR_OK;
994 static WERROR nk_to_key(TALLOC_CTX *, struct registry_hive *regf, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **);
999 * Process an LF Header and return a list of sub-keys
1001 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)
1003 REGF *regf = parent->hive->backend_data;
1004 int count, nk_off;
1005 NK_HDR *nk_hdr;
1006 WERROR error;
1008 if (!lf_hdr) return WERR_INVALID_PARAM;
1010 error = lf_verify(parent->hive, lf_hdr, size);
1011 if(!W_ERROR_IS_OK(error)) return error;
1013 SMB_REG_ASSERT(size < 0);
1015 count = SVAL(&lf_hdr->key_count,0);
1016 DEBUG(2, ("Key Count: %u\n", count));
1017 if (count <= 0) return WERR_GENERAL_FAILURE;
1018 if (n >= count) return WERR_NO_MORE_ITEMS;
1020 nk_off = IVAL(&lf_hdr->hr[n].nk_off,0);
1021 DEBUG(2, ("NK Offset: %0X\n", nk_off));
1022 nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off);
1023 return nk_to_key(mem_ctx, parent->hive, nk_hdr, BLK_SIZE(nk_hdr), parent, key);
1026 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)
1028 REGF *regf = h->backend_data;
1029 struct registry_key *tmp = NULL, *own;
1030 int namlen, clsname_len, sk_off, own_off;
1031 uint_t nk_id;
1032 SK_HDR *sk_hdr;
1033 int type;
1034 char key_name[1024];
1036 if (!nk_hdr) return WERR_INVALID_PARAM;
1038 if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) {
1039 DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n",
1040 nk_id, (int)nk_hdr, parent->hive->location));
1041 return WERR_INVALID_PARAM;
1044 SMB_REG_ASSERT(size < 0);
1046 namlen = SVAL(&nk_hdr->nam_len,0);
1047 clsname_len = SVAL(&nk_hdr->clsnam_len,0);
1050 * The value of -size should be ge
1051 * (sizeof(NK_HDR) - 1 + namlen)
1052 * The -1 accounts for the fact that we included the first byte of
1053 * the name in the structure. clsname_len is the length of the thing
1054 * pointed to by clsnam_off
1057 if (-size < (sizeof(NK_HDR) - 1 + namlen)) {
1058 DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr));
1059 DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n",
1060 sizeof(NK_HDR), namlen, clsname_len));
1061 return WERR_GENERAL_FAILURE;
1064 DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", namlen, clsname_len));
1066 /* Fish out the key name and process the LF list */
1068 SMB_REG_ASSERT(namlen < sizeof(key_name));
1070 strncpy(key_name, nk_hdr->key_nam, namlen);
1071 key_name[namlen] = '\0';
1073 type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY);
1074 if(type == REG_ROOT_KEY && parent) {
1075 DEBUG(0,("Root key encountered below root level!\n"));
1076 return WERR_GENERAL_FAILURE;
1079 tmp = talloc_p(mem_ctx, struct registry_key);
1080 tmp->name = talloc_strdup(mem_ctx, key_name);
1081 tmp->backend_data = nk_hdr;
1083 DEBUG(2, ("Key name: %s\n", key_name));
1086 * Fish out the class name, it is in UNICODE, while the key name is
1087 * ASCII :-)
1090 if (clsname_len) { /* Just print in Ascii for now */
1091 void *clsnamep;
1092 int clsnam_off;
1094 clsnam_off = IVAL(&nk_hdr->clsnam_off,0);
1095 clsnamep = LOCN(regf->base, clsnam_off);
1096 DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off));
1098 pull_ucs2_talloc(mem_ctx, &tmp->class_name, clsnamep);
1100 DEBUGADD(2,(" Class Name: %s\n", tmp->class_name));
1105 * Process the owner offset ...
1108 own_off = IVAL(&nk_hdr->own_off,0);
1109 own = (struct registry_key *)LOCN(regf->base, own_off);
1110 DEBUG(2, ("Owner Offset: %0X\n", own_off));
1112 DEBUGADD(2, (" Owner locn: %0X, Our locn: %0X\n",
1113 (uint_t)own, (uint_t)nk_hdr));
1116 * We should verify that the owner field is correct ...
1117 * for now, we don't worry ...
1121 * Also handle the SK header ...
1124 sk_off = IVAL(&nk_hdr->sk_off,0);
1125 sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off);
1126 DEBUG(2, ("SK Offset: %0X\n", sk_off));
1128 if (sk_off != -1) {
1130 #if 0
1131 tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr));
1132 #endif
1136 *key = tmp;
1137 return WERR_OK;
1140 #if 0 /* unused */
1143 * Allocate a new hbin block, set up the header for the block etc
1145 static HBIN_BLK *nt_create_hbin_blk(struct registry_hive *h, int size)
1147 REGF *regf = h->backend_data;
1148 HBIN_BLK *tmp;
1149 HBIN_HDR *hdr;
1151 if (!regf || !size) return NULL;
1153 /* Round size up to multiple of REGF_HDR_BLKSIZ */
1155 size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1);
1157 tmp = (HBIN_BLK *)malloc(sizeof(HBIN_BLK));
1158 memset(tmp, 0, sizeof(HBIN_BLK));
1160 tmp->data = malloc(size);
1162 memset(tmp->data, 0, size); /* Make it pristine */
1164 tmp->size = size;
1165 /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/
1167 tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR));
1168 tmp->fsp_off = size - tmp->free_space;
1171 * Now, build the header in the data block
1173 hdr = (HBIN_HDR *)tmp->data;
1174 hdr->HBIN_ID = str_to_dword("hbin");
1175 hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ;
1176 hdr->off_to_next = tmp->size;
1177 hdr->blk_size = tmp->size;
1180 * Now link it in
1183 regf->blk_tail->next = tmp;
1184 regf->blk_tail = tmp;
1185 if (!regf->free_space) regf->free_space = tmp;
1187 return tmp;
1191 * Allocate a unit of space ... and return a pointer as function param
1192 * and the block's offset as a side effect
1194 static void *nt_alloc_regf_space(struct registry_hive *h, int size, uint_t *off)
1196 REGF *regf = h->backend_data;
1197 int tmp = 0;
1198 void *ret = NULL;
1199 HBIN_BLK *blk;
1201 if (!regf || !size || !off) return NULL;
1203 SMB_REG_ASSERT(regf->blk_head != NULL);
1206 * round up size to include header and then to 8-byte boundary
1208 size = (size + 4 + 7) & ~7;
1211 * Check if there is space, if none, grab a block
1213 if (!regf->free_space) {
1214 if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ))
1215 return NULL;
1219 * Now, chain down the list of blocks looking for free space
1222 for (blk = regf->free_space; blk != NULL; blk = blk->next) {
1223 if (blk->free_space <= size) {
1224 tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
1225 ret = blk->data + blk->fsp_off;
1226 blk->free_space -= size;
1227 blk->fsp_off += size;
1229 /* Insert the header */
1230 ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
1233 * Fix up the free space ptr
1234 * If it is NULL, we fix it up next time
1237 if (!blk->free_space)
1238 regf->free_space = blk->next;
1240 *off = tmp;
1241 return (((char *)ret)+4);/* The pointer needs to be to the data struct */
1246 * If we got here, we need to add another block, which might be
1247 * larger than one block -- deal with that later
1249 if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) {
1250 blk = regf->free_space;
1251 tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
1252 ret = blk->data + blk->fsp_off;
1253 blk->free_space -= size;
1254 blk->fsp_off += size;
1256 /* Insert the header */
1257 ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
1260 * Fix up the free space ptr
1261 * If it is NULL, we fix it up next time
1264 if (!blk->free_space)
1265 regf->free_space = blk->next;
1267 *off = tmp;
1268 return (((char *)ret) + 4);/* The pointer needs to be to the data struct */
1271 return NULL;
1275 * Store a SID at the location provided
1277 static int nt_store_SID(struct registry_hive *regf, DOM_SID *sid, uint8_t *locn)
1279 int i;
1280 uint8_t *p = locn;
1282 if (!regf || !sid || !locn) return 0;
1284 *p = sid->sid_rev_num; p++;
1285 *p = sid->num_auths; p++;
1287 for (i=0; i < 6; i++) {
1288 *p = sid->id_auth[i]; p++;
1291 for (i=0; i < sid->num_auths; i++) {
1292 SIVAL(p, 0, sid->sub_auths[i]); p+=4;
1295 return p - locn;
1299 static int nt_store_ace(struct registry_hive *regf, SEC_ACE *ace, uint8_t *locn)
1301 int size = 0;
1302 SEC_ACE *reg_ace = (SEC_ACE *)locn;
1303 uint8_t *p;
1305 if (!regf || !ace || !locn) return 0;
1307 reg_ace->type = ace->type;
1308 reg_ace->flags = ace->flags;
1310 /* Deal with the length when we have stored the SID */
1312 p = (uint8_t *)&reg_ace->info.mask;
1314 SIVAL(p, 0, ace->info.mask); p += 4;
1316 size = nt_store_SID(regf, &ace->trustee, p);
1318 size += 8; /* Size of the fixed header */
1320 p = (uint8_t *)&reg_ace->size;
1322 SSVAL(p, 0, size);
1324 return size;
1328 * Store an ACL at the location provided
1330 static int nt_store_acl(struct registry_hive *regf, SEC_ACL *acl, uint8_t *locn) {
1331 int size = 0, i;
1332 uint8_t *p = locn, *s;
1334 if (!regf || !acl || !locn) return 0;
1337 * Now store the header and then the ACEs ...
1340 SSVAL(p, 0, acl->revision);
1342 p += 2; s = p; /* Save this for the size field */
1344 p += 2;
1346 SIVAL(p, 0, acl->num_aces);
1348 p += 4;
1350 for (i = 0; i < acl->num_aces; i++) {
1351 size = nt_store_ace(regf, &acl->ace[i], p);
1352 p += size;
1355 size = s - locn;
1356 SSVAL(s, 0, size);
1357 return size;
1361 * Flatten and store the Sec Desc
1362 * Windows lays out the DACL first, but since there is no SACL, it might be
1363 * that first, then the owner, then the group SID. So, we do it that way
1364 * too.
1366 static uint_t nt_store_sec_desc(struct registry_hive *regf, SEC_DESC *sd, char *locn)
1368 SEC_DESC *rsd = (SEC_DESC *)locn;
1369 uint_t size = 0, off = 0;
1371 if (!regf || !sd || !locn) return 0;
1374 * Now, fill in the first two fields, then lay out the various fields
1375 * as needed
1378 rsd->revision = SEC_DESC_REVISION;
1379 rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE;
1381 off = 4 * sizeof(DWORD) + 4;
1383 if (sd->sacl){
1384 size = nt_store_acl(regf, sd->sacl, (char *)(locn + off));
1385 rsd->off_sacl = off;
1387 else
1388 rsd->off_sacl = 0;
1390 off += size;
1392 if (sd->dacl) {
1393 rsd->off_dacl = off;
1394 size = nt_store_acl(regf, sd->dacl, (char *)(locn + off));
1396 else {
1397 rsd->off_dacl = 0;
1400 off += size;
1402 /* Now the owner and group SIDs */
1404 if (sd->owner_sid) {
1405 rsd->off_owner_sid = off;
1406 size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off));
1408 else {
1409 rsd->off_owner_sid = 0;
1412 off += size;
1414 if (sd->grp_sid) {
1415 rsd->off_grp_sid = off;
1416 size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off));
1418 else {
1419 rsd->off_grp_sid = 0;
1422 off += size;
1424 return size;
1428 * Store the security information
1430 * If it has already been stored, just get its offset from record
1431 * otherwise, store it and record its offset
1433 static uint_t nt_store_security(struct registry_hive *regf, KEY_SEC_DESC *sec)
1435 int size = 0;
1436 uint_t sk_off;
1437 SK_HDR *sk_hdr;
1439 if (sec->offset) return sec->offset;
1442 * OK, we don't have this one in the file yet. We must compute the
1443 * size taken by the security descriptor as a self-relative SD, which
1444 * means making one pass over each structure and figuring it out
1447 /* FIXME size = sec_desc_size(sec->sec_desc); */
1449 /* Allocate that much space */
1451 sk_hdr = nt_alloc_regf_space(regf, size, &sk_off);
1452 sec->sk_hdr = sk_hdr;
1454 if (!sk_hdr) return 0;
1456 /* Now, lay out the sec_desc in the space provided */
1458 sk_hdr->SK_ID = str_to_dword("sk");
1461 * We can't deal with the next and prev offset in the SK_HDRs until the
1462 * whole tree has been stored, then we can go and deal with them
1465 sk_hdr->ref_cnt = sec->ref_cnt;
1466 sk_hdr->rec_size = size; /* Is this correct */
1468 /* Now, lay out the sec_desc */
1470 if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc))
1471 return 0;
1473 return sk_off;
1478 * Store a KEY in the file ...
1480 * We store this depth first, and defer storing the lf struct until
1481 * all the sub-keys have been stored.
1483 * We store the NK hdr, any SK header, class name, and VK structure, then
1484 * recurse down the LF structures ...
1486 * We return the offset of the NK struct
1487 * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ...
1489 static int nt_store_reg_key(struct registry_hive *regf, struct registry_key *key)
1491 NK_HDR *nk_hdr;
1492 uint_t nk_off, sk_off, size;
1494 if (!regf || !key) return 0;
1496 size = sizeof(NK_HDR) + strlen(key->name) - 1;
1497 nk_hdr = nt_alloc_regf_space(regf, size, &nk_off);
1498 if (!nk_hdr) goto error;
1500 key->offset = nk_off; /* We will need this later */
1503 * Now fill in each field etc ...
1506 nk_hdr->NK_ID = str_to_dword("nk");
1507 if (key->type == REG_ROOT_KEY)
1508 nk_hdr->type = 0x2C;
1509 else
1510 nk_hdr->type = 0x20;
1512 /* FIXME: Fill in the time of last update */
1514 if (key->type != REG_ROOT_KEY)
1515 nk_hdr->own_off = key->owner->offset;
1517 if (key->sub_keys)
1518 nk_hdr->subk_num = key->sub_keys->key_count;
1521 * Now, process the Sec Desc and then store its offset
1524 sk_off = nt_store_security(regf, key->security);
1525 nk_hdr->sk_off = sk_off;
1528 * Then, store the val list and store its offset
1530 if (key->values) {
1531 nk_hdr->val_cnt = key->values->val_count;
1532 nk_hdr->val_off = nt_store_val_list(regf, key->values);
1534 else {
1535 nk_hdr->val_off = -1;
1536 nk_hdr->val_cnt = 0;
1540 * Finally, store the subkeys, and their offsets
1543 error:
1544 return 0;
1548 * Store the registry header ...
1549 * We actually create the registry header block and link it to the chain
1550 * of output blocks.
1552 static REGF_HDR *nt_get_reg_header(struct registry_hive *h) {
1553 REGF *regf = h->backend_data;
1554 HBIN_BLK *tmp = NULL;
1556 tmp = (HBIN_BLK *)malloc(sizeof(HBIN_BLK));
1558 memset(tmp, 0, sizeof(HBIN_BLK));
1559 tmp->type = REG_OUTBLK_HDR;
1560 tmp->size = REGF_HDR_BLKSIZ;
1561 tmp->data = malloc(REGF_HDR_BLKSIZ);
1562 if (!tmp->data) goto error;
1564 memset(tmp->data, 0, REGF_HDR_BLKSIZ); /* Make it pristine, unlike Windows */
1565 regf->blk_head = regf->blk_tail = tmp;
1567 return (REGF_HDR *)tmp->data;
1569 error:
1570 if (tmp) free(tmp);
1571 return NULL;
1574 #endif
1576 static WERROR nt_open_hive (TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **key)
1578 REGF *regf;
1579 REGF_HDR *regf_hdr;
1580 uint_t regf_id, hbin_id;
1581 HBIN_HDR *hbin_hdr;
1583 regf = (REGF *)talloc_p(mem_ctx, REGF);
1584 memset(regf, 0, sizeof(REGF));
1585 regf->owner_sid_str = h->credentials;
1586 h->backend_data = regf;
1588 DEBUG(5, ("Attempting to load registry file\n"));
1590 /* Get the header */
1592 if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) {
1593 DEBUG(0, ("Unable to get header\n"));
1594 return WERR_GENERAL_FAILURE;
1597 /* Now process that header and start to read the rest in */
1599 if ((regf_id = IVAL(&regf_hdr->REGF_ID,0)) != str_to_dword("regf")) {
1600 DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n",
1601 regf_id, h->location));
1602 return WERR_GENERAL_FAILURE;
1606 * Validate the header ...
1608 if (!valid_regf_hdr(regf_hdr)) {
1609 DEBUG(0, ("Registry file header does not validate: %s\n",
1610 h->location));
1611 return WERR_GENERAL_FAILURE;
1614 /* Update the last mod date, and then go get the first NK record and on */
1616 TTTONTTIME(regf, IVAL(&regf_hdr->tim1,0), IVAL(&regf_hdr->tim2,0));
1619 * The hbin hdr seems to be just uninteresting garbage. Check that
1620 * it is there, but that is all.
1623 hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ);
1625 if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) {
1626 DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n",
1627 hbin_id, h->location));
1628 return WERR_GENERAL_FAILURE;
1632 * Get a pointer to the first key from the hreg_hdr
1635 DEBUG(2, ("First Key: %0X\n",
1636 IVAL(&regf_hdr->first_key, 0)));
1638 regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(&regf_hdr->first_key,0));
1639 DEBUGADD(2, ("First Key Offset: %0X\n",
1640 IVAL(&regf_hdr->first_key, 0)));
1642 DEBUGADD(2, ("Data Block Size: %d\n",
1643 IVAL(&regf_hdr->dblk_size, 0)));
1645 DEBUGADD(2, ("Offset to next hbin block: %0X\n",
1646 IVAL(&hbin_hdr->off_to_next, 0)));
1648 DEBUGADD(2, ("HBIN block size: %0X\n",
1649 IVAL(&hbin_hdr->blk_size, 0)));
1652 * Unmap the registry file, as we might want to read in another
1653 * tree etc.
1656 h->backend_data = regf;
1658 return nk_to_key(mem_ctx, h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key);
1662 static WERROR nt_num_subkeys(struct registry_key *k, int *num)
1664 REGF *regf = k->hive->backend_data;
1665 LF_HDR *lf_hdr;
1666 int lf_off;
1667 NK_HDR *nk_hdr = k->backend_data;
1668 lf_off = IVAL(&nk_hdr->lf_off,0);
1669 DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
1670 if(lf_off == -1) {
1671 *num = 0;
1672 return WERR_OK;
1674 lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1676 return lf_num_entries(k->hive, lf_hdr, BLK_SIZE(lf_hdr), num);
1679 static WERROR nt_num_values(struct registry_key *k, int *count)
1681 NK_HDR *nk_hdr = k->backend_data;
1682 *count = IVAL(&nk_hdr->val_cnt,0);
1683 return WERR_OK;
1686 static WERROR nt_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_value **value)
1688 VL_TYPE *vl;
1689 int val_off, vk_off;
1690 int val_count;
1691 VK_HDR *vk_hdr;
1692 REGF *regf = k->hive->backend_data;
1693 NK_HDR *nk_hdr = k->backend_data;
1694 val_count = IVAL(&nk_hdr->val_cnt,0);
1695 val_off = IVAL(&nk_hdr->val_off,0);
1696 vl = (VL_TYPE *)LOCN(regf->base, val_off);
1697 DEBUG(2, ("Val List Offset: %0X\n", val_off));
1698 if(n < 0) return WERR_INVALID_PARAM;
1699 if(n >= val_count) return WERR_NO_MORE_ITEMS;
1701 vk_off = IVAL(&vl[n],0);
1702 vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off);
1703 return vk_to_val(mem_ctx, k, vk_hdr, BLK_SIZE(vk_hdr), value);
1706 static WERROR nt_key_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_key **subkey)
1708 REGF *regf = k->hive->backend_data;
1709 int lf_off;
1710 NK_HDR *nk_hdr = k->backend_data;
1711 LF_HDR *lf_hdr;
1712 lf_off = IVAL(&nk_hdr->lf_off,0);
1713 DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
1716 * No more subkeys if lf_off == -1
1719 if (lf_off != -1) {
1720 lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1721 return lf_get_entry(mem_ctx, k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey);
1724 return WERR_NO_MORE_ITEMS;
1727 static struct registry_operations reg_backend_nt4 = {
1728 .name = "nt4",
1729 .open_hive = nt_open_hive,
1730 .num_subkeys = nt_num_subkeys,
1731 .num_values = nt_num_values,
1732 .get_subkey_by_index = nt_key_by_index,
1733 .get_value_by_index = nt_value_by_index,
1735 /* TODO:
1736 .add_key
1737 .add_value
1738 .del_key
1739 .del_value
1740 .update_value
1744 NTSTATUS registry_nt4_init(void)
1746 return registry_register(&reg_backend_nt4);