2 Unix SMB/CIFS implementation.
3 Reading registry patch files
5 Copyright (C) Jelmer Vernooij 2004-2007
6 Copyright (C) Wilco Baan Hofman 2006
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, see <http://www.gnu.org/licenses/>.
23 #include "lib/registry/registry.h"
24 #include "system/filesys.h"
25 #include "param/param.h"
28 _PUBLIC_ WERROR
reg_preg_diff_load(int fd
,
29 struct smb_iconv_convenience
*iconv_convenience
,
30 const struct reg_diff_callbacks
*callbacks
,
33 _PUBLIC_ WERROR
reg_dotreg_diff_load(int fd
,
34 struct smb_iconv_convenience
*iconv_convenience
,
35 const struct reg_diff_callbacks
*callbacks
,
39 * Generate difference between two keys
41 WERROR
reg_generate_diff_key(struct registry_key
*oldkey
,
42 struct registry_key
*newkey
,
44 const struct reg_diff_callbacks
*callbacks
,
48 struct registry_key
*t1
= NULL
, *t2
= NULL
;
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
;
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 occured while getting key info: %s\n",
70 /* Subkeys that were deleted */
71 for (i
= 0; i
< old_num_subkeys
; i
++) {
72 error1
= reg_key_get_subkey_by_index(mem_ctx
, oldkey
, i
,
75 if (!W_ERROR_IS_OK(error1
)) {
76 DEBUG(0, ("Error occured while getting subkey by index: %s\n",
82 error2
= reg_open_key(mem_ctx
, newkey
, keyname1
, &t2
);
84 if (W_ERROR_IS_OK(error2
))
87 error2
= WERR_BADFILE
;
91 if (!W_ERROR_EQUAL(error2
, WERR_BADFILE
)) {
92 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
98 /* newkey didn't have such a subkey, add del diff */
99 tmppath
= talloc_asprintf(mem_ctx
, "%s\\%s", path
, keyname1
);
100 callbacks
->del_key(callback_data
, tmppath
);
101 talloc_free(tmppath
);
104 if (newkey
!= NULL
) {
105 error
= reg_key_get_info(mem_ctx
, newkey
, NULL
,
106 &new_num_subkeys
, &new_num_values
,
107 NULL
, NULL
, NULL
, NULL
);
108 if (!W_ERROR_IS_OK(error
)) {
109 DEBUG(0, ("Error occured while getting key info: %s\n",
118 /* Subkeys that were added */
119 for(i
= 0; i
< new_num_subkeys
; i
++) {
120 error1
= reg_key_get_subkey_by_index(mem_ctx
, newkey
,
123 if (!W_ERROR_IS_OK(error1
)) {
124 DEBUG(0, ("Error occured while getting subkey by index: %s\n",
125 win_errstr(error1
)));
126 talloc_free(mem_ctx
);
130 if (oldkey
!= NULL
) {
131 error2
= reg_open_key(mem_ctx
, oldkey
, keyname1
, &t1
);
133 if (W_ERROR_IS_OK(error2
))
137 error2
= WERR_BADFILE
;
140 if (!W_ERROR_EQUAL(error2
, WERR_BADFILE
)) {
141 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
142 win_errstr(error2
)));
143 talloc_free(mem_ctx
);
147 /* oldkey didn't have such a subkey, add add diff */
148 tmppath
= talloc_asprintf(mem_ctx
, "%s\\%s", path
, keyname1
);
149 callbacks
->add_key(callback_data
, tmppath
);
151 W_ERROR_NOT_OK_RETURN(
152 reg_open_key(mem_ctx
, newkey
, keyname1
, &t2
));
154 reg_generate_diff_key(t1
, t2
, tmppath
,
155 callbacks
, callback_data
);
156 talloc_free(tmppath
);
159 /* Values that were changed */
160 for(i
= 0; i
< new_num_values
; i
++) {
162 uint32_t type1
, type2
;
163 DATA_BLOB contents1
, contents2
;
165 error1
= reg_key_get_value_by_index(mem_ctx
, newkey
, i
,
166 &name
, &type1
, &contents1
);
167 if (!W_ERROR_IS_OK(error1
)) {
168 DEBUG(0, ("Unable to get key by index: %s\n",
169 win_errstr(error1
)));
170 talloc_free(mem_ctx
);
174 if (oldkey
!= NULL
) {
175 error2
= reg_key_get_value_by_name(mem_ctx
, oldkey
,
179 error2
= WERR_BADFILE
;
181 if(!W_ERROR_IS_OK(error2
) &&
182 !W_ERROR_EQUAL(error2
, WERR_BADFILE
)) {
183 DEBUG(0, ("Error occured while getting value by name: %s\n",
184 win_errstr(error2
)));
185 talloc_free(mem_ctx
);
189 if (W_ERROR_IS_OK(error2
) &&
190 data_blob_cmp(&contents1
, &contents2
) == 0)
193 callbacks
->set_value(callback_data
, path
, name
,
197 /* Values that were deleted */
198 for (i
= 0; i
< old_num_values
; i
++) {
200 error1
= reg_key_get_value_by_index(mem_ctx
, oldkey
, i
, &name
,
202 if (!W_ERROR_IS_OK(error1
)) {
203 DEBUG(0, ("Error ocurred getting value by index: %s\n",
204 win_errstr(error1
)));
205 talloc_free(mem_ctx
);
209 error2
= reg_key_get_value_by_name(mem_ctx
, newkey
, name
, NULL
,
212 if (W_ERROR_IS_OK(error2
))
215 if (!W_ERROR_EQUAL(error2
, WERR_BADFILE
)) {
216 DEBUG(0, ("Error occured while getting value by name: %s\n",
217 win_errstr(error2
)));
221 callbacks
->del_value(callback_data
, path
, name
);
224 talloc_free(mem_ctx
);
229 * Generate diff between two registry contexts
231 _PUBLIC_ WERROR
reg_generate_diff(struct registry_context
*ctx1
,
232 struct registry_context
*ctx2
,
233 const struct reg_diff_callbacks
*callbacks
,
239 for(i
= HKEY_FIRST
; i
<= HKEY_LAST
; i
++) {
240 struct registry_key
*r1
= NULL
, *r2
= NULL
;
241 error
= reg_get_predefined_key(ctx1
, i
, &r1
);
242 if (!W_ERROR_IS_OK(error
) &&
243 !W_ERROR_EQUAL(error
, WERR_BADFILE
)) {
244 DEBUG(0, ("Unable to open hive %s for backend 1\n",
245 reg_get_predef_name(i
)));
248 error
= reg_get_predefined_key(ctx2
, i
, &r2
);
249 if (!W_ERROR_IS_OK(error
) &&
250 !W_ERROR_EQUAL(error
, WERR_BADFILE
)) {
251 DEBUG(0, ("Unable to open hive %s for backend 2\n",
252 reg_get_predef_name(i
)));
255 if (r1
== NULL
&& r2
== NULL
)
258 error
= reg_generate_diff_key(r1
, r2
, reg_get_predef_name(i
),
259 callbacks
, callback_data
);
260 if (!W_ERROR_IS_OK(error
)) {
261 DEBUG(0, ("Unable to determine diff: %s\n",
266 if (callbacks
->done
!= NULL
) {
267 callbacks
->done(callback_data
);
275 _PUBLIC_ WERROR
reg_diff_load(const char *filename
,
276 struct smb_iconv_convenience
*iconv_convenience
,
277 const struct reg_diff_callbacks
*callbacks
,
283 fd
= open(filename
, O_RDONLY
, 0);
285 DEBUG(0, ("Error opening registry patch file `%s'\n",
287 return WERR_GENERAL_FAILURE
;
290 if (read(fd
, &hdr
, 4) != 4) {
291 DEBUG(0, ("Error reading registry patch file `%s'\n",
293 return WERR_GENERAL_FAILURE
;
296 /* Reset position in file */
297 lseek(fd
, 0, SEEK_SET
);
298 #if 0 /* These backends are not supported yet. */
299 if (strncmp(hdr
, "CREG", 4) == 0) {
300 /* Must be a W9x CREG Config.pol file */
301 return reg_creg_diff_load(diff
, fd
);
302 } else if (strncmp(hdr
, "regf", 4) == 0) {
303 /* Must be a REGF NTConfig.pol file */
304 return reg_regf_diff_load(diff
, fd
);
307 if (strncmp(hdr
, "PReg", 4) == 0) {
308 /* Must be a GPO Registry.pol file */
309 return reg_preg_diff_load(fd
, iconv_convenience
, callbacks
, callback_data
);
311 /* Must be a normal .REG file */
312 return reg_dotreg_diff_load(fd
, iconv_convenience
, callbacks
, callback_data
);
317 * The reg_diff_apply functions
319 static WERROR
reg_diff_apply_add_key(void *_ctx
, const char *key_name
)
321 struct registry_context
*ctx
= (struct registry_context
*)_ctx
;
322 struct registry_key
*tmp
;
325 error
= reg_key_add_abs(ctx
, ctx
, key_name
, 0, NULL
, &tmp
);
327 if (!W_ERROR_EQUAL(error
, WERR_ALREADY_EXISTS
) &&
328 !W_ERROR_IS_OK(error
)) {
329 DEBUG(0, ("Error adding new key '%s': %s\n",
330 key_name
, win_errstr(error
)));
336 static WERROR
reg_diff_apply_del_key(void *_ctx
, const char *key_name
)
338 struct registry_context
*ctx
= (struct registry_context
*)_ctx
;
341 error
= reg_key_del_abs(ctx
, key_name
);
343 if(!W_ERROR_IS_OK(error
)) {
344 DEBUG(0, ("Unable to delete key '%s'\n", key_name
));
351 static WERROR
reg_diff_apply_set_value(void *_ctx
, const char *path
,
352 const char *value_name
,
353 uint32_t value_type
, DATA_BLOB value
)
355 struct registry_context
*ctx
= (struct registry_context
*)_ctx
;
356 struct registry_key
*tmp
;
360 error
= reg_open_key_abs(ctx
, ctx
, path
, &tmp
);
362 if (W_ERROR_EQUAL(error
, WERR_BADFILE
)) {
363 DEBUG(0, ("Error opening key '%s'\n", path
));
368 error
= reg_val_set(tmp
, value_name
,
370 if (!W_ERROR_IS_OK(error
)) {
371 DEBUG(0, ("Error setting value '%s'\n", value_name
));
378 static WERROR
reg_diff_apply_del_value(void *_ctx
, const char *key_name
,
379 const char *value_name
)
381 struct registry_context
*ctx
= (struct registry_context
*)_ctx
;
382 struct registry_key
*tmp
;
386 error
= reg_open_key_abs(ctx
, ctx
, key_name
, &tmp
);
388 if (!W_ERROR_IS_OK(error
)) {
389 DEBUG(0, ("Error opening key '%s'\n", key_name
));
393 error
= reg_del_value(tmp
, value_name
);
394 if (!W_ERROR_IS_OK(error
)) {
395 DEBUG(0, ("Error deleting value '%s'\n", value_name
));
403 static WERROR
reg_diff_apply_del_all_values(void *_ctx
, const char *key_name
)
405 struct registry_context
*ctx
= (struct registry_context
*)_ctx
;
406 struct registry_key
*key
;
411 error
= reg_open_key_abs(ctx
, ctx
, key_name
, &key
);
413 if (!W_ERROR_IS_OK(error
)) {
414 DEBUG(0, ("Error opening key '%s'\n", key_name
));
418 W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx
, key
, NULL
,
419 NULL
, &num_values
, NULL
, NULL
, NULL
, NULL
));
421 for (i
= 0; i
< num_values
; i
++) {
423 W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx
, key
, i
,
426 W_ERROR_NOT_OK_RETURN(reg_del_value(key
, name
));
433 * Apply diff to a registry context
435 _PUBLIC_ WERROR
reg_diff_apply(struct registry_context
*ctx
, const char *filename
)
437 struct reg_diff_callbacks callbacks
;
439 callbacks
.add_key
= reg_diff_apply_add_key
;
440 callbacks
.del_key
= reg_diff_apply_del_key
;
441 callbacks
.set_value
= reg_diff_apply_set_value
;
442 callbacks
.del_value
= reg_diff_apply_del_value
;
443 callbacks
.del_all_values
= reg_diff_apply_del_all_values
;
444 callbacks
.done
= NULL
;
446 return reg_diff_load(filename
, lp_iconv_convenience(global_loadparm
),