r15356: Remove unused 'flags' argument from socket_send() and friends.
[bbaumbach/samba-autobuild/.git] / source4 / lib / registry / reg_backend_w95.c
1 /*
2    Samba Unix/Linux SMB client utility libeditreg.c 
3    Copyright (C) 2004 Jelmer Vernooij, jelmer@samba.org
4
5    Backend for Windows '95 registry files. Explanation of file format 
6    comes from http://www.cs.mun.ca/~michael/regutils/.
7
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.
12    
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.
17    
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.  */
21
22 #include "includes.h"
23 #include "registry.h"
24 #include "system/filesys.h"
25 #include "system/shmem.h"
26
27 /**
28  * The registry starts with a header that contains pointers to 
29  * the rgdb.
30  *
31  * After the main header follows the RGKN header (key index table).
32  * The RGKN keys are listed after each other. They are put into 
33  * blocks, the first having a length of 0x2000 bytes, the others 
34  * being 0x1000 bytes long.
35  *
36  * After the RGKN header follow one or more RGDB blocks. These blocks 
37  * contain keys. A key is followed by its name and its values.
38  *
39  * Values are followed by their name and then their data.
40  *
41  * Basically the idea is that the RGKN contains the associations between 
42  * the keys and the RGDB contains the actual data.
43  */
44
45 typedef uint32_t DWORD;
46 typedef unsigned short WORD;
47
48 typedef struct creg_block {
49         DWORD CREG_ID;          /* CREG */
50         DWORD uk1;
51         DWORD rgdb_offset;
52         DWORD chksum;
53         WORD  num_rgdb;
54         WORD  flags;
55         DWORD uk2;
56         DWORD uk3;
57         DWORD uk4;
58 } CREG_HDR;
59
60 typedef struct rgkn_block {
61         DWORD RGKN_ID;          /* RGKN */
62         DWORD size;
63         DWORD root_offset;
64         DWORD free_offset;
65         DWORD flags;
66         DWORD chksum;
67         DWORD uk1;
68         DWORD uk2;
69 } RGKN_HDR;
70
71 typedef struct reg_id {
72         WORD id;
73         WORD rgdb;
74 } REG_ID;
75
76 typedef struct rgkn_key {
77         DWORD type;                     /* 0x00000000 = normal key, 0x80000000 = free block */
78         DWORD hash;                     /* Contains either hash or size of free blocks that follows */
79         DWORD next_free;
80         DWORD parent_offset;
81         DWORD first_child_offset;
82         DWORD next_offset;
83         REG_ID id;
84 } RGKN_KEY;
85
86
87 typedef struct rgdb_block {
88         DWORD RGDB_ID;          /* RGDB */
89         DWORD size;
90         DWORD unused_size;
91         WORD flags;
92         WORD section;
93         DWORD free_offset;      /* -1 if there is no free space */
94         WORD max_id;
95         WORD first_free_id;
96         DWORD uk1;
97         DWORD chksum;
98 } RGDB_HDR;
99
100 typedef struct rgdb_key {
101         DWORD size;
102         REG_ID id;
103         DWORD used_size;
104         WORD  name_len;
105         WORD  num_values;
106         DWORD uk1;
107 } RGDB_KEY;
108
109 typedef struct rgdb_value {
110         DWORD type;
111         DWORD uk1;
112         WORD name_len;
113         WORD data_len;
114 } RGDB_VALUE;
115
116 typedef struct creg_struct_s {
117         int fd;
118         BOOL modified;
119         char *base;
120         struct stat sbuf;
121         CREG_HDR *creg_hdr;
122         RGKN_HDR *rgkn_hdr;
123         RGDB_KEY ***rgdb_keys;
124 } CREG;
125
126 #define RGKN_START_SIZE 0x2000
127 #define RGKN_INC_SIZE   0x1000
128
129 #define LOCN_RGKN(creg, o) ((RGKN_KEY *)((creg)->base + sizeof(CREG_HDR) + o))
130 #define LOCN_RGDB_BLOCK(creg, o) (((creg)->base + (creg)->creg_hdr->rgdb_offset + o))
131 #define LOCN_RGDB_KEY(creg, rgdb, id) ((RGDB_KEY *)((creg)->rgdb_keys[(rgdb)][(id)]))
132
133 static DWORD str_to_dword(const char *a) {
134     int i;
135     unsigned long ret = 0;
136     for(i = strlen(a)-1; i >= 0; i--) {
137         ret = ret * 0x100 + a[i];
138     }
139     return ret;
140 }
141
142 #if 0 /* unused */
143
144 static DWORD calc_hash(const char *str) {
145         DWORD ret = 0;
146         int i;
147         for(i = 0; str[i] && str[i] != '\\'; i++) {
148                 ret+=toupper(str[i]);
149         }
150         return ret;
151 }
152
153 static void parse_rgkn_block(CREG *creg, off_t start_off, off_t end_off) 
154 {
155         off_t i;
156         for(i = start_off; end_off - i > sizeof(RGKN_KEY); i+= sizeof(RGKN_KEY)) {
157                 RGKN_KEY *key = (RGKN_KEY *)LOCN_RGKN(creg, i);
158                 if(key->type == 0) {
159                         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));
160                 } else if(key->type == 0x80000000) {
161                         DEBUG(3,("free\n"));
162                         i += key->hash;
163                 } else {
164                         DEBUG(0,("Invalid key type in RGKN: %0X\n", key->type));
165                 }
166         }
167 }
168
169 #endif
170
171 static void parse_rgdb_block(CREG *creg, RGDB_HDR *rgdb_hdr)
172 {
173         DWORD used_size = rgdb_hdr->size - rgdb_hdr->unused_size;
174         DWORD offset = 0;
175
176         while(offset < used_size) {
177                 RGDB_KEY *key = (RGDB_KEY *)(((char *)rgdb_hdr) + sizeof(RGDB_HDR) + offset);
178                 
179                 if(!(key->id.id == 0xFFFF && key->id.rgdb == 0xFFFF))creg->rgdb_keys[key->id.rgdb][key->id.id] = key;
180                 offset += key->size;
181         }
182 }
183
184 static WERROR w95_open_reg (struct registry_hive *h, struct registry_key **root)
185 {
186         CREG *creg;
187         DWORD creg_id, rgkn_id;
188         DWORD i;
189         DWORD offset;
190
191         creg = talloc(h, CREG);
192         memset(creg, 0, sizeof(CREG));
193         h->backend_data = creg;
194
195         if((creg->fd = open(h->location, O_RDONLY, 0000)) < 0) {
196                 return WERR_FOOBAR;
197         }
198
199     if (fstat(creg->fd, &creg->sbuf) < 0) {
200                 return WERR_FOOBAR;
201     }
202
203     creg->base = mmap(0, creg->sbuf.st_size, PROT_READ, MAP_SHARED, creg->fd, 0);
204                                                                                                                                               
205     if ((int)creg->base == 1) {
206                 DEBUG(0,("Could not mmap file: %s, %s\n", h->location, strerror(errno)));
207         return WERR_FOOBAR;
208     }
209
210         creg->creg_hdr = (CREG_HDR *)creg->base;
211
212         if ((creg_id = IVAL(&creg->creg_hdr->CREG_ID,0)) != str_to_dword("CREG")) {
213                 DEBUG(0, ("Unrecognized Windows 95 registry header id: 0x%0X, %s\n", 
214                                   creg_id, h->location));
215                 return WERR_FOOBAR;
216         }
217
218         creg->rgkn_hdr = (RGKN_HDR *)LOCN_RGKN(creg, 0);
219
220         if ((rgkn_id = IVAL(&creg->rgkn_hdr->RGKN_ID,0)) != str_to_dword("RGKN")) {
221                 DEBUG(0, ("Unrecognized Windows 95 registry key index id: 0x%0X, %s\n", 
222                                   rgkn_id, h->location));
223                 return WERR_FOOBAR;
224         }
225
226 #if 0   
227         /* If'ed out because we only need to parse this stuff when allocating new 
228          * entries (which we don't do at the moment */
229         /* First parse the 0x2000 long block */
230         parse_rgkn_block(creg, sizeof(RGKN_HDR), 0x2000);
231
232         /* Then parse the other 0x1000 length blocks */
233         for(offset = 0x2000; offset < creg->rgkn_hdr->size; offset+=0x1000) {
234                 parse_rgkn_block(creg, offset, offset+0x1000);
235         }
236 #endif
237
238         creg->rgdb_keys = talloc_array(h, RGDB_KEY **, creg->creg_hdr->num_rgdb);
239
240         offset = 0;
241         DEBUG(3, ("Reading %d rgdb entries\n", creg->creg_hdr->num_rgdb));
242         for(i = 0; i < creg->creg_hdr->num_rgdb; i++) {
243                 RGDB_HDR *rgdb_hdr = (RGDB_HDR *)LOCN_RGDB_BLOCK(creg, offset);
244                 
245                 if(strncmp((char *)&(rgdb_hdr->RGDB_ID), "RGDB", 4)) {
246                         DEBUG(0, ("unrecognized rgdb entry: %4d, %s\n", 
247                                           rgdb_hdr->RGDB_ID, h->location));
248                         return WERR_FOOBAR;
249                 } else {
250                         DEBUG(3, ("Valid rgdb entry, first free id: %d, max id: %d\n", rgdb_hdr->first_free_id, rgdb_hdr->max_id));
251                 }
252
253
254                 creg->rgdb_keys[i] = talloc_array(h, RGDB_KEY *, rgdb_hdr->max_id+1);
255                 memset(creg->rgdb_keys[i], 0, sizeof(RGDB_KEY *) * (rgdb_hdr->max_id+1));
256
257                 parse_rgdb_block(creg, rgdb_hdr);
258
259                 offset+=rgdb_hdr->size;
260         }
261         
262         /* First element in rgkn should be root key */
263         *root = talloc(h, struct registry_key);
264         (*root)->name = NULL;
265         (*root)->backend_data = LOCN_RGKN(creg, sizeof(RGKN_HDR));
266         
267         return WERR_OK;
268 }
269
270 static WERROR w95_get_subkey_by_index (TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_key **key)
271 {
272         CREG *creg = parent->hive->backend_data;
273         RGKN_KEY *rgkn_key = parent->backend_data;
274         RGKN_KEY *child;
275         DWORD child_offset;
276         DWORD cur = 0;
277         
278         /* Get id of first child */
279         child_offset = rgkn_key->first_child_offset;
280
281         while(child_offset != 0xFFFFFFFF) {
282                 child = LOCN_RGKN(creg, child_offset);
283
284                 /* n == cur ? return! */
285                 if(cur == n) {
286                         RGDB_KEY *rgdb_key;
287                         rgdb_key = LOCN_RGDB_KEY(creg, child->id.rgdb, child->id.id);
288                         if(!rgdb_key) {
289                                 DEBUG(0, ("Can't find %d,%d in RGDB table!\n", child->id.rgdb, child->id.id));
290                                 return WERR_FOOBAR;
291                         }
292                         *key = talloc(mem_ctx, struct registry_key);
293                         (*key)->backend_data = child;
294                         (*key)->name = talloc_strndup(mem_ctx, (char *)rgdb_key + sizeof(RGDB_KEY), rgdb_key->name_len);
295                         return WERR_OK;
296                 }
297
298                 cur++;
299                 
300                 child_offset = child->next_offset;
301         }
302
303         return WERR_NO_MORE_ITEMS;
304 }
305
306 static WERROR w95_num_values(const struct registry_key *k, uint32_t *count)
307 {
308         RGKN_KEY *rgkn_key = k->backend_data;
309         RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
310
311         if(!rgdb_key) return WERR_FOOBAR;
312         
313         *count = rgdb_key->num_values;
314         
315         return WERR_OK;
316 }
317
318 static WERROR w95_get_value_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_value **value)
319 {
320         RGKN_KEY *rgkn_key = k->backend_data;
321         DWORD i;
322         DWORD offset = 0;
323         RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
324         RGDB_VALUE *curval = NULL;
325
326         if(!rgdb_key) return WERR_FOOBAR;
327         
328         if(idx >= rgdb_key->num_values) return WERR_NO_MORE_ITEMS;
329         
330         for(i = 0; i < idx; i++) {
331                 curval = (RGDB_VALUE *)(((char *)rgdb_key) + sizeof(RGDB_KEY) + rgdb_key->name_len + offset);
332                 offset+=sizeof(RGDB_VALUE) + curval->name_len + curval->data_len;
333         }
334
335         *value = talloc(mem_ctx, struct registry_value);
336         (*value)->name = talloc_strndup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE), curval->name_len);
337                 
338         (*value)->data = data_blob_talloc(mem_ctx, curval+sizeof(RGDB_VALUE)+curval->name_len, curval->data_len);
339         (*value)->data_type = curval->type;
340         
341         return WERR_OK;
342 }
343
344 static struct hive_operations reg_backend_w95 = {
345         .name = "w95",
346         .open_hive = w95_open_reg,
347         .get_value_by_index = w95_get_value_by_id,
348         .num_values = w95_num_values,
349         .get_subkey_by_index = w95_get_subkey_by_index,
350 };
351
352 NTSTATUS registry_w95_init(void)
353 {
354         return registry_register(&reg_backend_w95);
355 }