Copyright (C) Jelmer Vernooij 2004-2007
Copyright (C) Wilco Baan Hofman 2006
- Copyright (C) Matthias Dieter Wallnöfer 2008
+ Copyright (C) Matthias Dieter Wallnöfer 2008-2010
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "includes.h"
#include "lib/registry/registry.h"
#include "system/filesys.h"
-#include "param/param.h"
_PUBLIC_ WERROR reg_preg_diff_load(int fd,
- struct smb_iconv_convenience *iconv_convenience,
const struct reg_diff_callbacks *callbacks,
void *callback_data);
_PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
- struct smb_iconv_convenience *iconv_convenience,
const struct reg_diff_callbacks *callbacks,
void *callback_data);
const struct reg_diff_callbacks *callbacks,
void *callback_data)
{
- int i;
+ unsigned int i;
struct registry_key *t1 = NULL, *t2 = NULL;
char *tmppath;
const char *keyname1;
old_num_values = 0;
}
- /* Subkeys that were deleted */
+ /* Subkeys that were changed or deleted */
for (i = 0; i < old_num_subkeys; i++) {
error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
&keyname1, NULL, NULL);
if (newkey != NULL) {
error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
-
- if (W_ERROR_IS_OK(error2))
- continue;
} else {
- error2 = WERR_BADFILE;
+ error2 = WERR_FILE_NOT_FOUND;
t2 = NULL;
}
- if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
- DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ if (!W_ERROR_IS_OK(error2) && !W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
+ DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
win_errstr(error2)));
talloc_free(mem_ctx);
return error2;
}
- /* newkey didn't have such a subkey, add del diff */
+ /* if "error2" is going to be "WERR_FILE_NOT_FOUND", then newkey */
+ /* didn't have such a subkey and therefore add a del diff */
tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
- callbacks->del_key(callback_data, tmppath);
+ if (tmppath == NULL) {
+ DEBUG(0, ("Out of memory\n"));
+ talloc_free(mem_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ if (!W_ERROR_IS_OK(error2))
+ callbacks->del_key(callback_data, tmppath);
/* perform here also the recursive invocation */
error1 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
if (!W_ERROR_IS_OK(error1)) {
- DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
win_errstr(error1)));
talloc_free(mem_ctx);
return error1;
if (W_ERROR_IS_OK(error2))
continue;
} else {
- error2 = WERR_BADFILE;
+ error2 = WERR_FILE_NOT_FOUND;
t1 = NULL;
}
- if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
+ if (!W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
win_errstr(error2)));
talloc_free(mem_ctx);
return error2;
}
- /* oldkey didn't have such a subkey, add add diff */
+ /* oldkey didn't have such a subkey, add a add diff */
tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+ if (tmppath == NULL) {
+ DEBUG(0, ("Out of memory\n"));
+ talloc_free(mem_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
callbacks->add_key(callback_data, tmppath);
/* perform here also the recursive invocation */
error1 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
if (!W_ERROR_IS_OK(error1)) {
- DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
win_errstr(error1)));
talloc_free(mem_ctx);
return error1;
for(i = 0; i < new_num_values; i++) {
const char *name;
uint32_t type1, type2;
- DATA_BLOB contents1, contents2;
+ DATA_BLOB contents1 = { NULL, 0 }, contents2 = { NULL, 0 };
error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
&name, &type1, &contents1);
name, &type2,
&contents2);
} else
- error2 = WERR_BADFILE;
+ error2 = WERR_FILE_NOT_FOUND;
if (!W_ERROR_IS_OK(error2)
- && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
+ && !W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
DEBUG(0, ("Error occurred while getting value by name: %s\n",
win_errstr(error2)));
talloc_free(mem_ctx);
}
if (W_ERROR_IS_OK(error2)
- && (data_blob_cmp(&contents1, &contents2) == 0)
- && (type1 == type2))
+ && (data_blob_cmp(&contents1, &contents2) == 0)
+ && (type1 == type2)) {
+ talloc_free(discard_const_p(char, name));
+ talloc_free(contents1.data);
+ talloc_free(contents2.data);
continue;
+ }
callbacks->set_value(callback_data, path, name,
type1, contents1);
+
+ talloc_free(discard_const_p(char, name));
+ talloc_free(contents1.data);
+ talloc_free(contents2.data);
}
/* Values that were deleted */
for (i = 0; i < old_num_values; i++) {
const char *name;
uint32_t type;
- DATA_BLOB contents;
+ DATA_BLOB contents = { NULL, 0 };
error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
&type, &contents);
error2 = reg_key_get_value_by_name(mem_ctx, newkey,
name, &type, &contents);
else
- error2 = WERR_BADFILE;
+ error2 = WERR_FILE_NOT_FOUND;
- if (W_ERROR_IS_OK(error2))
+ if (W_ERROR_IS_OK(error2)) {
+ talloc_free(discard_const_p(char, name));
+ talloc_free(contents.data);
continue;
+ }
- if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
+ if (!W_ERROR_EQUAL(error2, WERR_FILE_NOT_FOUND)) {
DEBUG(0, ("Error occurred while getting value by name: %s\n",
win_errstr(error2)));
talloc_free(mem_ctx);
}
callbacks->del_value(callback_data, path, name);
+
+ talloc_free(discard_const_p(char, name));
+ talloc_free(contents.data);
}
talloc_free(mem_ctx);
const struct reg_diff_callbacks *callbacks,
void *callback_data)
{
- int i;
+ unsigned int i;
WERROR error;
for (i = 0; reg_predefined_keys[i].name; i++) {
error = reg_get_predefined_key(ctx1,
reg_predefined_keys[i].handle, &r1);
if (!W_ERROR_IS_OK(error) &&
- !W_ERROR_EQUAL(error, WERR_BADFILE)) {
+ !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 1\n",
reg_predefined_keys[i].name));
continue;
error = reg_get_predefined_key(ctx2,
reg_predefined_keys[i].handle, &r2);
if (!W_ERROR_IS_OK(error) &&
- !W_ERROR_EQUAL(error, WERR_BADFILE)) {
+ !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 2\n",
reg_predefined_keys[i].name));
continue;
}
+ /* if "r1" is NULL (old hive) and "r2" isn't (new hive) then
+ * the hive doesn't exist yet and we have to generate an add
+ * diff */
+ if ((r1 == NULL) && (r2 != NULL)) {
+ callbacks->add_key(callback_data,
+ reg_predefined_keys[i].name);
+ }
+ /* if "r1" isn't NULL (old hive) and "r2" is (new hive) then
+ * the hive shouldn't exist anymore and we have to generate a
+ * del diff */
+ if ((r1 != NULL) && (r2 == NULL)) {
+ callbacks->del_key(callback_data,
+ reg_predefined_keys[i].name);
+ }
+
error = reg_generate_diff_key(r1, r2,
reg_predefined_keys[i].name, callbacks,
callback_data);
* Load diff file
*/
_PUBLIC_ WERROR reg_diff_load(const char *filename,
- struct smb_iconv_convenience *iconv_convenience,
const struct reg_diff_callbacks *callbacks,
void *callback_data)
{
if (fd == -1) {
DEBUG(0, ("Error opening registry patch file `%s'\n",
filename));
- return WERR_GENERAL_FAILURE;
+ return WERR_GEN_FAILURE;
}
if (read(fd, &hdr, 4) != 4) {
DEBUG(0, ("Error reading registry patch file `%s'\n",
filename));
- return WERR_GENERAL_FAILURE;
+ close(fd);
+ return WERR_GEN_FAILURE;
}
/* Reset position in file */
#endif
if (strncmp(hdr, "PReg", 4) == 0) {
/* Must be a GPO Registry.pol file */
- return reg_preg_diff_load(fd, iconv_convenience, callbacks, callback_data);
+ return reg_preg_diff_load(fd, callbacks, callback_data);
} else {
/* Must be a normal .REG file */
- return reg_dotreg_diff_load(fd, iconv_convenience, callbacks, callback_data);
+ return reg_dotreg_diff_load(fd, callbacks, callback_data);
}
}
/* Recursively create the path */
buf = talloc_strdup(ctx, key_name);
+ W_ERROR_HAVE_NO_MEMORY(buf);
buf_ptr = buf;
while (*buf_ptr++ != '\0' ) {
return error;
}
*buf_ptr++ = '\\';
+ talloc_free(tmp);
}
}
+ talloc_free(buf);
+
/* Add the key */
error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
key_name, win_errstr(error)));
return error;
}
+ talloc_free(tmp);
+
return WERR_OK;
}
static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
{
struct registry_context *ctx = (struct registry_context *)_ctx;
- WERROR error;
- error = reg_key_del_abs(ctx, key_name);
+ /* We can't proof here for success, because a common superkey could */
+ /* have been deleted before the subkey's (diff order). This removed */
+ /* therefore all children recursively and the "WERR_FILE_NOT_FOUND" result is */
+ /* expected. */
- if(!W_ERROR_IS_OK(error)) {
- DEBUG(0, ("Unable to delete key '%s'\n", key_name));
- return error;
- }
+ reg_key_del_abs(ctx, key_name);
return WERR_OK;
}
/* Open key */
error = reg_open_key_abs(ctx, ctx, path, &tmp);
- if (W_ERROR_EQUAL(error, WERR_BADFILE)) {
+ if (W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
DEBUG(0, ("Error opening key '%s'\n", path));
return error;
}
return error;
}
+ talloc_free(tmp);
+
return WERR_OK;
}
return error;
}
- error = reg_del_value(tmp, value_name);
+ error = reg_del_value(ctx, tmp, value_name);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error deleting value '%s'\n", value_name));
return error;
}
+ talloc_free(tmp);
return WERR_OK;
}
struct registry_context *ctx = (struct registry_context *)_ctx;
struct registry_key *key;
WERROR error;
- int i;
- uint32_t num_values;
+ const char *value_name;
error = reg_open_key_abs(ctx, ctx, key_name, &key);
}
W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL,
- NULL, &num_values, NULL, NULL, NULL, NULL));
+ NULL, NULL, NULL, NULL, NULL, NULL));
- for (i = 0; i < num_values; i++) {
- const char *name;
- W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i,
- &name,
- NULL, NULL));
- W_ERROR_NOT_OK_RETURN(reg_del_value(key, name));
+ while (W_ERROR_IS_OK(reg_key_get_value_by_index(
+ ctx, key, 0, &value_name, NULL, NULL))) {
+ error = reg_del_value(ctx, key, value_name);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error deleting value '%s'\n", value_name));
+ return error;
+ }
+ talloc_free(discard_const_p(char, value_name));
}
+ talloc_free(key);
+
return WERR_OK;
}
/**
* Apply diff to a registry context
*/
-_PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, const char *filename)
+_PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx,
+ const char *filename)
{
struct reg_diff_callbacks callbacks;
callbacks.del_all_values = reg_diff_apply_del_all_values;
callbacks.done = NULL;
- return reg_diff_load(filename, lp_iconv_convenience(global_loadparm),
- &callbacks, ctx);
+ return reg_diff_load(filename, &callbacks, ctx);
}