2 Samba CIFS implementation
3 Registry backend for REGF files
4 Copyright (C) 2005 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. */
22 #include "system/filesys.h"
23 #include "lib/registry/tdr_regf.h"
26 * Read HBIN blocks into memory
31 struct hbin_block
**hbins
;
35 * Validate a regf header
36 * For now, do nothing, but we should check the checksum
38 static uint32_t regf_hdr_checksum(const uint8_t *buffer
)
40 uint32_t checksum
= 0, x
;
43 for (i
= 0; i
< 0x01FB; i
+= 4) {
51 static DATA_BLOB
regf_get_data(const struct regf_data
*data
, uint32_t offset
)
58 for (i
= 0; data
->hbins
[i
]; i
++) {
59 if (offset
>= data
->hbins
[i
]->offset_from_first
&&
60 offset
< data
->hbins
[i
]->offset_from_first
+
61 data
->hbins
[i
]->offset_to_next
)
65 if (data
->hbins
[i
] == NULL
) {
66 DEBUG(1, ("Can't find HBIN containing 0x%4x\n", offset
));
70 ret
.length
= IVAL(data
->hbins
[i
]->data
,
71 offset
- data
->hbins
[i
]->offset_from_first
- 0x20);
72 if (ret
.length
& 0x80000000) {
74 ret
.length
= (ret
.length
^ 0xffffffff) + 1;
76 ret
.data
= data
->hbins
[i
]->data
+
77 (offset
- data
->hbins
[i
]->offset_from_first
- 0x20) + 4;
83 static WERROR
regf_num_subkeys (struct registry_key
*key
, uint32_t *count
)
85 struct nk_block
*nk
= key
->backend_data
;
87 *count
= nk
->num_subkeys
;
92 static WERROR
regf_num_values (struct registry_key
*key
, uint32_t *count
)
94 struct nk_block
*nk
= key
->backend_data
;
96 *count
= nk
->num_values
;
101 static struct registry_key
*regf_get_key (TALLOC_CTX
*ctx
, struct regf_data
*regf
, uint32_t offset
)
103 DATA_BLOB data
= regf_get_data(regf
, offset
);
104 struct tdr_pull
*pull
;
105 struct registry_key
*ret
;
108 if (data
.data
== NULL
) {
109 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset
));
113 ret
= talloc_zero(ctx
, struct registry_key
);
114 pull
= talloc_zero(ret
, struct tdr_pull
);
116 nk
= talloc(ret
, struct nk_block
);
118 if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull
, nk
))) {
119 DEBUG(1, ("Error parsing 'nk' record\n"));
124 if (strcmp(nk
->header
, "nk") != 0) {
125 DEBUG(0, ("Expected nk record, got %s\n", nk
->header
));
130 ret
->name
= talloc_steal(ret
, nk
->key_name
);
131 ret
->last_mod
= nk
->last_change
;
132 ret
->class_name
= NULL
; /* FIXME: get somehow using clsname_offset */
133 ret
->backend_data
= nk
;
138 static WERROR
regf_get_value (TALLOC_CTX
*ctx
, struct registry_key
*key
, int idx
, struct registry_value
**ret
)
140 struct nk_block
*nk
= key
->backend_data
;
142 struct tdr_pull
*pull
;
146 if (idx
>= nk
->num_values
)
147 return WERR_NO_MORE_ITEMS
;
149 data
= regf_get_data(key
->hive
->backend_data
, nk
->values_offset
);
151 DEBUG(0, ("Unable to find value list\n"));
152 return WERR_GENERAL_FAILURE
;
155 if (data
.length
< nk
->num_values
* 4) {
156 DEBUG(1, ("Value counts mismatch\n"));
159 vk_offset
= IVAL(data
.data
, idx
* 4);
161 data
= regf_get_data(key
->hive
->backend_data
, vk_offset
);
163 DEBUG(0, ("Unable to find value\n"));
164 return WERR_GENERAL_FAILURE
;
167 *ret
= talloc_zero(ctx
, struct registry_value
);
171 vk
= talloc(*ret
, struct vk_block
);
175 pull
= talloc_zero(*ret
, struct tdr_pull
);
178 if (NT_STATUS_IS_ERR(tdr_pull_vk_block(pull
, vk
))) {
179 DEBUG(0, ("Error parsing vk block\n"));
180 return WERR_GENERAL_FAILURE
;
183 (*ret
)->name
= talloc_steal(*ret
, vk
->data_name
);
184 (*ret
)->data_type
= vk
->data_type
;
185 if (vk
->data_length
& 0x80000000) {
186 vk
->data_length
&= ~0x80000000;
187 (*ret
)->data
.data
= (uint8_t *)&vk
->data_offset
;
188 (*ret
)->data
.length
= vk
->data_length
;
190 (*ret
)->data
= regf_get_data(key
->hive
->backend_data
, vk
->data_offset
);
193 if ((*ret
)->data
.length
< vk
->data_length
) {
194 DEBUG(1, ("Read data less then indicated data length!\n"));
200 static WERROR
regf_get_subkey (TALLOC_CTX
*ctx
, struct registry_key
*key
, int idx
, struct registry_key
**ret
)
203 struct nk_block
*nk
= key
->backend_data
;
206 if (idx
>= nk
->num_subkeys
)
207 return WERR_NO_MORE_ITEMS
;
209 data
= regf_get_data(key
->hive
->backend_data
, nk
->subkeys_offset
);
211 DEBUG(0, ("Unable to find subkey list\n"));
212 return WERR_GENERAL_FAILURE
;
215 if (!strncmp((char *)data
.data
, "li", 2)) {
216 DEBUG(4, ("Subkeys in LI list\n"));
218 } else if (!strncmp((char *)data
.data
, "lf", 2)) {
220 struct tdr_pull
*pull
= talloc_zero(ctx
, struct tdr_pull
);
222 DEBUG(10, ("Subkeys in LF list\n"));
225 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull
, &lf
))) {
226 DEBUG(0, ("Error parsing LF list\n"));
227 return WERR_GENERAL_FAILURE
;
230 if (lf
.key_count
!= nk
->num_subkeys
) {
231 DEBUG(0, ("Subkey counts don't match\n"));
232 return WERR_GENERAL_FAILURE
;
235 key_off
= lf
.hr
[idx
].nk_off
;
238 } else if (!strncmp((char *)data
.data
, "ri", 2)) {
239 DEBUG(4, ("Subkeys in RI list\n"));
241 } else if (!strncmp((char *)data
.data
, "lh", 2)) {
242 DEBUG(4, ("Subkeys in LH list\n"));
245 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk
->subkeys_offset
, data
.data
[0], data
.data
[1]));
246 return WERR_GENERAL_FAILURE
;
249 *ret
= regf_get_key (ctx
, key
->hive
->backend_data
, key_off
);
254 static WERROR
nt_open_hive (struct registry_hive
*h
, struct registry_key
**key
)
256 struct regf_data
*regf
;
257 struct regf_hdr
*regf_hdr
;
258 struct tdr_pull
*pull
;
261 regf
= (struct regf_data
*)talloc_zero(h
, struct regf_data
);
262 h
->backend_data
= regf
;
264 DEBUG(5, ("Attempting to load registry file\n"));
268 regf
->data
.data
= (uint8_t *)file_load(h
->location
, ®f
->data
.length
, regf
);
269 if (regf
->data
.data
== NULL
) {
270 DEBUG(0,("Could not load file: %s, %s\n", h
->location
,
272 return WERR_GENERAL_FAILURE
;
275 pull
= talloc_zero(regf
, struct tdr_pull
);
279 pull
->data
= regf
->data
;
281 regf_hdr
= talloc(regf
, struct regf_hdr
);
282 if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull
, regf_hdr
))) {
283 return WERR_GENERAL_FAILURE
;
286 if (strcmp(regf_hdr
->REGF_ID
, "regf") != 0) {
287 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
288 regf_hdr
->REGF_ID
, h
->location
));
291 DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n",
292 regf_hdr
->description
, regf_hdr
->version
.major
,
293 regf_hdr
->version
.minor
, regf_hdr
->version
.release
,
294 regf_hdr
->version
.build
));
297 * Validate the header ...
299 if (regf_hdr_checksum(regf
->data
.data
) != regf_hdr
->chksum
) {
300 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
301 h
->location
, regf_hdr
->chksum
, regf_hdr_checksum(regf
->data
.data
)));
302 return WERR_GENERAL_FAILURE
;
305 pull
->offset
= 0x1000;
308 /* Read in all hbin blocks */
309 regf
->hbins
= talloc_array(regf
, struct hbin_block
*, 1);
310 regf
->hbins
[0] = NULL
;
312 while (pull
->offset
< pull
->data
.length
) {
313 struct hbin_block
*hbin
= talloc(regf
->hbins
, struct hbin_block
);
315 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull
, hbin
))) {
316 DEBUG(0, ("[%d] Error parsing HBIN block\n", i
));
320 if (strcmp(hbin
->HBIN_ID
, "hbin") != 0) {
321 DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i
, hbin
->HBIN_ID
));
325 regf
->hbins
[i
] = hbin
;
327 regf
->hbins
= talloc_realloc(regf
, regf
->hbins
, struct hbin_block
*, i
+2);
328 regf
->hbins
[i
] = NULL
;
331 DEBUG(1, ("%d HBIN blocks read\n", i
));
333 *key
= regf_get_key(h
, regf
, 0x20);
338 static struct hive_operations reg_backend_nt4
= {
340 .open_hive
= nt_open_hive
,
341 .num_subkeys
= regf_num_subkeys
,
342 .num_values
= regf_num_values
,
343 .get_subkey_by_index
= regf_get_subkey
,
344 .get_value_by_index
= regf_get_value
,
347 NTSTATUS
registry_nt4_init(void)
349 return registry_register(®_backend_nt4
);