1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source4/lib/registry/patchfile.c
Günther Deschner cc8f4eb3cd r25544: Cleanup some more indents in lib/registry.
Guenther
(This used to be commit 0d9826dc54)
2007-10-10 15:07:51 -05:00

449 lines
11 KiB
C

/*
Unix SMB/CIFS implementation.
Reading registry patch files
Copyright (C) Jelmer Vernooij 2004-2007
Copyright (C) Wilco Baan Hofman 2006
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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/registry/patchfile.h"
#include "lib/registry/registry.h"
#include "system/filesys.h"
_PUBLIC_ WERROR reg_preg_diff_load(int fd,
const struct reg_diff_callbacks *callbacks,
void *callback_data);
_PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
const struct reg_diff_callbacks *callbacks,
void *callback_data);
/*
* Generate difference between two keys
*/
WERROR reg_generate_diff_key(struct registry_key *oldkey,
struct registry_key *newkey,
const char *path,
const struct reg_diff_callbacks *callbacks,
void *callback_data)
{
int i;
struct registry_key *t1, *t2;
char *tmppath;
const char *keyname1;
WERROR error, error1, error2;
TALLOC_CTX *mem_ctx = talloc_init("writediff");
uint32_t old_num_subkeys, old_num_values,
new_num_subkeys, new_num_values;
if (oldkey != NULL) {
error = reg_key_get_info(mem_ctx, oldkey, NULL,
&old_num_subkeys, &old_num_values,
NULL);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error occured while getting key info: %s\n",
win_errstr(error)));
return error;
}
} else {
old_num_subkeys = 0;
old_num_values = 0;
}
/* Subkeys that were deleted */
for (i = 0; i < old_num_subkeys; i++) {
error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
&keyname1,
NULL, NULL);
if (!W_ERROR_IS_OK(error1)) {
DEBUG(0, ("Error occured while getting subkey by index: %s\n",
win_errstr(error2)));
continue;
}
if (newkey != NULL) {
error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
if (W_ERROR_IS_OK(error2))
continue;
} else {
error2 = WERR_DEST_NOT_FOUND;
t2 = NULL;
}
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
DEBUG(0, ("Error occured 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 */
tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
callbacks->del_key(callback_data, tmppath);
talloc_free(tmppath);
}
if (newkey != NULL) {
error = reg_key_get_info(mem_ctx, newkey, NULL,
&new_num_subkeys, &new_num_values,
NULL);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error occured while getting key info: %s\n",
win_errstr(error)));
return error;
}
} else {
new_num_subkeys = 0;
new_num_values = 0;
}
/* Subkeys that were added */
for(i = 0; i < new_num_subkeys; i++) {
error1 = reg_key_get_subkey_by_index(mem_ctx, newkey,
i, &keyname1,
NULL, NULL);
if (!W_ERROR_IS_OK(error1)) {
DEBUG(0, ("Error occured while getting subkey by index: %s\n",
win_errstr(error1)));
talloc_free(mem_ctx);
return error1;
}
if (oldkey != NULL) {
error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
if (W_ERROR_IS_OK(error2))
continue;
} else {
t1 = NULL;
error2 = WERR_DEST_NOT_FOUND;
}
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
DEBUG(0, ("Error occured 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 */
tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
callbacks->add_key(callback_data, tmppath);
W_ERROR_NOT_OK_RETURN(
reg_open_key(mem_ctx, newkey, keyname1, &t2));
reg_generate_diff_key(t1, t2, tmppath,
callbacks, callback_data);
talloc_free(tmppath);
}
/* Values that were changed */
for(i = 0; i < new_num_values; i++) {
const char *name;
uint32_t type1, type2;
DATA_BLOB contents1, contents2;
error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
&name, &type1, &contents1);
if (!W_ERROR_IS_OK(error1)) {
DEBUG(0, ("Unable to get key by index: %s\n",
win_errstr(error1)));
talloc_free(mem_ctx);
return error1;
}
if (oldkey != NULL) {
error2 = reg_key_get_value_by_name(mem_ctx, oldkey,
name, &type2,
&contents2);
} else
error2 = WERR_DEST_NOT_FOUND;
if(!W_ERROR_IS_OK(error2) &&
!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
DEBUG(0, ("Error occured while getting value by name: %s\n",
win_errstr(error2)));
talloc_free(mem_ctx);
return error2;
}
if (W_ERROR_IS_OK(error2) &&
data_blob_cmp(&contents1, &contents2) == 0)
continue;
callbacks->set_value(callback_data, path, name,
type1, contents1);
}
/* Values that were deleted */
for (i = 0; i < old_num_values; i++) {
const char *name;
error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
NULL, NULL);
if (!W_ERROR_IS_OK(error1)) {
DEBUG(0, ("Error ocurred getting value by index: %s\n",
win_errstr(error1)));
talloc_free(mem_ctx);
return error1;
}
error2 = reg_key_get_value_by_name(mem_ctx, newkey, name, NULL,
NULL);
if (W_ERROR_IS_OK(error2))
continue;
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
DEBUG(0, ("Error occured while getting value by name: %s\n",
win_errstr(error2)));
return error2;
}
callbacks->del_value(callback_data, path, name);
}
talloc_free(mem_ctx);
return WERR_OK;
}
/**
* Generate diff between two registry contexts
*/
_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
struct registry_context *ctx2,
const struct reg_diff_callbacks *callbacks,
void *callback_data)
{
int i;
WERROR error;
for(i = HKEY_FIRST; i <= HKEY_LAST; i++) {
struct registry_key *r1 = NULL, *r2 = NULL;
error = reg_get_predefined_key(ctx1, i, &r1);
if (!W_ERROR_IS_OK(error) &&
!W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 1\n",
reg_get_predef_name(i)));
}
error = reg_get_predefined_key(ctx2, i, &r2);
if (!W_ERROR_IS_OK(error) &&
!W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 2\n",
reg_get_predef_name(i)));
}
if (r1 == NULL && r2 == NULL)
continue;
error = reg_generate_diff_key(r1, r2, reg_get_predef_name(i),
callbacks, callback_data);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Unable to determine diff: %s\n",
win_errstr(error)));
return error;
}
}
if (callbacks->done != NULL) {
callbacks->done(callback_data);
}
return WERR_OK;
}
/**
* Load diff file
*/
_PUBLIC_ WERROR reg_diff_load(const char *filename,
const struct reg_diff_callbacks *callbacks,
void *callback_data)
{
int fd;
char hdr[4];
fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
DEBUG(0, ("Error opening registry patch file `%s'\n",
filename));
return WERR_GENERAL_FAILURE;
}
if (read(fd, &hdr, 4) != 4) {
DEBUG(0, ("Error reading registry patch file `%s'\n",
filename));
return WERR_GENERAL_FAILURE;
}
/* Reset position in file */
lseek(fd, 0, SEEK_SET);
#if 0
if (strncmp(hdr, "CREG", 4) == 0) {
/* Must be a W9x CREG Config.pol file */
return reg_creg_diff_load(diff, fd);
} else if (strncmp(hdr, "regf", 4) == 0) {
/* Must be a REGF NTConfig.pol file */
return reg_regf_diff_load(diff, fd);
} else
#endif
if (strncmp(hdr, "PReg", 4) == 0) {
/* Must be a GPO Registry.pol file */
return reg_preg_diff_load(fd, callbacks, callback_data);
} else {
/* Must be a normal .REG file */
return reg_dotreg_diff_load(fd, callbacks, callback_data);
}
}
/**
* The reg_diff_apply functions
*/
static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
{
struct registry_context *ctx = (struct registry_context *)_ctx;
struct registry_key *tmp;
WERROR error;
error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error adding new key '%s': %s\n",
key_name, win_errstr(error)));
return error;
}
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);
if(!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Unable to delete key '%s'\n", key_name));
return error;
}
return WERR_OK;
}
static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
const char *value_name,
uint32_t value_type, DATA_BLOB value)
{
struct registry_context *ctx = (struct registry_context *)_ctx;
struct registry_key *tmp;
WERROR error;
/* Open key */
error = reg_open_key_abs(ctx, ctx, path, &tmp);
if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
DEBUG(0, ("Error opening key '%s'\n", path));
return error;
}
/* Set value */
error = reg_val_set(tmp, value_name,
value_type, value);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error setting value '%s'\n", value_name));
return error;
}
return WERR_OK;
}
static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name,
const char *value_name)
{
struct registry_context *ctx = (struct registry_context *)_ctx;
struct registry_key *tmp;
WERROR error;
/* Open key */
error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening key '%s'\n", key_name));
return error;
}
error = reg_del_value(tmp, value_name);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error deleting value '%s'\n", value_name));
return error;
}
return WERR_OK;
}
static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
{
struct registry_context *ctx = (struct registry_context *)_ctx;
struct registry_key *key;
WERROR error;
int i;
uint32_t num_values;
error = reg_open_key_abs(ctx, ctx, key_name, &key);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening key '%s'\n", key_name));
return error;
}
W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key,
NULL,
NULL,
&num_values,
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));
}
return WERR_OK;
}
/**
* Apply diff to a registry context
*/
_PUBLIC_ WERROR reg_diff_apply(const char *filename,
struct registry_context *ctx)
{
struct reg_diff_callbacks callbacks;
callbacks.add_key = reg_diff_apply_add_key;
callbacks.del_key = reg_diff_apply_del_key;
callbacks.set_value = reg_diff_apply_set_value;
callbacks.del_value = reg_diff_apply_del_value;
callbacks.del_all_values = reg_diff_apply_del_all_values;
callbacks.done = NULL;
return reg_diff_load(filename, &callbacks, ctx);
}