r3737: - Get rid of the register_subsystem() and register_backend() functions.
[Samba/aatanasov.git] / source / lib / registry / reg_backend_w95 / reg_backend_w95.c
blobfb73e9052c296c006066ce4e2cb90a4fddfd9497
1 /*
2 Samba Unix/Linux SMB client utility libeditreg.c
3 Copyright (C) 2004 Jelmer Vernooij, jelmer@samba.org
5 Backend for Windows '95 registry files. Explanation of file format
6 comes from http://www.cs.mun.ca/~michael/regutils/.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22 #include "includes.h"
23 #include "registry.h"
24 #include "system/shmem.h"
26 /**
27 * The registry starts with a header that contains pointers to
28 * the rgdb.
30 * After the main header follows the RGKN header (key index table).
31 * The RGKN keys are listed after each other. They are put into
32 * blocks, the first having a length of 0x2000 bytes, the others
33 * being 0x1000 bytes long.
35 * After the RGKN header follow one or more RGDB blocks. These blocks
36 * contain keys. A key is followed by its name and its values.
38 * Values are followed by their name and then their data.
40 * Basically the idea is that the RGKN contains the associations between
41 * the keys and the RGDB contains the actual data.
44 typedef uint_t DWORD;
45 typedef unsigned short WORD;
47 typedef struct creg_block {
48 DWORD CREG_ID; /* CREG */
49 DWORD uk1;
50 DWORD rgdb_offset;
51 DWORD chksum;
52 WORD num_rgdb;
53 WORD flags;
54 DWORD uk2;
55 DWORD uk3;
56 DWORD uk4;
57 } CREG_HDR;
59 typedef struct rgkn_block {
60 DWORD RGKN_ID; /* RGKN */
61 DWORD size;
62 DWORD root_offset;
63 DWORD free_offset;
64 DWORD flags;
65 DWORD chksum;
66 DWORD uk1;
67 DWORD uk2;
68 } RGKN_HDR;
70 typedef struct reg_id {
71 WORD id;
72 WORD rgdb;
73 } REG_ID;
75 typedef struct rgkn_key {
76 DWORD type; /* 0x00000000 = normal key, 0x80000000 = free block */
77 DWORD hash; /* Contains either hash or size of free blocks that follows */
78 DWORD next_free;
79 DWORD parent_offset;
80 DWORD first_child_offset;
81 DWORD next_offset;
82 REG_ID id;
83 } RGKN_KEY;
86 typedef struct rgdb_block {
87 DWORD RGDB_ID; /* RGDB */
88 DWORD size;
89 DWORD unused_size;
90 WORD flags;
91 WORD section;
92 DWORD free_offset; /* -1 if there is no free space */
93 WORD max_id;
94 WORD first_free_id;
95 DWORD uk1;
96 DWORD chksum;
97 } RGDB_HDR;
99 typedef struct rgdb_key {
100 DWORD size;
101 REG_ID id;
102 DWORD used_size;
103 WORD name_len;
104 WORD num_values;
105 DWORD uk1;
106 } RGDB_KEY;
108 typedef struct rgdb_value {
109 DWORD type;
110 DWORD uk1;
111 WORD name_len;
112 WORD data_len;
113 } RGDB_VALUE;
115 typedef struct creg_struct_s {
116 int fd;
117 BOOL modified;
118 char *base;
119 struct stat sbuf;
120 CREG_HDR *creg_hdr;
121 RGKN_HDR *rgkn_hdr;
122 RGDB_KEY ***rgdb_keys;
123 } CREG;
125 #define RGKN_START_SIZE 0x2000
126 #define RGKN_INC_SIZE 0x1000
128 #define LOCN_RGKN(creg, o) ((RGKN_KEY *)((creg)->base + sizeof(CREG_HDR) + o))
129 #define LOCN_RGDB_BLOCK(creg, o) (((creg)->base + (creg)->creg_hdr->rgdb_offset + o))
130 #define LOCN_RGDB_KEY(creg, rgdb, id) ((RGDB_KEY *)((creg)->rgdb_keys[(rgdb)][(id)]))
132 static DWORD str_to_dword(const char *a) {
133 int i;
134 unsigned long ret = 0;
135 for(i = strlen(a)-1; i >= 0; i--) {
136 ret = ret * 0x100 + a[i];
138 return ret;
141 #if 0 /* unused */
143 static DWORD calc_hash(const char *str) {
144 DWORD ret = 0;
145 int i;
146 for(i = 0; str[i] && str[i] != '\\'; i++) {
147 ret+=toupper(str[i]);
149 return ret;
152 static void parse_rgkn_block(CREG *creg, off_t start_off, off_t end_off)
154 off_t i;
155 for(i = start_off; end_off - i > sizeof(RGKN_KEY); i+= sizeof(RGKN_KEY)) {
156 RGKN_KEY *key = (RGKN_KEY *)LOCN_RGKN(creg, i);
157 if(key->type == 0) {
158 DEBUG(4,("Regular, id: %d, %d, parent: %x, firstchild: %x, next: %x hash: %lX\n", key->id.id, key->id.rgdb, key->parent_offset, key->first_child_offset, key->next_offset, (long)key->hash));
159 } else if(key->type == 0x80000000) {
160 DEBUG(3,("free\n"));
161 i += key->hash;
162 } else {
163 DEBUG(0,("Invalid key type in RGKN: %0X\n", key->type));
168 #endif
170 static void parse_rgdb_block(CREG *creg, RGDB_HDR *rgdb_hdr)
172 DWORD used_size = rgdb_hdr->size - rgdb_hdr->unused_size;
173 DWORD offset = 0;
175 while(offset < used_size) {
176 RGDB_KEY *key = (RGDB_KEY *)(((char *)rgdb_hdr) + sizeof(RGDB_HDR) + offset);
178 if(!(key->id.id == 0xFFFF && key->id.rgdb == 0xFFFF))creg->rgdb_keys[key->id.rgdb][key->id.id] = key;
179 offset += key->size;
183 static WERROR w95_open_reg (TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **root)
185 CREG *creg;
186 DWORD creg_id, rgkn_id;
187 DWORD i;
188 DWORD offset;
190 creg = talloc_p(mem_ctx, CREG);
191 memset(creg, 0, sizeof(CREG));
192 h->backend_data = creg;
194 if((creg->fd = open(h->location, O_RDONLY, 0000)) < 0) {
195 return WERR_FOOBAR;
198 if (fstat(creg->fd, &creg->sbuf) < 0) {
199 return WERR_FOOBAR;
202 creg->base = mmap(0, creg->sbuf.st_size, PROT_READ, MAP_SHARED, creg->fd, 0);
204 if ((int)creg->base == 1) {
205 DEBUG(0,("Could not mmap file: %s, %s\n", h->location, strerror(errno)));
206 return WERR_FOOBAR;
209 creg->creg_hdr = (CREG_HDR *)creg->base;
211 if ((creg_id = IVAL(&creg->creg_hdr->CREG_ID,0)) != str_to_dword("CREG")) {
212 DEBUG(0, ("Unrecognized Windows 95 registry header id: 0x%0X, %s\n",
213 creg_id, h->location));
214 return WERR_FOOBAR;
217 creg->rgkn_hdr = (RGKN_HDR *)LOCN_RGKN(creg, 0);
219 if ((rgkn_id = IVAL(&creg->rgkn_hdr->RGKN_ID,0)) != str_to_dword("RGKN")) {
220 DEBUG(0, ("Unrecognized Windows 95 registry key index id: 0x%0X, %s\n",
221 rgkn_id, h->location));
222 return WERR_FOOBAR;
225 #if 0
226 /* If'ed out because we only need to parse this stuff when allocating new
227 * entries (which we don't do at the moment */
228 /* First parse the 0x2000 long block */
229 parse_rgkn_block(creg, sizeof(RGKN_HDR), 0x2000);
231 /* Then parse the other 0x1000 length blocks */
232 for(offset = 0x2000; offset < creg->rgkn_hdr->size; offset+=0x1000) {
233 parse_rgkn_block(creg, offset, offset+0x1000);
235 #endif
237 creg->rgdb_keys = talloc_array_p(mem_ctx, RGDB_KEY **, creg->creg_hdr->num_rgdb);
239 offset = 0;
240 DEBUG(3, ("Reading %d rgdb entries\n", creg->creg_hdr->num_rgdb));
241 for(i = 0; i < creg->creg_hdr->num_rgdb; i++) {
242 RGDB_HDR *rgdb_hdr = (RGDB_HDR *)LOCN_RGDB_BLOCK(creg, offset);
244 if(strncmp((char *)&(rgdb_hdr->RGDB_ID), "RGDB", 4)) {
245 DEBUG(0, ("unrecognized rgdb entry: %4d, %s\n",
246 rgdb_hdr->RGDB_ID, h->location));
247 return WERR_FOOBAR;
248 } else {
249 DEBUG(3, ("Valid rgdb entry, first free id: %d, max id: %d\n", rgdb_hdr->first_free_id, rgdb_hdr->max_id));
253 creg->rgdb_keys[i] = talloc_array_p(mem_ctx, RGDB_KEY *, rgdb_hdr->max_id+1);
254 memset(creg->rgdb_keys[i], 0, sizeof(RGDB_KEY *) * (rgdb_hdr->max_id+1));
256 parse_rgdb_block(creg, rgdb_hdr);
258 offset+=rgdb_hdr->size;
261 /* First element in rgkn should be root key */
262 *root = talloc_p(mem_ctx, struct registry_key);
263 (*root)->name = NULL;
264 (*root)->backend_data = LOCN_RGKN(creg, sizeof(RGKN_HDR));
266 return WERR_OK;
269 static WERROR w95_get_subkey_by_index (TALLOC_CTX *mem_ctx, struct registry_key *parent, int n, struct registry_key **key)
271 CREG *creg = parent->hive->backend_data;
272 RGKN_KEY *rgkn_key = parent->backend_data;
273 RGKN_KEY *child;
274 DWORD child_offset;
275 DWORD cur = 0;
277 /* Get id of first child */
278 child_offset = rgkn_key->first_child_offset;
280 while(child_offset != 0xFFFFFFFF) {
281 child = LOCN_RGKN(creg, child_offset);
283 /* n == cur ? return! */
284 if(cur == n) {
285 RGDB_KEY *rgdb_key;
286 rgdb_key = LOCN_RGDB_KEY(creg, child->id.rgdb, child->id.id);
287 if(!rgdb_key) {
288 DEBUG(0, ("Can't find %d,%d in RGDB table!\n", child->id.rgdb, child->id.id));
289 return WERR_FOOBAR;
291 *key = talloc_p(mem_ctx, struct registry_key);
292 (*key)->backend_data = child;
293 (*key)->name = talloc_strndup(mem_ctx, (char *)rgdb_key + sizeof(RGDB_KEY), rgdb_key->name_len);
294 return WERR_OK;
297 cur++;
299 child_offset = child->next_offset;
302 return WERR_NO_MORE_ITEMS;
305 static WERROR w95_num_values(struct registry_key *k, int *count)
307 RGKN_KEY *rgkn_key = k->backend_data;
308 RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
310 if(!rgdb_key) return WERR_FOOBAR;
312 *count = rgdb_key->num_values;
314 return WERR_OK;
317 static WERROR w95_get_value_by_id(TALLOC_CTX *mem_ctx, struct registry_key *k, int idx, struct registry_value **value)
319 RGKN_KEY *rgkn_key = k->backend_data;
320 DWORD i;
321 DWORD offset = 0;
322 RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
323 RGDB_VALUE *curval;
325 if(!rgdb_key) return WERR_FOOBAR;
327 if(idx >= rgdb_key->num_values) return WERR_NO_MORE_ITEMS;
329 for(i = 0; i < idx; i++) {
330 curval = (RGDB_VALUE *)(((char *)rgdb_key) + sizeof(RGDB_KEY) + rgdb_key->name_len + offset);
331 offset+=sizeof(RGDB_VALUE) + curval->name_len + curval->data_len;
334 *value = talloc_p(mem_ctx, struct registry_value);
335 (*value)->backend_data = curval;
336 (*value)->name = talloc_strndup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE), curval->name_len);
338 (*value)->data_len = curval->data_len;
339 (*value)->data_blk = talloc_memdup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE)+curval->name_len, curval->data_len);
340 (*value)->data_type = curval->type;
342 return WERR_OK;
345 static struct registry_operations reg_backend_w95 = {
346 .name = "w95",
347 .open_hive = w95_open_reg,
348 .get_value_by_index = w95_get_value_by_id,
349 .num_values = w95_num_values,
350 .get_subkey_by_index = w95_get_subkey_by_index,
353 NTSTATUS registry_w95_init(void)
355 return registry_register(&reg_backend_w95);