wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
PROJECT_NAME = REGISTRY
|
||||
OUTPUT_DIRECTORY = apidocs
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
SHOW_USED_FILES = NO
|
||||
SHOW_DIRECTORIES = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
INPUT = . common
|
||||
FILE_PATTERNS = *.c *.h *.dox
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
GENERATE_MAN = YES
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
@@ -0,0 +1,41 @@
|
||||
This is the registry library. The registry is basically a bunch of
|
||||
hives that can be loaded from different places.
|
||||
|
||||
The various registry backends provide support for loading/saving
|
||||
specific types of hives:
|
||||
|
||||
- ldb
|
||||
- w95 (USER.DAT-style files)
|
||||
- nt4 (NTUSER.DAT-style files)
|
||||
- gconf (GNOME configuration)
|
||||
- rpc (Remote individual hives)
|
||||
|
||||
Instead of opening individual hives, one can also open a 'complete'
|
||||
registry by using one of these three functions:
|
||||
|
||||
- reg_open_local() - load local registry, see below
|
||||
- reg_open_remote() - connect to remote registry over RPC
|
||||
- reg_open_wine() (not working yet)
|
||||
|
||||
reg_open_local() loads a set of hives based on smb.conf settings.
|
||||
Lines in smb.conf should have the following syntax:
|
||||
|
||||
registry:<hivename> = <backend>:<location>
|
||||
|
||||
So an example usage could be:
|
||||
|
||||
registry:HKEY_CURRENT_USER = nt4:NTUSER.DAT
|
||||
registry:HKEY_LOCAL_MACHINE = ldb:tdb://registry.tdb
|
||||
|
||||
WERR_NOT_SUPPORTED will be returned for all hives that haven't been set.
|
||||
|
||||
On Windows the various registry hives are loaded from:
|
||||
|
||||
HKEY_CURRENT_CONFIG: %SystemRoot%\System32\Config\System
|
||||
HKEY_CURRENT_USER: %Profile%\NTUser.dat
|
||||
HKEY_LOCAL_MACHINE\SAM: %SystemRoot%\System32\Config\Sam
|
||||
HKEY_LOCAL_MACHINE\Security: %SystemRoot%\System32\Config\Security
|
||||
HKEY_LOCAL_MACHINE\Software: %SystemRoot%\System32\Config\Software
|
||||
HKEY_LOCAL_MACHINE\System: %SystemRoot%\System32\Config\System
|
||||
HKEY_USERS\.DEFAULT: %SystemRoot%\System32\Config\Default
|
||||
HKEY_LOCAL_MACHINE\HARDWARE: is autogenerated
|
||||
@@ -0,0 +1,34 @@
|
||||
- ..\..\, \bla\blie support in regshell
|
||||
- finish rpc_server
|
||||
|
||||
reg_backend_dir:
|
||||
- value support
|
||||
|
||||
reg_backend_w95.c:
|
||||
- write support
|
||||
|
||||
reg_backend_nt4:
|
||||
- write support
|
||||
|
||||
reg_backend_rpc:
|
||||
- value enum support
|
||||
- write support
|
||||
- rewrite
|
||||
|
||||
reg_backend_ldb:
|
||||
- finish
|
||||
|
||||
reg_backend_wine.c:
|
||||
- finish
|
||||
|
||||
regshell:
|
||||
- support for security descriptors
|
||||
|
||||
gregedit.c:
|
||||
- support for editing values / adding values / deleting values
|
||||
- support for adding/deleting keys
|
||||
- support for security descriptors
|
||||
|
||||
- pass parsed paths around rather than strings (i.e. just a list of strings)
|
||||
- integrate various registry tools ?
|
||||
- finish new patchfile code
|
||||
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Transparent registry backend handling
|
||||
Copyright (C) Jelmer Vernooij 2003-2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "build.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Main registry functions
|
||||
*/
|
||||
|
||||
/* List of available backends */
|
||||
static struct reg_init_function_entry *backends = NULL;
|
||||
|
||||
static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
|
||||
|
||||
/** Register a new backend. */
|
||||
_PUBLIC_ NTSTATUS registry_register(const void *_hive_ops)
|
||||
{
|
||||
const struct hive_operations *hive_ops = _hive_ops;
|
||||
struct reg_init_function_entry *entry = backends;
|
||||
|
||||
DEBUG(5,("Attempting to register registry backend %s\n", hive_ops->name));
|
||||
|
||||
/* Check for duplicates */
|
||||
if (reg_find_backend_entry(hive_ops->name)) {
|
||||
DEBUG(0,("There already is a registry backend registered with the name %s!\n", hive_ops->name));
|
||||
return NT_STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
|
||||
entry = talloc(talloc_autofree_context(), struct reg_init_function_entry);
|
||||
entry->hive_functions = hive_ops;
|
||||
|
||||
DLIST_ADD(backends, entry);
|
||||
DEBUG(5,("Successfully added registry backend '%s'\n", hive_ops->name));
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/** Find a backend in the list of available backends */
|
||||
static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
|
||||
{
|
||||
struct reg_init_function_entry *entry;
|
||||
|
||||
entry = backends;
|
||||
|
||||
while(entry) {
|
||||
if (strcmp(entry->hive_functions->name, name) == 0) return entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Initialize the registry subsystem */
|
||||
_PUBLIC_ NTSTATUS registry_init(void)
|
||||
{
|
||||
init_module_fn static_init[] = STATIC_registry_MODULES;
|
||||
init_module_fn *shared_init = load_samba_modules(NULL, "registry");
|
||||
|
||||
run_init_functions(static_init);
|
||||
run_init_functions(shared_init);
|
||||
|
||||
talloc_free(shared_init);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/** Check whether a certain backend is present. */
|
||||
_PUBLIC_ BOOL reg_has_backend(const char *backend)
|
||||
{
|
||||
return reg_find_backend_entry(backend) != NULL?True:False;
|
||||
}
|
||||
|
||||
const struct reg_predefined_key reg_predefined_keys[] = {
|
||||
{HKEY_CLASSES_ROOT,"HKEY_CLASSES_ROOT" },
|
||||
{HKEY_CURRENT_USER,"HKEY_CURRENT_USER" },
|
||||
{HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
|
||||
{HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA" },
|
||||
{HKEY_USERS, "HKEY_USERS" },
|
||||
{HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
|
||||
{HKEY_DYN_DATA, "HKEY_DYN_DATA" },
|
||||
{HKEY_PERFORMANCE_TEXT, "HKEY_PERFORMANCE_TEXT" },
|
||||
{HKEY_PERFORMANCE_NLSTEXT, "HKEY_PERFORMANCE_NLSTEXT" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/** Obtain a list of predefined keys. */
|
||||
_PUBLIC_ int reg_list_predefs(TALLOC_CTX *mem_ctx, char ***predefs, uint32_t **hkeys)
|
||||
{
|
||||
int i;
|
||||
*predefs = talloc_array(mem_ctx, char *, ARRAY_SIZE(reg_predefined_keys));
|
||||
*hkeys = talloc_array(mem_ctx, uint32_t, ARRAY_SIZE(reg_predefined_keys));
|
||||
|
||||
for (i = 0; reg_predefined_keys[i].name; i++) {
|
||||
(*predefs)[i] = talloc_strdup(mem_ctx, reg_predefined_keys[i].name);
|
||||
(*hkeys)[i] = reg_predefined_keys[i].handle;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/** Obtain name of specific hkey. */
|
||||
_PUBLIC_ const char *reg_get_predef_name(uint32_t hkey)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; reg_predefined_keys[i].name; i++) {
|
||||
if (reg_predefined_keys[i].handle == hkey) return reg_predefined_keys[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Get predefined key by name. */
|
||||
_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, const char *name, struct registry_key **key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; reg_predefined_keys[i].name; i++) {
|
||||
if (!strcasecmp(reg_predefined_keys[i].name, name)) return reg_get_predefined_key(ctx, reg_predefined_keys[i].handle, key);
|
||||
}
|
||||
|
||||
DEBUG(1, ("No predefined key with name '%s'\n", name));
|
||||
|
||||
return WERR_BADFILE;
|
||||
}
|
||||
|
||||
/** Get predefined key by id. */
|
||||
_PUBLIC_ WERROR reg_get_predefined_key(struct registry_context *ctx, uint32_t hkey, struct registry_key **key)
|
||||
{
|
||||
WERROR ret = ctx->get_predefined_key(ctx, hkey, key);
|
||||
|
||||
if (W_ERROR_IS_OK(ret)) {
|
||||
(*key)->name = talloc_strdup(*key, reg_get_predef_name(hkey));
|
||||
(*key)->path = "";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Open a registry file/host/etc */
|
||||
_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *backend, const char *location, struct auth_session_info *session_info, struct cli_credentials *credentials, struct registry_key **root)
|
||||
{
|
||||
struct registry_hive *rethive;
|
||||
struct registry_key *retkey = NULL;
|
||||
struct reg_init_function_entry *entry;
|
||||
WERROR werr;
|
||||
|
||||
entry = reg_find_backend_entry(backend);
|
||||
|
||||
if (!entry) {
|
||||
DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
|
||||
return WERR_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
if(!entry->hive_functions || !entry->hive_functions->open_hive) {
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
rethive = talloc(parent_ctx, struct registry_hive);
|
||||
rethive->location = location?talloc_strdup(rethive, location):NULL;
|
||||
rethive->session_info = talloc_reference(rethive, session_info);
|
||||
rethive->credentials = talloc_reference(rethive, credentials);
|
||||
rethive->functions = entry->hive_functions;
|
||||
rethive->backend_data = NULL;
|
||||
|
||||
werr = entry->hive_functions->open_hive(rethive, &retkey);
|
||||
|
||||
if(!W_ERROR_IS_OK(werr)) {
|
||||
return werr;
|
||||
}
|
||||
|
||||
if(!retkey) {
|
||||
DEBUG(0, ("Backend %s didn't provide root key!\n", backend));
|
||||
return WERR_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
rethive->root = retkey;
|
||||
|
||||
retkey->hive = rethive;
|
||||
retkey->name = NULL;
|
||||
retkey->path = talloc_strdup(retkey, "");
|
||||
|
||||
*root = retkey;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a key
|
||||
* First tries to use the open_key function from the backend
|
||||
* then falls back to get_subkey_by_name and later get_subkey_by_index
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, struct registry_key **result)
|
||||
{
|
||||
WERROR error;
|
||||
|
||||
if(!parent) {
|
||||
DEBUG(0, ("Invalid parent key specified for open of '%s'\n", name));
|
||||
return WERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if(!parent->hive->functions->open_key &&
|
||||
(parent->hive->functions->get_subkey_by_name ||
|
||||
parent->hive->functions->get_subkey_by_index)) {
|
||||
char *orig = strdup(name),
|
||||
*curbegin = orig,
|
||||
*curend = strchr(orig, '\\');
|
||||
struct registry_key *curkey = parent;
|
||||
|
||||
while(curbegin && *curbegin) {
|
||||
if(curend)*curend = '\0';
|
||||
error = reg_key_get_subkey_by_name(mem_ctx, curkey, curbegin, &curkey);
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
SAFE_FREE(orig);
|
||||
return error;
|
||||
}
|
||||
if(!curend) break;
|
||||
curbegin = curend + 1;
|
||||
curend = strchr(curbegin, '\\');
|
||||
}
|
||||
SAFE_FREE(orig);
|
||||
|
||||
*result = curkey;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
if(!parent->hive->functions->open_key) {
|
||||
DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
error = parent->hive->functions->open_key(mem_ctx, parent, name, result);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
|
||||
(*result)->hive = parent->hive;
|
||||
(*result)->path = ((parent->hive->root == parent)?talloc_strdup(mem_ctx, name):talloc_asprintf(mem_ctx, "%s\\%s", parent->path, name));
|
||||
(*result)->hive = parent->hive;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value by index
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_value **val)
|
||||
{
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if(key->hive->functions->get_value_by_index) {
|
||||
WERROR status = key->hive->functions->get_value_by_index(mem_ctx, key, idx, val);
|
||||
if(!W_ERROR_IS_OK(status))
|
||||
return status;
|
||||
} else {
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of subkeys.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_num_subkeys(const struct registry_key *key, uint32_t *count)
|
||||
{
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if(key->hive->functions->num_subkeys) {
|
||||
return key->hive->functions->num_subkeys(key, count);
|
||||
}
|
||||
|
||||
if(key->hive->functions->get_subkey_by_index) {
|
||||
int i;
|
||||
WERROR error;
|
||||
struct registry_key *dest = NULL;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("num_subkeys");
|
||||
|
||||
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, key, i, &dest)); i++);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
*count = i;
|
||||
if(W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) error = WERR_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of values of a key.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_num_values(const struct registry_key *key, uint32_t *count)
|
||||
{
|
||||
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if (key->hive->functions->num_values) {
|
||||
return key->hive->functions->num_values(key, count);
|
||||
}
|
||||
|
||||
if(key->hive->functions->get_value_by_index) {
|
||||
int i;
|
||||
WERROR error;
|
||||
struct registry_value *dest;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("num_subkeys");
|
||||
|
||||
for(i = 0; W_ERROR_IS_OK(error = key->hive->functions->get_value_by_index(mem_ctx, key, i, &dest)); i++);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
*count = i;
|
||||
if(W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) error = WERR_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subkey by index.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_key **subkey)
|
||||
{
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if(key->hive->functions->get_subkey_by_index) {
|
||||
WERROR status = key->hive->functions->get_subkey_by_index(mem_ctx, key, idx, subkey);
|
||||
if(!NT_STATUS_IS_OK(status)) return status;
|
||||
} else {
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if(key->hive->root == key)
|
||||
(*subkey)->path = talloc_strdup(mem_ctx, (*subkey)->name);
|
||||
else
|
||||
(*subkey)->path = talloc_asprintf(mem_ctx, "%s\\%s", key->path, (*subkey)->name);
|
||||
|
||||
(*subkey)->hive = key->hive;
|
||||
return WERR_OK;;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subkey by name.
|
||||
*/
|
||||
WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_key **subkey)
|
||||
{
|
||||
int i;
|
||||
WERROR error = WERR_OK;
|
||||
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if(key->hive->functions->get_subkey_by_name) {
|
||||
error = key->hive->functions->get_subkey_by_name(mem_ctx, key,name,subkey);
|
||||
} else if(key->hive->functions->open_key) {
|
||||
error = key->hive->functions->open_key(mem_ctx, key, name, subkey);
|
||||
} else if(key->hive->functions->get_subkey_by_index) {
|
||||
for(i = 0; W_ERROR_IS_OK(error); i++) {
|
||||
error = reg_key_get_subkey_by_index(mem_ctx, key, i, subkey);
|
||||
if(W_ERROR_IS_OK(error) && !strcasecmp((*subkey)->name, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
|
||||
error = WERR_DEST_NOT_FOUND;
|
||||
} else {
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
|
||||
(*subkey)->path = talloc_asprintf(mem_ctx, "%s\\%s", key->path, (*subkey)->name);
|
||||
(*subkey)->hive = key->hive;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value by name.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_value **val)
|
||||
{
|
||||
int i;
|
||||
WERROR error = WERR_OK;
|
||||
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if(key->hive->functions->get_value_by_name) {
|
||||
error = key->hive->functions->get_value_by_name(mem_ctx, key,name, val);
|
||||
} else {
|
||||
for(i = 0; W_ERROR_IS_OK(error); i++) {
|
||||
error = reg_key_get_value_by_index(mem_ctx, key, i, val);
|
||||
if(W_ERROR_IS_OK(error) && !strcasecmp((*val)->name, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
|
||||
return WERR_DEST_NOT_FOUND;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name)
|
||||
{
|
||||
WERROR error;
|
||||
if(!parent) return WERR_INVALID_PARAM;
|
||||
|
||||
|
||||
if(!parent->hive->functions->del_key)
|
||||
return WERR_NOT_SUPPORTED;
|
||||
|
||||
error = parent->hive->functions->del_key(parent, name);
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *desc, struct registry_key **newkey)
|
||||
{
|
||||
WERROR error;
|
||||
|
||||
if (!parent) return WERR_INVALID_PARAM;
|
||||
|
||||
if (!parent->hive->functions->add_key) {
|
||||
DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->hive->functions->name));
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
error = parent->hive->functions->add_key(mem_ctx, parent, name, access_mask, desc, newkey);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
|
||||
if (!*newkey) {
|
||||
DEBUG(0, ("Backend returned WERR_OK, but didn't specify key!\n"));
|
||||
return WERR_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
(*newkey)->hive = parent->hive;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, uint32_t type, DATA_BLOB data)
|
||||
{
|
||||
/* A 'real' set function has preference */
|
||||
if (key->hive->functions->set_value)
|
||||
return key->hive->functions->set_value(key, value, type, data);
|
||||
|
||||
DEBUG(1, ("Backend '%s' doesn't support method set_value\n", key->hive->functions->name));
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security descriptor on a key.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **secdesc)
|
||||
{
|
||||
/* A 'real' set function has preference */
|
||||
if (key->hive->functions->key_get_sec_desc)
|
||||
return key->hive->functions->key_get_sec_desc(ctx, key, secdesc);
|
||||
|
||||
DEBUG(1, ("Backend '%s' doesn't support method get_sec_desc\n", key->hive->functions->name));
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a value.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_del_value(const struct registry_key *key, const char *valname)
|
||||
{
|
||||
WERROR ret = WERR_OK;
|
||||
if(!key->hive->functions->del_value)
|
||||
return WERR_NOT_SUPPORTED;
|
||||
|
||||
ret = key->hive->functions->del_value(key, valname);
|
||||
|
||||
if(!W_ERROR_IS_OK(ret)) return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush a key to disk.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_flush(const struct registry_key *key)
|
||||
{
|
||||
if (!key) {
|
||||
return WERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (key->hive->functions->flush_key) {
|
||||
return key->hive->functions->flush_key(key);
|
||||
}
|
||||
|
||||
/* No need for flushing, apparently */
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum name and data lengths of the subkeys.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_subkeysizes(const struct registry_key *key, uint32_t *max_subkeylen, uint32_t *max_subkeysize)
|
||||
{
|
||||
int i = 0;
|
||||
struct registry_key *subkey;
|
||||
WERROR error;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("subkeysize");
|
||||
|
||||
*max_subkeylen = *max_subkeysize = 0;
|
||||
|
||||
do {
|
||||
error = reg_key_get_subkey_by_index(mem_ctx, key, i, &subkey);
|
||||
|
||||
if (W_ERROR_IS_OK(error)) {
|
||||
*max_subkeysize = MAX(*max_subkeysize, 0xFF);
|
||||
*max_subkeylen = MAX(*max_subkeylen, strlen(subkey->name));
|
||||
}
|
||||
|
||||
i++;
|
||||
} while (W_ERROR_IS_OK(error));
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum name and data lengths of the values.
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_key_valuesizes(const struct registry_key *key, uint32_t *max_valnamelen, uint32_t *max_valbufsize)
|
||||
{
|
||||
int i = 0;
|
||||
struct registry_value *value;
|
||||
WERROR error;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("subkeysize");
|
||||
|
||||
*max_valnamelen = *max_valbufsize = 0;
|
||||
|
||||
do {
|
||||
error = reg_key_get_value_by_index(mem_ctx, key, i, &value);
|
||||
|
||||
if (W_ERROR_IS_OK(error)) {
|
||||
if (value->name) {
|
||||
*max_valnamelen = MAX(*max_valnamelen, strlen(value->name));
|
||||
}
|
||||
*max_valbufsize = MAX(*max_valbufsize, value->data.length);
|
||||
}
|
||||
|
||||
i++;
|
||||
} while (W_ERROR_IS_OK(error));
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Transparent registry backend handling
|
||||
Copyright (C) Jelmer Vernooij 2003-2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "librpc/gen_ndr/winreg.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Registry utility functions
|
||||
*/
|
||||
|
||||
static const struct {
|
||||
uint32_t id;
|
||||
const char *name;
|
||||
} reg_value_types[] = {
|
||||
{ REG_SZ, "REG_SZ" },
|
||||
{ REG_DWORD, "REG_DWORD" },
|
||||
{ REG_BINARY, "REG_BINARY" },
|
||||
{ REG_EXPAND_SZ, "REG_EXPAND_SZ" },
|
||||
{ REG_NONE, "REG_NONE" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/** Return string description of registry value type */
|
||||
_PUBLIC_ const char *str_regtype(int type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; reg_value_types[i].name; i++) {
|
||||
if (reg_value_types[i].id == type)
|
||||
return reg_value_types[i].name;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
if(data->length == 0) return talloc_strdup(mem_ctx, "");
|
||||
|
||||
switch (type) {
|
||||
case REG_EXPAND_SZ:
|
||||
case REG_SZ:
|
||||
convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, data->data, data->length, (void **)&ret);
|
||||
return ret;
|
||||
|
||||
case REG_BINARY:
|
||||
ret = data_blob_hex_string(mem_ctx, data);
|
||||
return ret;
|
||||
|
||||
case REG_DWORD:
|
||||
if (*(int *)data->data == 0)
|
||||
return talloc_strdup(mem_ctx, "0");
|
||||
|
||||
return talloc_asprintf(mem_ctx, "0x%x", *(int *)data->data);
|
||||
|
||||
case REG_MULTI_SZ:
|
||||
/* FIXME */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Generate a string that describes a registry value */
|
||||
_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val)
|
||||
{
|
||||
return talloc_asprintf(mem_ctx, "%s = %s : %s", val->name?val->name:"<No Name>", str_regtype(val->data_type), reg_val_data_string(mem_ctx, val->data_type, &val->data));
|
||||
}
|
||||
|
||||
_PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const char *data_str, uint32_t *type, DATA_BLOB *data)
|
||||
{
|
||||
int i;
|
||||
*type = -1;
|
||||
|
||||
/* Find the correct type */
|
||||
for (i = 0; reg_value_types[i].name; i++) {
|
||||
if (!strcmp(reg_value_types[i].name, type_str)) {
|
||||
*type = reg_value_types[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*type == -1)
|
||||
return False;
|
||||
|
||||
/* Convert data appropriately */
|
||||
|
||||
switch (*type)
|
||||
{
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
data->length = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, data_str, strlen(data_str), (void **)&data->data);
|
||||
break;
|
||||
|
||||
case REG_DWORD: {
|
||||
uint32_t tmp = strtol(data_str, NULL, 0);
|
||||
*data = data_blob_talloc(mem_ctx, &tmp, 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_NONE:
|
||||
ZERO_STRUCTP(data);
|
||||
break;
|
||||
|
||||
case REG_BINARY:
|
||||
*data = strhex_to_data_blob(data_str);
|
||||
talloc_steal(mem_ctx, data->data);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* FIXME */
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all \'s with /'s
|
||||
*/
|
||||
char *reg_path_win2unix(char *path)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; path[i]; i++) {
|
||||
if(path[i] == '\\') path[i] = '/';
|
||||
}
|
||||
return path;
|
||||
}
|
||||
/**
|
||||
* Replace all /'s with \'s
|
||||
*/
|
||||
char *reg_path_unix2win(char *path)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; path[i]; i++) {
|
||||
if(path[i] == '/') path[i] = '\\';
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/** Open a key by name (including the predefined key name!) */
|
||||
WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result)
|
||||
{
|
||||
struct registry_key *predef;
|
||||
WERROR error;
|
||||
int predeflength;
|
||||
char *predefname;
|
||||
|
||||
if(strchr(name, '\\')) predeflength = strchr(name, '\\')-name;
|
||||
else predeflength = strlen(name);
|
||||
|
||||
predefname = talloc_strndup(mem_ctx, name, predeflength);
|
||||
error = reg_get_predefined_key_by_name(handle, predefname, &predef);
|
||||
talloc_free(predefname);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (strchr(name, '\\')) {
|
||||
return reg_open_key(mem_ctx, predef, strchr(name, '\\')+1, result);
|
||||
} else {
|
||||
*result = predef;
|
||||
return WERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, struct registry_key **parent, const char **name)
|
||||
{
|
||||
char *parent_name;
|
||||
WERROR error;
|
||||
|
||||
if (strchr(path, '\\') == NULL) {
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-1-path);
|
||||
|
||||
error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
*name = talloc_strdup(mem_ctx, strchr(path, '\\')+1);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
|
||||
{
|
||||
struct registry_key *parent;
|
||||
const char *n;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("reg_key_del_abs");
|
||||
WERROR error;
|
||||
|
||||
if (!strchr(path, '\\')) {
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
|
||||
if (W_ERROR_IS_OK(error)) {
|
||||
error = reg_key_del(parent, n);
|
||||
}
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **result)
|
||||
{
|
||||
struct registry_key *parent;
|
||||
const char *n;
|
||||
WERROR error;
|
||||
|
||||
if (!strchr(path, '\\')) {
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
|
||||
if (W_ERROR_IS_OK(error)) {
|
||||
error = reg_key_add_name(mem_ctx, parent, n, access_mask, sec_desc, result);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Registry backends
|
||||
SMB_ENABLE(registry_gconf, NO)
|
||||
|
||||
SMB_EXT_LIB_FROM_PKGCONFIG(gconf, gconf-2.0)
|
||||
|
||||
AC_ARG_ENABLE(reg-gconf,
|
||||
[ --enable-reg-gconf Enable support for GConf registry backend],
|
||||
[
|
||||
if test t$enable = tyes; then
|
||||
SMB_ENABLE(registry_gconf, $SMB_ENABLE_gconf)
|
||||
fi
|
||||
])
|
||||
@@ -0,0 +1,150 @@
|
||||
# Registry backends
|
||||
|
||||
################################################
|
||||
# Start MODULE registry_nt4
|
||||
[MODULE::registry_nt4]
|
||||
INIT_FUNCTION = registry_nt4_init
|
||||
SUBSYSTEM = registry
|
||||
OBJ_FILES = \
|
||||
reg_backend_nt4.o
|
||||
PUBLIC_DEPENDENCIES = TDR_REGF
|
||||
# End MODULE registry_nt4
|
||||
################################################
|
||||
|
||||
[SUBSYSTEM::TDR_REGF]
|
||||
PUBLIC_DEPENDENCIES = TDR
|
||||
OBJ_FILES = tdr_regf.o
|
||||
|
||||
# Special support for external builddirs
|
||||
lib/registry/reg_backend_nt4.c: lib/registry/tdr_regf.c
|
||||
$(srcdir)/lib/registry/reg_backend_nt4.c: lib/registry/tdr_regf.c
|
||||
lib/registry/tdr_regf.h: lib/registry/tdr_regf.c
|
||||
lib/registry/tdr_regf.c: $(srcdir)/lib/registry/regf.idl
|
||||
@CPP="$(CPP)" $(PERL) $(srcdir)/pidl/pidl $(PIDL_ARGS) \
|
||||
--header --outputdir=lib/registry \
|
||||
--tdr-parser -- $(srcdir)/lib/registry/regf.idl
|
||||
|
||||
clean::
|
||||
@-rm -f lib/registry/regf.h lib/registry/tdr_regf*
|
||||
|
||||
################################################
|
||||
# Start MODULE registry_w95
|
||||
[MODULE::registry_w95]
|
||||
INIT_FUNCTION = registry_w95_init
|
||||
SUBSYSTEM = registry
|
||||
OBJ_FILES = \
|
||||
reg_backend_w95.o
|
||||
# End MODULE registry_w95
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE registry_dir
|
||||
[MODULE::registry_dir]
|
||||
INIT_FUNCTION = registry_dir_init
|
||||
SUBSYSTEM = registry
|
||||
OBJ_FILES = \
|
||||
reg_backend_dir.o
|
||||
PUBLIC_DEPENDENCIES = LIBTALLOC
|
||||
# End MODULE registry_dir
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE registry_rpc
|
||||
[MODULE::registry_rpc]
|
||||
INIT_FUNCTION = registry_rpc_init
|
||||
PRIVATE_PROTO_HEADER = reg_backend_rpc.h
|
||||
OUTPUT_TYPE = INTEGRATED
|
||||
SUBSYSTEM = registry
|
||||
OBJ_FILES = \
|
||||
reg_backend_rpc.o
|
||||
PUBLIC_DEPENDENCIES = RPC_NDR_WINREG
|
||||
# End MODULE registry_rpc
|
||||
################################################
|
||||
|
||||
|
||||
|
||||
################################################
|
||||
# Start MODULE registry_gconf
|
||||
[MODULE::registry_gconf]
|
||||
INIT_FUNCTION = registry_gconf_init
|
||||
SUBSYSTEM = registry
|
||||
OBJ_FILES = \
|
||||
reg_backend_gconf.o
|
||||
PUBLIC_DEPENDENCIES = gconf
|
||||
# End MODULE registry_gconf
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE registry_ldb
|
||||
[MODULE::registry_ldb]
|
||||
INIT_FUNCTION = registry_ldb_init
|
||||
SUBSYSTEM = registry
|
||||
OBJ_FILES = \
|
||||
reg_backend_ldb.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
ldb
|
||||
# End MODULE registry_ldb
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start SUBSYSTEM registry
|
||||
[LIBRARY::registry]
|
||||
VERSION = 0.0.1
|
||||
SO_VERSION = 0
|
||||
DESCRIPTION = Windows-style registry library
|
||||
OBJ_FILES = \
|
||||
common/reg_interface.o \
|
||||
common/reg_util.o \
|
||||
reg_samba.o \
|
||||
patchfile.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
LIBSAMBA-UTIL CHARSET
|
||||
PRIVATE_PROTO_HEADER = registry_proto.h
|
||||
PUBLIC_HEADERS = registry.h
|
||||
# End MODULE registry_ldb
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start BINARY regdiff
|
||||
[BINARY::regdiff]
|
||||
INSTALLDIR = BINDIR
|
||||
OBJ_FILES = tools/regdiff.o
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
LIBSAMBA-CONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS
|
||||
MANPAGE = man/regdiff.1
|
||||
# End BINARY regdiff
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start BINARY regpatch
|
||||
[BINARY::regpatch]
|
||||
INSTALLDIR = BINDIR
|
||||
OBJ_FILES = tools/regpatch.o
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
LIBSAMBA-CONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS
|
||||
MANPAGE = man/regpatch.1
|
||||
# End BINARY regpatch
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start BINARY regshell
|
||||
[BINARY::regshell]
|
||||
INSTALLDIR = BINDIR
|
||||
OBJ_FILES = tools/regshell.o
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \
|
||||
SMBREADLINE
|
||||
MANPAGE = man/regshell.1
|
||||
# End BINARY regshell
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start BINARY regtree
|
||||
[BINARY::regtree]
|
||||
INSTALLDIR = BINDIR
|
||||
OBJ_FILES = tools/regtree.o
|
||||
PRIVATE_DEPENDENCIES = \
|
||||
LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS
|
||||
MANPAGE = man/regtree.1
|
||||
# End BINARY regtree
|
||||
################################################
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="regdiff.1">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>regdiff</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>regdiff</refname>
|
||||
<refpurpose>Diff program for Windows registry files</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>regdiff</command>
|
||||
<arg choice="opt">--help</arg>
|
||||
<arg choice="opt">--backend=BACKEND</arg>
|
||||
<arg choice="opt">--backend=BACKEND</arg>
|
||||
<arg choice="opt">--credentials=CREDENTIALS</arg>
|
||||
<arg choice="opt">--credentials=CREDENTIALS</arg>
|
||||
<arg choice="opt">location</arg>
|
||||
<arg choice="opt">location</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
|
||||
<para>regdiff compares two Windows registry files key by key
|
||||
and value by value and generates a text file that contains the
|
||||
differences between the two files.</para>
|
||||
|
||||
<para>A file generated by regdiff can later be applied to a
|
||||
registry file by the regpatch utility. </para>
|
||||
|
||||
<para>regdiff and regpatch use the same file format as
|
||||
the regedit32.exe utility from Windows.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--help</term>
|
||||
<listitem><para>
|
||||
Show list of available options.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--backend BACKEND</term>
|
||||
<listitem><para>Name of backend to load. Possible values are:
|
||||
w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
This argument can be specified twice: once for the first
|
||||
registry file and once for the second.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--credentials=CREDENTIALS</term>
|
||||
<listitem><para>
|
||||
Credentials to use, if any. Password should be separated from user name by a percent sign.
|
||||
</para>
|
||||
<para>
|
||||
This argument can be specified twice: once for the first
|
||||
registry file and once for the second.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is correct for version 4.0 of the Samba suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
|
||||
<para>gregedit, regshell, regpatch, regtree, samba, patch, diff</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
|
||||
|
||||
<para>This manpage and regdiff were written by Jelmer Vernooij. </para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="regpatch.1">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>regpatch</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>regpatch</refname>
|
||||
<refpurpose>Applies registry patches to registry files</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>regpatch</command>
|
||||
<arg choice="opt">--help</arg>
|
||||
<arg choice="opt">--backend=BACKEND</arg>
|
||||
<arg choice="opt">--credentials=CREDENTIALS</arg>
|
||||
<arg choice="opt">location</arg>
|
||||
<arg choice="opt">patch-file</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
|
||||
<para>The regpatch utility applies registry patches to Windows registry
|
||||
files. The patch files should have the same format as is being used
|
||||
by the regdiff utility and regedit32.exe from Windows.</para>
|
||||
|
||||
<para>If no patch file is specified on the command line,
|
||||
regpatch attempts to read it from standard input.</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--help</term>
|
||||
<listitem><para>
|
||||
Show list of available options.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--backend BACKEND</term>
|
||||
<listitem><para>Name of backend to load. Possible values are:
|
||||
w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--credentials=CREDENTIALS</term>
|
||||
<listitem><para>
|
||||
Credentials to use, if any. Password should be separated from user name by a percent sign.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is correct for version 4.0 of the Samba suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
|
||||
<para>regdiff, regtree, regshell, gregedit, samba, diff, patch</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
|
||||
|
||||
<para>This manpage and regpatch were written by Jelmer Vernooij. </para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="regshell.1">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>regshell</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>regshell</refname>
|
||||
<refpurpose>Windows registry file browser using readline</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>regshell</command>
|
||||
<arg choice="opt">--help</arg>
|
||||
<arg choice="opt">--backend=BACKEND</arg>
|
||||
<arg choice="opt">--credentials=CREDENTIALS</arg>
|
||||
<arg choice="opt">location</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
|
||||
<para>
|
||||
regshell is a utility that lets you browse thru a Windows registry
|
||||
file as if you were using a regular unix shell to browse thru a
|
||||
file system.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--help</term>
|
||||
<listitem><para>
|
||||
Show list of available options.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--backend BACKEND</term>
|
||||
<listitem><para>Name of backend to load. Possible values are:
|
||||
w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--credentials=CREDENTIALS</term>
|
||||
<listitem><para>
|
||||
Credentials to use, if any. Password should be separated from user name by a percent sign.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>COMMANDS</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>ck|cd <keyname></term>
|
||||
<listitem><para>
|
||||
Go to the specified subkey.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>ch|predef [predefined-key-name]</term>
|
||||
<listitem><para>
|
||||
Go to the specified predefined key.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>list|ls</term>
|
||||
<listitem><para>
|
||||
List subkeys and values of the current key.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>mkkey|mkdir <keyname></term>
|
||||
<listitem><para>
|
||||
Create a key with the specified <replaceable>keyname</replaceable> as a subkey of the current key.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>rmval|rm <valname></term>
|
||||
<listitem><para>
|
||||
Delete the specified value.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>rmkey|rmdir <keyname></term>
|
||||
<listitem><para>
|
||||
Delete the specified subkey recursively.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>pwd|pwk</term>
|
||||
<listitem><para>Print the full name of the current key.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>set|update</term>
|
||||
<listitem><para>Update the value of a key value. Not implemented at the moment.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>help|?</term>
|
||||
<listitem><para>Print a list of available commands.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>exit|quit</term>
|
||||
<listitem><para>Leave regshell.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>EXAMPLES</title>
|
||||
|
||||
<para>Browsing thru a nt4 registry file</para>
|
||||
<screen>
|
||||
<userinput>regshell -b nt4 NTUSER.DAT</userinput>
|
||||
$$$PROTO.HIV> <userinput>ls</userinput>
|
||||
K AppEvents
|
||||
K Console
|
||||
K Control Panel
|
||||
K Environment
|
||||
K Identities
|
||||
K Keyboard Layout
|
||||
K Network
|
||||
K Printers
|
||||
K Software
|
||||
K UNICODE Program Groups
|
||||
K Windows 3.1 Migration Status
|
||||
$$$PROTO.HIV> <userinput>exit</userinput>
|
||||
</screen>
|
||||
|
||||
<para>Listing the subkeys of HKEY_CURRENT_USER\AppEvents on a remote computer:</para>
|
||||
<screen>
|
||||
<userinput>regshell --remote=ncacn_np:aurelia -c "jelmer%secret"</userinput>
|
||||
HKEY_CURRENT_MACHINE> <userinput>predef HKEY_CURRENT_USER</userinput>
|
||||
HKEY_CURRENT_USER> <userinput>cd AppEvents</userinput>
|
||||
Current path is: HKEY_CURRENT_USER\AppEvents
|
||||
HKEY_CURRENT_USER\AppEvents> <userinput>ls</userinput>
|
||||
K EventLabels
|
||||
K Schemes
|
||||
HKEY_CURRENT_USER\AppEvents> <userinput>exit</userinput>
|
||||
</screen>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is correct for version 4.0 of the Samba suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
|
||||
<para>regtree, regdiff, regpatch, gregedit, samba</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
|
||||
|
||||
<para>This manpage and regshell were written by Jelmer Vernooij. </para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
|
||||
<refentry id="regtree.1">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>regtree</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
|
||||
<refnamediv>
|
||||
<refname>regtree</refname>
|
||||
<refpurpose>Text-mode registry viewer</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>regtree</command>
|
||||
<arg choice="opt">--help</arg>
|
||||
<arg choice="opt">--backend=BACKEND</arg>
|
||||
<arg choice="opt">--fullpath</arg>
|
||||
<arg choice="opt">--no-values</arg>
|
||||
<arg choice="opt">--credentials=CREDENTIALS</arg>
|
||||
<arg choice="opt">location</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>DESCRIPTION</title>
|
||||
|
||||
<para>The regtree utility prints out all the contents of a
|
||||
Windows registry file. Subkeys are printed with one level
|
||||
more indentation than their parents. </para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>OPTIONS</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--help</term>
|
||||
<listitem><para>
|
||||
Show list of available options.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--backend BACKEND</term>
|
||||
<listitem><para>Name of backend to load. Possible values are:
|
||||
w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--credentials=CREDENTIALS</term>
|
||||
<listitem><para>
|
||||
Credentials to use, if any. Password should be separated from user name by a percent sign.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>--fullpath</term>
|
||||
<listitem><para>
|
||||
Print the full path to each key instead of only its name.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term>--no-values</term>
|
||||
<listitem><para>Don't print values, just keys.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>VERSION</title>
|
||||
|
||||
<para>This man page is correct for version 4.0 of the Samba suite.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>SEE ALSO</title>
|
||||
|
||||
<para>gregedit, regshell, regdiff, regpatch, samba</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>AUTHOR</title>
|
||||
|
||||
<para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
|
||||
|
||||
<para>This manpage and regtree were written by Jelmer Vernooij. </para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Reading .REG files
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2004
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Registry patch files
|
||||
*/
|
||||
|
||||
#define DEFAULT_IDENT_STRING "SAMBA4 REGISTRY"
|
||||
|
||||
static struct reg_diff_key *diff_find_add_key(struct reg_diff *diff, const char *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; diff->numkeys; i++) {
|
||||
if (!strcasecmp(diff->keys[i].name, path))
|
||||
return &diff->keys[i];
|
||||
}
|
||||
|
||||
diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
|
||||
diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, path);
|
||||
diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
|
||||
diff->keys[diff->numkeys].numvalues = 0;
|
||||
diff->keys[diff->numkeys].values = NULL;
|
||||
|
||||
diff->numkeys++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate difference between two keys
|
||||
*/
|
||||
static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *oldkey, struct registry_key *newkey)
|
||||
{
|
||||
int i;
|
||||
struct registry_key *t1, *t2;
|
||||
struct registry_value *v1, *v2;
|
||||
WERROR error1, error2;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("writediff");
|
||||
|
||||
/* Subkeys that were deleted */
|
||||
for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &t1)); i++) {
|
||||
error2 = reg_key_get_subkey_by_name(mem_ctx, newkey, t1->name, &t2);
|
||||
|
||||
if (W_ERROR_IS_OK(error2))
|
||||
continue;
|
||||
|
||||
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
|
||||
DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
|
||||
return error2;
|
||||
}
|
||||
|
||||
/* newkey didn't have such a subkey, add del diff */
|
||||
diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
|
||||
diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, t1->path);
|
||||
diff->keys[diff->numkeys].changetype = REG_DIFF_DEL_KEY;
|
||||
diff->numkeys++;
|
||||
}
|
||||
|
||||
if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1)));
|
||||
talloc_free(mem_ctx);
|
||||
return error1;
|
||||
}
|
||||
|
||||
/* Subkeys that were added */
|
||||
for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &t1)); i++) {
|
||||
error2 = reg_key_get_subkey_by_name(mem_ctx, oldkey, t1->name, &t2);
|
||||
|
||||
if (W_ERROR_IS_OK(error2))
|
||||
continue;
|
||||
|
||||
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
|
||||
DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
|
||||
return error2;
|
||||
}
|
||||
|
||||
/* oldkey didn't have such a subkey, add add diff */
|
||||
diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
|
||||
diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, t1->path);
|
||||
diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
|
||||
diff->keys[diff->numkeys].numvalues = 0;
|
||||
diff->keys[diff->numkeys].values = NULL;
|
||||
diff->numkeys++;
|
||||
|
||||
reg_generate_diff_key(diff, t1, t2);
|
||||
}
|
||||
|
||||
if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1)));
|
||||
talloc_free(mem_ctx);
|
||||
return error1;
|
||||
}
|
||||
|
||||
/* Values that were changed */
|
||||
for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_value_by_index(mem_ctx, newkey, i, &v1)); i++) {
|
||||
struct reg_diff_key *thiskey = NULL;
|
||||
error2 = reg_key_get_value_by_name(mem_ctx, oldkey, v1->name, &v2);
|
||||
|
||||
if(!W_ERROR_IS_OK(error2) &&
|
||||
!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
|
||||
DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
|
||||
return error2;
|
||||
}
|
||||
|
||||
if (W_ERROR_IS_OK(error2) && data_blob_equal(&v1->data, &v2->data))
|
||||
continue;
|
||||
|
||||
thiskey = diff_find_add_key(diff, oldkey->path);
|
||||
thiskey->values = talloc_realloc(diff, thiskey->values, struct reg_diff_value, thiskey->numvalues+2);
|
||||
thiskey->values[thiskey->numvalues].name = talloc_strdup(thiskey->values, v1->name);
|
||||
thiskey->values[thiskey->numvalues].type = v2->data_type;
|
||||
thiskey->values[thiskey->numvalues].changetype = REG_DIFF_SET_VAL;
|
||||
thiskey->values[thiskey->numvalues].data = data_blob_dup_talloc(thiskey->values, &v2->data);
|
||||
thiskey->numvalues++;
|
||||
}
|
||||
|
||||
if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1)));
|
||||
talloc_free(mem_ctx);
|
||||
return error1;
|
||||
}
|
||||
|
||||
/* Values that were deleted */
|
||||
for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &v1)); i++) {
|
||||
struct reg_diff_key *thiskey = NULL;
|
||||
error2 = reg_key_get_value_by_name(mem_ctx, newkey, v1->name, &v2);
|
||||
|
||||
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: %d\n", W_ERROR_V(error2)));
|
||||
return error2;
|
||||
}
|
||||
|
||||
thiskey = diff_find_add_key(diff, oldkey->path);
|
||||
thiskey->values = talloc_realloc(diff, thiskey->values, struct reg_diff_value, thiskey->numvalues+2);
|
||||
thiskey->values[thiskey->numvalues].name = talloc_strdup(thiskey->values, v1->name);
|
||||
thiskey->values[thiskey->numvalues].changetype = REG_DIFF_DEL_VAL;
|
||||
thiskey->numvalues++;
|
||||
}
|
||||
|
||||
if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1)));
|
||||
talloc_free(mem_ctx);
|
||||
return error1;
|
||||
}
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate diff between two registry contexts
|
||||
*/
|
||||
_PUBLIC_ struct reg_diff *reg_generate_diff(TALLOC_CTX *mem_ctx, struct registry_context *ctx1, struct registry_context *ctx2)
|
||||
{
|
||||
struct reg_diff *diff = talloc_zero(mem_ctx, struct reg_diff);
|
||||
int i;
|
||||
WERROR error;
|
||||
|
||||
for(i = HKEY_CLASSES_ROOT; i <= HKEY_PERFORMANCE_NLSTEXT; i++) {
|
||||
struct registry_key *r1, *r2;
|
||||
error = reg_get_predefined_key(ctx1, i, &r1);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_predef_name(i)));
|
||||
continue;
|
||||
}
|
||||
|
||||
error = reg_get_predefined_key(ctx2, i, &r2);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_predef_name(i)));
|
||||
continue;
|
||||
}
|
||||
|
||||
reg_generate_diff_key(diff, r1, r2);
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save registry diff
|
||||
*/
|
||||
_PUBLIC_ WERROR reg_diff_save(const struct reg_diff *diff, const char *filename)
|
||||
{
|
||||
int xf, i, j;
|
||||
|
||||
if (filename) {
|
||||
xf = open(filename, O_CREAT, 0755);
|
||||
if (xf == -1) {
|
||||
DEBUG(0, ("Unable to open %s\n", filename));
|
||||
return WERR_BADFILE;
|
||||
}
|
||||
} else
|
||||
xf = STDIN_FILENO;
|
||||
|
||||
fdprintf(xf, "%s\n\n", diff->format?diff->format:DEFAULT_IDENT_STRING);
|
||||
|
||||
for (i = 0; i < diff->numkeys; i++) {
|
||||
if (diff->keys[i].changetype == REG_DIFF_DEL_KEY) {
|
||||
fdprintf(xf, "-%s\n\n", diff->keys[i].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
fdprintf(xf, "[%s]\n", diff->keys[i].name);
|
||||
|
||||
for (j = 0; j < diff->keys[i].numvalues; j++) {
|
||||
fdprintf(xf, "\"%s\"=", diff->keys[i].values[j].name);
|
||||
switch (diff->keys[i].values[j].changetype) {
|
||||
case REG_DIFF_DEL_VAL:
|
||||
fdprintf(xf, "-\n");
|
||||
break;
|
||||
case REG_DIFF_SET_VAL:
|
||||
fdprintf(xf, "%s:%s\n",
|
||||
str_regtype(diff->keys[i].values[j].type),
|
||||
reg_val_data_string(NULL,
|
||||
diff->keys[i].values[j].type,
|
||||
&diff->keys[i].values[j].data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fdprintf(xf, "\n");
|
||||
}
|
||||
|
||||
close(xf);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load diff file
|
||||
*/
|
||||
_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn)
|
||||
{
|
||||
struct reg_diff *diff;
|
||||
int fd;
|
||||
char *line, *p, *q;
|
||||
struct reg_diff_key *curkey = NULL;
|
||||
struct reg_diff_value *curval;
|
||||
|
||||
fd = open(fn, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
DEBUG(0, ("Error opening registry patch file `%s'\n", fn));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
diff = talloc_zero(ctx, struct reg_diff);
|
||||
if (diff == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
diff->format = afdgets(fd, diff, 0);
|
||||
if (!diff->format) {
|
||||
talloc_free(diff);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((line = afdgets(fd, diff, 0))) {
|
||||
/* Ignore comments and empty lines */
|
||||
if (strlen(line) == 0 || line[0] == ';') {
|
||||
curkey = NULL;
|
||||
talloc_free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Start of key */
|
||||
if (line[0] == '[') {
|
||||
p = strchr_m(line, ']');
|
||||
if (p[strlen(p)-2] != ']') {
|
||||
DEBUG(0, ("Malformed line\n"));
|
||||
return NULL;
|
||||
}
|
||||
diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
|
||||
diff->keys[diff->numkeys].name = talloc_strndup(diff->keys, line+1, strlen(line)-2);
|
||||
diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
|
||||
diff->keys[diff->numkeys].numvalues = 0;
|
||||
diff->keys[diff->numkeys].values = NULL;
|
||||
curkey = &diff->keys[diff->numkeys];
|
||||
diff->numkeys++;
|
||||
talloc_free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deleting key */
|
||||
if (line[0] == '-') {
|
||||
diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
|
||||
diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, line+1);
|
||||
diff->keys[diff->numkeys].changetype = REG_DIFF_DEL_KEY;
|
||||
diff->numkeys++;
|
||||
talloc_free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deleting/Changing value */
|
||||
p = strchr_m(line, '=');
|
||||
if (p == NULL) {
|
||||
DEBUG(0, ("Malformed line\n"));
|
||||
talloc_free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
*p = '\0'; p++;
|
||||
|
||||
if (curkey == NULL) {
|
||||
DEBUG(0, ("Value change without key\n"));
|
||||
talloc_free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
curkey->values = talloc_realloc(diff->keys, curkey->values, struct reg_diff_value, curkey->numvalues+2);
|
||||
curval = &curkey->values[curkey->numvalues];
|
||||
curkey->numvalues++;
|
||||
curval->name = talloc_strdup(curkey->values, line);
|
||||
|
||||
/* Delete value */
|
||||
if (strcmp(p, "-")) {
|
||||
curval->changetype = REG_DIFF_DEL_VAL;
|
||||
talloc_free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
q = strchr_m(p, ':');
|
||||
if (q) {
|
||||
*q = '\0';
|
||||
q++;
|
||||
}
|
||||
|
||||
curval->changetype = REG_DIFF_SET_VAL;
|
||||
reg_string_to_val(curkey->values, q?p:"REG_SZ", q?q:p, &curval->type, &curval->data);
|
||||
|
||||
talloc_free(line);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply diff to a registry context
|
||||
*/
|
||||
_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx = talloc_init("apply_cmd_file");
|
||||
struct registry_key *tmp = NULL;
|
||||
WERROR error;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < diff->numkeys; i++) {
|
||||
if (diff->keys[i].changetype == REG_DIFF_DEL_KEY) {
|
||||
error = reg_key_del_abs(ctx, diff->keys[i].name);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
DEBUG(0, ("Unable to delete key '%s'\n", diff->keys[i].name));
|
||||
return False;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add / change key */
|
||||
error = reg_open_key_abs(mem_ctx, ctx, diff->keys[i].name, &tmp);
|
||||
|
||||
/* If we found it, apply the other bits, else create such a key */
|
||||
if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
|
||||
if(!W_ERROR_IS_OK(reg_key_add_abs(mem_ctx, ctx, diff->keys[i].name, 0, NULL, &tmp))) {
|
||||
DEBUG(0, ("Error adding new key '%s'\n", diff->keys[i].name));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < diff->keys[i].numvalues; j++) {
|
||||
if (diff->keys[i].values[j].changetype == REG_DIFF_DEL_VAL) {
|
||||
error = reg_del_value(tmp, diff->keys[i].values[j].name);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
DEBUG(0, ("Error deleting value '%s'\n", diff->keys[i].values[j].name));
|
||||
return False;
|
||||
}
|
||||
|
||||
error = reg_val_set(tmp, diff->keys[i].values[j].name,
|
||||
diff->keys[i].values[j].type,
|
||||
diff->keys[i].values[j].data);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
DEBUG(0, ("Error setting value '%s'\n", diff->keys[i].values[j].name));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Registry interface
|
||||
Copyright (C) Jelmer Vernooij 2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "registry.h"
|
||||
#include "system/dir.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *desc, struct registry_key **result)
|
||||
{
|
||||
char *path;
|
||||
int ret;
|
||||
asprintf(&path, "%s%s\\%s", parent->hive->location, parent->path, name);
|
||||
path = reg_path_win2unix(path);
|
||||
ret = mkdir(path, 0700);
|
||||
SAFE_FREE(path);
|
||||
if(ret == 0)return WERR_OK; /* FIXME */
|
||||
return WERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
static WERROR reg_dir_del_key(const struct registry_key *k, const char *name)
|
||||
{
|
||||
char *child = talloc_asprintf(NULL, "%s/%s", (char *)k->backend_data, name);
|
||||
WERROR ret;
|
||||
|
||||
if (rmdir(child) == 0) ret = WERR_OK; else ret = WERR_GENERAL_FAILURE;
|
||||
|
||||
talloc_free(child);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *p, const char *name, struct registry_key **subkey)
|
||||
{
|
||||
DIR *d;
|
||||
char *fullpath, *unixpath;
|
||||
struct registry_key *ret;
|
||||
|
||||
if(!name) {
|
||||
DEBUG(0, ("NULL pointer passed as directory name!"));
|
||||
return WERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
|
||||
fullpath = talloc_asprintf(mem_ctx, "%s/%s", (char *)p->backend_data, name);
|
||||
unixpath = reg_path_win2unix(fullpath);
|
||||
|
||||
d = opendir(unixpath);
|
||||
if(!d) {
|
||||
DEBUG(3,("Unable to open '%s': %s\n", unixpath, strerror(errno)));
|
||||
return WERR_BADFILE;
|
||||
}
|
||||
closedir(d);
|
||||
ret = talloc(mem_ctx, struct registry_key);
|
||||
ret->hive = p->hive;
|
||||
ret->path = fullpath;
|
||||
ret->backend_data = unixpath;
|
||||
*subkey = ret;
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_key **key)
|
||||
{
|
||||
struct dirent *e;
|
||||
char *fullpath = k->backend_data;
|
||||
int i = 0;
|
||||
DIR *d;
|
||||
|
||||
d = opendir(fullpath);
|
||||
|
||||
if(!d) return WERR_INVALID_PARAM;
|
||||
|
||||
while((e = readdir(d))) {
|
||||
if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
|
||||
struct stat stbuf;
|
||||
char *thispath;
|
||||
|
||||
/* Check if file is a directory */
|
||||
asprintf(&thispath, "%s/%s", fullpath, e->d_name);
|
||||
stat(thispath, &stbuf);
|
||||
|
||||
if(S_ISDIR(stbuf.st_mode)) {
|
||||
if(i == idx) {
|
||||
(*key) = talloc(mem_ctx, struct registry_key);
|
||||
(*key)->name = talloc_strdup(*key, e->d_name);
|
||||
(*key)->path = NULL;
|
||||
(*key)->backend_data = talloc_strdup(*key, thispath);
|
||||
SAFE_FREE(thispath);
|
||||
closedir(d);
|
||||
return WERR_OK;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
SAFE_FREE(thispath);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
return WERR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
static WERROR reg_dir_open(struct registry_hive *h, struct registry_key **key)
|
||||
{
|
||||
if(!h->location) return WERR_INVALID_PARAM;
|
||||
|
||||
*key = talloc(h, struct registry_key);
|
||||
(*key)->backend_data = talloc_strdup(*key, h->location);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static struct hive_operations reg_backend_dir = {
|
||||
.name = "dir",
|
||||
.open_hive = reg_dir_open,
|
||||
.open_key = reg_dir_open_key,
|
||||
.add_key = reg_dir_add_key,
|
||||
.del_key = reg_dir_del_key,
|
||||
.get_subkey_by_index = reg_dir_key_by_index
|
||||
};
|
||||
|
||||
NTSTATUS registry_dir_init(void)
|
||||
{
|
||||
return registry_register(®_backend_dir);
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Registry interface
|
||||
Copyright (C) Jelmer Vernooij 2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "registry.h"
|
||||
#include <gconf/gconf-client.h>
|
||||
|
||||
static WERROR gerror_to_werror(GError *error)
|
||||
{
|
||||
if(error == NULL) return WERR_OK;
|
||||
/* FIXME */
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
static WERROR reg_open_gconf_hive(struct registry_hive *h, struct registry_key **k)
|
||||
{
|
||||
g_type_init();
|
||||
h->backend_data = (void *)gconf_client_get_default();
|
||||
if(!h->backend_data) return WERR_FOOBAR;
|
||||
|
||||
*k = talloc(h, struct registry_key);
|
||||
(*k)->name = talloc_strdup(*k, "");
|
||||
(*k)->path = talloc_strdup(*k, "");
|
||||
(*k)->backend_data = talloc_strdup(*k, "/");
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR gconf_open_key (TALLOC_CTX *mem_ctx, struct registry_key *h, const char *name, struct registry_key **key)
|
||||
{
|
||||
struct registry_key *ret;
|
||||
char *fullpath;
|
||||
|
||||
fullpath = talloc_asprintf(mem_ctx, "%s%s%s",
|
||||
(char *)h->backend_data,
|
||||
strlen((char *)h->backend_data) == 1?"":"/",
|
||||
reg_path_win2unix(talloc_strdup(mem_ctx, name)));
|
||||
|
||||
/* Check if key exists */
|
||||
if(!gconf_client_dir_exists((GConfClient *)h->hive->backend_data, fullpath, NULL)) {
|
||||
return WERR_DEST_NOT_FOUND;
|
||||
}
|
||||
|
||||
ret = talloc(mem_ctx, struct registry_key);
|
||||
ret->backend_data = fullpath;
|
||||
|
||||
*key = ret;
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR gconf_get_value_by_id(TALLOC_CTX *mem_ctx, struct registry_key *p, int idx, struct registry_value **val)
|
||||
{
|
||||
GSList *entries;
|
||||
GSList *cur;
|
||||
GConfEntry *entry;
|
||||
GConfValue *value;
|
||||
struct registry_value *newval;
|
||||
char *fullpath = p->backend_data;
|
||||
const char *tmp;
|
||||
int i;
|
||||
cur = entries = gconf_client_all_entries((GConfClient*)p->hive->backend_data, fullpath, NULL);
|
||||
|
||||
for(i = 0; i < idx && cur; i++) cur = cur->next;
|
||||
|
||||
if(!cur) return WERR_NO_MORE_ITEMS;
|
||||
|
||||
entry = cur->data;
|
||||
value = gconf_entry_get_value(entry);
|
||||
|
||||
newval = talloc(mem_ctx, struct registry_value);
|
||||
newval->name = talloc_strdup(mem_ctx, strrchr(gconf_entry_get_key(entry), '/')+1);
|
||||
if(value) {
|
||||
switch(value->type) {
|
||||
case GCONF_VALUE_INVALID:
|
||||
newval->data_type = REG_NONE;
|
||||
break;
|
||||
|
||||
case GCONF_VALUE_STRING:
|
||||
newval->data_type = REG_SZ;
|
||||
tmp = gconf_value_get_string(value);
|
||||
newval->data_len = convert_string_talloc(mem_ctx, CH_UTF8, CH_UTF16, tmp, strlen(tmp), &(newval->data_blk));
|
||||
break;
|
||||
|
||||
case GCONF_VALUE_INT:
|
||||
newval->data_type = REG_DWORD;
|
||||
newval->data_blk = talloc(mem_ctx, long);
|
||||
*((long *)newval->data_blk) = gconf_value_get_int(value);
|
||||
newval->data_len = sizeof(long);
|
||||
break;
|
||||
|
||||
case GCONF_VALUE_FLOAT:
|
||||
newval->data_blk = talloc(mem_ctx, double);
|
||||
newval->data_type = REG_BINARY;
|
||||
*((double *)newval->data_blk) = gconf_value_get_float(value);
|
||||
newval->data_len = sizeof(double);
|
||||
break;
|
||||
|
||||
case GCONF_VALUE_BOOL:
|
||||
newval->data_blk = talloc(mem_ctx, BOOL);
|
||||
newval->data_type = REG_BINARY;
|
||||
*((BOOL *)newval->data_blk) = gconf_value_get_bool(value);
|
||||
newval->data_len = sizeof(BOOL);
|
||||
break;
|
||||
|
||||
default:
|
||||
newval->data_type = REG_NONE;
|
||||
DEBUG(0, ("Not implemented..\n"));
|
||||
break;
|
||||
}
|
||||
} else newval->data_type = REG_NONE;
|
||||
|
||||
g_slist_free(entries);
|
||||
*val = newval;
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR gconf_get_subkey_by_id(TALLOC_CTX *mem_ctx, struct registry_key *p, int idx, struct registry_key **sub)
|
||||
{
|
||||
GSList *dirs;
|
||||
GSList *cur;
|
||||
int i;
|
||||
char *fullpath = p->backend_data;
|
||||
cur = dirs = gconf_client_all_dirs((GConfClient*)p->hive->backend_data, fullpath,NULL);
|
||||
|
||||
for(i = 0; i < idx && cur; i++) cur = cur->next;
|
||||
|
||||
if(!cur) return WERR_NO_MORE_ITEMS;
|
||||
|
||||
*sub = talloc(mem_ctx, struct registry_key);
|
||||
(*sub)->name = talloc_strdup(mem_ctx, strrchr((char *)cur->data, '/')+1);
|
||||
(*sub)->backend_data = talloc_strdup(mem_ctx, cur->data);
|
||||
|
||||
g_slist_free(dirs);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR gconf_set_value(struct registry_key *key, const char *valname, uint32_t type, void *data, int len)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *valpath;
|
||||
asprintf(&valpath, "%s/%s", key->path, valname);
|
||||
|
||||
switch(type) {
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
gconf_client_set_string((GConfClient *)key->hive->backend_data, valpath, data, &error);
|
||||
SAFE_FREE(valpath);
|
||||
return gerror_to_werror(error);
|
||||
|
||||
case REG_DWORD:
|
||||
gconf_client_set_int((GConfClient *)key->hive->backend_data, valpath,
|
||||
*((int *)data), &error);
|
||||
SAFE_FREE(valpath);
|
||||
return gerror_to_werror(error);
|
||||
default:
|
||||
DEBUG(0, ("Unsupported type: %d\n", type));
|
||||
SAFE_FREE(valpath);
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static struct hive_operations reg_backend_gconf = {
|
||||
.name = "gconf",
|
||||
.open_hive = reg_open_gconf_hive,
|
||||
.open_key = gconf_open_key,
|
||||
.get_subkey_by_index = gconf_get_subkey_by_id,
|
||||
.get_value_by_index = gconf_get_value_by_id,
|
||||
.set_value = gconf_set_value,
|
||||
|
||||
/* Note:
|
||||
* since GConf uses schemas for what keys and values are allowed, there
|
||||
* is no way of 'emulating' add_key and del_key here.
|
||||
*/
|
||||
};
|
||||
|
||||
NTSTATUS registry_gconf_init(void)
|
||||
{
|
||||
return registry_register(®_backend_gconf);
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Registry interface
|
||||
Copyright (C) Jelmer Vernooij 2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "registry.h"
|
||||
#include "lib/ldb/include/ldb.h"
|
||||
#include "lib/ldb/include/ldb_errors.h"
|
||||
#include "db_wrap.h"
|
||||
#include "librpc/gen_ndr/winreg.h"
|
||||
|
||||
struct ldb_key_data
|
||||
{
|
||||
struct ldb_dn *dn;
|
||||
struct ldb_message **subkeys, **values;
|
||||
int subkey_count, value_count;
|
||||
};
|
||||
|
||||
static int ldb_free_hive (struct registry_hive *hive)
|
||||
{
|
||||
talloc_free(hive->backend_data);
|
||||
hive->backend_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char **name, uint32_t *type, DATA_BLOB *data)
|
||||
{
|
||||
const struct ldb_val *val;
|
||||
*name = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "value", NULL));
|
||||
*type = ldb_msg_find_attr_as_uint(msg, "type", 0);
|
||||
val = ldb_msg_find_ldb_val(msg, "data");
|
||||
|
||||
switch (*type)
|
||||
{
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
data->length = convert_string_talloc(mem_ctx, CH_UTF8, CH_UTF16, val->data, val->length, (void **)&data->data);
|
||||
break;
|
||||
|
||||
case REG_DWORD: {
|
||||
uint32_t tmp = strtoul((char *)val->data, NULL, 0);
|
||||
*data = data_blob_talloc(mem_ctx, &tmp, 4);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*data = data_blob_talloc(mem_ctx, val->data, val->length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, const char *name, uint32_t type, DATA_BLOB data)
|
||||
{
|
||||
struct ldb_val val;
|
||||
struct ldb_message *msg = talloc_zero(mem_ctx, struct ldb_message);
|
||||
char *type_s;
|
||||
|
||||
ldb_msg_add_string(msg, "value", talloc_strdup(mem_ctx, name));
|
||||
|
||||
switch (type) {
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
val.length = convert_string_talloc(mem_ctx, CH_UTF16, CH_UTF8, (void *)data.data, data.length, (void **)&val.data);
|
||||
ldb_msg_add_value(msg, "data", &val, NULL);
|
||||
break;
|
||||
|
||||
case REG_DWORD:
|
||||
ldb_msg_add_string(msg, "data", talloc_asprintf(mem_ctx, "0x%x", IVAL(data.data, 0)));
|
||||
break;
|
||||
default:
|
||||
ldb_msg_add_value(msg, "data", &data, NULL);
|
||||
}
|
||||
|
||||
|
||||
type_s = talloc_asprintf(mem_ctx, "%u", type);
|
||||
ldb_msg_add_string(msg, "type", type_s);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
static int reg_close_ldb_key(struct registry_key *key)
|
||||
{
|
||||
struct ldb_key_data *kd = talloc_get_type(key->backend_data, struct ldb_key_data);
|
||||
/* struct ldb_context *c = key->hive->backend_data; */
|
||||
|
||||
if (kd->subkeys) {
|
||||
talloc_free(kd->subkeys);
|
||||
kd->subkeys = NULL;
|
||||
}
|
||||
|
||||
if (kd->values) {
|
||||
talloc_free(kd->values);
|
||||
kd->values = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ldb_dn *reg_path_to_ldb(TALLOC_CTX *mem_ctx, const struct registry_key *from, const char *path, const char *add)
|
||||
{
|
||||
TALLOC_CTX *local_ctx;
|
||||
struct ldb_dn *ret;
|
||||
char *mypath = talloc_strdup(mem_ctx, path);
|
||||
char *begin;
|
||||
struct ldb_key_data *kd = talloc_get_type(from->backend_data, struct ldb_key_data);
|
||||
struct ldb_context *ldb = talloc_get_type(from->hive->backend_data, struct ldb_context);
|
||||
|
||||
local_ctx = talloc_new(mem_ctx);
|
||||
|
||||
if (add) {
|
||||
ret = ldb_dn_new(mem_ctx, ldb, add);
|
||||
} else {
|
||||
ret = ldb_dn_new(mem_ctx, ldb, NULL);
|
||||
}
|
||||
if ( ! ldb_dn_validate(ret)) {
|
||||
talloc_free(ret);
|
||||
talloc_free(local_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(mypath) {
|
||||
char *keyname;
|
||||
|
||||
begin = strrchr(mypath, '\\');
|
||||
|
||||
if (begin) keyname = begin + 1;
|
||||
else keyname = mypath;
|
||||
|
||||
if(strlen(keyname)) {
|
||||
ldb_dn_add_base_fmt(ret, "key=%s", keyname);
|
||||
}
|
||||
|
||||
if(begin) {
|
||||
*begin = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ldb_dn_add_base(ret, kd->dn);
|
||||
|
||||
talloc_free(local_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_key **subkey)
|
||||
{
|
||||
struct ldb_context *c = talloc_get_type(k->hive->backend_data, struct ldb_context);
|
||||
struct ldb_message_element *el;
|
||||
struct ldb_key_data *kd = talloc_get_type(k->backend_data, struct ldb_key_data);
|
||||
struct ldb_key_data *newkd;
|
||||
|
||||
/* Do a search if necessary */
|
||||
if (kd->subkeys == NULL) {
|
||||
struct ldb_result *res;
|
||||
int ret;
|
||||
|
||||
ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(key=*)", NULL, &res);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(0, ("Error getting subkeys for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
kd->subkey_count = res->count;
|
||||
kd->subkeys = talloc_steal(kd, res->msgs);
|
||||
talloc_free(res);
|
||||
}
|
||||
|
||||
if (idx >= kd->subkey_count) return WERR_NO_MORE_ITEMS;
|
||||
|
||||
el = ldb_msg_find_element(kd->subkeys[idx], "key");
|
||||
|
||||
*subkey = talloc(mem_ctx, struct registry_key);
|
||||
talloc_set_destructor(*subkey, reg_close_ldb_key);
|
||||
(*subkey)->name = talloc_strdup(mem_ctx, (char *)el->values[0].data);
|
||||
(*subkey)->backend_data = newkd = talloc_zero(*subkey, struct ldb_key_data);
|
||||
(*subkey)->last_mod = 0; /* TODO: we need to add this to the
|
||||
ldb backend properly */
|
||||
newkd->dn = ldb_dn_copy(mem_ctx, kd->subkeys[idx]->dn);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_value **value)
|
||||
{
|
||||
struct ldb_context *c = talloc_get_type(k->hive->backend_data, struct ldb_context);
|
||||
struct ldb_key_data *kd = talloc_get_type(k->backend_data, struct ldb_key_data);
|
||||
|
||||
/* Do the search if necessary */
|
||||
if (kd->values == NULL) {
|
||||
struct ldb_result *res;
|
||||
int ret;
|
||||
|
||||
ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(value=*)", NULL, &res);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(0, ("Error getting values for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
kd->value_count = res->count;
|
||||
kd->values = talloc_steal(kd, res->msgs);
|
||||
talloc_free(res);
|
||||
}
|
||||
|
||||
if(idx >= kd->value_count) return WERR_NO_MORE_ITEMS;
|
||||
|
||||
*value = talloc(mem_ctx, struct registry_value);
|
||||
|
||||
reg_ldb_unpack_value(mem_ctx, kd->values[idx], &(*value)->name, &(*value)->data_type, &(*value)->data);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *h, const char *name, struct registry_key **key)
|
||||
{
|
||||
struct ldb_context *c = talloc_get_type(h->hive->backend_data, struct ldb_context);
|
||||
struct ldb_result *res;
|
||||
struct ldb_dn *ldap_path;
|
||||
int ret;
|
||||
struct ldb_key_data *newkd;
|
||||
|
||||
ldap_path = reg_path_to_ldb(mem_ctx, h, name, NULL);
|
||||
|
||||
ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL, &res);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(0, ("Error opening key '%s': %s\n", ldb_dn_get_linearized(ldap_path), ldb_errstring(c)));
|
||||
return WERR_FOOBAR;
|
||||
} else if (res->count == 0) {
|
||||
talloc_free(res);
|
||||
return WERR_BADFILE;
|
||||
}
|
||||
|
||||
*key = talloc(mem_ctx, struct registry_key);
|
||||
talloc_set_destructor(*key, reg_close_ldb_key);
|
||||
(*key)->name = talloc_strdup(mem_ctx, strrchr(name, '\\')?strchr(name, '\\'):name);
|
||||
(*key)->backend_data = newkd = talloc_zero(*key, struct ldb_key_data);
|
||||
newkd->dn = ldb_dn_copy(mem_ctx, res->msgs[0]->dn);
|
||||
|
||||
talloc_free(res);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_open_hive(struct registry_hive *hive, struct registry_key **k)
|
||||
{
|
||||
struct ldb_key_data *kd;
|
||||
struct ldb_context *wrap;
|
||||
|
||||
if (!hive->location) return WERR_INVALID_PARAM;
|
||||
|
||||
wrap = ldb_wrap_connect(hive, hive->location, hive->session_info, hive->credentials, 0, NULL);
|
||||
|
||||
if(!wrap) {
|
||||
DEBUG(1, ("ldb_open_hive: unable to connect\n"));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
ldb_set_debug_stderr(wrap);
|
||||
hive->backend_data = wrap;
|
||||
|
||||
*k = talloc_zero(hive, struct registry_key);
|
||||
talloc_set_destructor (*k, reg_close_ldb_key);
|
||||
talloc_set_destructor (hive, ldb_free_hive);
|
||||
(*k)->name = talloc_strdup(*k, "");
|
||||
(*k)->backend_data = kd = talloc_zero(*k, struct ldb_key_data);
|
||||
kd->dn = ldb_dn_new(*k, wrap, "hive=NONE");
|
||||
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_add_key (TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sd, struct registry_key **newkey)
|
||||
{
|
||||
struct ldb_context *ctx = talloc_get_type(parent->hive->backend_data, struct ldb_context);
|
||||
struct ldb_message *msg;
|
||||
struct ldb_key_data *newkd;
|
||||
int ret;
|
||||
|
||||
msg = ldb_msg_new(mem_ctx);
|
||||
|
||||
msg->dn = reg_path_to_ldb(msg, parent, name, NULL);
|
||||
|
||||
ldb_msg_add_string(msg, "key", talloc_strdup(mem_ctx, name));
|
||||
|
||||
ret = ldb_add(ctx, msg);
|
||||
if (ret < 0) {
|
||||
DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(ctx)));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
*newkey = talloc_zero(mem_ctx, struct registry_key);
|
||||
(*newkey)->name = talloc_strdup(mem_ctx, name);
|
||||
|
||||
(*newkey)->backend_data = newkd = talloc_zero(*newkey, struct ldb_key_data);
|
||||
newkd->dn = talloc_steal(newkd, msg->dn);
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_del_key (const struct registry_key *key, const char *child)
|
||||
{
|
||||
struct ldb_context *ctx = talloc_get_type(key->hive->backend_data, struct ldb_context);
|
||||
int ret;
|
||||
struct ldb_key_data *kd = talloc_get_type(key->backend_data, struct ldb_key_data);
|
||||
struct ldb_dn *childdn;
|
||||
|
||||
childdn = ldb_dn_copy(ctx, kd->dn);
|
||||
ldb_dn_add_child_fmt(childdn, "key=%s", child);
|
||||
|
||||
ret = ldb_delete(ctx, childdn);
|
||||
|
||||
talloc_free(childdn);
|
||||
|
||||
if (ret < 0) {
|
||||
DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(ctx)));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_del_value (const struct registry_key *key, const char *child)
|
||||
{
|
||||
int ret;
|
||||
struct ldb_context *ctx = talloc_get_type(key->hive->backend_data, struct ldb_context);
|
||||
struct ldb_key_data *kd = talloc_get_type(key->backend_data, struct ldb_key_data);
|
||||
struct ldb_dn *childdn;
|
||||
|
||||
childdn = ldb_dn_copy(ctx, kd->dn);
|
||||
ldb_dn_add_child_fmt(childdn, "value=%s", child);
|
||||
|
||||
ret = ldb_delete(ctx, childdn);
|
||||
|
||||
talloc_free(childdn);
|
||||
|
||||
if (ret < 0) {
|
||||
DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(ctx)));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR ldb_set_value (const struct registry_key *parent, const char *name, uint32_t type, DATA_BLOB data)
|
||||
{
|
||||
struct ldb_context *ctx = talloc_get_type(parent->hive->backend_data, struct ldb_context);
|
||||
struct ldb_message *msg;
|
||||
struct ldb_key_data *kd = talloc_get_type(parent->backend_data, struct ldb_key_data);
|
||||
int ret;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("ldb_set_value");
|
||||
|
||||
msg = reg_ldb_pack_value(ctx, mem_ctx, name, type, data);
|
||||
|
||||
msg->dn = ldb_dn_copy(msg, kd->dn);
|
||||
ldb_dn_add_child_fmt(msg->dn, "value=%s", name);
|
||||
|
||||
ret = ldb_add(ctx, msg);
|
||||
if (ret < 0) {
|
||||
ret = ldb_modify(ctx, msg);
|
||||
if (ret < 0) {
|
||||
DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(ctx)));
|
||||
talloc_free(mem_ctx);
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static struct hive_operations reg_backend_ldb = {
|
||||
.name = "ldb",
|
||||
.add_key = ldb_add_key,
|
||||
.del_key = ldb_del_key,
|
||||
.open_hive = ldb_open_hive,
|
||||
.open_key = ldb_open_key,
|
||||
.get_value_by_index = ldb_get_value_by_id,
|
||||
.get_subkey_by_index = ldb_get_subkey_by_id,
|
||||
.set_value = ldb_set_value,
|
||||
.del_value = ldb_del_value,
|
||||
};
|
||||
|
||||
NTSTATUS registry_ldb_init(void)
|
||||
{
|
||||
return registry_register(®_backend_ldb);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB implementation
|
||||
RPC backend for the registry library
|
||||
Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "registry.h"
|
||||
#include "librpc/gen_ndr/ndr_winreg_c.h"
|
||||
|
||||
static struct hive_operations reg_backend_rpc;
|
||||
|
||||
/**
|
||||
* This is the RPC backend for the registry library.
|
||||
*/
|
||||
|
||||
static void init_winreg_String(struct winreg_String *name, const char *s)
|
||||
{
|
||||
name->name = s;
|
||||
}
|
||||
|
||||
|
||||
#define openhive(u) static WERROR open_ ## u(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *hnd) \
|
||||
{ \
|
||||
struct winreg_Open ## u r; \
|
||||
NTSTATUS status; \
|
||||
\
|
||||
r.in.system_name = NULL; \
|
||||
r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; \
|
||||
r.out.handle = hnd;\
|
||||
\
|
||||
status = dcerpc_winreg_Open ## u(p, mem_ctx, &r); \
|
||||
if (NT_STATUS_IS_ERR(status)) {\
|
||||
DEBUG(0,("Error executing open\n"));\
|
||||
return ntstatus_to_werror(status);\
|
||||
}\
|
||||
\
|
||||
return r.out.result;\
|
||||
}
|
||||
|
||||
openhive(HKLM)
|
||||
openhive(HKCU)
|
||||
openhive(HKPD)
|
||||
openhive(HKU)
|
||||
openhive(HKCR)
|
||||
openhive(HKDD)
|
||||
openhive(HKCC)
|
||||
|
||||
struct rpc_key_data {
|
||||
struct policy_handle pol;
|
||||
int num_subkeys;
|
||||
int num_values;
|
||||
int max_valnamelen;
|
||||
int max_valdatalen;
|
||||
};
|
||||
|
||||
static struct {
|
||||
uint32_t hkey;
|
||||
WERROR (*open) (struct dcerpc_pipe *p, TALLOC_CTX *, struct policy_handle *h);
|
||||
} known_hives[] = {
|
||||
{ HKEY_LOCAL_MACHINE, open_HKLM },
|
||||
{ HKEY_CURRENT_USER, open_HKCU },
|
||||
{ HKEY_CLASSES_ROOT, open_HKCR },
|
||||
{ HKEY_PERFORMANCE_DATA, open_HKPD },
|
||||
{ HKEY_USERS, open_HKU },
|
||||
{ HKEY_DYN_DATA, open_HKDD },
|
||||
{ HKEY_CURRENT_CONFIG, open_HKCC },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static WERROR rpc_query_key(const struct registry_key *k);
|
||||
|
||||
static WERROR rpc_get_predefined_key (struct registry_context *ctx, uint32_t hkey_type, struct registry_key **k)
|
||||
{
|
||||
int n;
|
||||
struct registry_hive *h;
|
||||
struct rpc_key_data *mykeydata;
|
||||
|
||||
for(n = 0; known_hives[n].hkey; n++)
|
||||
{
|
||||
if(known_hives[n].hkey == hkey_type) break;
|
||||
}
|
||||
|
||||
if(!known_hives[n].open) {
|
||||
DEBUG(1, ("No such hive %d\n", hkey_type));
|
||||
return WERR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
h = talloc(ctx, struct registry_hive);
|
||||
h->functions = ®_backend_rpc;
|
||||
h->location = NULL;
|
||||
h->backend_data = ctx->backend_data;
|
||||
|
||||
(*k) = h->root = talloc(h, struct registry_key);
|
||||
(*k)->hive = h;
|
||||
(*k)->backend_data = mykeydata = talloc(*k, struct rpc_key_data);
|
||||
mykeydata->num_values = -1;
|
||||
mykeydata->num_subkeys = -1;
|
||||
return known_hives[n].open((struct dcerpc_pipe *)ctx->backend_data, *k, &(mykeydata->pol));
|
||||
}
|
||||
|
||||
#if 0
|
||||
static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k)
|
||||
{
|
||||
struct winreg_OpenKey r;
|
||||
struct rpc_key_data *mykeydata;
|
||||
|
||||
k->backend_data = mykeydata = talloc(mem_ctx, struct rpc_key_data);
|
||||
mykeydata->num_values = -1;
|
||||
mykeydata->num_subkeys = -1;
|
||||
|
||||
/* Then, open the handle using the hive */
|
||||
|
||||
memset(&r, 0, sizeof(struct winreg_OpenKey));
|
||||
r.in.handle = &(((struct rpc_key_data *)k->hive->root->backend_data)->pol);
|
||||
init_winreg_String(&r.in.keyname, k->path);
|
||||
r.in.unknown = 0x00000000;
|
||||
r.in.access_mask = 0x02000000;
|
||||
r.out.handle = &mykeydata->pol;
|
||||
|
||||
dcerpc_winreg_OpenKey((struct dcerpc_pipe *)k->hive->backend_data, mem_ctx, &r);
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *h, const char *name, struct registry_key **key)
|
||||
{
|
||||
struct rpc_key_data *mykeydata;
|
||||
struct winreg_OpenKey r;
|
||||
|
||||
*key = talloc(mem_ctx, struct registry_key);
|
||||
(*key)->name = talloc_strdup(mem_ctx, name);
|
||||
|
||||
(*key)->backend_data = mykeydata = talloc(mem_ctx, struct rpc_key_data);
|
||||
mykeydata->num_values = -1;
|
||||
mykeydata->num_subkeys = -1;
|
||||
|
||||
/* Then, open the handle using the hive */
|
||||
|
||||
memset(&r, 0, sizeof(struct winreg_OpenKey));
|
||||
r.in.parent_handle = &(((struct rpc_key_data *)h->backend_data)->pol);
|
||||
init_winreg_String(&r.in.keyname, name);
|
||||
r.in.unknown = 0x00000000;
|
||||
r.in.access_mask = 0x02000000;
|
||||
r.out.handle = &mykeydata->pol;
|
||||
|
||||
dcerpc_winreg_OpenKey((struct dcerpc_pipe *)(h->hive->backend_data), mem_ctx, &r);
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
|
||||
static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_value **value)
|
||||
{
|
||||
struct rpc_key_data *mykeydata = parent->backend_data;
|
||||
WERROR error;
|
||||
struct winreg_EnumValue r;
|
||||
uint32_t len1, zero = 0;
|
||||
enum winreg_Type type;
|
||||
NTSTATUS status;
|
||||
struct winreg_StringBuf name;
|
||||
uint8_t u8;
|
||||
|
||||
if(mykeydata->num_values == -1) {
|
||||
error = rpc_query_key(parent);
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
}
|
||||
|
||||
len1 = mykeydata->max_valdatalen;
|
||||
|
||||
name.length = 0;
|
||||
name.size = mykeydata->max_valnamelen * 2;
|
||||
name.name = "";
|
||||
|
||||
r.in.handle = &mykeydata->pol;
|
||||
r.in.enum_index = n;
|
||||
r.in.name = &name;
|
||||
r.in.type = &type;
|
||||
r.in.value = &u8;
|
||||
r.in.length = &zero;
|
||||
r.in.size = &len1;
|
||||
r.out.name = &name;
|
||||
|
||||
status = dcerpc_winreg_EnumValue((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
|
||||
if(NT_STATUS_IS_ERR(status)) {
|
||||
DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status)));
|
||||
return WERR_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
if(NT_STATUS_IS_OK(status) &&
|
||||
W_ERROR_IS_OK(r.out.result) && r.out.length) {
|
||||
*value = talloc(mem_ctx, struct registry_value);
|
||||
(*value)->name = talloc_strdup(mem_ctx, r.out.name->name);
|
||||
(*value)->data_type = type;
|
||||
(*value)->data = data_blob_talloc(mem_ctx, r.out.value, *r.out.length);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
|
||||
static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_key **subkey)
|
||||
{
|
||||
struct winreg_EnumKey r;
|
||||
struct rpc_key_data *mykeydata = parent->backend_data;
|
||||
NTSTATUS status;
|
||||
struct winreg_StringBuf namebuf, classbuf;
|
||||
NTTIME change_time = 0;
|
||||
|
||||
namebuf.length = 0;
|
||||
namebuf.size = 1024;
|
||||
namebuf.name = NULL;
|
||||
classbuf.length = 0;
|
||||
classbuf.size = 0;
|
||||
classbuf.name = NULL;
|
||||
|
||||
r.in.handle = &mykeydata->pol;
|
||||
r.in.enum_index = n;
|
||||
r.in.name = &namebuf;
|
||||
r.in.keyclass = &classbuf;
|
||||
r.in.last_changed_time = &change_time;
|
||||
r.out.name = &namebuf;
|
||||
|
||||
status = dcerpc_winreg_EnumKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
|
||||
if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
|
||||
char *name = talloc_strdup(mem_ctx, r.out.name->name);
|
||||
return rpc_open_key(mem_ctx, parent, name, subkey);
|
||||
}
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
|
||||
static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec, struct registry_key **key)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct winreg_CreateKey r;
|
||||
|
||||
init_winreg_String(&r.in.name, name);
|
||||
init_winreg_String(&r.in.keyclass, NULL);
|
||||
|
||||
r.in.handle = parent->backend_data;
|
||||
r.out.new_handle = talloc(mem_ctx, struct policy_handle);
|
||||
r.in.options = 0;
|
||||
r.in.access_mask = access_mask;
|
||||
r.in.secdesc = NULL;
|
||||
|
||||
status = dcerpc_winreg_CreateKey((struct dcerpc_pipe *)(parent->hive->backend_data), mem_ctx, &r);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("CreateKey failed - %s\n", nt_errstr(status)));
|
||||
return ntstatus_to_werror(status);
|
||||
}
|
||||
|
||||
if (W_ERROR_IS_OK(r.out.result)) {
|
||||
*key = talloc(mem_ctx, struct registry_key);
|
||||
(*key)->name = talloc_strdup(*key, name);
|
||||
(*key)->backend_data = r.out.new_handle;
|
||||
}
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
|
||||
static WERROR rpc_query_key(const struct registry_key *k)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct winreg_QueryInfoKey r;
|
||||
struct rpc_key_data *mykeydata = k->backend_data;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("query_key");
|
||||
|
||||
init_winreg_String(&r.in.class_in, NULL);
|
||||
r.in.handle = &mykeydata->pol;
|
||||
|
||||
status = dcerpc_winreg_QueryInfoKey((struct dcerpc_pipe *)(k->hive->backend_data), mem_ctx, &r);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1, ("QueryInfoKey failed - %s\n", nt_errstr(status)));
|
||||
return ntstatus_to_werror(status);
|
||||
}
|
||||
|
||||
if (W_ERROR_IS_OK(r.out.result)) {
|
||||
mykeydata->num_subkeys = *r.out.num_subkeys;
|
||||
mykeydata->num_values = *r.out.num_values;
|
||||
mykeydata->max_valnamelen = *r.out.max_valnamelen;
|
||||
mykeydata->max_valdatalen = *r.out.max_valbufsize;
|
||||
}
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
|
||||
static WERROR rpc_del_key(const struct registry_key *parent, const char *name)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct rpc_key_data *mykeydata = parent->backend_data;
|
||||
struct winreg_DeleteKey r;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("del_key");
|
||||
|
||||
r.in.handle = &mykeydata->pol;
|
||||
init_winreg_String(&r.in.key, name);
|
||||
|
||||
status = dcerpc_winreg_DeleteKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return r.out.result;
|
||||
}
|
||||
|
||||
static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count)
|
||||
{
|
||||
struct rpc_key_data *mykeydata = key->backend_data;
|
||||
WERROR error;
|
||||
|
||||
if(mykeydata->num_values == -1) {
|
||||
error = rpc_query_key(key);
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
}
|
||||
|
||||
*count = mykeydata->num_values;
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR rpc_num_subkeys(const struct registry_key *key, uint32_t *count)
|
||||
{
|
||||
struct rpc_key_data *mykeydata = key->backend_data;
|
||||
WERROR error;
|
||||
|
||||
if(mykeydata->num_subkeys == -1) {
|
||||
error = rpc_query_key(key);
|
||||
if(!W_ERROR_IS_OK(error)) return error;
|
||||
}
|
||||
|
||||
*count = mykeydata->num_subkeys;
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static struct hive_operations reg_backend_rpc = {
|
||||
.name = "rpc",
|
||||
.open_key = rpc_open_key,
|
||||
.get_subkey_by_index = rpc_get_subkey_by_index,
|
||||
.get_value_by_index = rpc_get_value_by_index,
|
||||
.add_key = rpc_add_key,
|
||||
.del_key = rpc_del_key,
|
||||
.num_subkeys = rpc_num_subkeys,
|
||||
.num_values = rpc_num_values,
|
||||
};
|
||||
|
||||
_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_session_info *session_info, struct cli_credentials *credentials,
|
||||
const char *location, struct event_context *ev)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct dcerpc_pipe *p;
|
||||
|
||||
*ctx = talloc(NULL, struct registry_context);
|
||||
|
||||
/* Default to local smbd if no connection is specified */
|
||||
if (!location) {
|
||||
location = talloc_strdup(ctx, "ncalrpc:");
|
||||
}
|
||||
|
||||
status = dcerpc_pipe_connect(*ctx /* TALLOC_CTX */,
|
||||
&p, location,
|
||||
&dcerpc_table_winreg,
|
||||
credentials, ev);
|
||||
(*ctx)->backend_data = p;
|
||||
|
||||
if(NT_STATUS_IS_ERR(status)) {
|
||||
DEBUG(1, ("Unable to open '%s': %s\n", location, nt_errstr(status)));
|
||||
talloc_free(*ctx);
|
||||
*ctx = NULL;
|
||||
return ntstatus_to_werror(status);
|
||||
}
|
||||
|
||||
(*ctx)->get_predefined_key = rpc_get_predefined_key;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
NTSTATUS registry_rpc_init(void)
|
||||
{
|
||||
dcerpc_init();
|
||||
return registry_register(®_backend_rpc);
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client utility libeditreg.c
|
||||
Copyright (C) 2004 Jelmer Vernooij, jelmer@samba.org
|
||||
|
||||
Backend for Windows '95 registry files. Explanation of file format
|
||||
comes from http://www.cs.mun.ca/~michael/regutils/.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "registry.h"
|
||||
#include "system/filesys.h"
|
||||
#include "system/shmem.h"
|
||||
|
||||
/**
|
||||
* The registry starts with a header that contains pointers to
|
||||
* the rgdb.
|
||||
*
|
||||
* After the main header follows the RGKN header (key index table).
|
||||
* The RGKN keys are listed after each other. They are put into
|
||||
* blocks, the first having a length of 0x2000 bytes, the others
|
||||
* being 0x1000 bytes long.
|
||||
*
|
||||
* After the RGKN header follow one or more RGDB blocks. These blocks
|
||||
* contain keys. A key is followed by its name and its values.
|
||||
*
|
||||
* Values are followed by their name and then their data.
|
||||
*
|
||||
* Basically the idea is that the RGKN contains the associations between
|
||||
* the keys and the RGDB contains the actual data.
|
||||
*/
|
||||
|
||||
typedef uint32_t DWORD;
|
||||
typedef unsigned short WORD;
|
||||
|
||||
typedef struct creg_block {
|
||||
DWORD CREG_ID; /* CREG */
|
||||
DWORD uk1;
|
||||
DWORD rgdb_offset;
|
||||
DWORD chksum;
|
||||
WORD num_rgdb;
|
||||
WORD flags;
|
||||
DWORD uk2;
|
||||
DWORD uk3;
|
||||
DWORD uk4;
|
||||
} CREG_HDR;
|
||||
|
||||
typedef struct rgkn_block {
|
||||
DWORD RGKN_ID; /* RGKN */
|
||||
DWORD size;
|
||||
DWORD root_offset;
|
||||
DWORD free_offset;
|
||||
DWORD flags;
|
||||
DWORD chksum;
|
||||
DWORD uk1;
|
||||
DWORD uk2;
|
||||
} RGKN_HDR;
|
||||
|
||||
typedef struct reg_id {
|
||||
WORD id;
|
||||
WORD rgdb;
|
||||
} REG_ID;
|
||||
|
||||
typedef struct rgkn_key {
|
||||
DWORD type; /* 0x00000000 = normal key, 0x80000000 = free block */
|
||||
DWORD hash; /* Contains either hash or size of free blocks that follows */
|
||||
DWORD next_free;
|
||||
DWORD parent_offset;
|
||||
DWORD first_child_offset;
|
||||
DWORD next_offset;
|
||||
REG_ID id;
|
||||
} RGKN_KEY;
|
||||
|
||||
|
||||
typedef struct rgdb_block {
|
||||
DWORD RGDB_ID; /* RGDB */
|
||||
DWORD size;
|
||||
DWORD unused_size;
|
||||
WORD flags;
|
||||
WORD section;
|
||||
DWORD free_offset; /* -1 if there is no free space */
|
||||
WORD max_id;
|
||||
WORD first_free_id;
|
||||
DWORD uk1;
|
||||
DWORD chksum;
|
||||
} RGDB_HDR;
|
||||
|
||||
typedef struct rgdb_key {
|
||||
DWORD size;
|
||||
REG_ID id;
|
||||
DWORD used_size;
|
||||
WORD name_len;
|
||||
WORD num_values;
|
||||
DWORD uk1;
|
||||
} RGDB_KEY;
|
||||
|
||||
typedef struct rgdb_value {
|
||||
DWORD type;
|
||||
DWORD uk1;
|
||||
WORD name_len;
|
||||
WORD data_len;
|
||||
} RGDB_VALUE;
|
||||
|
||||
typedef struct creg_struct_s {
|
||||
int fd;
|
||||
BOOL modified;
|
||||
char *base;
|
||||
struct stat sbuf;
|
||||
CREG_HDR *creg_hdr;
|
||||
RGKN_HDR *rgkn_hdr;
|
||||
RGDB_KEY ***rgdb_keys;
|
||||
} CREG;
|
||||
|
||||
#if 0 /* unused */
|
||||
#define RGKN_START_SIZE 0x2000
|
||||
#define RGKN_INC_SIZE 0x1000
|
||||
#endif
|
||||
|
||||
#define LOCN_RGKN(creg, o) ((RGKN_KEY *)((creg)->base + sizeof(CREG_HDR) + o))
|
||||
#define LOCN_RGDB_BLOCK(creg, o) (((creg)->base + (creg)->creg_hdr->rgdb_offset + o))
|
||||
#define LOCN_RGDB_KEY(creg, rgdb, id) ((RGDB_KEY *)((creg)->rgdb_keys[(rgdb)][(id)]))
|
||||
|
||||
static DWORD str_to_dword(const char *a) {
|
||||
int i;
|
||||
unsigned long ret = 0;
|
||||
for(i = strlen(a)-1; i >= 0; i--) {
|
||||
ret = ret * 0x100 + a[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
|
||||
static DWORD calc_hash(const char *str) {
|
||||
DWORD ret = 0;
|
||||
int i;
|
||||
for(i = 0; str[i] && str[i] != '\\'; i++) {
|
||||
ret+=toupper(str[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void parse_rgkn_block(CREG *creg, off_t start_off, off_t end_off)
|
||||
{
|
||||
off_t i;
|
||||
for(i = start_off; end_off - i > sizeof(RGKN_KEY); i+= sizeof(RGKN_KEY)) {
|
||||
RGKN_KEY *key = (RGKN_KEY *)LOCN_RGKN(creg, i);
|
||||
if(key->type == 0) {
|
||||
DEBUG(4,("Regular, id: %d, %d, parent: %x, firstchild: %x, next: %x hash: %lX\n", key->id.id, key->id.rgdb, key->parent_offset, key->first_child_offset, key->next_offset, (long)key->hash));
|
||||
} else if(key->type == 0x80000000) {
|
||||
DEBUG(3,("free\n"));
|
||||
i += key->hash;
|
||||
} else {
|
||||
DEBUG(0,("Invalid key type in RGKN: %0X\n", key->type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void parse_rgdb_block(CREG *creg, RGDB_HDR *rgdb_hdr)
|
||||
{
|
||||
DWORD used_size = rgdb_hdr->size - rgdb_hdr->unused_size;
|
||||
DWORD offset = 0;
|
||||
|
||||
while(offset < used_size) {
|
||||
RGDB_KEY *key = (RGDB_KEY *)(((char *)rgdb_hdr) + sizeof(RGDB_HDR) + offset);
|
||||
|
||||
if(!(key->id.id == 0xFFFF && key->id.rgdb == 0xFFFF))creg->rgdb_keys[key->id.rgdb][key->id.id] = key;
|
||||
offset += key->size;
|
||||
}
|
||||
}
|
||||
|
||||
static WERROR w95_open_reg (struct registry_hive *h, struct registry_key **root)
|
||||
{
|
||||
CREG *creg;
|
||||
DWORD creg_id, rgkn_id;
|
||||
DWORD i;
|
||||
DWORD offset;
|
||||
|
||||
creg = talloc(h, CREG);
|
||||
memset(creg, 0, sizeof(CREG));
|
||||
h->backend_data = creg;
|
||||
|
||||
if((creg->fd = open(h->location, O_RDONLY, 0000)) < 0) {
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
if (fstat(creg->fd, &creg->sbuf) < 0) {
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
creg->base = mmap(0, creg->sbuf.st_size, PROT_READ, MAP_SHARED, creg->fd, 0);
|
||||
|
||||
if (creg->base == (void *)-1) {
|
||||
DEBUG(0,("Could not mmap file: %s, %s\n", h->location, strerror(errno)));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
creg->creg_hdr = (CREG_HDR *)creg->base;
|
||||
|
||||
if ((creg_id = IVAL(&creg->creg_hdr->CREG_ID,0)) != str_to_dword("CREG")) {
|
||||
DEBUG(0, ("Unrecognized Windows 95 registry header id: 0x%0X, %s\n",
|
||||
creg_id, h->location));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
creg->rgkn_hdr = (RGKN_HDR *)LOCN_RGKN(creg, 0);
|
||||
|
||||
if ((rgkn_id = IVAL(&creg->rgkn_hdr->RGKN_ID,0)) != str_to_dword("RGKN")) {
|
||||
DEBUG(0, ("Unrecognized Windows 95 registry key index id: 0x%0X, %s\n",
|
||||
rgkn_id, h->location));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* If'ed out because we only need to parse this stuff when allocating new
|
||||
* entries (which we don't do at the moment */
|
||||
/* First parse the 0x2000 long block */
|
||||
parse_rgkn_block(creg, sizeof(RGKN_HDR), 0x2000);
|
||||
|
||||
/* Then parse the other 0x1000 length blocks */
|
||||
for(offset = 0x2000; offset < creg->rgkn_hdr->size; offset+=0x1000) {
|
||||
parse_rgkn_block(creg, offset, offset+0x1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
creg->rgdb_keys = talloc_array(h, RGDB_KEY **, creg->creg_hdr->num_rgdb);
|
||||
|
||||
offset = 0;
|
||||
DEBUG(3, ("Reading %d rgdb entries\n", creg->creg_hdr->num_rgdb));
|
||||
for(i = 0; i < creg->creg_hdr->num_rgdb; i++) {
|
||||
RGDB_HDR *rgdb_hdr = (RGDB_HDR *)LOCN_RGDB_BLOCK(creg, offset);
|
||||
|
||||
if(strncmp((char *)&(rgdb_hdr->RGDB_ID), "RGDB", 4)) {
|
||||
DEBUG(0, ("unrecognized rgdb entry: %4d, %s\n",
|
||||
rgdb_hdr->RGDB_ID, h->location));
|
||||
return WERR_FOOBAR;
|
||||
} else {
|
||||
DEBUG(3, ("Valid rgdb entry, first free id: %d, max id: %d\n", rgdb_hdr->first_free_id, rgdb_hdr->max_id));
|
||||
}
|
||||
|
||||
|
||||
creg->rgdb_keys[i] = talloc_array(h, RGDB_KEY *, rgdb_hdr->max_id+1);
|
||||
memset(creg->rgdb_keys[i], 0, sizeof(RGDB_KEY *) * (rgdb_hdr->max_id+1));
|
||||
|
||||
parse_rgdb_block(creg, rgdb_hdr);
|
||||
|
||||
offset+=rgdb_hdr->size;
|
||||
}
|
||||
|
||||
/* First element in rgkn should be root key */
|
||||
*root = talloc(h, struct registry_key);
|
||||
(*root)->name = NULL;
|
||||
(*root)->backend_data = LOCN_RGKN(creg, sizeof(RGKN_HDR));
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR w95_get_subkey_by_index (TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_key **key)
|
||||
{
|
||||
CREG *creg = parent->hive->backend_data;
|
||||
RGKN_KEY *rgkn_key = parent->backend_data;
|
||||
RGKN_KEY *child;
|
||||
DWORD child_offset;
|
||||
DWORD cur = 0;
|
||||
|
||||
/* Get id of first child */
|
||||
child_offset = rgkn_key->first_child_offset;
|
||||
|
||||
while(child_offset != 0xFFFFFFFF) {
|
||||
child = LOCN_RGKN(creg, child_offset);
|
||||
|
||||
/* n == cur ? return! */
|
||||
if(cur == n) {
|
||||
RGDB_KEY *rgdb_key;
|
||||
rgdb_key = LOCN_RGDB_KEY(creg, child->id.rgdb, child->id.id);
|
||||
if(!rgdb_key) {
|
||||
DEBUG(0, ("Can't find %d,%d in RGDB table!\n", child->id.rgdb, child->id.id));
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
*key = talloc(mem_ctx, struct registry_key);
|
||||
(*key)->backend_data = child;
|
||||
(*key)->name = talloc_strndup(mem_ctx, (char *)rgdb_key + sizeof(RGDB_KEY), rgdb_key->name_len);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
cur++;
|
||||
|
||||
child_offset = child->next_offset;
|
||||
}
|
||||
|
||||
return WERR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
static WERROR w95_num_values(const struct registry_key *k, uint32_t *count)
|
||||
{
|
||||
RGKN_KEY *rgkn_key = k->backend_data;
|
||||
RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
|
||||
|
||||
if(!rgdb_key) return WERR_FOOBAR;
|
||||
|
||||
*count = rgdb_key->num_values;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR w95_get_value_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_value **value)
|
||||
{
|
||||
RGKN_KEY *rgkn_key = k->backend_data;
|
||||
DWORD i;
|
||||
DWORD offset = 0;
|
||||
RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
|
||||
RGDB_VALUE *curval = NULL;
|
||||
|
||||
if(!rgdb_key) return WERR_FOOBAR;
|
||||
|
||||
if(idx >= rgdb_key->num_values) return WERR_NO_MORE_ITEMS;
|
||||
|
||||
for(i = 0; i < idx; i++) {
|
||||
curval = (RGDB_VALUE *)(((char *)rgdb_key) + sizeof(RGDB_KEY) + rgdb_key->name_len + offset);
|
||||
offset+=sizeof(RGDB_VALUE) + curval->name_len + curval->data_len;
|
||||
}
|
||||
|
||||
*value = talloc(mem_ctx, struct registry_value);
|
||||
(*value)->name = talloc_strndup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE), curval->name_len);
|
||||
|
||||
(*value)->data = data_blob_talloc(mem_ctx, curval+sizeof(RGDB_VALUE)+curval->name_len, curval->data_len);
|
||||
(*value)->data_type = curval->type;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static struct hive_operations reg_backend_w95 = {
|
||||
.name = "w95",
|
||||
.open_hive = w95_open_reg,
|
||||
.get_value_by_index = w95_get_value_by_id,
|
||||
.num_values = w95_num_values,
|
||||
.get_subkey_by_index = w95_get_subkey_by_index,
|
||||
};
|
||||
|
||||
NTSTATUS registry_w95_init(void)
|
||||
{
|
||||
return registry_register(®_backend_w95);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Registry interface
|
||||
Copyright (C) Jelmer Vernooij 2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/registry/common/registry.h"
|
||||
#include "windows/registry.h"
|
||||
|
||||
static WERROR wine_open_reg (struct registry_hive *h, struct registry_key **key)
|
||||
{
|
||||
/* FIXME: Open h->location and mmap it */
|
||||
}
|
||||
|
||||
|
||||
|
||||
static REG_OPS reg_backend_wine = {
|
||||
.name = "wine",
|
||||
.open_hive = wine_open_reg,
|
||||
|
||||
};
|
||||
|
||||
NTSTATUS registry_wine_init(void)
|
||||
{
|
||||
register_backend("registry", ®_backend_wine);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
WERROR reg_open_wine(struct registry_key **ctx)
|
||||
{
|
||||
/* FIXME: Open ~/.wine/system.reg, etc */
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Copyright (C) Jelmer Vernooij 2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "registry.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Samba-specific registry functions
|
||||
*/
|
||||
|
||||
static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey, struct registry_key **k)
|
||||
{
|
||||
WERROR error;
|
||||
const char *conf;
|
||||
char *backend;
|
||||
const char *location;
|
||||
const char *hivename = reg_get_predef_name(hkey);
|
||||
|
||||
*k = NULL;
|
||||
|
||||
conf = lp_parm_string(-1, "registry", hivename);
|
||||
|
||||
if (!conf) {
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
location = strchr(conf, ':');
|
||||
if (location) {
|
||||
backend = talloc_strndup(ctx, conf, (int)(location - conf));
|
||||
location++;
|
||||
} else {
|
||||
backend = talloc_strdup(ctx, "ldb");
|
||||
location = conf;
|
||||
}
|
||||
|
||||
/* FIXME: Different hive backend for HKEY_CLASSES_ROOT: merged view of HKEY_LOCAL_MACHINE\Software\Classes
|
||||
* and HKEY_CURRENT_USER\Software\Classes */
|
||||
|
||||
/* FIXME: HKEY_CURRENT_CONFIG is an alias for HKEY_LOCAL_MACHINE\System\CurrentControlSet\Hardware Profiles\Current */
|
||||
|
||||
/* FIXME: HKEY_PERFORMANCE_DATA is dynamically generated */
|
||||
|
||||
/* FIXME: HKEY_LOCAL_MACHINE\Hardware is autogenerated */
|
||||
|
||||
/* FIXME: HKEY_LOCAL_MACHINE\Security\SAM is an alias for HKEY_LOCAL_MACHINE\SAM */
|
||||
|
||||
error = reg_open_hive(ctx, backend, location, ctx->session_info, ctx->credentials, k);
|
||||
|
||||
talloc_free(backend);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_PUBLIC_ WERROR reg_open_local (TALLOC_CTX *mem_ctx,
|
||||
struct registry_context **ctx,
|
||||
struct auth_session_info *session_info,
|
||||
struct cli_credentials *credentials)
|
||||
{
|
||||
*ctx = talloc(mem_ctx, struct registry_context);
|
||||
(*ctx)->credentials = talloc_reference(*ctx, credentials);
|
||||
(*ctx)->session_info = talloc_reference(*ctx, session_info);
|
||||
(*ctx)->get_predefined_key = reg_samba_get_predef;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
Definitions for the REGF registry file format as used by
|
||||
Windows NT4 and above.
|
||||
|
||||
Copyright (C) 2005 Jelmer Vernooij, jelmer@samba.org
|
||||
Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
|
||||
|
||||
Based on two files from Samba 3:
|
||||
regedit.c by Richard Sharpe
|
||||
regfio.c by Jerry Carter
|
||||
|
||||
*/
|
||||
|
||||
interface regf
|
||||
{
|
||||
const int REGF_OFFSET_NONE = 0xffffffff;
|
||||
|
||||
/*
|
||||
* Registry version number
|
||||
* 1.2.0.1 for WinNT 3.51
|
||||
* 1.3.0.1 for WinNT 4
|
||||
* 1.5.0.1 for WinXP
|
||||
*/
|
||||
|
||||
typedef [noprint] struct {
|
||||
[value(1)] uint32 major;
|
||||
[value(3)] uint32 minor;
|
||||
[value(0)] uint32 release;
|
||||
[value(1)] uint32 build;
|
||||
} regf_version;
|
||||
|
||||
/*
|
||||
"regf" is obviously the abbreviation for "Registry file". "regf" is the
|
||||
signature of the header-block which is always 4kb in size, although only
|
||||
the first 64 bytes seem to be used and a checksum is calculated over
|
||||
the first 0x200 bytes only!
|
||||
*/
|
||||
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 REGF_ID[4]; /* 'regf' */
|
||||
uint32 update_counter1;
|
||||
uint32 update_counter2;
|
||||
NTTIME modtime;
|
||||
regf_version version;
|
||||
uint32 data_offset;
|
||||
uint32 last_block;
|
||||
[value(1)] uint32 uk7; /* 1 */
|
||||
[charset(UTF16)] uint16 description[0x40];
|
||||
uint32 padding[83]; /* Padding */
|
||||
/* Checksum of first 0x200 bytes XOR-ed */
|
||||
uint32 chksum;
|
||||
} regf_hdr;
|
||||
|
||||
/*
|
||||
hbin probably means hive-bin (i.e. hive-container)
|
||||
This block is always a multiple
|
||||
of 4kb in size.
|
||||
*/
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 HBIN_ID[4]; /* hbin */
|
||||
uint32 offset_from_first; /* Offset from 1st hbin-Block */
|
||||
uint32 offset_to_next; /* Offset to the next hbin-Block */
|
||||
uint32 unknown[2];
|
||||
NTTIME last_change;
|
||||
uint32 block_size; /* Block size (including the header!) */
|
||||
uint8 data[offset_to_next-0x20];
|
||||
/* data is filled with:
|
||||
uint32 length;
|
||||
Negative if in used, positive otherwise
|
||||
Always a multiple of 8
|
||||
uint8_t data[length];
|
||||
Free space marker if 0xffffffff
|
||||
*/
|
||||
} hbin_block;
|
||||
|
||||
typedef [base_type(uint16),noprint] enum {
|
||||
REG_ROOT_KEY = 0x20,
|
||||
REG_SUB_KEY = 0x2C,
|
||||
REG_SYM_LINK = 0x10
|
||||
} reg_key_type;
|
||||
|
||||
/*
|
||||
The nk-record can be treated as a combination of tree-record and
|
||||
key-record of the win 95 registry.
|
||||
*/
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
reg_key_type type;
|
||||
NTTIME last_change;
|
||||
uint32 uk1;
|
||||
uint32 parent_offset;
|
||||
uint32 num_subkeys;
|
||||
uint32 uk2;
|
||||
uint32 subkeys_offset;
|
||||
uint32 unknown_offset;
|
||||
uint32 num_values;
|
||||
uint32 values_offset; /* Points to a list of offsets of vk-records */
|
||||
uint32 sk_offset;
|
||||
uint32 clsname_offset;
|
||||
uint32 unk3[5];
|
||||
[value(strlen(key_name))] uint16 name_length;
|
||||
uint16 clsname_length;
|
||||
[charset(DOS)] uint8 key_name[name_length];
|
||||
} nk_block;
|
||||
|
||||
/* sk (? Security Key ?) is the ACL of the registry. */
|
||||
typedef [noprint,public] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
uint16 tag;
|
||||
uint32 prev_offset;
|
||||
uint32 next_offset;
|
||||
uint32 ref_cnt;
|
||||
uint32 rec_size;
|
||||
uint8 sec_desc[rec_size];
|
||||
} sk_block;
|
||||
|
||||
typedef [noprint] struct {
|
||||
uint32 nk_offset;
|
||||
uint32 base37; /* base37 of key name */
|
||||
} lh_hash;
|
||||
|
||||
/* Subkey listing with hash of first 4 characters */
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
uint16 key_count;
|
||||
lh_hash hr[key_count];
|
||||
} lh_block;
|
||||
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
uint16 key_count;
|
||||
uint32 nk_offset[key_count];
|
||||
} li_block;
|
||||
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
uint16 key_count;
|
||||
uint32 offset[key_count]; /* li/lh offset */
|
||||
} ri_block;
|
||||
|
||||
/* The vk-record consists information to a single value (value key). */
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
[value(strlen(data_name))] uint16 name_length;
|
||||
uint32 data_length; /* If top-bit set, offset contains the data */
|
||||
uint32 data_offset;
|
||||
uint32 data_type;
|
||||
uint16 flag; /* =1, has name, else no name (=Default). */
|
||||
uint16 unk1;
|
||||
[charset(DOS)] uint8 data_name[name_length];
|
||||
} vk_block;
|
||||
|
||||
typedef [noprint] struct {
|
||||
uint32 nk_offset;
|
||||
[charset(DOS)] uint8 hash[4];
|
||||
} hash_record;
|
||||
|
||||
/*
|
||||
The lf-record is the counterpart to the RGKN-record (the
|
||||
hash-function)
|
||||
*/
|
||||
typedef [public,noprint] struct {
|
||||
[charset(DOS)] uint8 header[2];
|
||||
uint16 key_count;
|
||||
hash_record hr[key_count]; /* Array of hash records, depending on key_count */
|
||||
} lf_block;
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Registry interface
|
||||
Copyright (C) Gerald Carter 2002.
|
||||
Copyright (C) Jelmer Vernooij 2003-2004.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTRY_H /* _REGISTRY_H */
|
||||
#define _REGISTRY_H
|
||||
|
||||
#include "librpc/gen_ndr/security.h"
|
||||
|
||||
/* Handles for the predefined keys */
|
||||
#define HKEY_CLASSES_ROOT 0x80000000
|
||||
#define HKEY_CURRENT_USER 0x80000001
|
||||
#define HKEY_LOCAL_MACHINE 0x80000002
|
||||
#define HKEY_USERS 0x80000003
|
||||
#define HKEY_PERFORMANCE_DATA 0x80000004
|
||||
#define HKEY_CURRENT_CONFIG 0x80000005
|
||||
#define HKEY_DYN_DATA 0x80000006
|
||||
#define HKEY_PERFORMANCE_TEXT 0x80000050
|
||||
#define HKEY_PERFORMANCE_NLSTEXT 0x80000060
|
||||
|
||||
struct reg_predefined_key {
|
||||
uint32_t handle;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern const struct reg_predefined_key reg_predefined_keys[];
|
||||
|
||||
#define REG_DELETE -1
|
||||
|
||||
/*
|
||||
* The general idea here is that every backend provides a 'hive'. Combining
|
||||
* various hives gives you a complete registry like windows has
|
||||
*/
|
||||
|
||||
#define REGISTRY_INTERFACE_VERSION 1
|
||||
|
||||
/* structure to store the registry handles */
|
||||
struct registry_key
|
||||
{
|
||||
const char *name;
|
||||
const char *path;
|
||||
const char *class_name;
|
||||
NTTIME last_mod;
|
||||
struct registry_hive *hive;
|
||||
void *backend_data;
|
||||
};
|
||||
|
||||
struct registry_value
|
||||
{
|
||||
const char *name;
|
||||
unsigned int data_type;
|
||||
DATA_BLOB data;
|
||||
};
|
||||
|
||||
/* FIXME */
|
||||
typedef void (*reg_key_notification_function) (void);
|
||||
typedef void (*reg_value_notification_function) (void);
|
||||
|
||||
/*
|
||||
* Container for function pointers to enumeration routines
|
||||
* for virtual registry view
|
||||
*
|
||||
* Backends can provide :
|
||||
* - just one hive (example: nt4, w95)
|
||||
* - several hives (example: rpc).
|
||||
*
|
||||
* Backends should always do case-insensitive compares
|
||||
* (everything is case-insensitive but case-preserving,
|
||||
* just like the FS)
|
||||
*
|
||||
* There is no save function as all operations are expected to
|
||||
* be atomic.
|
||||
*/
|
||||
|
||||
struct hive_operations {
|
||||
const char *name;
|
||||
|
||||
/* Implement this one */
|
||||
WERROR (*open_hive) (struct registry_hive *, struct registry_key **);
|
||||
|
||||
/* Or this one */
|
||||
WERROR (*open_key) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_key **);
|
||||
|
||||
WERROR (*num_subkeys) (const struct registry_key *, uint32_t *count);
|
||||
WERROR (*num_values) (const struct registry_key *, uint32_t *count);
|
||||
WERROR (*get_subkey_by_index) (TALLOC_CTX *, const struct registry_key *, int idx, struct registry_key **);
|
||||
|
||||
/* Can not contain more than one level */
|
||||
WERROR (*get_subkey_by_name) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_key **);
|
||||
WERROR (*get_value_by_index) (TALLOC_CTX *, const struct registry_key *, int idx, struct registry_value **);
|
||||
|
||||
/* Can not contain more than one level */
|
||||
WERROR (*get_value_by_name) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_value **);
|
||||
|
||||
/* Security control */
|
||||
WERROR (*key_get_sec_desc) (TALLOC_CTX *, const struct registry_key *, struct security_descriptor **);
|
||||
WERROR (*key_set_sec_desc) (const struct registry_key *, const struct security_descriptor *);
|
||||
|
||||
/* Notification */
|
||||
WERROR (*request_key_change_notify) (const struct registry_key *, reg_key_notification_function);
|
||||
WERROR (*request_value_change_notify) (const struct registry_value *, reg_value_notification_function);
|
||||
|
||||
/* Key management */
|
||||
WERROR (*add_key)(TALLOC_CTX *, const struct registry_key *, const char *name, uint32_t access_mask, struct security_descriptor *, struct registry_key **);
|
||||
WERROR (*del_key)(const struct registry_key *, const char *name);
|
||||
WERROR (*flush_key) (const struct registry_key *);
|
||||
|
||||
/* Value management */
|
||||
WERROR (*set_value)(const struct registry_key *, const char *name, uint32_t type, const DATA_BLOB data);
|
||||
WERROR (*del_value)(const struct registry_key *, const char *valname);
|
||||
};
|
||||
|
||||
struct cli_credentials;
|
||||
|
||||
struct registry_hive
|
||||
{
|
||||
const struct hive_operations *functions;
|
||||
struct registry_key *root;
|
||||
struct auth_session_info *session_info;
|
||||
struct cli_credentials *credentials;
|
||||
void *backend_data;
|
||||
const char *location;
|
||||
};
|
||||
|
||||
/* Handle to a full registry
|
||||
* contains zero or more hives */
|
||||
struct registry_context {
|
||||
void *backend_data;
|
||||
struct cli_credentials *credentials;
|
||||
struct auth_session_info *session_info;
|
||||
WERROR (*get_predefined_key) (struct registry_context *, uint32_t hkey, struct registry_key **);
|
||||
};
|
||||
|
||||
struct reg_init_function_entry {
|
||||
const struct hive_operations *hive_functions;
|
||||
struct reg_init_function_entry *prev, *next;
|
||||
};
|
||||
|
||||
/* Representing differences between registry files */
|
||||
|
||||
struct reg_diff_value
|
||||
{
|
||||
const char *name;
|
||||
enum { REG_DIFF_DEL_VAL, REG_DIFF_SET_VAL } changetype;
|
||||
uint32_t type;
|
||||
DATA_BLOB data;
|
||||
};
|
||||
|
||||
struct reg_diff_key
|
||||
{
|
||||
const char *name;
|
||||
enum { REG_DIFF_CHANGE_KEY, REG_DIFF_DEL_KEY } changetype;
|
||||
uint32_t numvalues;
|
||||
struct reg_diff_value *values;
|
||||
};
|
||||
|
||||
struct reg_diff
|
||||
{
|
||||
const char *format;
|
||||
uint32_t numkeys;
|
||||
struct reg_diff_key *keys;
|
||||
};
|
||||
|
||||
struct auth_session_info;
|
||||
struct event_context;
|
||||
|
||||
#include "lib/registry/registry_proto.h"
|
||||
|
||||
#endif /* _REGISTRY_H */
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
simple registry frontend
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2004-2005
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/registry/reg_backend_rpc.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
poptContext pc;
|
||||
char *outputfile = NULL;
|
||||
struct registry_context *h1 = NULL, *h2 = NULL;
|
||||
int from_null = 0;
|
||||
WERROR error;
|
||||
struct reg_diff *diff;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"output", 'o', POPT_ARG_STRING, &outputfile, 'o', "output file to use", NULL },
|
||||
{"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL", NULL },
|
||||
{"remote", 'R', POPT_ARG_STRING, NULL, 0, "Connect to remote server" , NULL },
|
||||
{"local", 'L', POPT_ARG_NONE, NULL, 0, "Open local registry", NULL },
|
||||
POPT_COMMON_SAMBA
|
||||
POPT_COMMON_CREDENTIALS
|
||||
POPT_COMMON_VERSION
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
registry_init();
|
||||
|
||||
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
error = WERR_OK;
|
||||
switch(opt) {
|
||||
case 'L':
|
||||
if (!h1 && !from_null) error = reg_open_local(NULL, &h1, NULL, cmdline_credentials);
|
||||
else if (!h2) error = reg_open_local(NULL, &h2, NULL, cmdline_credentials);
|
||||
break;
|
||||
case 'R':
|
||||
if (!h1 && !from_null)
|
||||
error = reg_open_remote(&h1, NULL, cmdline_credentials,
|
||||
poptGetOptArg(pc), NULL);
|
||||
else if (!h2) error = reg_open_remote(&h2, NULL, cmdline_credentials,
|
||||
poptGetOptArg(pc), NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Error: %s\n", win_errstr(error));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
poptFreeContext(pc);
|
||||
|
||||
diff = reg_generate_diff(NULL, h1, h2);
|
||||
if (!diff) {
|
||||
fprintf(stderr, "Unable to generate diff between keys\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg_diff_save(diff, outputfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
simple registry frontend
|
||||
|
||||
Copyright (C) 2004-2005 Jelmer Vernooij, jelmer@samba.org
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
#include "lib/registry/reg_backend_rpc.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
poptContext pc;
|
||||
const char *patch;
|
||||
struct registry_context *h;
|
||||
const char *remote = NULL;
|
||||
struct reg_diff *diff;
|
||||
WERROR error;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
|
||||
POPT_COMMON_SAMBA
|
||||
POPT_COMMON_CREDENTIALS
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
}
|
||||
|
||||
registry_init();
|
||||
|
||||
if (remote) {
|
||||
error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL);
|
||||
} else {
|
||||
error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
|
||||
}
|
||||
|
||||
if (W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Error: %s\n", win_errstr(error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
patch = poptGetArg(pc);
|
||||
poptFreeContext(pc);
|
||||
|
||||
diff = reg_diff_load(NULL, patch);
|
||||
if (!diff) {
|
||||
fprintf(stderr, "Unable to load registry patch from `%s'\n", patch);
|
||||
return 1;
|
||||
}
|
||||
|
||||
reg_diff_apply(diff, h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
simple registry frontend
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2004
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/registry/reg_backend_rpc.h"
|
||||
#include "system/time.h"
|
||||
#include "lib/smbreadline/smbreadline.h"
|
||||
#include "librpc/gen_ndr/ndr_security.h"
|
||||
|
||||
/*
|
||||
* ck/cd - change key
|
||||
* ls - list values/keys
|
||||
* rmval/rm - remove value
|
||||
* rmkey/rmdir - remove key
|
||||
* mkkey/mkdir - make key
|
||||
* ch - change hive
|
||||
* info - show key info
|
||||
* save - save hive
|
||||
* print - print value
|
||||
* help
|
||||
* exit
|
||||
*/
|
||||
|
||||
static struct registry_key *cmd_info(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
struct security_descriptor *sec_desc = NULL;
|
||||
time_t last_mod;
|
||||
WERROR error;
|
||||
|
||||
printf("Name: %s\n", cur->name);
|
||||
printf("Full path: %s\n", cur->path);
|
||||
printf("Key Class: %s\n", cur->class_name);
|
||||
last_mod = nt_time_to_unix(cur->last_mod);
|
||||
printf("Time Last Modified: %s\n", ctime(&last_mod));
|
||||
|
||||
error = reg_get_sec_desc(mem_ctx, cur, &sec_desc);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
printf("Error getting security descriptor\n");
|
||||
} else {
|
||||
ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
|
||||
}
|
||||
talloc_free(sec_desc);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
struct registry_key *ret = NULL;
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: predef predefined-key-name\n");
|
||||
} else if (!ctx) {
|
||||
fprintf(stderr, "No full registry loaded, no predefined keys defined\n");
|
||||
} else {
|
||||
WERROR error = reg_get_predefined_key_by_name(ctx, argv[1], &ret);
|
||||
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Error opening predefined key %s: %s\n", argv[1], win_errstr(error));
|
||||
ret = NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_pwd(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
printf("%s\n", cur->path);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_set(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
struct registry_value val;
|
||||
WERROR error;
|
||||
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Usage: set value-name type value\n");
|
||||
return cur;
|
||||
}
|
||||
|
||||
if (!reg_string_to_val(mem_ctx, argv[2], argv[3], &val.data_type, &val.data)) {
|
||||
fprintf(stderr, "Unable to interpret data\n");
|
||||
return cur;
|
||||
}
|
||||
|
||||
error = reg_val_set(cur, argv[1], val.data_type, val.data);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Error setting value: %s\n", win_errstr(error));
|
||||
return NULL;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_ck(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
struct registry_key *new = NULL;
|
||||
WERROR error;
|
||||
if(argc < 2) {
|
||||
new = cur;
|
||||
} else {
|
||||
error = reg_open_key(mem_ctx, cur, argv[1], &new);
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
DEBUG(0, ("Error opening specified key: %s\n", win_errstr(error)));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Current path is: %s\n", new->path);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_print(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
struct registry_value *value;
|
||||
WERROR error;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: print <valuename>");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = reg_key_get_value_by_name(mem_ctx, cur, argv[1], &value);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "No such value '%s'\n", argv[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("%s\n%s\n", str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_ls(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
WERROR error;
|
||||
struct registry_value *value;
|
||||
struct registry_key *sub;
|
||||
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, cur, i, &sub)); i++) {
|
||||
printf("K %s\n", sub->name);
|
||||
}
|
||||
|
||||
if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while browsing thru keys: %s\n", win_errstr(error)));
|
||||
}
|
||||
|
||||
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, cur, i, &value)); i++) {
|
||||
printf("V \"%s\" %s %s\n", value->name, str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static struct registry_key *cmd_mkkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
struct registry_key *tmp;
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "Usage: mkkey <keyname>\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!W_ERROR_IS_OK(reg_key_add_name(mem_ctx, cur, argv[1], 0, NULL, &tmp))) {
|
||||
fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_rmkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "Usage: rmkey <name>\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!W_ERROR_IS_OK(reg_key_del(cur, argv[1]))) {
|
||||
fprintf(stderr, "Error deleting '%s'\n", argv[1]);
|
||||
} else {
|
||||
fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "Usage: rmval <valuename>\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!W_ERROR_IS_OK(reg_del_value(cur, argv[1]))) {
|
||||
fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
|
||||
} else {
|
||||
fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_exit(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int, char **);
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
const char *alias;
|
||||
const char *help;
|
||||
struct registry_key *(*handle)(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int argc, char **argv);
|
||||
} regshell_cmds[] = {
|
||||
{"ck", "cd", "Change current key", cmd_ck },
|
||||
{"info", "i", "Show detailed information of a key", cmd_info },
|
||||
{"list", "ls", "List values/keys in current key", cmd_ls },
|
||||
{"print", "p", "Print value", cmd_print },
|
||||
{"mkkey", "mkdir", "Make new key", cmd_mkkey },
|
||||
{"rmval", "rm", "Remove value", cmd_rmval },
|
||||
{"rmkey", "rmdir", "Remove key", cmd_rmkey },
|
||||
{"pwd", "pwk", "Printing current key", cmd_pwd },
|
||||
{"set", "update", "Update value", cmd_set },
|
||||
{"help", "?", "Help", cmd_help },
|
||||
{"exit", "quit", "Exit", cmd_exit },
|
||||
{"predef", "predefined", "Go to predefined key", cmd_predef },
|
||||
{NULL }
|
||||
};
|
||||
|
||||
static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
printf("Available commands:\n");
|
||||
for(i = 0; regshell_cmds[i].name; i++) {
|
||||
printf("%s - %s\n", regshell_cmds[i].name, regshell_cmds[i].help);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *k, char *line)
|
||||
{
|
||||
int argc;
|
||||
char **argv = NULL;
|
||||
int ret, i;
|
||||
|
||||
if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
|
||||
fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
|
||||
return k;
|
||||
}
|
||||
|
||||
for(i = 0; regshell_cmds[i].name; i++) {
|
||||
if(!strcmp(regshell_cmds[i].name, argv[0]) ||
|
||||
(regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
|
||||
return regshell_cmds[i].handle(mem_ctx, ctx, k, argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "No such command '%s'\n", argv[0]);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
#define MAX_COMPLETIONS 100
|
||||
|
||||
static struct registry_key *current_key = NULL;
|
||||
|
||||
static char **reg_complete_command(const char *text, int start, int end)
|
||||
{
|
||||
/* Complete command */
|
||||
char **matches;
|
||||
int i, len, samelen=0, count=1;
|
||||
|
||||
matches = malloc_array_p(char *, MAX_COMPLETIONS);
|
||||
if (!matches) return NULL;
|
||||
matches[0] = NULL;
|
||||
|
||||
len = strlen(text);
|
||||
for (i=0;regshell_cmds[i].handle && count < MAX_COMPLETIONS-1;i++) {
|
||||
if (strncmp(text, regshell_cmds[i].name, len) == 0) {
|
||||
matches[count] = strdup(regshell_cmds[i].name);
|
||||
if (!matches[count])
|
||||
goto cleanup;
|
||||
if (count == 1)
|
||||
samelen = strlen(matches[count]);
|
||||
else
|
||||
while (strncmp(matches[count], matches[count-1], samelen) != 0)
|
||||
samelen--;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
switch (count) {
|
||||
case 0: /* should never happen */
|
||||
case 1:
|
||||
goto cleanup;
|
||||
case 2:
|
||||
matches[0] = strdup(matches[1]);
|
||||
break;
|
||||
default:
|
||||
matches[0] = strndup(matches[1], samelen);
|
||||
}
|
||||
matches[count] = NULL;
|
||||
return matches;
|
||||
|
||||
cleanup:
|
||||
count--;
|
||||
while (count >= 0) {
|
||||
free(matches[count]);
|
||||
count--;
|
||||
}
|
||||
free(matches);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char **reg_complete_key(const char *text, int start, int end)
|
||||
{
|
||||
struct registry_key *base;
|
||||
struct registry_key *subkey;
|
||||
int i, j = 1;
|
||||
int samelen = 0;
|
||||
int len;
|
||||
char **matches;
|
||||
const char *base_n = "";
|
||||
TALLOC_CTX *mem_ctx;
|
||||
WERROR status;
|
||||
|
||||
matches = malloc_array_p(char *, MAX_COMPLETIONS);
|
||||
if (!matches) return NULL;
|
||||
matches[0] = NULL;
|
||||
mem_ctx = talloc_init("completion");
|
||||
|
||||
base = current_key;
|
||||
|
||||
len = strlen(text);
|
||||
for(i = 0; j < MAX_COMPLETIONS-1; i++) {
|
||||
status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkey);
|
||||
if(W_ERROR_IS_OK(status)) {
|
||||
if(!strncmp(text, subkey->name, len)) {
|
||||
matches[j] = strdup(subkey->name);
|
||||
j++;
|
||||
|
||||
if (j == 1)
|
||||
samelen = strlen(matches[j]);
|
||||
else
|
||||
while (strncmp(matches[j], matches[j-1], samelen) != 0)
|
||||
samelen--;
|
||||
}
|
||||
} else if(W_ERROR_EQUAL(status, WERR_NO_MORE_ITEMS)) {
|
||||
break;
|
||||
} else {
|
||||
printf("Error creating completion list: %s\n", win_errstr(status));
|
||||
talloc_free(mem_ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == 1) { /* No matches at all */
|
||||
SAFE_FREE(matches);
|
||||
talloc_free(mem_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (j == 2) { /* Exact match */
|
||||
asprintf(&matches[0], "%s%s", base_n, matches[1]);
|
||||
} else {
|
||||
asprintf(&matches[0], "%s%s", base_n, talloc_strndup(mem_ctx, matches[1], samelen));
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
matches[j] = NULL;
|
||||
return matches;
|
||||
}
|
||||
|
||||
static char **reg_completion(const char *text, int start, int end)
|
||||
{
|
||||
smb_readline_ca_char(' ');
|
||||
|
||||
if (start == 0) {
|
||||
return reg_complete_command(text, start, end);
|
||||
} else {
|
||||
return reg_complete_key(text, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
const char *backend = NULL;
|
||||
struct registry_key *curkey = NULL;
|
||||
poptContext pc;
|
||||
WERROR error;
|
||||
TALLOC_CTX *mem_ctx = talloc_init("cmd");
|
||||
const char *remote = NULL;
|
||||
struct registry_context *h = NULL;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
|
||||
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
|
||||
POPT_COMMON_SAMBA
|
||||
POPT_COMMON_CREDENTIALS
|
||||
POPT_COMMON_VERSION
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
}
|
||||
|
||||
registry_init();
|
||||
|
||||
if (remote) {
|
||||
error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL);
|
||||
} else if (backend) {
|
||||
error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, cmdline_credentials, &curkey);
|
||||
} else {
|
||||
error = reg_open_local(NULL, &h, NULL, cmdline_credentials);
|
||||
}
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Unable to open registry\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (h) {
|
||||
int i;
|
||||
|
||||
for (i = 0; reg_predefined_keys[i].handle; i++) {
|
||||
WERROR err;
|
||||
err = reg_get_predefined_key(h, reg_predefined_keys[i].handle, &curkey);
|
||||
if (W_ERROR_IS_OK(err)) {
|
||||
break;
|
||||
} else {
|
||||
curkey = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!curkey) {
|
||||
fprintf(stderr, "Unable to access any of the predefined keys\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
poptFreeContext(pc);
|
||||
|
||||
while(True) {
|
||||
char *line, *prompt;
|
||||
|
||||
if(curkey->hive->root->name) {
|
||||
asprintf(&prompt, "%s:%s> ", curkey->hive->root->name, curkey->path);
|
||||
} else {
|
||||
asprintf(&prompt, "%s> ", curkey->path);
|
||||
}
|
||||
|
||||
current_key = curkey; /* No way to pass a void * pointer
|
||||
via readline :-( */
|
||||
line = smb_readline(prompt, NULL, reg_completion);
|
||||
|
||||
if(!line)
|
||||
break;
|
||||
|
||||
if(line[0] != '\n') {
|
||||
struct registry_key *new = process_cmd(mem_ctx, h, curkey, line);
|
||||
if(new)curkey = new;
|
||||
}
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
simple registry frontend
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2004
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/registry/registry.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "lib/registry/reg_backend_rpc.h"
|
||||
#include "lib/cmdline/popt_common.h"
|
||||
|
||||
static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
|
||||
{
|
||||
struct registry_key *subkey;
|
||||
struct registry_value *value;
|
||||
struct security_descriptor *sec_desc;
|
||||
WERROR error;
|
||||
int i;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
for(i = 0; i < l; i++) putchar(' ');
|
||||
|
||||
/* Hive name */
|
||||
if(p->hive->root == p) {
|
||||
if(p->hive->root->name) printf("%s\n", p->hive->root->name); else printf("<No Name>\n");
|
||||
} else {
|
||||
if(!p->name) printf("<No Name>\n");
|
||||
if(fullpath) printf("%s\n", p->path);
|
||||
else printf("%s\n", p->name?p->name:"(NULL)");
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("print_tree");
|
||||
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, p, i, &subkey)); i++) {
|
||||
print_tree(l+1, subkey, fullpath, novals);
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n", p->path, win_errstr(error)));
|
||||
}
|
||||
|
||||
if(!novals) {
|
||||
mem_ctx = talloc_init("print_tree");
|
||||
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, p, i, &value)); i++) {
|
||||
int j;
|
||||
char *desc;
|
||||
for(j = 0; j < l+1; j++) putchar(' ');
|
||||
desc = reg_val_description(mem_ctx, value);
|
||||
printf("%s\n", desc);
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
|
||||
DEBUG(0, ("Error occured while fetching values for '%s': %s\n", p->path, win_errstr(error)));
|
||||
}
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("sec_desc");
|
||||
if (NT_STATUS_IS_ERR(reg_get_sec_desc(mem_ctx, p, &sec_desc))) {
|
||||
DEBUG(0, ("Error getting security descriptor\n"));
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt, i;
|
||||
const char *backend = NULL;
|
||||
const char *remote = NULL;
|
||||
poptContext pc;
|
||||
struct registry_context *h = NULL;
|
||||
struct registry_key *root = NULL;
|
||||
WERROR error;
|
||||
int fullpath = 0, no_values = 0;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
|
||||
{"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
|
||||
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL },
|
||||
{"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL},
|
||||
POPT_COMMON_SAMBA
|
||||
POPT_COMMON_CREDENTIALS
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
}
|
||||
|
||||
registry_init();
|
||||
|
||||
if (remote) {
|
||||
error = reg_open_remote(&h, NULL, cmdline_credentials, remote, NULL);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Unable to open remote registry at %s:%s \n", remote, win_errstr(error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
} else if (backend) {
|
||||
error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, cmdline_credentials, &root);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Unable to open '%s' with backend '%s':%s \n", poptGetArg(pc), backend, win_errstr(error));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
|
||||
|
||||
if(!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Unable to open local registry:%s \n", win_errstr(error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
poptFreeContext(pc);
|
||||
|
||||
error = WERR_OK;
|
||||
|
||||
if (root != NULL) {
|
||||
print_tree(0, root, fullpath, no_values);
|
||||
} else {
|
||||
for(i = 0; reg_predefined_keys[i].handle; i++) {
|
||||
error = reg_get_predefined_key(h, reg_predefined_keys[i].handle, &root);
|
||||
if (!W_ERROR_IS_OK(error)) {
|
||||
fprintf(stderr, "Skipping %s\n", reg_predefined_keys[i].name);
|
||||
continue;
|
||||
}
|
||||
SMB_ASSERT(root);
|
||||
print_tree(0, root, fullpath, no_values);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user