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