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/patchfile.h"
24 #include "lib/registry/registry.h"
25 #include "system/filesys.h"
28 _PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
30 _PUBLIC_ WERROR reg_dotreg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
33 * Generate difference between two keys
35 WERROR reg_generate_diff_key(struct registry_key *oldkey,
36 struct registry_key *newkey,
38 const struct reg_diff_callbacks *callbacks,
42 struct registry_key *t1, *t2;
45 WERROR error, error1, error2;
46 TALLOC_CTX *mem_ctx = talloc_init("writediff");
47 uint32_t old_num_subkeys, old_num_values,
48 new_num_subkeys, new_num_values;
51 error = reg_key_get_info(mem_ctx, oldkey, NULL, &old_num_subkeys, &old_num_values,
53 if (!W_ERROR_IS_OK(error)) {
54 DEBUG(0, ("Error occured while getting key info: %s\n",
63 /* Subkeys that were deleted */
64 for (i = 0; i < old_num_subkeys; i++) {
65 error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &keyname1,
67 if (!W_ERROR_IS_OK(error1)) {
68 DEBUG(0, ("Error occured while getting subkey by index: %s\n",
74 error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
76 if (W_ERROR_IS_OK(error2))
79 error2 = WERR_DEST_NOT_FOUND;
83 if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
84 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
90 /* newkey didn't have such a subkey, add del diff */
91 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
92 callbacks->del_key(callback_data, tmppath);
97 error = reg_key_get_info(mem_ctx, newkey, NULL, &new_num_subkeys, &new_num_values,
99 if (!W_ERROR_IS_OK(error)) {
100 DEBUG(0, ("Error occured while getting key info: %s\n",
109 /* Subkeys that were added */
110 for(i = 0; i < new_num_subkeys; i++) {
111 error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &keyname1,
113 if (!W_ERROR_IS_OK(error1)) {
114 DEBUG(0, ("Error occured while getting subkey by index: %s\n",
115 win_errstr(error1)));
116 talloc_free(mem_ctx);
120 if (oldkey != NULL) {
121 error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
123 if (W_ERROR_IS_OK(error2))
127 error2 = WERR_DEST_NOT_FOUND;
130 if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
131 DEBUG(0, ("Error occured while getting subkey by name: %s\n",
132 win_errstr(error2)));
133 talloc_free(mem_ctx);
137 /* oldkey didn't have such a subkey, add add diff */
138 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
139 callbacks->add_key(callback_data, tmppath);
141 W_ERROR_NOT_OK_RETURN(
142 reg_open_key(mem_ctx, newkey, keyname1, &t2));
144 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
145 talloc_free(tmppath);
148 /* Values that were changed */
149 for(i = 0; i < new_num_values; i++) {
151 uint32_t type1, type2;
152 DATA_BLOB contents1, contents2;
154 error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
155 &name, &type1, &contents1);
156 if (!W_ERROR_IS_OK(error1)) {
157 DEBUG(0, ("Unable to get key by index: %s\n",
158 win_errstr(error1)));
159 talloc_free(mem_ctx);
163 if (oldkey != NULL) {
164 error2 = reg_key_get_value_by_name(mem_ctx, oldkey, name,
167 error2 = WERR_DEST_NOT_FOUND;
169 if(!W_ERROR_IS_OK(error2) &&
170 !W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
171 DEBUG(0, ("Error occured while getting value by name: %s\n",
172 win_errstr(error2)));
173 talloc_free(mem_ctx);
177 if (W_ERROR_IS_OK(error2) && data_blob_cmp(&contents1, &contents2) == 0)
180 callbacks->set_value(callback_data, path, name, type1, contents1);
183 /* Values that were deleted */
184 for (i = 0; i < old_num_values; i++) {
186 error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
188 if (!W_ERROR_IS_OK(error1)) {
189 DEBUG(0, ("Error ocurred getting value by index: %s\n",
190 win_errstr(error1)));
191 talloc_free(mem_ctx);
195 error2 = reg_key_get_value_by_name(mem_ctx, newkey, name, NULL,
198 if (W_ERROR_IS_OK(error2))
201 if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
202 DEBUG(0, ("Error occured while getting value by name: %s\n",
203 win_errstr(error2)));
207 callbacks->del_value(callback_data, path, name);
210 talloc_free(mem_ctx);
215 * Generate diff between two registry contexts
217 _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
218 struct registry_context *ctx2,
219 const struct reg_diff_callbacks *callbacks,
225 for(i = HKEY_FIRST; i <= HKEY_LAST; i++) {
226 struct registry_key *r1 = NULL, *r2 = NULL;
227 error = reg_get_predefined_key(ctx1, i, &r1);
228 if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
229 DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_predef_name(i)));
232 error = reg_get_predefined_key(ctx2, i, &r2);
233 if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
234 DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_predef_name(i)));
237 if (r1 == NULL && r2 == NULL)
240 error = reg_generate_diff_key(r1, r2, reg_get_predef_name(i), callbacks, callback_data);
241 if (!W_ERROR_IS_OK(error)) {
242 DEBUG(0, ("Unable to determine diff: %s\n", win_errstr(error)));
246 if (callbacks->done != NULL) {
247 callbacks->done(callback_data);
255 _PUBLIC_ WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data)
260 fd = open(filename, O_RDONLY, 0);
262 DEBUG(0, ("Error opening registry patch file `%s'\n", filename));
263 return WERR_GENERAL_FAILURE;
266 if (read(fd, &hdr, 4) != 4) {
267 DEBUG(0, ("Error reading registry patch file `%s'\n", filename));
268 return WERR_GENERAL_FAILURE;
271 /* Reset position in file */
272 lseek(fd, 0, SEEK_SET);
274 if (strncmp(hdr, "CREG", 4) == 0) {
275 /* Must be a W9x CREG Config.pol file */
276 return reg_creg_diff_load(diff, fd);
277 } else if (strncmp(hdr, "regf", 4) == 0) {
278 /* Must be a REGF NTConfig.pol file */
279 return reg_regf_diff_load(diff, fd);
282 if (strncmp(hdr, "PReg", 4) == 0) {
283 /* Must be a GPO Registry.pol file */
284 return reg_preg_diff_load(fd, callbacks, callback_data);
286 /* Must be a normal .REG file */
287 return reg_dotreg_diff_load(fd, callbacks, callback_data);
292 * The reg_diff_apply functions
294 static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
296 struct registry_context *ctx = _ctx;
297 struct registry_key *tmp;
300 error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
302 if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) && !W_ERROR_IS_OK(error)) {
303 DEBUG(0, ("Error adding new key '%s': %s\n", key_name, win_errstr(error)));
309 static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
311 struct registry_context *ctx = _ctx;
314 error = reg_key_del_abs(ctx, key_name);
316 if(!W_ERROR_IS_OK(error)) {
317 DEBUG(0, ("Unable to delete key '%s'\n", key_name));
324 static WERROR reg_diff_apply_set_value(void *_ctx, const char *path, const char *value_name, uint32_t value_type, DATA_BLOB value)
326 struct registry_context *ctx = _ctx;
327 struct registry_key *tmp;
331 error = reg_open_key_abs(ctx, ctx, path, &tmp);
333 if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
334 DEBUG(0, ("Error opening key '%s'\n", path));
339 error = reg_val_set(tmp, value_name,
341 if (!W_ERROR_IS_OK(error)) {
342 DEBUG(0, ("Error setting value '%s'\n", value_name));
349 static WERROR reg_diff_apply_del_value (void *_ctx, const char *key_name, const char *value_name)
351 struct registry_context *ctx = _ctx;
352 struct registry_key *tmp;
356 error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
358 if (!W_ERROR_IS_OK(error)) {
359 DEBUG(0, ("Error opening key '%s'\n", key_name));
363 error = reg_del_value(tmp, value_name);
364 if (!W_ERROR_IS_OK(error)) {
365 DEBUG(0, ("Error deleting value '%s'\n", value_name));
373 static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
375 struct registry_context *ctx = _ctx;
376 struct registry_key *key;
381 error = reg_open_key_abs(ctx, ctx, key_name, &key);
383 if (!W_ERROR_IS_OK(error)) {
384 DEBUG(0, ("Error opening key '%s'\n", key_name));
388 W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key,
394 for (i = 0; i < num_values; i++) {
396 W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i, &name,
398 W_ERROR_NOT_OK_RETURN(reg_del_value(key, name));
405 * Apply diff to a registry context
407 _PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
409 struct reg_diff_callbacks callbacks;
411 callbacks.add_key = reg_diff_apply_add_key;
412 callbacks.del_key = reg_diff_apply_del_key;
413 callbacks.set_value = reg_diff_apply_set_value;
414 callbacks.del_value = reg_diff_apply_del_value;
415 callbacks.del_all_values = reg_diff_apply_del_all_values;
416 callbacks.done = NULL;
418 return reg_diff_load(filename, &callbacks, ctx);