More patchfile fixes. Write support should work now.
[Samba/gebeck_regimport.git] / source4 / lib / registry / patchfile_preg.c
blobc2bc8d10b351c33f7d215b55be40a8dd93f22cdb
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 "param/param.h"
26 #include "librpc/gen_ndr/winreg.h"
28 struct preg_data {
29 int fd;
30 TALLOC_CTX *ctx;
31 struct smb_iconv_convenience *ic;
34 static WERROR preg_read_utf16(struct smb_iconv_convenience *ic, int fd, char *c)
36 uint16_t v;
38 if (read(fd, &v, 2) < 2) {
39 return WERR_GENERAL_FAILURE;
41 push_codepoint(ic, c, v);
42 return WERR_OK;
44 static WERROR preg_write_utf16(struct smb_iconv_convenience *ic, int fd, const char *string)
46 codepoint_t v;
47 uint16_t i;
48 size_t size;
50 for (i = 0; i < strlen(string); i+=size) {
51 v = next_codepoint(ic, &string[i], &size);
52 if (write(fd, &v, 2) < 2) {
53 return WERR_GENERAL_FAILURE;
56 return WERR_OK;
58 /* PReg does not support adding keys. */
59 static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
61 return WERR_OK;
64 static WERROR reg_preg_diff_set_value(void *_data, const char *key_name,
65 const char *value_name,
66 uint32_t value_type, DATA_BLOB value_data)
68 struct preg_data *data = _data;
69 uint32_t buf;
71 preg_write_utf16(data->ic, data->fd, "[");
72 preg_write_utf16(data->ic, data->fd, key_name);
73 preg_write_utf16(data->ic, data->fd, ";");
74 preg_write_utf16(data->ic, data->fd, value_name);
75 preg_write_utf16(data->ic, data->fd, ";");
76 SIVAL(&buf, 0, value_type);
77 write(data->fd, &buf, sizeof(uint32_t));
78 preg_write_utf16(data->ic, data->fd, ";");
79 SIVAL(&buf, 0, value_data.length);
80 write(data->fd, &buf, sizeof(uint32_t));
81 preg_write_utf16(data->ic, data->fd, ";");
82 write(data->fd, value_data.data, value_data.length);
83 preg_write_utf16(data->ic, data->fd, "]");
85 return WERR_OK;
88 static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
90 struct preg_data *data = _data;
91 char *parent_name;
92 DATA_BLOB blob;
94 parent_name = talloc_strndup(data->ctx, key_name, strrchr(key_name, '\\')-key_name);
95 blob.data = (void *)talloc_strndup(data->ctx, key_name+(strrchr(key_name, '\\')-key_name)+1,
96 strlen(key_name)-(strrchr(key_name, '\\')-key_name));
97 blob.length = strlen((char *)blob.data)+1;
100 /* FIXME: These values should be accumulated to be written at done(). */
101 return reg_preg_diff_set_value(data, parent_name, "**DeleteKeys", REG_SZ, blob);
104 static WERROR reg_preg_diff_del_value(void *_data, const char *key_name,
105 const char *value_name)
107 struct preg_data *data = _data;
108 char *val;
109 DATA_BLOB blob;
111 val = talloc_asprintf(data->ctx, "**Del.%s", value_name);
113 blob.data = (void *)talloc(data->ctx, uint32_t);
114 *(uint32_t *)blob.data = 0;
115 blob.length = 4;
116 return reg_preg_diff_set_value(data, key_name, val, REG_DWORD, blob);
119 static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
121 struct preg_data *data = _data;
122 DATA_BLOB blob;
124 blob.data = (void *)talloc(data->ctx, uint32_t);
125 *(uint32_t *)blob.data = 0;
126 blob.length = 4;
128 return reg_preg_diff_set_value(data, key_name, "**DelVals.", REG_DWORD, blob);
131 static WERROR reg_preg_diff_done(void *_data)
133 struct preg_data *data = (struct preg_data *)_data;
135 close(data->fd);
136 talloc_free(data);
137 return WERR_OK;
141 * Save registry diff
143 _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
144 struct smb_iconv_convenience *ic,
145 struct reg_diff_callbacks **callbacks,
146 void **callback_data)
148 struct preg_data *data;
149 struct {
150 char hdr[4];
151 uint32_t version;
152 } preg_header;
155 data = talloc_zero(ctx, struct preg_data);
156 *callback_data = data;
158 if (filename) {
159 data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
160 if (data->fd < 0) {
161 DEBUG(0, ("Unable to open %s\n", filename));
162 return WERR_BADFILE;
164 } else {
165 data->fd = STDOUT_FILENO;
168 memcpy(preg_header.hdr, "PReg", 4);
169 SIVAL(&preg_header, 4, 1);
170 write(data->fd, (uint8_t *)&preg_header,8);
172 data->ctx = ctx;
173 data->ic = ic;
175 *callbacks = talloc(ctx, struct reg_diff_callbacks);
177 (*callbacks)->add_key = reg_preg_diff_add_key;
178 (*callbacks)->del_key = reg_preg_diff_del_key;
179 (*callbacks)->set_value = reg_preg_diff_set_value;
180 (*callbacks)->del_value = reg_preg_diff_del_value;
181 (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
182 (*callbacks)->done = reg_preg_diff_done;
184 return WERR_OK;
187 * Load diff file
189 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
190 struct smb_iconv_convenience *iconv_convenience,
191 const struct reg_diff_callbacks *callbacks,
192 void *callback_data)
194 struct {
195 char hdr[4];
196 uint32_t version;
197 } preg_header;
198 char *buf;
199 size_t buf_size = 1024;
200 char *buf_ptr;
201 TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
202 WERROR ret = WERR_OK;
203 DATA_BLOB data = {NULL, 0};
204 char *key = NULL;
205 char *value_name = NULL;
207 buf = talloc_array(mem_ctx, char, buf_size);
208 buf_ptr = buf;
210 /* Read first 8 bytes (the header) */
211 if (read(fd, &preg_header, 8) != 8) {
212 DEBUG(0, ("Could not read PReg file: %s\n",
213 strerror(errno)));
214 ret = WERR_GENERAL_FAILURE;
215 goto cleanup;
217 preg_header.version = IVAL(&preg_header.version, 0);
219 if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
220 DEBUG(0, ("This file is not a valid preg registry file\n"));
221 ret = WERR_GENERAL_FAILURE;
222 goto cleanup;
224 if (preg_header.version > 1) {
225 DEBUG(0, ("Warning: file format version is higher than expected.\n"));
228 /* Read the entries */
229 while(1) {
230 uint32_t value_type, length;
232 if (!W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr))) {
233 break;
235 if (*buf_ptr != '[') {
236 DEBUG(0, ("Error in PReg file.\n"));
237 ret = WERR_GENERAL_FAILURE;
238 goto cleanup;
241 /* Get the path */
242 buf_ptr = buf;
243 while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
244 *buf_ptr != ';' && buf_ptr-buf < buf_size) {
245 buf_ptr++;
247 buf[buf_ptr-buf] = '\0';
248 key = talloc_strdup(mem_ctx, buf);
250 /* Get the name */
251 buf_ptr = buf;
252 while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
253 *buf_ptr != ';' && buf_ptr-buf < buf_size) {
254 buf_ptr++;
256 buf[buf_ptr-buf] = '\0';
257 value_name = talloc_strdup(mem_ctx, buf);
259 /* Get the type */
260 if (read(fd, &value_type, 4) < 4) {
261 DEBUG(0, ("Error while reading PReg\n"));
262 ret = WERR_GENERAL_FAILURE;
263 goto cleanup;
265 value_type = IVAL(&value_type, 0);
267 /* Read past delimiter */
268 buf_ptr = buf;
269 if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
270 *buf_ptr == ';') && buf_ptr-buf < buf_size) {
271 DEBUG(0, ("Error in PReg file.\n"));
272 ret = WERR_GENERAL_FAILURE;
273 goto cleanup;
275 /* Get data length */
276 if (read(fd, &length, 4) < 4) {
277 DEBUG(0, ("Error while reading PReg\n"));
278 ret = WERR_GENERAL_FAILURE;
279 goto cleanup;
281 /* Read past delimiter */
282 buf_ptr = buf;
283 if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
284 *buf_ptr == ';') && buf_ptr-buf < buf_size) {
285 DEBUG(0, ("Error in PReg file.\n"));
286 ret = WERR_GENERAL_FAILURE;
287 goto cleanup;
289 /* Get the data */
290 buf_ptr = buf;
291 if (length < buf_size &&
292 read(fd, buf_ptr, length) != length) {
293 DEBUG(0, ("Error while reading PReg\n"));
294 ret = WERR_GENERAL_FAILURE;
295 goto cleanup;
297 data = data_blob_talloc(mem_ctx, buf, length);
299 /* Check if delimiter is in place (whine if it isn't) */
300 buf_ptr = buf;
301 if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
302 *buf_ptr == ']') && buf_ptr-buf < buf_size) {
303 DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",
304 *buf_ptr, *buf_ptr));
307 if (strcasecmp(value_name, "**DelVals") == 0) {
308 callbacks->del_all_values(callback_data, key);
309 } else if (strncasecmp(value_name, "**Del.",6) == 0) {
310 char *p = value_name+6;
312 callbacks->del_value(callback_data, key, p);
313 } else if (strcasecmp(value_name, "**DeleteValues") == 0) {
314 char *p, *q;
316 p = (char *) data.data;
318 while ((q = strchr_m(p, ';'))) {
319 *q = '\0';
320 q++;
322 callbacks->del_value(callback_data, key, p);
324 p = q;
326 callbacks->del_value(callback_data, key, p);
327 } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
328 char *p, *q, *full_key;
330 p = (char *) data.data;
332 while ((q = strchr_m(p, ';'))) {
333 *q = '\0';
334 q++;
336 full_key = talloc_asprintf(mem_ctx, "%s\\%s",
337 key, p);
338 callbacks->del_key(callback_data, full_key);
339 talloc_free(full_key);
341 p = q;
343 full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
344 callbacks->del_key(callback_data, full_key);
345 talloc_free(full_key);
346 } else {
347 callbacks->add_key(callback_data, key);
348 callbacks->set_value(callback_data, key, value_name,
349 value_type, data);
352 cleanup:
353 close(fd);
354 talloc_free(data.data);
355 talloc_free(key);
356 talloc_free(value_name);
357 talloc_free(buf);
358 return ret;