r10015: Change the NT4 registry backend to use the IDL-generate parse functions.
[Samba/aatanasov.git] / source / lib / registry / reg_backend_nt4.c
blobe0f5ccd08c902e8e9777f923a0bedbfacc754c6e
1 /*
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. */
20 #include "includes.h"
21 #include "registry.h"
22 #include "system/filesys.h"
23 #include "lib/registry/tdr_regf.h"
26 * Read HBIN blocks into memory
29 struct regf_data {
30 DATA_BLOB data;
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;
41 int i;
43 for (i = 0; i < 0x01FB; i+= 4) {
44 x = IVAL(buffer, i);
45 checksum ^= x;
48 return checksum;
51 static DATA_BLOB regf_get_data(const struct regf_data *data, uint32_t offset)
53 int i;
54 DATA_BLOB ret;
55 ret.data = NULL;
56 ret.length = 0;
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)
62 break;
65 if (data->hbins[i] == NULL) {
66 DEBUG(1, ("Can't find HBIN containing 0x%4x\n", offset));
67 return ret;
70 ret.length = IVAL(data->hbins[i]->data,
71 offset - data->hbins[i]->offset_from_first - 0x20);
72 if (ret.length & 0x80000000) {
73 /* absolute value */
74 ret.length = (ret.length ^ 0xffffffff) + 1;
76 ret.data = data->hbins[i]->data +
77 (offset - data->hbins[i]->offset_from_first - 0x20) + 4;
79 return ret;
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;
89 return WERR_OK;
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;
98 return WERR_OK;
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;
106 struct nk_block *nk;
108 if (data.data == NULL) {
109 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
110 return NULL;
113 ret = talloc_zero(ctx, struct registry_key);
114 pull = talloc_zero(ret, struct tdr_pull);
115 pull->data = data;
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"));
120 talloc_free(ret);
121 return NULL;
124 if (strcmp(nk->header, "nk") != 0) {
125 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
126 talloc_free(ret);
127 return NULL;
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;
135 return ret;
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;
141 struct vk_block *vk;
142 struct tdr_pull *pull;
143 uint32_t vk_offset;
144 DATA_BLOB data;
146 if (idx >= nk->num_values)
147 return WERR_NO_MORE_ITEMS;
149 data = regf_get_data(key->hive->backend_data, nk->values_offset);
150 if (!data.data) {
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);
162 if (!data.data) {
163 DEBUG(0, ("Unable to find value\n"));
164 return WERR_GENERAL_FAILURE;
167 *ret = talloc_zero(ctx, struct registry_value);
168 if (!(*ret))
169 return WERR_NOMEM;
171 vk = talloc(*ret, struct vk_block);
172 if (!vk)
173 return WERR_NOMEM;
175 pull = talloc_zero(*ret, struct tdr_pull);
176 pull->data = data;
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;
189 } else {
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"));
197 return WERR_OK;
200 static WERROR regf_get_subkey (TALLOC_CTX *ctx, struct registry_key *key, int idx, struct registry_key **ret)
202 DATA_BLOB data;
203 struct nk_block *nk = key->backend_data;
204 uint32_t key_off;
206 if (idx >= nk->num_subkeys)
207 return WERR_NO_MORE_ITEMS;
209 data = regf_get_data(key->hive->backend_data, nk->subkeys_offset);
210 if (!data.data) {
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"));
217 SMB_ASSERT(0);
218 } else if (!strncmp((char *)data.data, "lf", 2)) {
219 struct lf_block lf;
220 struct tdr_pull *pull = talloc_zero(ctx, struct tdr_pull);
222 DEBUG(10, ("Subkeys in LF list\n"));
223 pull->data = data;
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;
237 talloc_free(pull);
238 } else if (!strncmp((char *)data.data, "ri", 2)) {
239 DEBUG(4, ("Subkeys in RI list\n"));
240 SMB_ASSERT(0);
241 } else if (!strncmp((char *)data.data, "lh", 2)) {
242 DEBUG(4, ("Subkeys in LH list\n"));
243 SMB_ASSERT(0);
244 } else {
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);
251 return WERR_OK;
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;
259 int i;
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"));
266 /* Get the header */
268 regf->data.data = (uint8_t *)file_load(h->location, &regf->data.length, regf);
269 if (regf->data.data == NULL) {
270 DEBUG(0,("Could not load file: %s, %s\n", h->location,
271 strerror(errno)));
272 return WERR_GENERAL_FAILURE;
275 pull = talloc_zero(regf, struct tdr_pull);
276 if (!pull)
277 return WERR_NOMEM;
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;
307 i = 0;
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));
317 return WERR_FOOBAR;
320 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
321 DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
322 return WERR_FOOBAR;
325 regf->hbins[i] = hbin;
326 i++;
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);
335 return WERR_OK;
338 static struct hive_operations reg_backend_nt4 = {
339 .name = "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(&reg_backend_nt4);