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 0 : static WERROR preg_read_utf16(int fd, char *c)
37 : {
38 : uint16_t v;
39 :
40 0 : if (read(fd, &v, sizeof(uint16_t)) < sizeof(uint16_t)) {
41 0 : return WERR_GEN_FAILURE;
42 : }
43 0 : push_codepoint(c, v);
44 0 : return WERR_OK;
45 : }
46 0 : static WERROR preg_write_utf16(int fd, const char *string)
47 : {
48 : uint16_t v;
49 : size_t i, size;
50 :
51 0 : for (i = 0; i < strlen(string); i+=size) {
52 0 : v = next_codepoint(&string[i], &size);
53 0 : if (write(fd, &v, sizeof(uint16_t)) < sizeof(uint16_t)) {
54 0 : return WERR_GEN_FAILURE;
55 : }
56 : }
57 0 : return WERR_OK;
58 : }
59 : /* PReg does not support adding keys. */
60 0 : static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
61 : {
62 0 : return WERR_OK;
63 : }
64 :
65 0 : 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 0 : struct preg_data *data = (struct preg_data *)_data;
70 : uint32_t buf;
71 :
72 0 : preg_write_utf16(data->fd, "[");
73 0 : preg_write_utf16(data->fd, key_name);
74 0 : preg_write_utf16(data->fd, ";");
75 0 : preg_write_utf16(data->fd, value_name);
76 0 : preg_write_utf16(data->fd, ";");
77 0 : SIVAL(&buf, 0, value_type);
78 0 : sys_write_v(data->fd, &buf, sizeof(uint32_t));
79 0 : preg_write_utf16(data->fd, ";");
80 0 : SIVAL(&buf, 0, value_data.length);
81 0 : sys_write_v(data->fd, &buf, sizeof(uint32_t));
82 0 : preg_write_utf16(data->fd, ";");
83 0 : sys_write_v(data->fd, value_data.data, value_data.length);
84 0 : preg_write_utf16(data->fd, "]");
85 :
86 0 : return WERR_OK;
87 : }
88 :
89 0 : static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
90 : {
91 0 : struct preg_data *data = (struct preg_data *)_data;
92 : char *parent_name;
93 : DATA_BLOB blob;
94 : WERROR werr;
95 :
96 0 : parent_name = talloc_strndup(data->ctx, key_name,
97 0 : strrchr(key_name, '\\')-key_name);
98 0 : W_ERROR_HAVE_NO_MEMORY(parent_name);
99 0 : blob.data = (uint8_t*)talloc_strndup(data->ctx,
100 0 : key_name+(strrchr(key_name, '\\')-key_name)+1,
101 0 : strlen(key_name)-(strrchr(key_name, '\\')-key_name));
102 0 : W_ERROR_HAVE_NO_MEMORY(blob.data);
103 0 : blob.length = strlen((char *)blob.data)+1;
104 :
105 :
106 : /* FIXME: These values should be accumulated to be written at done(). */
107 0 : werr = reg_preg_diff_set_value(data, parent_name, "**DeleteKeys",
108 : REG_SZ, blob);
109 :
110 0 : talloc_free(parent_name);
111 0 : talloc_free(blob.data);
112 :
113 0 : 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 : char *val;
121 : DATA_BLOB blob;
122 : 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 : DATA_BLOB blob;
143 : 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 0 : static WERROR reg_preg_diff_done(void *_data)
159 : {
160 0 : struct preg_data *data = (struct preg_data *)_data;
161 :
162 0 : close(data->fd);
163 0 : talloc_free(data);
164 0 : return WERR_OK;
165 : }
166 :
167 : /**
168 : * Save registry diff
169 : */
170 0 : _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
171 : struct reg_diff_callbacks **callbacks,
172 : void **callback_data)
173 : {
174 : struct preg_data *data;
175 : struct {
176 : char hdr[4];
177 : uint32_t version;
178 : } preg_header;
179 :
180 :
181 0 : data = talloc_zero(ctx, struct preg_data);
182 0 : *callback_data = data;
183 :
184 0 : if (filename) {
185 0 : data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
186 0 : 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 0 : memcpy(preg_header.hdr, "PReg", sizeof(preg_header.hdr));
195 0 : SIVAL(&preg_header.version, 0, 1);
196 0 : sys_write_v(data->fd, (uint8_t *)&preg_header, sizeof(preg_header));
197 :
198 0 : data->ctx = ctx;
199 :
200 0 : *callbacks = talloc(ctx, struct reg_diff_callbacks);
201 :
202 0 : (*callbacks)->add_key = reg_preg_diff_add_key;
203 0 : (*callbacks)->del_key = reg_preg_diff_del_key;
204 0 : (*callbacks)->set_value = reg_preg_diff_set_value;
205 0 : (*callbacks)->del_value = reg_preg_diff_del_value;
206 0 : (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
207 0 : (*callbacks)->done = reg_preg_diff_done;
208 :
209 0 : return WERR_OK;
210 : }
211 : /**
212 : * Load diff file
213 : */
214 0 : _PUBLIC_ WERROR reg_preg_diff_load(int fd,
215 : const struct reg_diff_callbacks *callbacks,
216 : void *callback_data)
217 : {
218 : struct {
219 : char hdr[4];
220 : uint32_t version;
221 : } preg_header;
222 : char *buf;
223 0 : size_t buf_size = 1024;
224 : char *buf_ptr;
225 0 : TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
226 0 : WERROR ret = WERR_OK;
227 :
228 0 : buf = talloc_array(mem_ctx, char, buf_size);
229 0 : buf_ptr = buf;
230 :
231 : /* Read first 8 bytes (the header) */
232 0 : 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 0 : preg_header.version = IVAL(&preg_header.version, 0);
239 :
240 0 : 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 0 : 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 0 : while(1) {
251 : uint32_t value_type, length;
252 0 : char *key = NULL;
253 0 : char *value_name = NULL;
254 0 : DATA_BLOB data = {NULL, 0};
255 :
256 0 : if (!W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr))) {
257 0 : break;
258 : }
259 0 : 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 0 : while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
268 0 : *buf_ptr != ';' && buf_ptr-buf < buf_size) {
269 0 : buf_ptr++;
270 : }
271 0 : buf[buf_ptr-buf] = '\0';
272 0 : key = talloc_strdup(mem_ctx, buf);
273 :
274 : /* Get the name */
275 0 : buf_ptr = buf;
276 0 : while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
277 0 : *buf_ptr != ';' && buf_ptr-buf < buf_size) {
278 0 : buf_ptr++;
279 : }
280 0 : buf[buf_ptr-buf] = '\0';
281 0 : value_name = talloc_strdup(mem_ctx, buf);
282 :
283 : /* Get the type */
284 0 : 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 0 : value_type = IVAL(&value_type, 0);
290 :
291 : /* Read past delimiter */
292 0 : buf_ptr = buf;
293 0 : if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
294 0 : *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 0 : 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 0 : length = IVAL(&length, 0);
307 :
308 : /* Read past delimiter */
309 0 : buf_ptr = buf;
310 0 : if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
311 0 : *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 0 : buf_ptr = buf;
319 0 : if (length < buf_size &&
320 0 : 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 0 : data = data_blob_talloc(mem_ctx, buf, length);
326 :
327 : /* Check if delimiter is in place (whine if it isn't) */
328 0 : buf_ptr = buf;
329 0 : if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
330 0 : *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 0 : if (strcasecmp(value_name, "**DelVals") == 0) {
336 0 : callbacks->del_all_values(callback_data, key);
337 0 : } 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 0 : } else if (strcasecmp(value_name, "**DeleteValues") == 0) {
342 : 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 0 : } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
356 : char *p, *q, *full_key;
357 :
358 0 : p = (char *) data.data;
359 :
360 0 : 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 0 : full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
372 0 : callbacks->del_key(callback_data, full_key);
373 0 : talloc_free(full_key);
374 : } else {
375 0 : callbacks->add_key(callback_data, key);
376 0 : callbacks->set_value(callback_data, key, value_name,
377 : value_type, data);
378 : }
379 0 : TALLOC_FREE(key);
380 0 : TALLOC_FREE(value_name);
381 0 : data_blob_free(&data);
382 : }
383 0 : cleanup:
384 0 : close(fd);
385 0 : TALLOC_FREE(mem_ctx);
386 0 : return ret;
387 : }
|