libwbclient: Make wbcGetDisplayName not use talloc
[Samba/ekacnet.git] / source4 / lib / registry / patchfile.c
bloba01c3554c406f78530c2b0745eda35435c6d89c1
1 /*
2 Unix SMB/CIFS implementation.
3 Reading registry patch files
5 Copyright (C) Jelmer Vernooij 2004-2007
6 Copyright (C) Wilco Baan Hofman 2006
7 Copyright (C) Matthias Dieter Wallnöfer 2008-2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "lib/registry/registry.h"
25 #include "system/filesys.h"
28 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
29 struct smb_iconv_convenience *iconv_convenience,
30 const struct reg_diff_callbacks *callbacks,
31 void *callback_data);
33 _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
34 struct smb_iconv_convenience *iconv_convenience,
35 const struct reg_diff_callbacks *callbacks,
36 void *callback_data);
39 * Generate difference between two keys
41 WERROR reg_generate_diff_key(struct registry_key *oldkey,
42 struct registry_key *newkey,
43 const char *path,
44 const struct reg_diff_callbacks *callbacks,
45 void *callback_data)
47 unsigned int i;
48 struct registry_key *t1 = NULL, *t2 = NULL;
49 char *tmppath;
50 const char *keyname1;
51 WERROR error, error1, error2;
52 TALLOC_CTX *mem_ctx = talloc_init("writediff");
53 uint32_t old_num_subkeys, old_num_values,
54 new_num_subkeys, new_num_values;
56 if (oldkey != NULL) {
57 error = reg_key_get_info(mem_ctx, oldkey, NULL,
58 &old_num_subkeys, &old_num_values,
59 NULL, NULL, NULL, NULL);
60 if (!W_ERROR_IS_OK(error)) {
61 DEBUG(0, ("Error occurred while getting key info: %s\n",
62 win_errstr(error)));
63 talloc_free(mem_ctx);
64 return error;
66 } else {
67 old_num_subkeys = 0;
68 old_num_values = 0;
71 /* Subkeys that were changed or deleted */
72 for (i = 0; i < old_num_subkeys; i++) {
73 error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
74 &keyname1, NULL, NULL);
75 if (!W_ERROR_IS_OK(error1)) {
76 DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
77 win_errstr(error1)));
78 continue;
81 if (newkey != NULL) {
82 error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
83 } else {
84 error2 = WERR_BADFILE;
85 t2 = NULL;
88 if (!W_ERROR_IS_OK(error2) && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
89 DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
90 win_errstr(error2)));
91 talloc_free(mem_ctx);
92 return error2;
95 /* if "error2" is going to be "WERR_BADFILE", then newkey */
96 /* didn't have such a subkey and therefore add a del diff */
97 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
98 if (tmppath == NULL) {
99 DEBUG(0, ("Out of memory\n"));
100 talloc_free(mem_ctx);
101 return WERR_NOMEM;
103 if (!W_ERROR_IS_OK(error2))
104 callbacks->del_key(callback_data, tmppath);
106 /* perform here also the recursive invocation */
107 error1 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
108 if (!W_ERROR_IS_OK(error1)) {
109 DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
110 win_errstr(error1)));
111 talloc_free(mem_ctx);
112 return error1;
114 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
116 talloc_free(tmppath);
119 if (newkey != NULL) {
120 error = reg_key_get_info(mem_ctx, newkey, NULL,
121 &new_num_subkeys, &new_num_values,
122 NULL, NULL, NULL, NULL);
123 if (!W_ERROR_IS_OK(error)) {
124 DEBUG(0, ("Error occurred while getting key info: %s\n",
125 win_errstr(error)));
126 talloc_free(mem_ctx);
127 return error;
129 } else {
130 new_num_subkeys = 0;
131 new_num_values = 0;
134 /* Subkeys that were added */
135 for(i = 0; i < new_num_subkeys; i++) {
136 error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i,
137 &keyname1, NULL, NULL);
138 if (!W_ERROR_IS_OK(error1)) {
139 DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
140 win_errstr(error1)));
141 talloc_free(mem_ctx);
142 return error1;
145 if (oldkey != NULL) {
146 error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
148 if (W_ERROR_IS_OK(error2))
149 continue;
150 } else {
151 error2 = WERR_BADFILE;
152 t1 = NULL;
155 if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
156 DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
157 win_errstr(error2)));
158 talloc_free(mem_ctx);
159 return error2;
162 /* oldkey didn't have such a subkey, add a add diff */
163 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
164 if (tmppath == NULL) {
165 DEBUG(0, ("Out of memory\n"));
166 talloc_free(mem_ctx);
167 return WERR_NOMEM;
169 callbacks->add_key(callback_data, tmppath);
171 /* perform here also the recursive invocation */
172 error1 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
173 if (!W_ERROR_IS_OK(error1)) {
174 DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
175 win_errstr(error1)));
176 talloc_free(mem_ctx);
177 return error1;
179 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
181 talloc_free(tmppath);
184 /* Values that were added or changed */
185 for(i = 0; i < new_num_values; i++) {
186 const char *name;
187 uint32_t type1, type2;
188 DATA_BLOB contents1 = { NULL, 0 }, contents2 = { NULL, 0 };
190 error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
191 &name, &type1, &contents1);
192 if (!W_ERROR_IS_OK(error1)) {
193 DEBUG(0, ("Unable to get value by index: %s\n",
194 win_errstr(error1)));
195 talloc_free(mem_ctx);
196 return error1;
199 if (oldkey != NULL) {
200 error2 = reg_key_get_value_by_name(mem_ctx, oldkey,
201 name, &type2,
202 &contents2);
203 } else
204 error2 = WERR_BADFILE;
206 if (!W_ERROR_IS_OK(error2)
207 && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
208 DEBUG(0, ("Error occurred while getting value by name: %s\n",
209 win_errstr(error2)));
210 talloc_free(mem_ctx);
211 return error2;
214 if (W_ERROR_IS_OK(error2)
215 && (data_blob_cmp(&contents1, &contents2) == 0)
216 && (type1 == type2)) {
217 talloc_free(discard_const_p(char, name));
218 talloc_free(contents1.data);
219 talloc_free(contents2.data);
220 continue;
223 callbacks->set_value(callback_data, path, name,
224 type1, contents1);
226 talloc_free(discard_const_p(char, name));
227 talloc_free(contents1.data);
228 talloc_free(contents2.data);
231 /* Values that were deleted */
232 for (i = 0; i < old_num_values; i++) {
233 const char *name;
234 uint32_t type;
235 DATA_BLOB contents = { NULL, 0 };
237 error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
238 &type, &contents);
239 if (!W_ERROR_IS_OK(error1)) {
240 DEBUG(0, ("Unable to get value by index: %s\n",
241 win_errstr(error1)));
242 talloc_free(mem_ctx);
243 return error1;
246 if (newkey != NULL)
247 error2 = reg_key_get_value_by_name(mem_ctx, newkey,
248 name, &type, &contents);
249 else
250 error2 = WERR_BADFILE;
252 if (W_ERROR_IS_OK(error2)) {
253 talloc_free(discard_const_p(char, name));
254 talloc_free(contents.data);
255 continue;
258 if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
259 DEBUG(0, ("Error occurred while getting value by name: %s\n",
260 win_errstr(error2)));
261 talloc_free(mem_ctx);
262 return error2;
265 callbacks->del_value(callback_data, path, name);
267 talloc_free(discard_const_p(char, name));
268 talloc_free(contents.data);
271 talloc_free(mem_ctx);
272 return WERR_OK;
276 * Generate diff between two registry contexts
278 _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
279 struct registry_context *ctx2,
280 const struct reg_diff_callbacks *callbacks,
281 void *callback_data)
283 unsigned int i;
284 WERROR error;
286 for (i = 0; reg_predefined_keys[i].name; i++) {
287 struct registry_key *r1 = NULL, *r2 = NULL;
289 error = reg_get_predefined_key(ctx1,
290 reg_predefined_keys[i].handle, &r1);
291 if (!W_ERROR_IS_OK(error) &&
292 !W_ERROR_EQUAL(error, WERR_BADFILE)) {
293 DEBUG(0, ("Unable to open hive %s for backend 1\n",
294 reg_predefined_keys[i].name));
295 continue;
298 error = reg_get_predefined_key(ctx2,
299 reg_predefined_keys[i].handle, &r2);
300 if (!W_ERROR_IS_OK(error) &&
301 !W_ERROR_EQUAL(error, WERR_BADFILE)) {
302 DEBUG(0, ("Unable to open hive %s for backend 2\n",
303 reg_predefined_keys[i].name));
304 continue;
307 /* if "r1" is NULL (old hive) and "r2" isn't (new hive) then
308 * the hive doesn't exist yet and we have to generate an add
309 * diff */
310 if ((r1 == NULL) && (r2 != NULL)) {
311 callbacks->add_key(callback_data,
312 reg_predefined_keys[i].name);
314 /* if "r1" isn't NULL (old hive) and "r2" is (new hive) then
315 * the hive shouldn't exist anymore and we have to generate a
316 * del diff */
317 if ((r1 != NULL) && (r2 == NULL)) {
318 callbacks->del_key(callback_data,
319 reg_predefined_keys[i].name);
322 error = reg_generate_diff_key(r1, r2,
323 reg_predefined_keys[i].name, callbacks,
324 callback_data);
325 if (!W_ERROR_IS_OK(error)) {
326 DEBUG(0, ("Unable to determine diff: %s\n",
327 win_errstr(error)));
328 return error;
331 if (callbacks->done != NULL) {
332 callbacks->done(callback_data);
334 return WERR_OK;
338 * Load diff file
340 _PUBLIC_ WERROR reg_diff_load(const char *filename,
341 struct smb_iconv_convenience *iconv_convenience,
342 const struct reg_diff_callbacks *callbacks,
343 void *callback_data)
345 int fd;
346 char hdr[4];
348 fd = open(filename, O_RDONLY, 0);
349 if (fd == -1) {
350 DEBUG(0, ("Error opening registry patch file `%s'\n",
351 filename));
352 return WERR_GENERAL_FAILURE;
355 if (read(fd, &hdr, 4) != 4) {
356 DEBUG(0, ("Error reading registry patch file `%s'\n",
357 filename));
358 close(fd);
359 return WERR_GENERAL_FAILURE;
362 /* Reset position in file */
363 lseek(fd, 0, SEEK_SET);
364 #if 0 /* These backends are not supported yet. */
365 if (strncmp(hdr, "CREG", 4) == 0) {
366 /* Must be a W9x CREG Config.pol file */
367 return reg_creg_diff_load(diff, fd);
368 } else if (strncmp(hdr, "regf", 4) == 0) {
369 /* Must be a REGF NTConfig.pol file */
370 return reg_regf_diff_load(diff, fd);
371 } else
372 #endif
373 if (strncmp(hdr, "PReg", 4) == 0) {
374 /* Must be a GPO Registry.pol file */
375 return reg_preg_diff_load(fd, iconv_convenience, callbacks, callback_data);
376 } else {
377 /* Must be a normal .REG file */
378 return reg_dotreg_diff_load(fd, iconv_convenience, callbacks, callback_data);
383 * The reg_diff_apply functions
385 static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
387 struct registry_context *ctx = (struct registry_context *)_ctx;
388 struct registry_key *tmp;
389 char *buf, *buf_ptr;
390 WERROR error;
392 /* Recursively create the path */
393 buf = talloc_strdup(ctx, key_name);
394 W_ERROR_HAVE_NO_MEMORY(buf);
395 buf_ptr = buf;
397 while (*buf_ptr++ != '\0' ) {
398 if (*buf_ptr == '\\') {
399 *buf_ptr = '\0';
400 error = reg_key_add_abs(ctx, ctx, buf, 0, NULL, &tmp);
402 if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
403 !W_ERROR_IS_OK(error)) {
404 DEBUG(0, ("Error adding new key '%s': %s\n",
405 key_name, win_errstr(error)));
406 return error;
408 *buf_ptr++ = '\\';
409 talloc_free(tmp);
413 talloc_free(buf);
415 /* Add the key */
416 error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
418 if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
419 !W_ERROR_IS_OK(error)) {
420 DEBUG(0, ("Error adding new key '%s': %s\n",
421 key_name, win_errstr(error)));
422 return error;
424 talloc_free(tmp);
426 return WERR_OK;
429 static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
431 struct registry_context *ctx = (struct registry_context *)_ctx;
433 /* We can't proof here for success, because a common superkey could */
434 /* have been deleted before the subkey's (diff order). This removed */
435 /* therefore all children recursively and the "WERR_BADFILE" result is */
436 /* expected. */
438 reg_key_del_abs(ctx, key_name);
440 return WERR_OK;
443 static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
444 const char *value_name,
445 uint32_t value_type, DATA_BLOB value)
447 struct registry_context *ctx = (struct registry_context *)_ctx;
448 struct registry_key *tmp;
449 WERROR error;
451 /* Open key */
452 error = reg_open_key_abs(ctx, ctx, path, &tmp);
454 if (W_ERROR_EQUAL(error, WERR_BADFILE)) {
455 DEBUG(0, ("Error opening key '%s'\n", path));
456 return error;
459 /* Set value */
460 error = reg_val_set(tmp, value_name,
461 value_type, value);
462 if (!W_ERROR_IS_OK(error)) {
463 DEBUG(0, ("Error setting value '%s'\n", value_name));
464 return error;
467 talloc_free(tmp);
469 return WERR_OK;
472 static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name,
473 const char *value_name)
475 struct registry_context *ctx = (struct registry_context *)_ctx;
476 struct registry_key *tmp;
477 WERROR error;
479 /* Open key */
480 error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
482 if (!W_ERROR_IS_OK(error)) {
483 DEBUG(0, ("Error opening key '%s'\n", key_name));
484 return error;
487 error = reg_del_value(ctx, tmp, value_name);
488 if (!W_ERROR_IS_OK(error)) {
489 DEBUG(0, ("Error deleting value '%s'\n", value_name));
490 return error;
493 talloc_free(tmp);
495 return WERR_OK;
498 static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
500 struct registry_context *ctx = (struct registry_context *)_ctx;
501 struct registry_key *key;
502 WERROR error;
503 const char *value_name;
505 error = reg_open_key_abs(ctx, ctx, key_name, &key);
507 if (!W_ERROR_IS_OK(error)) {
508 DEBUG(0, ("Error opening key '%s'\n", key_name));
509 return error;
512 W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL,
513 NULL, NULL, NULL, NULL, NULL, NULL));
515 while (W_ERROR_IS_OK(reg_key_get_value_by_index(
516 ctx, key, 0, &value_name, NULL, NULL))) {
517 error = reg_del_value(ctx, key, value_name);
518 if (!W_ERROR_IS_OK(error)) {
519 DEBUG(0, ("Error deleting value '%s'\n", value_name));
520 return error;
522 talloc_free(discard_const_p(char, value_name));
525 talloc_free(key);
527 return WERR_OK;
531 * Apply diff to a registry context
533 _PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx,
534 struct smb_iconv_convenience *iconv_convenience,
535 const char *filename)
537 struct reg_diff_callbacks callbacks;
539 callbacks.add_key = reg_diff_apply_add_key;
540 callbacks.del_key = reg_diff_apply_del_key;
541 callbacks.set_value = reg_diff_apply_set_value;
542 callbacks.del_value = reg_diff_apply_del_value;
543 callbacks.del_all_values = reg_diff_apply_del_all_values;
544 callbacks.done = NULL;
546 return reg_diff_load(filename, iconv_convenience,
547 &callbacks, ctx);