s3:torture:delete: fix a comment
[Samba/gebeck_regimport.git] / source4 / lib / registry / patchfile_preg.c
blob28b56dd7e95f3af843d6ae37bbd23cb95ab40fb9
1 /*
2 Unix SMB/CIFS implementation.
3 Reading Registry.pol PReg registry files
5 Copyright (C) Wilco Baan Hofman 2006-2008
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.
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.
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.
22 #include "includes.h"
23 #include "lib/registry/registry.h"
24 #include "system/filesys.h"
25 #include "librpc/gen_ndr/winreg.h"
27 struct preg_data {
28 int fd;
29 TALLOC_CTX *ctx;
32 static WERROR preg_read_utf16(int fd, char *c)
34 uint16_t v;
36 if (read(fd, &v, sizeof(uint16_t)) < sizeof(uint16_t)) {
37 return WERR_GENERAL_FAILURE;
39 push_codepoint(c, v);
40 return WERR_OK;
42 static WERROR preg_write_utf16(int fd, const char *string)
44 uint16_t v;
45 size_t i, size;
47 for (i = 0; i < strlen(string); i+=size) {
48 v = next_codepoint(&string[i], &size);
49 if (write(fd, &v, sizeof(uint16_t)) < sizeof(uint16_t)) {
50 return WERR_GENERAL_FAILURE;
53 return WERR_OK;
55 /* PReg does not support adding keys. */
56 static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
58 return WERR_OK;
61 static WERROR reg_preg_diff_set_value(void *_data, const char *key_name,
62 const char *value_name,
63 uint32_t value_type, DATA_BLOB value_data)
65 struct preg_data *data = (struct preg_data *)_data;
66 uint32_t buf;
68 preg_write_utf16(data->fd, "[");
69 preg_write_utf16(data->fd, key_name);
70 preg_write_utf16(data->fd, ";");
71 preg_write_utf16(data->fd, value_name);
72 preg_write_utf16(data->fd, ";");
73 SIVAL(&buf, 0, value_type);
74 write(data->fd, &buf, sizeof(uint32_t));
75 preg_write_utf16(data->fd, ";");
76 SIVAL(&buf, 0, value_data.length);
77 write(data->fd, &buf, sizeof(uint32_t));
78 preg_write_utf16(data->fd, ";");
79 write(data->fd, value_data.data, value_data.length);
80 preg_write_utf16(data->fd, "]");
82 return WERR_OK;
85 static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
87 struct preg_data *data = (struct preg_data *)_data;
88 char *parent_name;
89 DATA_BLOB blob;
90 WERROR werr;
92 parent_name = talloc_strndup(data->ctx, key_name,
93 strrchr(key_name, '\\')-key_name);
94 W_ERROR_HAVE_NO_MEMORY(parent_name);
95 blob.data = (uint8_t*)talloc_strndup(data->ctx,
96 key_name+(strrchr(key_name, '\\')-key_name)+1,
97 strlen(key_name)-(strrchr(key_name, '\\')-key_name));
98 W_ERROR_HAVE_NO_MEMORY(blob.data);
99 blob.length = strlen((char *)blob.data)+1;
102 /* FIXME: These values should be accumulated to be written at done(). */
103 werr = reg_preg_diff_set_value(data, parent_name, "**DeleteKeys",
104 REG_SZ, blob);
106 talloc_free(parent_name);
107 talloc_free(blob.data);
109 return werr;
112 static WERROR reg_preg_diff_del_value(void *_data, const char *key_name,
113 const char *value_name)
115 struct preg_data *data = (struct preg_data *)_data;
116 char *val;
117 DATA_BLOB blob;
118 WERROR werr;
120 val = talloc_asprintf(data->ctx, "**Del.%s", value_name);
121 W_ERROR_HAVE_NO_MEMORY(val);
122 blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
123 W_ERROR_HAVE_NO_MEMORY(blob.data);
124 SIVAL(blob.data, 0, 0);
125 blob.length = sizeof(uint32_t);
127 werr = reg_preg_diff_set_value(data, key_name, val, REG_DWORD, blob);
129 talloc_free(val);
130 talloc_free(blob.data);
132 return werr;
135 static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
137 struct preg_data *data = (struct preg_data *)_data;
138 DATA_BLOB blob;
139 WERROR werr;
141 blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
142 W_ERROR_HAVE_NO_MEMORY(blob.data);
143 SIVAL(blob.data, 0, 0);
144 blob.length = sizeof(uint32_t);
146 werr = reg_preg_diff_set_value(data, key_name, "**DelVals.", REG_DWORD,
147 blob);
149 talloc_free(blob.data);
151 return werr;
154 static WERROR reg_preg_diff_done(void *_data)
156 struct preg_data *data = (struct preg_data *)_data;
158 close(data->fd);
159 talloc_free(data);
160 return WERR_OK;
164 * Save registry diff
166 _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
167 struct reg_diff_callbacks **callbacks,
168 void **callback_data)
170 struct preg_data *data;
171 struct {
172 char hdr[4];
173 uint32_t version;
174 } preg_header;
177 data = talloc_zero(ctx, struct preg_data);
178 *callback_data = data;
180 if (filename) {
181 data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
182 if (data->fd < 0) {
183 DEBUG(0, ("Unable to open %s\n", filename));
184 return WERR_BADFILE;
186 } else {
187 data->fd = STDOUT_FILENO;
190 strncpy(preg_header.hdr, "PReg", 4);
191 SIVAL(&preg_header.version, 0, 1);
192 write(data->fd, (uint8_t *)&preg_header, sizeof(preg_header));
194 data->ctx = ctx;
196 *callbacks = talloc(ctx, struct reg_diff_callbacks);
198 (*callbacks)->add_key = reg_preg_diff_add_key;
199 (*callbacks)->del_key = reg_preg_diff_del_key;
200 (*callbacks)->set_value = reg_preg_diff_set_value;
201 (*callbacks)->del_value = reg_preg_diff_del_value;
202 (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
203 (*callbacks)->done = reg_preg_diff_done;
205 return WERR_OK;
208 * Load diff file
210 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
211 const struct reg_diff_callbacks *callbacks,
212 void *callback_data)
214 struct {
215 char hdr[4];
216 uint32_t version;
217 } preg_header;
218 char *buf;
219 size_t buf_size = 1024;
220 char *buf_ptr;
221 TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
222 WERROR ret = WERR_OK;
223 DATA_BLOB data = {NULL, 0};
224 char *key = NULL;
225 char *value_name = NULL;
227 buf = talloc_array(mem_ctx, char, buf_size);
228 buf_ptr = buf;
230 /* Read first 8 bytes (the header) */
231 if (read(fd, &preg_header, sizeof(preg_header)) != sizeof(preg_header)) {
232 DEBUG(0, ("Could not read PReg file: %s\n",
233 strerror(errno)));
234 ret = WERR_GENERAL_FAILURE;
235 goto cleanup;
237 preg_header.version = IVAL(&preg_header.version, 0);
239 if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
240 DEBUG(0, ("This file is not a valid preg registry file\n"));
241 ret = WERR_GENERAL_FAILURE;
242 goto cleanup;
244 if (preg_header.version > 1) {
245 DEBUG(0, ("Warning: file format version is higher than expected.\n"));
248 /* Read the entries */
249 while(1) {
250 uint32_t value_type, length;
252 if (!W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr))) {
253 break;
255 if (*buf_ptr != '[') {
256 DEBUG(0, ("Error in PReg file.\n"));
257 ret = WERR_GENERAL_FAILURE;
258 goto cleanup;
261 /* Get the path */
262 buf_ptr = buf;
263 while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
264 *buf_ptr != ';' && buf_ptr-buf < buf_size) {
265 buf_ptr++;
267 buf[buf_ptr-buf] = '\0';
268 key = talloc_strdup(mem_ctx, buf);
270 /* Get the name */
271 buf_ptr = buf;
272 while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
273 *buf_ptr != ';' && buf_ptr-buf < buf_size) {
274 buf_ptr++;
276 buf[buf_ptr-buf] = '\0';
277 value_name = talloc_strdup(mem_ctx, buf);
279 /* Get the type */
280 if (read(fd, &value_type, sizeof(uint32_t)) < sizeof(uint32_t)) {
281 DEBUG(0, ("Error while reading PReg\n"));
282 ret = WERR_GENERAL_FAILURE;
283 goto cleanup;
285 value_type = IVAL(&value_type, 0);
287 /* Read past delimiter */
288 buf_ptr = buf;
289 if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
290 *buf_ptr == ';') && buf_ptr-buf < buf_size) {
291 DEBUG(0, ("Error in PReg file.\n"));
292 ret = WERR_GENERAL_FAILURE;
293 goto cleanup;
296 /* Get data length */
297 if (read(fd, &length, sizeof(uint32_t)) < sizeof(uint32_t)) {
298 DEBUG(0, ("Error while reading PReg\n"));
299 ret = WERR_GENERAL_FAILURE;
300 goto cleanup;
302 length = IVAL(&length, 0);
304 /* Read past delimiter */
305 buf_ptr = buf;
306 if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
307 *buf_ptr == ';') && buf_ptr-buf < buf_size) {
308 DEBUG(0, ("Error in PReg file.\n"));
309 ret = WERR_GENERAL_FAILURE;
310 goto cleanup;
313 /* Get the data */
314 buf_ptr = buf;
315 if (length < buf_size &&
316 read(fd, buf_ptr, length) != length) {
317 DEBUG(0, ("Error while reading PReg\n"));
318 ret = WERR_GENERAL_FAILURE;
319 goto cleanup;
321 data = data_blob_talloc(mem_ctx, buf, length);
323 /* Check if delimiter is in place (whine if it isn't) */
324 buf_ptr = buf;
325 if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
326 *buf_ptr == ']') && buf_ptr-buf < buf_size) {
327 DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",
328 *buf_ptr, *buf_ptr));
331 if (strcasecmp(value_name, "**DelVals") == 0) {
332 callbacks->del_all_values(callback_data, key);
333 } else if (strncasecmp(value_name, "**Del.",6) == 0) {
334 char *p = value_name+6;
336 callbacks->del_value(callback_data, key, p);
337 } else if (strcasecmp(value_name, "**DeleteValues") == 0) {
338 char *p, *q;
340 p = (char *) data.data;
342 while ((q = strchr_m(p, ';'))) {
343 *q = '\0';
344 q++;
346 callbacks->del_value(callback_data, key, p);
348 p = q;
350 callbacks->del_value(callback_data, key, p);
351 } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
352 char *p, *q, *full_key;
354 p = (char *) data.data;
356 while ((q = strchr_m(p, ';'))) {
357 *q = '\0';
358 q++;
360 full_key = talloc_asprintf(mem_ctx, "%s\\%s",
361 key, p);
362 callbacks->del_key(callback_data, full_key);
363 talloc_free(full_key);
365 p = q;
367 full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
368 callbacks->del_key(callback_data, full_key);
369 talloc_free(full_key);
370 } else {
371 callbacks->add_key(callback_data, key);
372 callbacks->set_value(callback_data, key, value_name,
373 value_type, data);
376 cleanup:
377 close(fd);
378 talloc_free(data.data);
379 talloc_free(key);
380 talloc_free(value_name);
381 talloc_free(buf);
382 return ret;