WHATSNEW: Finish release notes for Samba 3.6.9.
[Samba.git] / source4 / lib / registry / patchfile_dotreg.c
blob8fac00ba44f3fe4277ebc926af0c9045b39b20a4
1 /*
2 Unix SMB/CIFS implementation.
3 Reading .REG files
5 Copyright (C) Jelmer Vernooij 2004-2007
6 Copyright (C) Wilco Baan Hofman 2006-2010
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.
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.
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.
23 /* FIXME:
24 * - Newer .REG files, created by Windows XP and above use unicode UCS-2
25 * - @="" constructions should write value with empty name.
28 #include "includes.h"
29 #include "lib/registry/registry.h"
30 #include "system/filesys.h"
32 /**
33 * @file
34 * @brief Registry patch files
37 #define HEADER_STRING "REGEDIT4"
39 struct dotreg_data {
40 int fd;
43 /*
44 * This is basically a copy of data_blob_hex_string_upper, but with comma's
45 * between the bytes in hex.
47 static char *dotreg_data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
49 size_t i;
50 char *hex_string;
52 hex_string = talloc_array(mem_ctx, char, (blob->length*3)+1);
53 if (!hex_string) {
54 return NULL;
57 for (i = 0; i < blob->length; i++)
58 slprintf(&hex_string[i*3], 4, "%02X,", blob->data[i]);
60 /* Remove last comma and NULL-terminate the string */
61 hex_string[(blob->length*3)-1] = '\0';
62 return hex_string;
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.
70 static char *reg_val_dotreg_string(TALLOC_CTX *mem_ctx, uint32_t type,
71 const DATA_BLOB data)
73 char *ret = NULL;
75 if (data.length == 0)
76 return talloc_strdup(mem_ctx, "");
78 switch (type) {
79 case REG_EXPAND_SZ:
80 case REG_SZ:
81 convert_string_talloc(mem_ctx,
82 CH_UTF16, CH_UNIX, data.data, data.length,
83 (void **)&ret, NULL, false);
84 break;
85 case REG_DWORD:
86 case REG_DWORD_BIG_ENDIAN:
87 SMB_ASSERT(data.length == sizeof(uint32_t));
88 ret = talloc_asprintf(mem_ctx, "%08x",
89 IVAL(data.data, 0));
90 break;
91 default: /* default means treat as binary */
92 case REG_BINARY:
93 ret = dotreg_data_blob_hex_string(mem_ctx, &data);
94 break;
97 return ret;
100 static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name)
102 struct dotreg_data *data = (struct dotreg_data *)_data;
104 fdprintf(data->fd, "\n[%s]\n", key_name);
106 return WERR_OK;
109 static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name)
111 struct dotreg_data *data = (struct dotreg_data *)_data;
113 fdprintf(data->fd, "\n[-%s]\n", key_name);
115 return WERR_OK;
118 static WERROR reg_dotreg_diff_set_value(void *_data, const char *path,
119 const char *value_name,
120 uint32_t value_type, DATA_BLOB value)
122 struct dotreg_data *data = (struct dotreg_data *)_data;
123 char *data_string = reg_val_dotreg_string(NULL,
124 value_type, value);
125 char *data_incl_type;
127 W_ERROR_HAVE_NO_MEMORY(data_string);
129 switch (value_type) {
130 case REG_SZ:
131 data_incl_type = talloc_asprintf(data_string, "\"%s\"",
132 data_string);
133 break;
134 case REG_DWORD:
135 data_incl_type = talloc_asprintf(data_string,
136 "dword:%s", data_string);
137 break;
138 case REG_BINARY:
139 data_incl_type = talloc_asprintf(data_string, "hex:%s",
140 data_string);
141 break;
142 default:
143 data_incl_type = talloc_asprintf(data_string, "hex(%x):%s",
144 value_type, data_string);
145 break;
148 if (value_name[0] == '\0') {
149 fdprintf(data->fd, "@=%s\n", data_incl_type);
150 } else {
151 fdprintf(data->fd, "\"%s\"=%s\n",
152 value_name, data_incl_type);
155 talloc_free(data_string);
157 return WERR_OK;
160 static WERROR reg_dotreg_diff_del_value(void *_data, const char *path,
161 const char *value_name)
163 struct dotreg_data *data = (struct dotreg_data *)_data;
165 fdprintf(data->fd, "\"%s\"=-\n", value_name);
167 return WERR_OK;
170 static WERROR reg_dotreg_diff_done(void *_data)
172 struct dotreg_data *data = (struct dotreg_data *)_data;
174 close(data->fd);
175 talloc_free(data);
177 return WERR_OK;
180 static WERROR reg_dotreg_diff_del_all_values(void *callback_data,
181 const char *key_name)
183 return WERR_NOT_SUPPORTED;
187 * Save registry diff
189 _PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename,
190 struct reg_diff_callbacks **callbacks,
191 void **callback_data)
193 struct dotreg_data *data;
195 data = talloc_zero(ctx, struct dotreg_data);
196 *callback_data = data;
198 if (filename) {
199 data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
200 if (data->fd < 0) {
201 DEBUG(0, ("Unable to open %s\n", filename));
202 return WERR_BADFILE;
204 } else {
205 data->fd = STDOUT_FILENO;
208 fdprintf(data->fd, "%s\n\n", HEADER_STRING);
210 *callbacks = talloc(ctx, struct reg_diff_callbacks);
212 (*callbacks)->add_key = reg_dotreg_diff_add_key;
213 (*callbacks)->del_key = reg_dotreg_diff_del_key;
214 (*callbacks)->set_value = reg_dotreg_diff_set_value;
215 (*callbacks)->del_value = reg_dotreg_diff_del_value;
216 (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values;
217 (*callbacks)->done = reg_dotreg_diff_done;
219 return WERR_OK;
223 * Load diff file
225 _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
226 const struct reg_diff_callbacks *callbacks,
227 void *callback_data)
229 char *line, *p, *q;
230 char *curkey = NULL;
231 TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load");
232 WERROR error;
233 uint32_t value_type;
234 DATA_BLOB data;
235 bool result;
236 char *type_str = NULL;
237 char *data_str;
238 char *value;
239 bool continue_next_line = 0;
241 line = afdgets(fd, mem_ctx, 0);
242 if (!line) {
243 DEBUG(0, ("Can't read from file.\n"));
244 talloc_free(mem_ctx);
245 close(fd);
246 return WERR_GENERAL_FAILURE;
249 while ((line = afdgets(fd, mem_ctx, 0))) {
250 /* Remove '\r' if it's a Windows text file */
251 if (line[strlen(line)-1] == '\r') {
252 line[strlen(line)-1] = '\0';
255 /* Ignore comments and empty lines */
256 if (strlen(line) == 0 || line[0] == ';') {
257 talloc_free(line);
259 if (curkey) {
260 talloc_free(curkey);
262 curkey = NULL;
263 continue;
266 /* Start of key */
267 if (line[0] == '[') {
268 if (line[strlen(line)-1] != ']') {
269 DEBUG(0, ("Missing ']' on line: %s\n", line));
270 talloc_free(line);
271 continue;
274 /* Deleting key */
275 if (line[1] == '-') {
276 curkey = talloc_strndup(line, line+2, strlen(line)-3);
277 W_ERROR_HAVE_NO_MEMORY(curkey);
279 error = callbacks->del_key(callback_data,
280 curkey);
282 if (!W_ERROR_IS_OK(error)) {
283 DEBUG(0,("Error deleting key %s\n",
284 curkey));
285 talloc_free(mem_ctx);
286 return error;
289 talloc_free(line);
290 curkey = NULL;
291 continue;
293 curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2);
294 W_ERROR_HAVE_NO_MEMORY(curkey);
296 error = callbacks->add_key(callback_data, curkey);
297 if (!W_ERROR_IS_OK(error)) {
298 DEBUG(0,("Error adding key %s\n", curkey));
299 talloc_free(mem_ctx);
300 return error;
303 talloc_free(line);
304 continue;
307 /* Deleting/Changing value */
308 if (continue_next_line) {
309 continue_next_line = 0;
311 /* Continued data start with two whitespaces */
312 if (line[0] != ' ' || line[1] != ' ') {
313 DEBUG(0, ("Malformed line: %s\n", line));
314 talloc_free(line);
315 continue;
317 p = line + 2;
319 /* Continue again if line ends with a backslash */
320 if (line[strlen(line)-1] == '\\') {
321 line[strlen(line)-1] = '\0';
322 continue_next_line = 1;
323 data_str = talloc_strdup_append(data_str, p);
324 talloc_free(line);
325 continue;
327 data_str = talloc_strdup_append(data_str, p);
328 } else {
329 p = strchr_m(line, '=');
330 if (p == NULL) {
331 DEBUG(0, ("Malformed line: %s\n", line));
332 talloc_free(line);
333 continue;
336 *p = '\0'; p++;
339 if (curkey == NULL) {
340 DEBUG(0, ("Value change without key\n"));
341 talloc_free(line);
342 continue;
345 /* Values should be double-quoted */
346 if (line[0] != '"') {
347 DEBUG(0, ("Malformed line\n"));
348 talloc_free(line);
349 continue;
352 /* Chop of the quotes and store as value */
353 value = talloc_strndup(mem_ctx, line+1,strlen(line)-2);
355 /* Delete value */
356 if (p[0] == '-') {
357 error = callbacks->del_value(callback_data,
358 curkey, value);
360 /* Ignore if key does not exist (WERR_BADFILE)
361 * Consistent with Windows behaviour */
362 if (!W_ERROR_IS_OK(error) &&
363 !W_ERROR_EQUAL(error, WERR_BADFILE)) {
364 DEBUG(0, ("Error deleting value %s in key %s\n",
365 value, curkey));
366 talloc_free(mem_ctx);
367 return error;
370 talloc_free(line);
371 talloc_free(value);
372 continue;
375 /* Do not look for colons in strings */
376 if (p[0] == '"') {
377 q = NULL;
378 data_str = talloc_strndup(mem_ctx, p+1,strlen(p)-2);
379 } else {
380 /* Split the value type from the data */
381 q = strchr_m(p, ':');
382 if (q) {
383 *q = '\0';
384 q++;
385 type_str = talloc_strdup(mem_ctx, p);
386 data_str = talloc_strdup(mem_ctx, q);
387 } else {
388 data_str = talloc_strdup(mem_ctx, p);
392 /* Backslash before the CRLF means continue on next line */
393 if (data_str[strlen(data_str)-1] == '\\') {
394 data_str[strlen(data_str)-1] = '\0';
395 talloc_free(line);
396 continue_next_line = 1;
397 continue;
400 DEBUG(9, ("About to write %s with type %s, length %ld: %s\n", value, type_str, (long) strlen(data_str), data_str));
401 result = reg_string_to_val(value,
402 type_str?type_str:"REG_SZ", data_str,
403 &value_type, &data);
404 if (!result) {
405 DEBUG(0, ("Error converting string to value for line:\n%s\n",
406 line));
407 return WERR_GENERAL_FAILURE;
410 error = callbacks->set_value(callback_data, curkey, value,
411 value_type, data);
412 if (!W_ERROR_IS_OK(error)) {
413 DEBUG(0, ("Error setting value for %s in %s\n",
414 value, curkey));
415 talloc_free(mem_ctx);
416 return error;
419 /* Clean up buffers */
420 if (type_str != NULL) {
421 talloc_free(type_str);
422 type_str = NULL;
424 talloc_free(data_str);
425 talloc_free(value);
426 talloc_free(line);
429 close(fd);
431 talloc_free(mem_ctx);
433 return WERR_OK;