Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Reading Registry.pol PReg registry files
4 :
5 : Copyright (C) Wilco Baan Hofman 2006-2008
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program; if not, write to the Free Software
19 : Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/registry/registry.h"
24 : #include "system/filesys.h"
25 : #include "librpc/gen_ndr/winreg.h"
26 : #include "lib/util/sys_rw.h"
27 :
28 : #undef strcasecmp
29 : #undef strncasecmp
30 :
31 : struct preg_data {
32 : int fd;
33 : TALLOC_CTX *ctx;
34 : };
35 :
36 171 : static WERROR preg_read_utf16(int fd, char *c)
37 : {
38 171 : uint16_t v;
39 :
40 171 : if (read(fd, &v, sizeof(uint16_t)) < sizeof(uint16_t)) {
41 1 : return WERR_GEN_FAILURE;
42 : }
43 170 : push_codepoint(c, v);
44 170 : return WERR_OK;
45 : }
46 24 : static WERROR preg_write_utf16(int fd, const char *string)
47 : {
48 24 : uint16_t v;
49 24 : size_t i, size;
50 :
51 194 : for (i = 0; i < strlen(string); i+=size) {
52 170 : v = next_codepoint(&string[i], &size);
53 170 : if (write(fd, &v, sizeof(uint16_t)) < sizeof(uint16_t)) {
54 0 : return WERR_GEN_FAILURE;
55 : }
56 : }
57 24 : return WERR_OK;
58 : }
59 : /* PReg does not support adding keys. */
60 6 : static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
61 : {
62 6 : return WERR_OK;
63 : }
64 :
65 3 : static WERROR reg_preg_diff_set_value(void *_data, const char *key_name,
66 : const char *value_name,
67 : uint32_t value_type, DATA_BLOB value_data)
68 : {
69 3 : struct preg_data *data = (struct preg_data *)_data;
70 3 : uint32_t buf;
71 :
72 3 : preg_write_utf16(data->fd, "[");
73 3 : preg_write_utf16(data->fd, key_name);
74 3 : preg_write_utf16(data->fd, ";");
75 3 : preg_write_utf16(data->fd, value_name);
76 3 : preg_write_utf16(data->fd, ";");
77 3 : SIVAL(&buf, 0, value_type);
78 3 : sys_write_v(data->fd, &buf, sizeof(uint32_t));
79 3 : preg_write_utf16(data->fd, ";");
80 3 : SIVAL(&buf, 0, value_data.length);
81 3 : sys_write_v(data->fd, &buf, sizeof(uint32_t));
82 3 : preg_write_utf16(data->fd, ";");
83 3 : sys_write_v(data->fd, value_data.data, value_data.length);
84 3 : preg_write_utf16(data->fd, "]");
85 :
86 3 : return WERR_OK;
87 : }
88 :
89 2 : static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
90 : {
91 2 : struct preg_data *data = (struct preg_data *)_data;
92 2 : char *parent_name;
93 2 : DATA_BLOB blob;
94 2 : WERROR werr;
95 :
96 4 : parent_name = talloc_strndup(data->ctx, key_name,
97 2 : strrchr(key_name, '\\')-key_name);
98 2 : W_ERROR_HAVE_NO_MEMORY(parent_name);
99 4 : blob.data = (uint8_t*)talloc_strndup(data->ctx,
100 0 : key_name+(strrchr(key_name, '\\')-key_name)+1,
101 2 : strlen(key_name)-(strrchr(key_name, '\\')-key_name));
102 2 : W_ERROR_HAVE_NO_MEMORY(blob.data);
103 2 : blob.length = strlen((char *)blob.data)+1;
104 :
105 :
106 : /* FIXME: These values should be accumulated to be written at done(). */
107 2 : werr = reg_preg_diff_set_value(data, parent_name, "**DeleteKeys",
108 : REG_SZ, blob);
109 :
110 2 : talloc_free(parent_name);
111 2 : talloc_free(blob.data);
112 :
113 2 : return werr;
114 : }
115 :
116 0 : static WERROR reg_preg_diff_del_value(void *_data, const char *key_name,
117 : const char *value_name)
118 : {
119 0 : struct preg_data *data = (struct preg_data *)_data;
120 0 : char *val;
121 0 : DATA_BLOB blob;
122 0 : WERROR werr;
123 :
124 0 : val = talloc_asprintf(data->ctx, "**Del.%s", value_name);
125 0 : W_ERROR_HAVE_NO_MEMORY(val);
126 0 : blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
127 0 : W_ERROR_HAVE_NO_MEMORY(blob.data);
128 0 : SIVAL(blob.data, 0, 0);
129 0 : blob.length = sizeof(uint32_t);
130 :
131 0 : werr = reg_preg_diff_set_value(data, key_name, val, REG_DWORD, blob);
132 :
133 0 : talloc_free(val);
134 0 : talloc_free(blob.data);
135 :
136 0 : return werr;
137 : }
138 :
139 0 : static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
140 : {
141 0 : struct preg_data *data = (struct preg_data *)_data;
142 0 : DATA_BLOB blob;
143 0 : WERROR werr;
144 :
145 0 : blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
146 0 : W_ERROR_HAVE_NO_MEMORY(blob.data);
147 0 : SIVAL(blob.data, 0, 0);
148 0 : blob.length = sizeof(uint32_t);
149 :
150 0 : werr = reg_preg_diff_set_value(data, key_name, "**DelVals.", REG_DWORD,
151 : blob);
152 :
153 0 : talloc_free(blob.data);
154 :
155 0 : return werr;
156 : }
157 :
158 1 : static WERROR reg_preg_diff_done(void *_data)
159 : {
160 1 : struct preg_data *data = (struct preg_data *)_data;
161 :
162 1 : close(data->fd);
163 1 : talloc_free(data);
164 1 : return WERR_OK;
165 : }
166 :
167 : /**
168 : * Save registry diff
169 : */
170 1 : _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
171 : struct reg_diff_callbacks **callbacks,
172 : void **callback_data)
173 : {
174 1 : struct preg_data *data;
175 1 : struct {
176 : char hdr[4];
177 : uint32_t version;
178 : } preg_header;
179 :
180 :
181 1 : data = talloc_zero(ctx, struct preg_data);
182 1 : *callback_data = data;
183 :
184 1 : if (filename) {
185 1 : data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
186 1 : if (data->fd < 0) {
187 0 : DEBUG(0, ("Unable to open %s\n", filename));
188 0 : return WERR_FILE_NOT_FOUND;
189 : }
190 : } else {
191 0 : data->fd = STDOUT_FILENO;
192 : }
193 :
194 1 : memcpy(preg_header.hdr, "PReg", sizeof(preg_header.hdr));
195 1 : SIVAL(&preg_header.version, 0, 1);
196 1 : sys_write_v(data->fd, (uint8_t *)&preg_header, sizeof(preg_header));
197 :
198 1 : data->ctx = ctx;
199 :
200 1 : *callbacks = talloc(ctx, struct reg_diff_callbacks);
201 :
202 1 : (*callbacks)->add_key = reg_preg_diff_add_key;
203 1 : (*callbacks)->del_key = reg_preg_diff_del_key;
204 1 : (*callbacks)->set_value = reg_preg_diff_set_value;
205 1 : (*callbacks)->del_value = reg_preg_diff_del_value;
206 1 : (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
207 1 : (*callbacks)->done = reg_preg_diff_done;
208 :
209 1 : return WERR_OK;
210 : }
211 : /**
212 : * Load diff file
213 : */
214 1 : _PUBLIC_ WERROR reg_preg_diff_load(int fd,
215 : const struct reg_diff_callbacks *callbacks,
216 : void *callback_data)
217 : {
218 1 : struct {
219 : char hdr[4];
220 : uint32_t version;
221 : } preg_header;
222 1 : char *buf;
223 1 : size_t buf_size = 1024;
224 1 : char *buf_ptr;
225 1 : TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
226 1 : WERROR ret = WERR_OK;
227 :
228 1 : buf = talloc_array(mem_ctx, char, buf_size);
229 1 : buf_ptr = buf;
230 :
231 : /* Read first 8 bytes (the header) */
232 1 : if (read(fd, &preg_header, sizeof(preg_header)) != sizeof(preg_header)) {
233 0 : DEBUG(0, ("Could not read PReg file: %s\n",
234 : strerror(errno)));
235 0 : ret = WERR_GEN_FAILURE;
236 0 : goto cleanup;
237 : }
238 1 : preg_header.version = IVAL(&preg_header.version, 0);
239 :
240 1 : if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
241 0 : DEBUG(0, ("This file is not a valid preg registry file\n"));
242 0 : ret = WERR_GEN_FAILURE;
243 0 : goto cleanup;
244 : }
245 1 : if (preg_header.version > 1) {
246 0 : DEBUG(0, ("Warning: file format version is higher than expected.\n"));
247 : }
248 :
249 : /* Read the entries */
250 3 : while(1) {
251 4 : uint32_t value_type, length;
252 4 : char *key = NULL;
253 4 : char *value_name = NULL;
254 4 : DATA_BLOB data = {NULL, 0};
255 :
256 4 : if (!W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr))) {
257 0 : break;
258 : }
259 3 : if (*buf_ptr != '[') {
260 0 : DEBUG(0, ("Error in PReg file.\n"));
261 0 : ret = WERR_GEN_FAILURE;
262 0 : goto cleanup;
263 : }
264 :
265 : /* Get the path */
266 0 : buf_ptr = buf;
267 369 : while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
268 123 : *buf_ptr != ';' && buf_ptr-buf < buf_size) {
269 120 : buf_ptr++;
270 : }
271 3 : buf[buf_ptr-buf] = '\0';
272 3 : key = talloc_strdup(mem_ctx, buf);
273 :
274 : /* Get the name */
275 3 : buf_ptr = buf;
276 3 : while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
277 35 : *buf_ptr != ';' && buf_ptr-buf < buf_size) {
278 32 : buf_ptr++;
279 : }
280 3 : buf[buf_ptr-buf] = '\0';
281 3 : value_name = talloc_strdup(mem_ctx, buf);
282 :
283 : /* Get the type */
284 3 : if (read(fd, &value_type, sizeof(uint32_t)) < sizeof(uint32_t)) {
285 0 : DEBUG(0, ("Error while reading PReg\n"));
286 0 : ret = WERR_GEN_FAILURE;
287 0 : goto cleanup;
288 : }
289 3 : value_type = IVAL(&value_type, 0);
290 :
291 : /* Read past delimiter */
292 3 : buf_ptr = buf;
293 3 : if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
294 3 : *buf_ptr == ';') && buf_ptr-buf < buf_size) {
295 0 : DEBUG(0, ("Error in PReg file.\n"));
296 0 : ret = WERR_GEN_FAILURE;
297 0 : goto cleanup;
298 : }
299 :
300 : /* Get data length */
301 3 : if (read(fd, &length, sizeof(uint32_t)) < sizeof(uint32_t)) {
302 0 : DEBUG(0, ("Error while reading PReg\n"));
303 0 : ret = WERR_GEN_FAILURE;
304 0 : goto cleanup;
305 : }
306 3 : length = IVAL(&length, 0);
307 :
308 : /* Read past delimiter */
309 3 : buf_ptr = buf;
310 3 : if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
311 3 : *buf_ptr == ';') && buf_ptr-buf < buf_size) {
312 0 : DEBUG(0, ("Error in PReg file.\n"));
313 0 : ret = WERR_GEN_FAILURE;
314 0 : goto cleanup;
315 : }
316 :
317 : /* Get the data */
318 3 : buf_ptr = buf;
319 3 : if (length < buf_size &&
320 6 : read(fd, buf_ptr, length) != length) {
321 0 : DEBUG(0, ("Error while reading PReg\n"));
322 0 : ret = WERR_GEN_FAILURE;
323 0 : goto cleanup;
324 : }
325 3 : data = data_blob_talloc(mem_ctx, buf, length);
326 :
327 : /* Check if delimiter is in place (whine if it isn't) */
328 3 : buf_ptr = buf;
329 3 : if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
330 3 : *buf_ptr == ']') && buf_ptr-buf < buf_size) {
331 0 : DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",
332 : *buf_ptr, *buf_ptr));
333 : }
334 :
335 3 : if (strcasecmp(value_name, "**DelVals") == 0) {
336 0 : callbacks->del_all_values(callback_data, key);
337 3 : } else if (strncasecmp(value_name, "**Del.",6) == 0) {
338 0 : char *p = value_name+6;
339 :
340 0 : callbacks->del_value(callback_data, key, p);
341 3 : } else if (strcasecmp(value_name, "**DeleteValues") == 0) {
342 0 : char *p, *q;
343 :
344 0 : p = (char *) data.data;
345 :
346 0 : while ((q = strchr_m(p, ';'))) {
347 0 : *q = '\0';
348 0 : q++;
349 :
350 0 : callbacks->del_value(callback_data, key, p);
351 :
352 0 : p = q;
353 : }
354 0 : callbacks->del_value(callback_data, key, p);
355 3 : } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
356 2 : char *p, *q, *full_key;
357 :
358 2 : p = (char *) data.data;
359 :
360 2 : while ((q = strchr_m(p, ';'))) {
361 0 : *q = '\0';
362 0 : q++;
363 :
364 0 : full_key = talloc_asprintf(mem_ctx, "%s\\%s",
365 : key, p);
366 0 : callbacks->del_key(callback_data, full_key);
367 0 : talloc_free(full_key);
368 :
369 0 : p = q;
370 : }
371 2 : full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
372 2 : callbacks->del_key(callback_data, full_key);
373 2 : talloc_free(full_key);
374 : } else {
375 1 : callbacks->add_key(callback_data, key);
376 1 : callbacks->set_value(callback_data, key, value_name,
377 : value_type, data);
378 : }
379 3 : TALLOC_FREE(key);
380 3 : TALLOC_FREE(value_name);
381 3 : data_blob_free(&data);
382 : }
383 1 : cleanup:
384 1 : close(fd);
385 1 : TALLOC_FREE(mem_ctx);
386 1 : return ret;
387 : }
|