Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Reading .REG files
4 :
5 : Copyright (C) Jelmer Vernooij 2004-2007
6 : Copyright (C) Wilco Baan Hofman 2006-2010
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 3 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 :
23 : /* FIXME:
24 : * - Newer .REG files, created by Windows XP and above use unicode UCS-2
25 : * - @="" constructions should write value with empty name.
26 : */
27 :
28 : #include "includes.h"
29 : #include "lib/util/util_file.h"
30 : #include "lib/registry/registry.h"
31 : #include "system/filesys.h"
32 :
33 : /**
34 : * @file
35 : * @brief Registry patch files
36 : */
37 :
38 : #define HEADER_STRING "REGEDIT4"
39 :
40 : struct dotreg_data {
41 : int fd;
42 : };
43 :
44 : /*
45 : * This is basically a copy of data_blob_hex_string_upper, but with comma's
46 : * between the bytes in hex.
47 : */
48 0 : static char *dotreg_data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
49 : {
50 0 : size_t i;
51 0 : char *hex_string;
52 :
53 0 : hex_string = talloc_array(mem_ctx, char, (blob->length*3)+1);
54 0 : if (!hex_string) {
55 0 : return NULL;
56 : }
57 :
58 0 : for (i = 0; i < blob->length; i++)
59 0 : slprintf(&hex_string[i*3], 4, "%02X,", blob->data[i]);
60 :
61 : /* Remove last comma and NULL-terminate the string */
62 0 : hex_string[(blob->length*3)-1] = '\0';
63 0 : return hex_string;
64 : }
65 :
66 : /*
67 : * This is basically a copy of reg_val_data_string, except that this function
68 : * has no 0x for dwords, everything else is regarded as binary, and binary
69 : * strings are represented with bytes comma-separated.
70 : */
71 1 : static char *reg_val_dotreg_string(TALLOC_CTX *mem_ctx, uint32_t type,
72 : const DATA_BLOB data)
73 : {
74 1 : size_t converted_size = 0;
75 1 : char *ret = NULL;
76 :
77 1 : if (data.length == 0)
78 0 : return talloc_strdup(mem_ctx, "");
79 :
80 1 : switch (type) {
81 0 : case REG_EXPAND_SZ:
82 : case REG_SZ:
83 0 : convert_string_talloc(mem_ctx,
84 0 : CH_UTF16, CH_UNIX, data.data, data.length,
85 : (void **)&ret, &converted_size);
86 0 : break;
87 1 : case REG_DWORD:
88 : case REG_DWORD_BIG_ENDIAN:
89 1 : SMB_ASSERT(data.length == sizeof(uint32_t));
90 2 : ret = talloc_asprintf(mem_ctx, "%08x",
91 1 : IVAL(data.data, 0));
92 1 : break;
93 0 : default: /* default means treat as binary */
94 : case REG_BINARY:
95 0 : ret = dotreg_data_blob_hex_string(mem_ctx, &data);
96 0 : break;
97 : }
98 :
99 1 : return ret;
100 : }
101 :
102 6 : static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name)
103 : {
104 6 : struct dotreg_data *data = (struct dotreg_data *)_data;
105 :
106 6 : fdprintf(data->fd, "\n[%s]\n", key_name);
107 :
108 6 : return WERR_OK;
109 : }
110 :
111 2 : static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name)
112 : {
113 2 : struct dotreg_data *data = (struct dotreg_data *)_data;
114 :
115 2 : fdprintf(data->fd, "\n[-%s]\n", key_name);
116 :
117 2 : return WERR_OK;
118 : }
119 :
120 1 : static WERROR reg_dotreg_diff_set_value(void *_data, const char *path,
121 : const char *value_name,
122 : uint32_t value_type, DATA_BLOB value)
123 : {
124 1 : struct dotreg_data *data = (struct dotreg_data *)_data;
125 1 : char *data_string = reg_val_dotreg_string(NULL,
126 : value_type, value);
127 1 : char *data_incl_type;
128 :
129 1 : W_ERROR_HAVE_NO_MEMORY(data_string);
130 :
131 1 : switch (value_type) {
132 0 : case REG_SZ:
133 0 : data_incl_type = talloc_asprintf(data_string, "\"%s\"",
134 : data_string);
135 0 : break;
136 1 : case REG_DWORD:
137 1 : data_incl_type = talloc_asprintf(data_string,
138 : "dword:%s", data_string);
139 1 : break;
140 0 : case REG_BINARY:
141 0 : data_incl_type = talloc_asprintf(data_string, "hex:%s",
142 : data_string);
143 0 : break;
144 0 : default:
145 0 : data_incl_type = talloc_asprintf(data_string, "hex(%x):%s",
146 : value_type, data_string);
147 0 : break;
148 : }
149 :
150 1 : if (value_name[0] == '\0') {
151 0 : fdprintf(data->fd, "@=%s\n", data_incl_type);
152 : } else {
153 1 : fdprintf(data->fd, "\"%s\"=%s\n",
154 : value_name, data_incl_type);
155 : }
156 :
157 1 : talloc_free(data_string);
158 :
159 1 : return WERR_OK;
160 : }
161 :
162 0 : static WERROR reg_dotreg_diff_del_value(void *_data, const char *path,
163 : const char *value_name)
164 : {
165 0 : struct dotreg_data *data = (struct dotreg_data *)_data;
166 :
167 0 : fdprintf(data->fd, "\"%s\"=-\n", value_name);
168 :
169 0 : return WERR_OK;
170 : }
171 :
172 1 : static WERROR reg_dotreg_diff_done(void *_data)
173 : {
174 1 : struct dotreg_data *data = (struct dotreg_data *)_data;
175 :
176 1 : close(data->fd);
177 1 : talloc_free(data);
178 :
179 1 : return WERR_OK;
180 : }
181 :
182 0 : static WERROR reg_dotreg_diff_del_all_values(void *callback_data,
183 : const char *key_name)
184 : {
185 0 : return WERR_NOT_SUPPORTED;
186 : }
187 :
188 : /**
189 : * Save registry diff
190 : */
191 1 : _PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename,
192 : struct reg_diff_callbacks **callbacks,
193 : void **callback_data)
194 : {
195 1 : struct dotreg_data *data;
196 :
197 1 : data = talloc_zero(ctx, struct dotreg_data);
198 1 : *callback_data = data;
199 :
200 1 : if (filename) {
201 1 : data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
202 1 : if (data->fd < 0) {
203 0 : DEBUG(0, ("Unable to open %s\n", filename));
204 0 : return WERR_FILE_NOT_FOUND;
205 : }
206 : } else {
207 0 : data->fd = STDOUT_FILENO;
208 : }
209 :
210 1 : fdprintf(data->fd, "%s\n\n", HEADER_STRING);
211 :
212 1 : *callbacks = talloc(ctx, struct reg_diff_callbacks);
213 :
214 1 : (*callbacks)->add_key = reg_dotreg_diff_add_key;
215 1 : (*callbacks)->del_key = reg_dotreg_diff_del_key;
216 1 : (*callbacks)->set_value = reg_dotreg_diff_set_value;
217 1 : (*callbacks)->del_value = reg_dotreg_diff_del_value;
218 1 : (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values;
219 1 : (*callbacks)->done = reg_dotreg_diff_done;
220 :
221 1 : return WERR_OK;
222 : }
223 :
224 : /**
225 : * Load diff file
226 : */
227 206 : _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
228 : const struct reg_diff_callbacks *callbacks,
229 : void *callback_data)
230 : {
231 24 : char *line, *p, *q;
232 206 : char *curkey = NULL;
233 206 : TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load");
234 24 : WERROR error;
235 24 : uint32_t value_type;
236 24 : DATA_BLOB data;
237 24 : bool result;
238 206 : char *type_str = NULL;
239 206 : char *data_str = NULL;
240 206 : char *value = NULL;
241 206 : bool continue_next_line = 0;
242 :
243 206 : line = afdgets(fd, mem_ctx, 0);
244 206 : if (!line) {
245 0 : DEBUG(0, ("Can't read from file.\n"));
246 0 : talloc_free(mem_ctx);
247 0 : close(fd);
248 0 : return WERR_GEN_FAILURE;
249 : }
250 :
251 9244 : while ((line = afdgets(fd, mem_ctx, 0))) {
252 : /* Remove '\r' if it's a Windows text file */
253 9038 : if (strlen(line) && line[strlen(line)-1] == '\r') {
254 0 : line[strlen(line)-1] = '\0';
255 : }
256 :
257 : /* Ignore comments and empty lines */
258 9038 : if (strlen(line) == 0 || line[0] == ';') {
259 4314 : talloc_free(line);
260 :
261 4314 : if (curkey) {
262 4105 : talloc_free(curkey);
263 : }
264 4314 : curkey = NULL;
265 4314 : continue;
266 : }
267 :
268 : /* Start of key */
269 4724 : if (line[0] == '[') {
270 4108 : if (line[strlen(line)-1] != ']') {
271 0 : DEBUG(0, ("Missing ']' on line: %s\n", line));
272 0 : talloc_free(line);
273 0 : continue;
274 : }
275 :
276 : /* Deleting key */
277 4108 : if (line[1] == '-') {
278 2 : curkey = talloc_strndup(line, line+2, strlen(line)-3);
279 2 : W_ERROR_HAVE_NO_MEMORY(curkey);
280 :
281 2 : error = callbacks->del_key(callback_data,
282 : curkey);
283 :
284 2 : if (!W_ERROR_IS_OK(error)) {
285 0 : DEBUG(0,("Error deleting key %s\n",
286 : curkey));
287 0 : talloc_free(mem_ctx);
288 0 : return error;
289 : }
290 :
291 2 : talloc_free(line);
292 2 : curkey = NULL;
293 2 : continue;
294 : }
295 4106 : curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2);
296 4106 : W_ERROR_HAVE_NO_MEMORY(curkey);
297 :
298 4106 : error = callbacks->add_key(callback_data, curkey);
299 4106 : if (!W_ERROR_IS_OK(error)) {
300 0 : DEBUG(0,("Error adding key %s\n", curkey));
301 0 : talloc_free(mem_ctx);
302 0 : return error;
303 : }
304 :
305 4106 : talloc_free(line);
306 4106 : continue;
307 : }
308 :
309 : /* Deleting/Changing value */
310 616 : if (continue_next_line) {
311 0 : continue_next_line = 0;
312 :
313 : /* Continued data start with two whitespaces */
314 0 : if (line[0] != ' ' || line[1] != ' ') {
315 0 : DEBUG(0, ("Malformed line: %s\n", line));
316 0 : talloc_free(line);
317 0 : continue;
318 : }
319 0 : p = line + 2;
320 :
321 : /* Continue again if line ends with a backslash */
322 0 : if (line[strlen(line)-1] == '\\') {
323 0 : line[strlen(line)-1] = '\0';
324 0 : continue_next_line = 1;
325 0 : data_str = talloc_strdup_append(data_str, p);
326 0 : talloc_free(line);
327 0 : continue;
328 : }
329 0 : data_str = talloc_strdup_append(data_str, p);
330 : } else {
331 616 : p = strchr_m(line, '=');
332 616 : if (p == NULL) {
333 0 : DEBUG(0, ("Malformed line: %s\n", line));
334 0 : talloc_free(line);
335 0 : continue;
336 : }
337 :
338 616 : *p = '\0'; p++;
339 :
340 :
341 616 : if (curkey == NULL) {
342 0 : DEBUG(0, ("Value change without key\n"));
343 0 : talloc_free(line);
344 0 : continue;
345 : }
346 :
347 : /* Values should be double-quoted */
348 616 : if (line[0] != '"') {
349 0 : DEBUG(0, ("Malformed line\n"));
350 0 : talloc_free(line);
351 0 : continue;
352 : }
353 :
354 : /* Chop of the quotes and store as value */
355 616 : value = talloc_strndup(mem_ctx, line+1,strlen(line)-2);
356 :
357 : /* Delete value */
358 616 : if (p[0] == '-') {
359 0 : error = callbacks->del_value(callback_data,
360 : curkey, value);
361 :
362 : /* Ignore if key does not exist (WERR_FILE_NOT_FOUND)
363 : * Consistent with Windows behaviour */
364 0 : if (!W_ERROR_IS_OK(error) &&
365 0 : !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
366 0 : DEBUG(0, ("Error deleting value %s in key %s\n",
367 : value, curkey));
368 0 : talloc_free(mem_ctx);
369 0 : return error;
370 : }
371 :
372 0 : talloc_free(line);
373 0 : talloc_free(value);
374 0 : continue;
375 : }
376 :
377 : /* Do not look for colons in strings */
378 616 : if (p[0] == '"') {
379 410 : q = NULL;
380 410 : data_str = talloc_strndup(mem_ctx, p+1,strlen(p)-2);
381 : } else {
382 : /* Split the value type from the data */
383 206 : q = strchr_m(p, ':');
384 206 : if (q) {
385 206 : *q = '\0';
386 206 : q++;
387 206 : type_str = talloc_strdup(mem_ctx, p);
388 206 : data_str = talloc_strdup(mem_ctx, q);
389 : } else {
390 0 : data_str = talloc_strdup(mem_ctx, p);
391 : }
392 : }
393 :
394 : /* Backslash before the CRLF means continue on next line */
395 616 : if (data_str[strlen(data_str)-1] == '\\') {
396 0 : data_str[strlen(data_str)-1] = '\0';
397 0 : talloc_free(line);
398 0 : continue_next_line = 1;
399 0 : continue;
400 : }
401 : }
402 616 : DEBUG(9, ("About to write %s with type %s, length %ld: %s\n", value, type_str, (long) strlen(data_str), data_str));
403 662 : result = reg_string_to_val(value,
404 : type_str?type_str:"REG_SZ", data_str,
405 : &value_type, &data);
406 616 : if (!result) {
407 0 : DEBUG(0, ("Error converting string to value for line:\n%s\n",
408 : line));
409 0 : return WERR_GEN_FAILURE;
410 : }
411 :
412 616 : error = callbacks->set_value(callback_data, curkey, value,
413 : value_type, data);
414 616 : if (!W_ERROR_IS_OK(error)) {
415 0 : DEBUG(0, ("Error setting value for %s in %s\n",
416 : value, curkey));
417 0 : talloc_free(mem_ctx);
418 0 : return error;
419 : }
420 :
421 : /* Clean up buffers */
422 616 : if (type_str != NULL) {
423 206 : talloc_free(type_str);
424 206 : type_str = NULL;
425 : }
426 616 : talloc_free(data_str);
427 616 : talloc_free(value);
428 616 : talloc_free(line);
429 : }
430 :
431 206 : close(fd);
432 :
433 206 : talloc_free(mem_ctx);
434 :
435 206 : return WERR_OK;
436 : }
|