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
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/>.
24 #include "lib/registry/registry.h"
25 #include "system/filesys.h"
26 #include "param/param.h"
29 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
30 struct smb_iconv_convenience *iconv_convenience,
31 const struct reg_diff_callbacks *callbacks,
34 _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
35 struct smb_iconv_convenience *iconv_convenience,
36 const struct reg_diff_callbacks *callbacks,
40 * Generate difference between two keys
42 WERROR reg_generate_diff_key(struct registry_key *oldkey,
43 struct registry_key *newkey,
45 const struct reg_diff_callbacks *callbacks,
49 struct registry_key *t1 = NULL, *t2 = NULL;
52 WERROR error, error1, error2;
53 TALLOC_CTX *mem_ctx = talloc_init("writediff");
54 uint32_t old_num_subkeys, old_num_values,
55 new_num_subkeys, new_num_values;
58 error = reg_key_get_info(mem_ctx, oldkey, NULL,
59 &old_num_subkeys, &old_num_values,
60 NULL, NULL, NULL, NULL);
61 if (!W_ERROR_IS_OK(error)) {
62 DEBUG(0, ("Error occurred while getting key info: %s\n",
72 /* Subkeys that were changed or deleted */
73 for (i = 0; i < old_num_subkeys; i++) {
74 error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
75 &keyname1, NULL, NULL);
76 if (!W_ERROR_IS_OK(error1)) {
77 DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
83 error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
85 error2 = WERR_BADFILE;
89 if (!W_ERROR_IS_OK(error2) && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
90 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
96 /* if "error2" is going to be "WERR_BADFILE", then newkey */
97 /* didn't have such a subkey and therefore add a del diff */
98 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
99 if (!W_ERROR_IS_OK(error2))
100 callbacks->del_key(callback_data, tmppath);
102 /* perform here also the recursive invocation */
103 error1 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
104 if (!W_ERROR_IS_OK(error1)) {
105 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
106 win_errstr(error1)));
107 talloc_free(mem_ctx);
110 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
112 talloc_free(tmppath);
115 if (newkey != NULL) {
116 error = reg_key_get_info(mem_ctx, newkey, NULL,
117 &new_num_subkeys, &new_num_values,
118 NULL, NULL, NULL, NULL);
119 if (!W_ERROR_IS_OK(error)) {
120 DEBUG(0, ("Error occurred while getting key info: %s\n",
122 talloc_free(mem_ctx);
130 /* Subkeys that were added */
131 for(i = 0; i < new_num_subkeys; i++) {
132 error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i,
133 &keyname1, NULL, NULL);
134 if (!W_ERROR_IS_OK(error1)) {
135 DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
136 win_errstr(error1)));
137 talloc_free(mem_ctx);
141 if (oldkey != NULL) {
142 error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
144 if (W_ERROR_IS_OK(error2))
147 error2 = WERR_BADFILE;
151 if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
152 DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
153 win_errstr(error2)));
154 talloc_free(mem_ctx);
158 /* oldkey didn't have such a subkey, add add diff */
159 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
160 callbacks->add_key(callback_data, tmppath);
162 /* perform here also the recursive invocation */
163 error1 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
164 if (!W_ERROR_IS_OK(error1)) {
165 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
166 win_errstr(error1)));
167 talloc_free(mem_ctx);
170 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
172 talloc_free(tmppath);
175 /* Values that were added or changed */
176 for(i = 0; i < new_num_values; i++) {
178 uint32_t type1, type2;
179 DATA_BLOB contents1, contents2;
181 error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
182 &name, &type1, &contents1);
183 if (!W_ERROR_IS_OK(error1)) {
184 DEBUG(0, ("Unable to get value by index: %s\n",
185 win_errstr(error1)));
186 talloc_free(mem_ctx);
190 if (oldkey != NULL) {
191 error2 = reg_key_get_value_by_name(mem_ctx, oldkey,
195 error2 = WERR_BADFILE;
197 if (!W_ERROR_IS_OK(error2)
198 && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
199 DEBUG(0, ("Error occurred while getting value by name: %s\n",
200 win_errstr(error2)));
201 talloc_free(mem_ctx);
205 if (W_ERROR_IS_OK(error2)
206 && (data_blob_cmp(&contents1, &contents2) == 0)
210 callbacks->set_value(callback_data, path, name,
214 /* Values that were deleted */
215 for (i = 0; i < old_num_values; i++) {
220 error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
222 if (!W_ERROR_IS_OK(error1)) {
223 DEBUG(0, ("Unable to get value by index: %s\n",
224 win_errstr(error1)));
225 talloc_free(mem_ctx);
230 error2 = reg_key_get_value_by_name(mem_ctx, newkey,
231 name, &type, &contents);
233 error2 = WERR_BADFILE;
235 if (W_ERROR_IS_OK(error2))
238 if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
239 DEBUG(0, ("Error occurred while getting value by name: %s\n",
240 win_errstr(error2)));
241 talloc_free(mem_ctx);
245 callbacks->del_value(callback_data, path, name);
248 talloc_free(mem_ctx);
253 * Generate diff between two registry contexts
255 _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
256 struct registry_context *ctx2,
257 const struct reg_diff_callbacks *callbacks,
263 for (i = 0; reg_predefined_keys[i].name; i++) {
264 struct registry_key *r1 = NULL, *r2 = NULL;
266 error = reg_get_predefined_key(ctx1,
267 reg_predefined_keys[i].handle, &r1);
268 if (!W_ERROR_IS_OK(error) &&
269 !W_ERROR_EQUAL(error, WERR_BADFILE)) {
270 DEBUG(0, ("Unable to open hive %s for backend 1\n",
271 reg_predefined_keys[i].name));
275 error = reg_get_predefined_key(ctx2,
276 reg_predefined_keys[i].handle, &r2);
277 if (!W_ERROR_IS_OK(error) &&
278 !W_ERROR_EQUAL(error, WERR_BADFILE)) {
279 DEBUG(0, ("Unable to open hive %s for backend 2\n",
280 reg_predefined_keys[i].name));
284 error = reg_generate_diff_key(r1, r2,
285 reg_predefined_keys[i].name, callbacks,
287 if (!W_ERROR_IS_OK(error)) {
288 DEBUG(0, ("Unable to determine diff: %s\n",
293 if (callbacks->done != NULL) {
294 callbacks->done(callback_data);
302 _PUBLIC_ WERROR reg_diff_load(const char *filename,
303 struct smb_iconv_convenience *iconv_convenience,
304 const struct reg_diff_callbacks *callbacks,
310 fd = open(filename, O_RDONLY, 0);
312 DEBUG(0, ("Error opening registry patch file `%s'\n",
314 return WERR_GENERAL_FAILURE;
317 if (read(fd, &hdr, 4) != 4) {
318 DEBUG(0, ("Error reading registry patch file `%s'\n",
320 return WERR_GENERAL_FAILURE;
323 /* Reset position in file */
324 lseek(fd, 0, SEEK_SET);
325 #if 0 /* These backends are not supported yet. */
326 if (strncmp(hdr, "CREG", 4) == 0) {
327 /* Must be a W9x CREG Config.pol file */
328 return reg_creg_diff_load(diff, fd);
329 } else if (strncmp(hdr, "regf", 4) == 0) {
330 /* Must be a REGF NTConfig.pol file */
331 return reg_regf_diff_load(diff, fd);
334 if (strncmp(hdr, "PReg", 4) == 0) {
335 /* Must be a GPO Registry.pol file */
336 return reg_preg_diff_load(fd, iconv_convenience, callbacks, callback_data);
338 /* Must be a normal .REG file */
339 return reg_dotreg_diff_load(fd, iconv_convenience, callbacks, callback_data);
344 * The reg_diff_apply functions
346 static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
348 struct registry_context *ctx = (struct registry_context *)_ctx;
349 struct registry_key *tmp;
353 /* Recursively create the path */
354 buf = talloc_strdup(ctx, key_name);
357 while (*buf_ptr++ != '\0' ) {
358 if (*buf_ptr == '\\') {
360 error = reg_key_add_abs(ctx, ctx, buf, 0, NULL, &tmp);
362 if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
363 !W_ERROR_IS_OK(error)) {
364 DEBUG(0, ("Error adding new key '%s': %s\n",
365 key_name, win_errstr(error)));
373 error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
375 if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
376 !W_ERROR_IS_OK(error)) {
377 DEBUG(0, ("Error adding new key '%s': %s\n",
378 key_name, win_errstr(error)));
384 static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
386 struct registry_context *ctx = (struct registry_context *)_ctx;
388 /* We can't proof here for success, because a common superkey could */
389 /* have been deleted before the subkey's (diff order). This removed */
390 /* therefore all childs recursively and the "WERR_BADFILE" result is */
393 reg_key_del_abs(ctx, key_name);
398 static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
399 const char *value_name,
400 uint32_t value_type, DATA_BLOB value)
402 struct registry_context *ctx = (struct registry_context *)_ctx;
403 struct registry_key *tmp;
407 error = reg_open_key_abs(ctx, ctx, path, &tmp);
409 if (W_ERROR_EQUAL(error, WERR_BADFILE)) {
410 DEBUG(0, ("Error opening key '%s'\n", path));
415 error = reg_val_set(tmp, value_name,
417 if (!W_ERROR_IS_OK(error)) {
418 DEBUG(0, ("Error setting value '%s'\n", value_name));
425 static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name,
426 const char *value_name)
428 struct registry_context *ctx = (struct registry_context *)_ctx;
429 struct registry_key *tmp;
433 error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
435 if (!W_ERROR_IS_OK(error)) {
436 DEBUG(0, ("Error opening key '%s'\n", key_name));
440 error = reg_del_value(tmp, value_name);
441 if (!W_ERROR_IS_OK(error)) {
442 DEBUG(0, ("Error deleting value '%s'\n", value_name));
450 static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
452 struct registry_context *ctx = (struct registry_context *)_ctx;
453 struct registry_key *key;
455 const char* value_name;
457 error = reg_open_key_abs(ctx, ctx, key_name, &key);
459 if (!W_ERROR_IS_OK(error)) {
460 DEBUG(0, ("Error opening key '%s'\n", key_name));
464 W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL,
465 NULL, NULL, NULL, NULL, NULL, NULL));
467 while (W_ERROR_IS_OK(reg_key_get_value_by_index(
468 ctx, key, 0, &value_name, NULL, NULL))) {
469 error = reg_del_value(key, value_name);
470 if (!W_ERROR_IS_OK(error)) {
471 DEBUG(0, ("Error deleting value '%s'\n", value_name));
480 * Apply diff to a registry context
482 _PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, const char *filename)
484 struct reg_diff_callbacks callbacks;
486 callbacks.add_key = reg_diff_apply_add_key;
487 callbacks.del_key = reg_diff_apply_del_key;
488 callbacks.set_value = reg_diff_apply_set_value;
489 callbacks.del_value = reg_diff_apply_del_value;
490 callbacks.del_all_values = reg_diff_apply_del_all_values;
491 callbacks.done = NULL;
493 return reg_diff_load(filename, lp_iconv_convenience(global_loadparm),