summaryrefslogtreecommitdiff
path: root/source4/lib/registry
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/registry')
-rw-r--r--source4/lib/registry/Doxyfile2
-rw-r--r--source4/lib/registry/README31
-rw-r--r--source4/lib/registry/TODO4
-rw-r--r--source4/lib/registry/common/reg_interface.c584
-rw-r--r--source4/lib/registry/config.mk96
-rw-r--r--source4/lib/registry/dir.c333
-rw-r--r--source4/lib/registry/hive.c145
-rw-r--r--source4/lib/registry/hive.h197
-rw-r--r--source4/lib/registry/interface.c277
-rw-r--r--source4/lib/registry/ldb.c501
-rw-r--r--source4/lib/registry/local.c333
-rw-r--r--source4/lib/registry/man/regdiff.1.xml2
-rw-r--r--source4/lib/registry/man/regpatch.1.xml2
-rw-r--r--source4/lib/registry/man/regshell.1.xml2
-rw-r--r--source4/lib/registry/man/regtree.1.xml2
-rw-r--r--source4/lib/registry/patchfile.c561
-rw-r--r--source4/lib/registry/patchfile.h52
-rw-r--r--source4/lib/registry/patchfile_dotreg.c247
-rw-r--r--source4/lib/registry/patchfile_preg.c270
-rw-r--r--source4/lib/registry/reg_backend_dir.c141
-rw-r--r--source4/lib/registry/reg_backend_ldb.c405
-rw-r--r--source4/lib/registry/reg_backend_nt4.c1124
-rw-r--r--source4/lib/registry/reg_backend_w95.c356
-rw-r--r--source4/lib/registry/regf.c1923
-rw-r--r--source4/lib/registry/regf.idl6
-rw-r--r--source4/lib/registry/registry.h309
-rw-r--r--source4/lib/registry/rpc.c (renamed from source4/lib/registry/reg_backend_rpc.c)222
-rw-r--r--source4/lib/registry/samba.c (renamed from source4/lib/registry/reg_samba.c)74
-rw-r--r--source4/lib/registry/tests/diff.c105
-rw-r--r--source4/lib/registry/tests/generic.c66
-rw-r--r--source4/lib/registry/tests/hive.c383
-rw-r--r--source4/lib/registry/tests/registry.c486
-rw-r--r--source4/lib/registry/tools/common.c75
-rw-r--r--source4/lib/registry/tools/regdiff.c103
-rw-r--r--source4/lib/registry/tools/regpatch.c31
-rw-r--r--source4/lib/registry/tools/regshell.c266
-rw-r--r--source4/lib/registry/tools/regtree.c114
-rw-r--r--source4/lib/registry/util.c (renamed from source4/lib/registry/common/reg_util.c)79
-rw-r--r--source4/lib/registry/wine.c (renamed from source4/lib/registry/reg_backend_wine.c)4
39 files changed, 6371 insertions, 3542 deletions
diff --git a/source4/lib/registry/Doxyfile b/source4/lib/registry/Doxyfile
index ff591b6fe4..efc01cd355 100644
--- a/source4/lib/registry/Doxyfile
+++ b/source4/lib/registry/Doxyfile
@@ -15,7 +15,7 @@ WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
-INPUT = . common
+INPUT = .
FILE_PATTERNS = *.c *.h *.dox
GENERATE_HTML = YES
HTML_OUTPUT = html
diff --git a/source4/lib/registry/README b/source4/lib/registry/README
index db1fb7a678..07b2c01684 100644
--- a/source4/lib/registry/README
+++ b/source4/lib/registry/README
@@ -1,30 +1,31 @@
This is the registry library. The registry is basically a bunch of
-hives that can be loaded from different places.
+hives, each of which is loaded from a file. When using a local registry,
+it is possible to specify where hives should be loaded from, etc.
-The various registry backends provide support for loading/saving
-specific types of hives:
+There are separate APIs for accessing the data in a hive and the
+data in the registry itself. Each supports different backends.
+
+The following "full registry" backends are currently provided:
+
+ * Remote (over DCE/RPC)
+ * Local (allows "mounting" hives)
+ * Wine (uses the wine plain-text file)
+
+The following hive backends are supported:
- ldb
- - w95 (USER.DAT-style files)
- - nt4 (NTUSER.DAT-style files)
- - gconf (GNOME configuration)
+ - regf (NTUSER.DAT-style files)
- rpc (Remote individual hives)
+ - directory
-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.
+reg_open_samba() 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_CURRENT_USER = regf:NTUSER.DAT
registry:HKEY_LOCAL_MACHINE = ldb:tdb://registry.tdb
WERR_NOT_SUPPORTED will be returned for all hives that haven't been set.
diff --git a/source4/lib/registry/TODO b/source4/lib/registry/TODO
index 562ed5657e..5f1e7d034b 100644
--- a/source4/lib/registry/TODO
+++ b/source4/lib/registry/TODO
@@ -4,10 +4,10 @@
reg_backend_dir:
- value support
-reg_backend_w95.c:
+reg_backend_creg.c:
- write support
-reg_backend_nt4:
+reg_backend_regf:
- write support
reg_backend_rpc:
diff --git a/source4/lib/registry/common/reg_interface.c b/source4/lib/registry/common/reg_interface.c
deleted file mode 100644
index 6ee8a726dc..0000000000
--- a/source4/lib/registry/common/reg_interface.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- 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 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "lib/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;
-}
diff --git a/source4/lib/registry/config.mk b/source4/lib/registry/config.mk
index cea37e7e2f..de276d2b5e 100644
--- a/source4/lib/registry/config.mk
+++ b/source4/lib/registry/config.mk
@@ -1,23 +1,10 @@
-# Registry backends
-
-################################################
-# Start MODULE registry_nt4
-[MODULE::registry_nt4]
-INIT_FUNCTION = registry_nt4_init
-SUBSYSTEM = registry
-OBJ_FILES = \
- reg_backend_nt4.o
-PRIVATE_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/regf.c: lib/registry/tdr_regf.c
+$(srcdir)/lib/registry/regf.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)" srcdir="$(srcdir)" $(PERL) $(srcdir)/pidl/pidl $(PIDL_ARGS) \
@@ -28,67 +15,36 @@ 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
-PRIVATE_DEPENDENCIES = LIBTALLOC
-# End MODULE registry_dir
-################################################
-
-################################################
-# Start MODULE registry_rpc
-[MODULE::registry_rpc]
-INIT_FUNCTION = registry_rpc_init
-OUTPUT_TYPE = INTEGRATED
-SUBSYSTEM = registry
-OBJ_FILES = \
- reg_backend_rpc.o
-PRIVATE_DEPENDENCIES = RPC_NDR_WINREG
-# End MODULE registry_rpc
-################################################
-
-################################################
-# Start MODULE registry_ldb
-[MODULE::registry_ldb]
-INIT_FUNCTION = registry_ldb_init
-SUBSYSTEM = registry
-OBJ_FILES = \
- reg_backend_ldb.o
-PRIVATE_DEPENDENCIES = \
- LIBLDB
-# 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
-PRIVATE_DEPENDENCIES = \
- LIBSAMBA-UTIL CHARSET
+ interface.o \
+ util.o \
+ samba.o \
+ patchfile_dotreg.o \
+ patchfile_preg.o \
+ patchfile.o \
+ regf.o \
+ hive.o \
+ local.o \
+ ldb.o \
+ dir.o \
+ rpc.o
+PUBLIC_DEPENDENCIES = \
+ LIBSAMBA-UTIL CHARSET TDR_REGF LIBLDB \
+ RPC_NDR_WINREG
PUBLIC_HEADERS = registry.h
# End MODULE registry_ldb
################################################
+[SUBSYSTEM::registry_common]
+PUBLIC_DEPENDENCIES = registry
+OBJ_FILES = tools/common.o
+PUBLIC_PROTO_HEADER = tools/common.h
+
################################################
# Start BINARY regdiff
[BINARY::regdiff]
@@ -106,7 +62,8 @@ MANPAGE = man/regdiff.1
INSTALLDIR = BINDIR
OBJ_FILES = tools/regpatch.o
PRIVATE_DEPENDENCIES = \
- LIBSAMBA-CONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS
+ LIBSAMBA-CONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS \
+ registry_common
MANPAGE = man/regpatch.1
# End BINARY regpatch
################################################
@@ -118,7 +75,7 @@ INSTALLDIR = BINDIR
OBJ_FILES = tools/regshell.o
PRIVATE_DEPENDENCIES = \
LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \
- SMBREADLINE
+ SMBREADLINE registry_common
MANPAGE = man/regshell.1
# End BINARY regshell
################################################
@@ -129,7 +86,8 @@ MANPAGE = man/regshell.1
INSTALLDIR = BINDIR
OBJ_FILES = tools/regtree.o
PRIVATE_DEPENDENCIES = \
- LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS
+ LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \
+ registry_common
MANPAGE = man/regtree.1
# End BINARY regtree
################################################
diff --git a/source4/lib/registry/dir.c b/source4/lib/registry/dir.c
new file mode 100644
index 0000000000..146c5197fd
--- /dev/null
+++ b/source4/lib/registry/dir.c
@@ -0,0 +1,333 @@
+/*
+ Unix SMB/CIFS implementation.
+ Registry interface
+ Copyright (C) Jelmer Vernooij 2004-2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "hive.h"
+#include "system/dir.h"
+#include "system/filesys.h"
+
+struct dir_key {
+ struct hive_key key;
+ const char *path;
+};
+
+static struct hive_operations reg_backend_dir;
+
+static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx,
+ const struct hive_key *parent,
+ const char *name, const char *classname,
+ struct security_descriptor *desc,
+ struct hive_key **result)
+{
+ struct dir_key *dk = talloc_get_type(parent, struct dir_key);
+ char *path;
+ int ret;
+
+ path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
+ ret = mkdir(path, 0700);
+ if (ret == 0) {
+ struct dir_key *key = talloc(mem_ctx, struct dir_key);
+ key->key.ops = &reg_backend_dir;
+ key->path = talloc_steal(key, path);
+ *result = (struct hive_key *)key;
+ return WERR_OK;
+ }
+
+ if (errno == EEXIST)
+ return WERR_ALREADY_EXISTS;
+ printf("FAILED %s BECAUSE: %s\n", path, strerror(errno));
+ return WERR_GENERAL_FAILURE;
+}
+
+static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
+{
+ struct dir_key *dk = talloc_get_type(k, struct dir_key);
+ char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name);
+ WERROR ret;
+
+ if (rmdir(child) == 0)
+ ret = WERR_OK;
+ else if (errno == ENOENT)
+ ret = WERR_NOT_FOUND;
+ else
+ ret = WERR_GENERAL_FAILURE;
+
+ talloc_free(child);
+
+ return ret;
+}
+
+static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx,
+ const struct hive_key *parent,
+ const char *name, struct hive_key **subkey)
+{
+ DIR *d;
+ char *fullpath;
+ const struct dir_key *p = talloc_get_type(parent, struct dir_key);
+ struct dir_key *ret;
+
+ if (name == NULL) {
+ DEBUG(0, ("NULL pointer passed as directory name!"));
+ return WERR_INVALID_PARAM;
+ }
+
+ fullpath = talloc_asprintf(mem_ctx, "%s/%s", p->path, name);
+
+ d = opendir(fullpath);
+ if (d == NULL) {
+ DEBUG(3,("Unable to open '%s': %s\n", fullpath, strerror(errno)));
+ return WERR_BADFILE;
+ }
+ closedir(d);
+ ret = talloc(mem_ctx, struct dir_key);
+ ret->key.ops = &reg_backend_dir;
+ ret->path = talloc_steal(ret, fullpath);
+ *subkey = (struct hive_key *)ret;
+ return WERR_OK;
+}
+
+static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx,
+ const struct hive_key *k, uint32_t idx,
+ const char **name,
+ const char **classname,
+ NTTIME *last_mod_time)
+{
+ struct dirent *e;
+ const struct dir_key *dk = talloc_get_type(k, struct dir_key);
+ int i = 0;
+ DIR *d;
+
+ d = opendir(dk->path);
+
+ if (d == NULL)
+ 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", dk->path, e->d_name);
+ stat(thispath, &stbuf);
+
+ if (!S_ISDIR(stbuf.st_mode)) {
+ SAFE_FREE(thispath);
+ continue;
+ }
+
+ if (i == idx) {
+ struct stat st;
+ *name = talloc_strdup(mem_ctx, e->d_name);
+ *classname = NULL;
+ stat(thispath, &st);
+ unix_to_nt_time(last_mod_time, st.st_mtime);
+ SAFE_FREE(thispath);
+ closedir(d);
+ return WERR_OK;
+ }
+ i++;
+
+ SAFE_FREE(thispath);
+ }
+ }
+
+ closedir(d);
+
+ return WERR_NO_MORE_ITEMS;
+}
+
+WERROR reg_open_directory(TALLOC_CTX *parent_ctx,
+ const char *location, struct hive_key **key)
+{
+ struct dir_key *dk;
+
+ if (location == NULL)
+ return WERR_INVALID_PARAM;
+
+ dk = talloc(parent_ctx, struct dir_key);
+ dk->key.ops = &reg_backend_dir;
+ dk->path = talloc_strdup(dk, location);
+ *key = (struct hive_key *)dk;
+ return WERR_OK;
+}
+
+WERROR reg_create_directory(TALLOC_CTX *parent_ctx,
+ const char *location, struct hive_key **key)
+{
+ if (mkdir(location, 0700) != 0) {
+ *key = NULL;
+ return WERR_GENERAL_FAILURE;
+ }
+
+ return reg_open_directory(parent_ctx, location, key);
+}
+
+static WERROR reg_dir_get_info(TALLOC_CTX *ctx, const struct hive_key *key,
+ const char **classname,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *lastmod)
+{
+ DIR *d;
+ const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+ struct dirent *e;
+ struct stat st;
+
+ SMB_ASSERT(key != NULL);
+
+ if (classname != NULL)
+ *classname = NULL;
+
+ d = opendir(dk->path);
+ if (d == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (num_subkeys != NULL)
+ *num_subkeys = 0;
+
+ if (num_values != NULL)
+ *num_values = 0;
+
+ while((e = readdir(d))) {
+ if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
+ char *path = talloc_asprintf(ctx, "%s/%s", dk->path, e->d_name);
+
+ if (stat(path, &st) < 0) {
+ DEBUG(0, ("Error statting %s: %s\n", path, strerror(errno)));
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode) && num_subkeys != NULL)
+ (*num_subkeys)++;
+
+ if (!S_ISDIR(st.st_mode) && num_values != NULL)
+ (*num_values)++;
+
+ talloc_free(path);
+ }
+ }
+
+ closedir(d);
+
+ if (lastmod != NULL)
+ *lastmod = 0;
+ return WERR_OK;
+}
+
+static WERROR reg_dir_set_value (struct hive_key *key, const char *name,
+ uint32_t type, const DATA_BLOB data)
+{
+ const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+ char *path = talloc_asprintf(dk, "%s/%s", dk->path, name);
+
+ if (!file_save(path, data.data, data.length))
+ return WERR_GENERAL_FAILURE;
+
+ /* FIXME: Type */
+
+ return WERR_OK;
+}
+
+static WERROR reg_dir_get_value (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, const char *name,
+ uint32_t *type, DATA_BLOB *data)
+{
+ const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+ char *path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
+ size_t size;
+ char *contents;
+
+ contents = file_load(path, &size, mem_ctx);
+ talloc_free(path);
+ if (contents == NULL)
+ return WERR_NOT_FOUND;
+
+ if (type != NULL)
+ *type = 4; /* FIXME */
+
+ data->data = (uint8_t *)contents;
+ data->length = size;
+
+ return WERR_OK;
+}
+
+static WERROR reg_dir_enum_value (TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, int idx,
+ const char **name,
+ uint32_t *type, DATA_BLOB *data)
+{
+ const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+ DIR *d;
+ struct dirent *e;
+ int i;
+
+ d = opendir(dk->path);
+ if (d == NULL) {
+ DEBUG(3,("Unable to open '%s': %s\n", dk->path, strerror(errno)));
+ return WERR_BADFILE;
+ }
+
+ i = 0;
+ while((e = readdir(d))) {
+ if (ISDOT(e->d_name) || ISDOTDOT(e->d_name))
+ continue;
+
+ if (i == idx) {
+ if (name != NULL)
+ *name = talloc_strdup(mem_ctx, e->d_name);
+ W_ERROR_NOT_OK_RETURN(reg_dir_get_value(mem_ctx, key, *name, type, data));
+ return WERR_OK;
+ }
+
+ i++;
+ }
+ closedir(d);
+
+ return WERR_NO_MORE_ITEMS;
+}
+
+
+static WERROR reg_dir_del_value (struct hive_key *key, const char *name)
+{
+ const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+ char *path = talloc_asprintf(key, "%s/%s", dk->path, name);
+ if (unlink(path) < 0) {
+ talloc_free(path);
+ if (errno == ENOENT)
+ return WERR_NOT_FOUND;
+ return WERR_GENERAL_FAILURE;
+ }
+ talloc_free(path);
+
+ return WERR_OK;
+}
+
+static struct hive_operations reg_backend_dir = {
+ .name = "dir",
+ .get_key_by_name = reg_dir_open_key,
+ .get_key_info = reg_dir_get_info,
+ .add_key = reg_dir_add_key,
+ .del_key = reg_dir_del_key,
+ .enum_key = reg_dir_key_by_index,
+ .set_value = reg_dir_set_value,
+ .get_value_by_name = reg_dir_get_value,
+ .enum_value = reg_dir_enum_value,
+ .delete_value = reg_dir_del_value,
+};
diff --git a/source4/lib/registry/hive.c b/source4/lib/registry/hive.c
new file mode 100644
index 0000000000..b2c826b93d
--- /dev/null
+++ b/source4/lib/registry/hive.c
@@ -0,0 +1,145 @@
+
+/*
+ Unix SMB/CIFS implementation.
+ Registry hive interface
+ Copyright (C) Jelmer Vernooij 2003-2007.
+
+ 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 "hive.h"
+#include "system/filesys.h"
+
+/** Open a registry file/host/etc */
+_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ struct hive_key **root)
+{
+ int fd, num;
+ char peek[20];
+
+ /* Check for directory */
+ if (directory_exist(location)) {
+ return reg_open_directory(parent_ctx, location, root);
+ }
+
+ fd = open(location, O_RDWR);
+ if (fd == -1) {
+ return WERR_BADFILE;
+ }
+
+ num = read(fd, peek, 20);
+ if (num == -1) {
+ return WERR_BADFILE;
+ }
+
+ if (!strncmp(peek, "regf", 4)) {
+ close(fd);
+ return reg_open_regf_file(parent_ctx, location, root);
+ } else if (!strncmp(peek, "TDB file", 8)) {
+ close(fd);
+ return reg_open_ldb_file(parent_ctx, location, session_info, credentials, root);
+ }
+
+ return WERR_BADFILE;
+}
+
+_PUBLIC_ WERROR hive_key_get_info(TALLOC_CTX *mem_ctx, const struct hive_key *key,
+ const char **classname, uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time)
+{
+ return key->ops->get_key_info(mem_ctx, key, classname, num_subkeys,
+ num_values, last_change_time);
+}
+
+_PUBLIC_ WERROR hive_key_add_name(TALLOC_CTX *ctx, const struct hive_key *parent_key,
+ const char *name, const char *classname, struct security_descriptor *desc,
+ struct hive_key **key)
+{
+ SMB_ASSERT(strchr(name, '\\') == NULL);
+
+ return parent_key->ops->add_key(ctx, parent_key, name, classname, desc, key);
+}
+
+_PUBLIC_ WERROR hive_key_del(const struct hive_key *key, const char *name)
+{
+ return key->ops->del_key(key, name);
+}
+
+_PUBLIC_ WERROR hive_get_key_by_name(TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, const char *name,
+ struct hive_key **subkey)
+{
+ return key->ops->get_key_by_name(mem_ctx, key, name, subkey);
+}
+
+WERROR hive_enum_key(TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, uint32_t idx,
+ const char **name,
+ const char **classname,
+ NTTIME *last_mod_time)
+{
+ return key->ops->enum_key(mem_ctx, key, idx, name, classname,
+ last_mod_time);
+}
+
+WERROR hive_set_value(struct hive_key *key, const char *name, uint32_t type,
+ const DATA_BLOB data)
+{
+ if (key->ops->set_value == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->ops->set_value(key, name, type, data);
+}
+
+WERROR hive_get_value (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, const char *name,
+ uint32_t *type, DATA_BLOB *data)
+{
+ if (key->ops->get_value_by_name == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->ops->get_value_by_name(mem_ctx, key, name, type, data);
+}
+
+WERROR hive_get_value_by_index (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, uint32_t idx, const char **name,
+ uint32_t *type, DATA_BLOB *data)
+{
+ if (key->ops->enum_value == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->ops->enum_value(mem_ctx, key, idx, name, type, data);
+}
+
+
+WERROR hive_del_value (struct hive_key *key, const char *name)
+{
+ if (key->ops->delete_value == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->ops->delete_value(key, name);
+}
+
+WERROR hive_key_flush(struct hive_key *key)
+{
+ if (key->ops->flush_key == NULL)
+ return WERR_OK;
+
+ return key->ops->flush_key(key);
+}
diff --git a/source4/lib/registry/hive.h b/source4/lib/registry/hive.h
new file mode 100644
index 0000000000..33759fdecc
--- /dev/null
+++ b/source4/lib/registry/hive.h
@@ -0,0 +1,197 @@
+/*
+ Unix SMB/CIFS implementation.
+ Registry hive interface
+ Copyright (C) Jelmer Vernooij 2003-2007.
+
+ 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_HIVE_H__
+#define __REGISTRY_HIVE_H__
+
+#include "core.h"
+#include "talloc.h"
+#include "librpc/gen_ndr/security.h"
+
+/**
+ * This file contains the hive API. This API is generally used for
+ * reading a specific file that contains just one hive.
+ *
+ * Good examples are .DAT (NTUSER.DAT) files.
+ *
+ * This API does not have any notification support (that
+ * should be provided by the registry implementation), nor
+ * does it understand what predefined keys are.
+ */
+
+struct hive_key {
+ const struct hive_operations *ops;
+};
+
+struct hive_operations {
+ const char *name;
+
+ /**
+ * Open a specific subkey
+ */
+ WERROR (*enum_key) (TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, uint32_t idx,
+ const char **name,
+ const char **classname,
+ NTTIME *last_mod_time);
+
+ /**
+ * Open a subkey by name
+ */
+ WERROR (*get_key_by_name) (TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, const char *name,
+ struct hive_key **subkey);
+
+ /**
+ * Add a new key.
+ */
+ WERROR (*add_key) (TALLOC_CTX *ctx,
+ const struct hive_key *parent_key, const char *name,
+ const char *classname, struct security_descriptor *desc,
+ struct hive_key **key);
+ /**
+ * Remove an existing key.
+ */
+ WERROR (*del_key) (const struct hive_key *key, const char *name);
+
+ /**
+ * Force write of a key to disk.
+ */
+ WERROR (*flush_key) (struct hive_key *key);
+
+ /**
+ * Retrieve a registry value with a specific index.
+ */
+ WERROR (*enum_value) (TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, int idx,
+ const char **name, uint32_t *type,
+ DATA_BLOB *data);
+
+ /**
+ * Retrieve a registry value with the specified name
+ */
+ WERROR (*get_value_by_name) (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, const char *name,
+ uint32_t *type, DATA_BLOB *data);
+
+ /**
+ * Set a value on the specified registry key.
+ */
+ WERROR (*set_value) (struct hive_key *key, const char *name,
+ uint32_t type, const DATA_BLOB data);
+
+ /**
+ * Remove a value.
+ */
+ WERROR (*delete_value) (struct hive_key *key, const char *name);
+
+ /* Security Descriptors */
+
+ /**
+ * Change the security descriptor on a registry key.
+ *
+ * This should return WERR_NOT_SUPPORTED if the underlying
+ * format does not have a mechanism for storing
+ * security descriptors.
+ */
+ WERROR (*set_sec_desc) (struct hive_key *key,
+ const struct security_descriptor *desc);
+
+ /**
+ * Retrieve the security descriptor on a registry key.
+ *
+ * This should return WERR_NOT_SUPPORTED if the underlying
+ * format does not have a mechanism for storing
+ * security descriptors.
+ */
+ WERROR (*get_sec_desc) (TALLOC_CTX *ctx,
+ const struct hive_key *key,
+ struct security_descriptor **desc);
+
+ /**
+ * Retrieve general information about a key.
+ */
+ WERROR (*get_key_info) (TALLOC_CTX *mem_ctx,
+ const struct hive_key *key,
+ const char **classname,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time);
+};
+
+struct cli_credentials;
+struct auth_session_info;
+
+WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ struct hive_key **root);
+WERROR hive_key_get_info(TALLOC_CTX *mem_ctx, const struct hive_key *key,
+ const char **classname, uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time);
+WERROR hive_key_add_name(TALLOC_CTX *ctx, const struct hive_key *parent_key,
+ const char *name, const char *classname, struct security_descriptor *desc,
+ struct hive_key **key);
+_PUBLIC_ WERROR hive_key_del(const struct hive_key *key, const char *name);
+_PUBLIC_ WERROR hive_get_key_by_name(TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, const char *name,
+ struct hive_key **subkey);
+WERROR hive_enum_key(TALLOC_CTX *mem_ctx,
+ const struct hive_key *key, uint32_t idx,
+ const char **name,
+ const char **classname,
+ NTTIME *last_mod_time);
+
+WERROR hive_set_value (struct hive_key *key, const char *name,
+ uint32_t type, const DATA_BLOB data);
+
+WERROR hive_get_value (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, const char *name,
+ uint32_t *type, DATA_BLOB *data);
+WERROR hive_get_value_by_index (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, uint32_t idx, const char **name,
+ uint32_t *type, DATA_BLOB *data);
+
+WERROR hive_del_value (struct hive_key *key, const char *name);
+
+WERROR hive_key_flush(struct hive_key *key);
+
+
+/* Individual backends */
+WERROR reg_open_directory(TALLOC_CTX *parent_ctx,
+ const char *location, struct hive_key **key);
+WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx,
+ const char *location, struct hive_key **key);
+WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ struct hive_key **k);
+
+
+WERROR reg_create_directory(TALLOC_CTX *parent_ctx,
+ const char *location, struct hive_key **key);
+WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx,
+ const char *location,
+ int major_version,
+ struct hive_key **key);
+
+
+#endif /* __REGISTRY_HIVE_H__ */
diff --git a/source4/lib/registry/interface.c b/source4/lib/registry/interface.c
new file mode 100644
index 0000000000..4d75e99f00
--- /dev/null
+++ b/source4/lib/registry/interface.c
@@ -0,0 +1,277 @@
+/*
+ Unix SMB/CIFS implementation.
+ Transparent registry backend handling
+ Copyright (C) Jelmer Vernooij 2003-2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/dlinklist.h"
+#include "lib/registry/registry.h"
+#include "system/filesys.h"
+#include "build.h"
+
+
+/**
+ * @file
+ * @brief Main registry functions
+ */
+
+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 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(const struct registry_context *ctx,
+ uint32_t hkey, struct registry_key **key)
+{
+ return ctx->ops->get_predefined_key(ctx, hkey, key);
+}
+
+/**
+ * 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)
+{
+ if (parent == NULL) {
+ DEBUG(0, ("Invalid parent key specified for open of '%s'\n", name));
+ return WERR_INVALID_PARAM;
+ }
+
+ if (parent->context->ops->open_key == NULL) {
+ DEBUG(0, ("Registry backend doesn't have open_key!\n"));
+ return WERR_NOT_SUPPORTED;
+ }
+
+ return parent->context->ops->open_key(mem_ctx, parent, name, result);
+}
+
+/**
+ * Get value by index
+ */
+_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ uint32_t idx,
+ const char **name,
+ uint32_t *type,
+ DATA_BLOB *data)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (key->context->ops->enum_value == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->enum_value(mem_ctx, key, idx, name, type,
+ data);
+}
+
+/**
+ * Get the number of subkeys.
+ */
+_PUBLIC_ WERROR reg_key_get_info(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char **classname,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (key->context->ops->get_key_info == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->get_key_info(mem_ctx,
+ key, classname, num_subkeys,
+ num_values, last_change_time);
+}
+
+/**
+ * Get subkey by index.
+ */
+_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key, int idx, const char **name,
+ const char **keyclass, NTTIME *last_changed_time)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (key->context->ops->enum_key == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->enum_key(mem_ctx, key, idx, name,
+ keyclass, last_changed_time);
+}
+
+/**
+ * Get value by name.
+ */
+_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char *name,
+ uint32_t *type,
+ DATA_BLOB *data)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (key->context->ops->get_value == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->get_value(mem_ctx, key, name, type, data);
+}
+
+/**
+ * Delete a key.
+ */
+_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name)
+{
+ if (parent == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (parent->context->ops->delete_key == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return parent->context->ops->delete_key(parent, name);
+}
+
+/**
+ * Add a key.
+ */
+_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
+ const char *name, const char *key_class,
+ struct security_descriptor *desc,
+ struct registry_key **newkey)
+{
+ if (parent == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (parent->context->ops->create_key == NULL) {
+ DEBUG(1, ("Backend '%s' doesn't support method add_key\n",
+ parent->context->ops->name));
+ return WERR_NOT_SUPPORTED;
+ }
+
+ return parent->context->ops->create_key(mem_ctx, parent, name,
+ key_class, desc, newkey);
+}
+
+/**
+ * Set a value.
+ */
+_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value,
+ uint32_t type, const DATA_BLOB data)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ /* A 'real' set function has preference */
+ if (key->context->ops->set_value == NULL) {
+ DEBUG(1, ("Backend '%s' doesn't support method set_value\n",
+ key->context->ops->name));
+ return WERR_NOT_SUPPORTED;
+ }
+
+ return key->context->ops->set_value(key, value, type, data);
+}
+
+/**
+ * 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)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ /* A 'real' set function has preference */
+ if (key->context->ops->get_security == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->get_security(ctx, key, secdesc);
+}
+
+/**
+ * Delete a value.
+ */
+_PUBLIC_ WERROR reg_del_value(struct registry_key *key, const char *valname)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (key->context->ops->delete_value == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->delete_value(key, valname);
+}
+
+/**
+ * Flush a key to disk.
+ */
+_PUBLIC_ WERROR reg_key_flush(struct registry_key *key)
+{
+ if (key == NULL)
+ return WERR_INVALID_PARAM;
+
+ if (key->context->ops->flush_key == NULL)
+ return WERR_NOT_SUPPORTED;
+
+ return key->context->ops->flush_key(key);
+}
diff --git a/source4/lib/registry/ldb.c b/source4/lib/registry/ldb.c
new file mode 100644
index 0000000000..8ee4d9f932
--- /dev/null
+++ b/source4/lib/registry/ldb.c
@@ -0,0 +1,501 @@
+/*
+ Unix SMB/CIFS implementation.
+ Registry interface
+ Copyright (C) Jelmer Vernooij 2004-2007.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "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"
+
+static struct hive_operations reg_backend_ldb;
+
+struct ldb_key_data
+{
+ struct hive_key key;
+ struct ldb_context *ldb;
+ struct ldb_dn *dn;
+ struct ldb_message **subkeys, **values;
+ int subkey_count, value_count;
+};
+
+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;
+ if (name != NULL)
+ *name = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "value", NULL));
+
+ if (type != 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 ldb_key_data *key)
+{
+ if (key->subkeys != NULL) {
+ talloc_free(key->subkeys);
+ key->subkeys = NULL;
+ }
+
+ if (key->values != NULL) {
+ talloc_free(key->values);
+ key->values = NULL;
+ }
+ return 0;
+}
+
+static struct ldb_dn *reg_path_to_ldb(TALLOC_CTX *mem_ctx,
+ const struct hive_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, struct ldb_key_data);
+ struct ldb_context *ldb = kd->ldb;
+
+ 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 cache_subkeys(struct ldb_key_data *kd)
+{
+ struct ldb_context *c = kd->ldb;
+ 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);
+
+ return WERR_OK;
+}
+
+static WERROR cache_values(struct ldb_key_data *kd)
+{
+ struct ldb_context *c = kd->ldb;
+ 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);
+ return WERR_OK;
+}
+
+
+static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx,
+ const struct hive_key *k, uint32_t idx,
+ const char **name,
+ const char **classname,
+ NTTIME *last_mod_time)
+{
+ struct ldb_message_element *el;
+ struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
+
+ /* Do a search if necessary */
+ if (kd->subkeys == NULL) {
+ W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
+ }
+
+ if (idx >= kd->subkey_count)
+ return WERR_NO_MORE_ITEMS;
+
+ el = ldb_msg_find_element(kd->subkeys[idx], "key");
+ SMB_ASSERT(el != NULL);
+ SMB_ASSERT(el->num_values != 0);
+
+ if (name != NULL)
+ *name = talloc_strdup(mem_ctx, (char *)el->values[0].data);
+
+ if (classname != NULL)
+ *classname = NULL; /* TODO: Store properly */
+
+ if (last_mod_time != NULL)
+ *last_mod_time = 0; /* TODO: we need to add this to the
+ ldb backend properly */
+
+ return WERR_OK;
+}
+
+static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, const struct hive_key *k, int idx,
+ const char **name, uint32_t *data_type, DATA_BLOB *data)
+{
+ struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
+
+ /* Do the search if necessary */
+ if (kd->values == NULL) {
+ W_ERROR_NOT_OK_RETURN(cache_values(kd));
+ }
+
+ if(idx >= kd->value_count) return WERR_NO_MORE_ITEMS;
+
+ reg_ldb_unpack_value(mem_ctx, kd->values[idx],
+ name, data_type, data);
+
+ return WERR_OK;
+}
+
+static WERROR ldb_get_value(TALLOC_CTX *mem_ctx, struct hive_key *k,
+ const char *name, uint32_t *data_type, DATA_BLOB *data)
+{
+ struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
+ struct ldb_context *c = kd->ldb;
+ struct ldb_result *res;
+ int ret;
+ char *query = talloc_asprintf(mem_ctx, "(value=%s)", name);
+
+ ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, query, NULL, &res);
+
+ talloc_free(query);
+
+ 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;
+ }
+
+ if (res->count == 0)
+ return WERR_NOT_FOUND;
+
+ reg_ldb_unpack_value(mem_ctx, res->msgs[0], NULL, data_type, data);
+
+ return WERR_OK;
+}
+
+static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, const struct hive_key *h,
+ const char *name, struct hive_key **key)
+{
+ struct ldb_result *res;
+ struct ldb_dn *ldap_path;
+ int ret;
+ struct ldb_key_data *newkd;
+ struct ldb_key_data *kd = talloc_get_type(h, struct ldb_key_data);
+ struct ldb_context *c = kd->ldb;
+
+ 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) {
+ DEBUG(0, ("Key '%s' not found\n", ldb_dn_get_linearized(ldap_path)));
+ talloc_free(res);
+ return WERR_NOT_FOUND;
+ }
+
+ newkd = talloc_zero(mem_ctx, struct ldb_key_data);
+ newkd->key.ops = &reg_backend_ldb;
+ newkd->ldb = talloc_reference(newkd, kd->ldb);
+ newkd->dn = ldb_dn_copy(mem_ctx, res->msgs[0]->dn);
+
+ *key = (struct hive_key *)newkd;
+
+ talloc_free(res);
+
+ return WERR_OK;
+}
+
+WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials,
+ struct hive_key **k)
+{
+ struct ldb_key_data *kd;
+ struct ldb_context *wrap;
+
+ if (location == NULL)
+ return WERR_INVALID_PARAM;
+
+ wrap = ldb_wrap_connect(parent_ctx, location, session_info,
+ credentials, 0, NULL);
+
+ if (wrap == NULL) {
+ DEBUG(1, (__FILE__": unable to connect\n"));
+ return WERR_FOOBAR;
+ }
+
+ ldb_set_debug_stderr(wrap);
+
+ kd = talloc_zero(parent_ctx, struct ldb_key_data);
+ kd->key.ops = &reg_backend_ldb;
+ kd->ldb = talloc_reference(kd, wrap);
+ talloc_set_destructor (kd, reg_close_ldb_key);
+ kd->dn = ldb_dn_new(kd, wrap, "hive=NONE");
+
+ *k = (struct hive_key *)kd;
+
+ return WERR_OK;
+}
+
+static WERROR ldb_add_key (TALLOC_CTX *mem_ctx, const struct hive_key *parent,
+ const char *name, const char *classname,
+ struct security_descriptor *sd,
+ struct hive_key **newkey)
+{
+ const struct ldb_key_data *parentkd = (const struct ldb_key_data *)parent;
+ 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));
+ if (classname != NULL)
+ ldb_msg_add_string(msg, "classname", talloc_strdup(mem_ctx, classname));
+
+ ret = ldb_add(parentkd->ldb, msg);
+ if (ret < 0) {
+ DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(parentkd->ldb)));
+ return WERR_FOOBAR;
+ }
+
+ DEBUG(2, ("key added: %s\n", ldb_dn_get_linearized(msg->dn)));
+
+ newkd = talloc_zero(mem_ctx, struct ldb_key_data);
+ newkd->ldb = talloc_reference(newkd, parentkd->ldb);
+ newkd->key.ops = &reg_backend_ldb;
+ newkd->dn = talloc_steal(newkd, msg->dn);
+
+ *newkey = (struct hive_key *)newkd;
+
+ return WERR_OK;
+}
+
+static WERROR ldb_del_key (const struct hive_key *key, const char *child)
+{
+ int ret;
+ struct ldb_key_data *parentkd = talloc_get_type(key, struct ldb_key_data);
+ struct ldb_dn *childdn;
+
+ childdn = ldb_dn_copy(parentkd->ldb, parentkd->dn);
+ ldb_dn_add_child_fmt(childdn, "key=%s", child);
+
+ ret = ldb_delete(parentkd->ldb, childdn);
+
+ talloc_free(childdn);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ return WERR_NOT_FOUND;
+ } else if (ret < 0) {
+ DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(parentkd->ldb)));
+ return WERR_FOOBAR;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR ldb_del_value (struct hive_key *key, const char *child)
+{
+ int ret;
+ struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
+ struct ldb_dn *childdn;
+
+ childdn = ldb_dn_copy(kd->ldb, kd->dn);
+ ldb_dn_add_child_fmt(childdn, "value=%s", child);
+
+ ret = ldb_delete(kd->ldb, childdn);
+
+ talloc_free(childdn);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ return WERR_NOT_FOUND;
+ } else if (ret < 0) {
+ DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb)));
+ return WERR_FOOBAR;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR ldb_set_value(struct hive_key *parent,
+ const char *name, uint32_t type,
+ const DATA_BLOB data)
+{
+ struct ldb_message *msg;
+ struct ldb_key_data *kd = talloc_get_type(parent, struct ldb_key_data);
+ int ret;
+ TALLOC_CTX *mem_ctx = talloc_init("ldb_set_value");
+
+ msg = reg_ldb_pack_value(kd->ldb, 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(kd->ldb, msg);
+ if (ret < 0) {
+ ret = ldb_modify(kd->ldb, msg);
+ if (ret < 0) {
+ DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(kd->ldb)));
+ talloc_free(mem_ctx);
+ return WERR_FOOBAR;
+ }
+ }
+
+ talloc_free(mem_ctx);
+ return WERR_OK;
+}
+
+static WERROR ldb_get_key_info(TALLOC_CTX *mem_ctx,
+ const struct hive_key *key,
+ const char **classname,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time)
+{
+ struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
+
+ /* FIXME */
+ if (classname != NULL)
+ *classname = NULL;
+
+ if (num_subkeys != NULL) {
+ W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
+ *num_subkeys = kd->subkey_count;
+ }
+
+ if (num_values != NULL) {
+ W_ERROR_NOT_OK_RETURN(cache_values(kd));
+ *num_values = kd->value_count;
+ }
+
+ if (last_change_time != NULL)
+ *last_change_time = 0;
+
+ return WERR_OK;
+}
+
+static struct hive_operations reg_backend_ldb = {
+ .name = "ldb",
+ .add_key = ldb_add_key,
+ .del_key = ldb_del_key,
+ .get_key_by_name = ldb_open_key,
+ .enum_value = ldb_get_value_by_id,
+ .enum_key = ldb_get_subkey_by_id,
+ .set_value = ldb_set_value,
+ .get_value_by_name = ldb_get_value,
+ .delete_value = ldb_del_value,
+ .get_key_info = ldb_get_key_info,
+};
diff --git a/source4/lib/registry/local.c b/source4/lib/registry/local.c
new file mode 100644
index 0000000000..aefb11bde2
--- /dev/null
+++ b/source4/lib/registry/local.c
@@ -0,0 +1,333 @@
+/*
+ Unix SMB/CIFS implementation.
+ Transparent registry backend handling
+ Copyright (C) Jelmer Vernooij 2003-2007.
+
+ 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 "system/filesys.h"
+#include "build.h"
+
+struct reg_key_path {
+ uint32_t predefined_key;
+ const char **elements;
+};
+
+struct registry_local {
+ struct registry_context registry;
+
+ struct mountpoint {
+ struct reg_key_path path;
+ struct hive_key *key;
+ struct mountpoint *prev, *next;
+ } *mountpoints;
+
+ struct auth_session_info *session_info;
+ struct cli_credentials *credentials;
+};
+
+struct local_key {
+ struct registry_key global;
+ struct reg_key_path path;
+ struct hive_key *hive_key;
+};
+
+
+struct registry_key *reg_import_hive_key(struct registry_context *ctx,
+ struct hive_key *hive,
+ uint32_t predefined_key,
+ const char **elements)
+{
+ struct local_key *local_key;
+ struct reg_key_path parent_path;
+
+ parent_path.predefined_key = predefined_key;
+ parent_path.elements = elements;
+
+ local_key = talloc(ctx, struct local_key);
+ local_key->hive_key = talloc_steal(local_key, hive);
+ local_key->global.context = talloc_reference(local_key, ctx);
+ local_key->path = parent_path;
+
+ return (struct registry_key *)local_key;
+}
+
+
+static WERROR local_open_key(TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
+ const char *path,
+ struct registry_key **result)
+{
+ char *orig = talloc_strdup(mem_ctx, path),
+ *curbegin = orig,
+ *curend = strchr(orig, '\\');
+ struct local_key *local_parent = talloc_get_type(parent, struct local_key);
+ struct hive_key *curkey = local_parent->hive_key;
+ WERROR error;
+ const char **elements = NULL;
+ int el;
+
+ if (local_parent->path.elements != NULL) {
+ elements = talloc_array(mem_ctx, const char *,
+ str_list_length(local_parent->path.elements) + 1);
+ for (el = 0; local_parent->path.elements[el] != NULL; el++) {
+ elements[el] = talloc_reference(elements,
+ local_parent->path.elements[el]);
+ }
+ elements[el] = NULL;
+ } else {
+ elements = NULL;
+ el = 0;
+ }
+
+ while (curbegin != NULL && *curbegin) {
+ if (curend != NULL)
+ *curend = '\0';
+ elements = talloc_realloc(mem_ctx, elements, const char *, el+2);
+ elements[el] = talloc_strdup(elements, curbegin);
+ el++;
+ elements[el] = NULL;
+ error = hive_get_key_by_name(mem_ctx, curkey, curbegin, &curkey);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(2, ("Opening key %s failed: %s\n", curbegin, win_errstr(error)));
+ talloc_free(orig);
+ return error;
+ }
+ if (curend == NULL)
+ break;
+ curbegin = curend + 1;
+ curend = strchr(curbegin, '\\');
+ }
+ talloc_free(orig);
+
+ *result = reg_import_hive_key(local_parent->global.context, curkey,
+ local_parent->path.predefined_key,
+ talloc_steal(curkey, elements));
+
+ return WERR_OK;
+}
+
+WERROR local_get_predefined_key (const struct registry_context *ctx,
+ uint32_t key_id, struct registry_key **key)
+{
+ struct registry_local *rctx = talloc_get_type(ctx, struct registry_local);
+ struct mountpoint *mp;
+
+ for (mp = rctx->mountpoints; mp != NULL; mp = mp->next) {
+ if (mp->path.predefined_key == key_id &&
+ mp->path.elements == NULL)
+ break;
+ }
+
+ if (mp == NULL)
+ return WERR_NOT_FOUND;
+
+ *key = reg_import_hive_key(ctx, mp->key,
+ mp->path.predefined_key,
+ mp->path.elements
+ );
+
+ return WERR_OK;
+}
+
+WERROR local_enum_key(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key, uint32_t idx,
+ const char **name,
+ const char **keyclass,
+ NTTIME *last_changed_time)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_enum_key(mem_ctx, local->hive_key, idx, name, keyclass,
+ last_changed_time);
+}
+
+static WERROR local_create_key (TALLOC_CTX *mem_ctx,
+ struct registry_key *parent_key,
+ const char *name,
+ const char *key_class,
+ struct security_descriptor *security,
+ struct registry_key **key)
+{
+ const struct local_key *local_parent;
+ struct hive_key *hivekey;
+ const char **elements;
+ int i;
+ char *last_part;
+
+ last_part = strrchr(name, '\\');
+ if (last_part == NULL) {
+ last_part = name;
+ local_parent = (const struct local_key *)parent_key;
+ } else {
+ W_ERROR_NOT_OK_RETURN(reg_open_key(mem_ctx, parent_key,
+ talloc_strndup(mem_ctx, name, last_part-name),
+ &local_parent));
+ last_part++;
+ }
+
+ W_ERROR_NOT_OK_RETURN(hive_key_add_name(mem_ctx, local_parent->hive_key,
+ last_part, key_class, security, &hivekey));
+
+ if (local_parent->path.elements != NULL) {
+ elements = talloc_array(hivekey, const char *,
+ str_list_length(local_parent->path.elements)+2);
+ for (i = 0; local_parent->path.elements[i] != NULL; i++) {
+ elements[i] = talloc_reference(elements,
+ local_parent->path.elements[i]);
+ }
+ } else {
+ elements = talloc_array(hivekey, const char *, 2);
+ i = 0;
+ }
+
+ elements[i] = talloc_strdup(elements, name);
+ elements[i+1] = NULL;
+
+ *key = reg_import_hive_key(local_parent->global.context, hivekey,
+ local_parent->path.predefined_key,
+ elements);
+
+ return WERR_OK;
+}
+
+static WERROR local_set_value (struct registry_key *key, const char *name,
+ uint32_t type, const DATA_BLOB data)
+{
+ struct local_key *local = (struct local_key *)key;
+
+ return hive_set_value(local->hive_key, name, type, data);
+}
+
+static WERROR local_get_value (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char *name, uint32_t *type, DATA_BLOB *data)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_get_value(mem_ctx, local->hive_key, name, type, data);
+}
+
+static WERROR local_enum_value (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key, uint32_t idx,
+ const char **name,
+ uint32_t *type,
+ DATA_BLOB *data)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_get_value_by_index(mem_ctx, local->hive_key, idx,
+ name, type, data);
+}
+
+static WERROR local_delete_key (struct registry_key *key, const char *name)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_key_del(local->hive_key, name);
+}
+
+static WERROR local_delete_value (struct registry_key *key, const char *name)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_del_value(local->hive_key, name);
+}
+
+static WERROR local_flush_key (struct registry_key *key)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_key_flush(local->hive_key);
+}
+
+static WERROR local_get_key_info (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char **classname,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time)
+{
+ const struct local_key *local = (const struct local_key *)key;
+
+ return hive_key_get_info(mem_ctx, local->hive_key,
+ classname, num_subkeys, num_values,
+ last_change_time);
+}
+
+const static struct registry_operations local_ops = {
+ .name = "local",
+ .open_key = local_open_key,
+ .get_predefined_key = local_get_predefined_key,
+ .enum_key = local_enum_key,
+ .create_key = local_create_key,
+ .set_value = local_set_value,
+ .get_value = local_get_value,
+ .enum_value = local_enum_value,
+ .delete_key = local_delete_key,
+ .delete_value = local_delete_value,
+ .flush_key = local_flush_key,
+ .get_key_info = local_get_key_info,
+};
+
+WERROR reg_open_local(TALLOC_CTX *mem_ctx, struct registry_context **ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials)
+{
+ struct registry_local *ret = talloc_zero(mem_ctx, struct registry_local);
+
+ W_ERROR_HAVE_NO_MEMORY(ret);
+
+ ret->registry.ops = &local_ops;
+ ret->session_info = session_info;
+ ret->credentials = credentials;
+
+ *ctx = (struct registry_context *)ret;
+
+ return WERR_OK;
+}
+
+WERROR reg_mount_hive(struct registry_context *rctx,
+ struct hive_key *hive_key,
+ uint32_t key_id,
+ const char **elements)
+{
+ struct registry_local *reg_local = talloc_get_type(rctx, struct registry_local);
+ struct mountpoint *mp = talloc(rctx, struct mountpoint);
+ int i = 0;
+
+ mp->path.predefined_key = key_id;
+ mp->prev = mp->next = NULL;
+ mp->key = hive_key;
+ if (elements != NULL) {
+ mp->path.elements = talloc_array(mp, const char *,
+ str_list_length(elements));
+ for (i = 0; elements[i] != NULL; i++) {
+ mp->path.elements[i] = talloc_reference(mp->path.elements,
+ elements[i]);
+ }
+ mp->path.elements[i] = NULL;
+ } else {
+ mp->path.elements = NULL;
+ }
+
+ DLIST_ADD(reg_local->mountpoints, mp);
+
+ return WERR_OK;
+}
diff --git a/source4/lib/registry/man/regdiff.1.xml b/source4/lib/registry/man/regdiff.1.xml
index 0e237bfece..7bcaa1502c 100644
--- a/source4/lib/registry/man/regdiff.1.xml
+++ b/source4/lib/registry/man/regdiff.1.xml
@@ -54,7 +54,7 @@
<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>.
+ creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
</para>
<para>
This argument can be specified twice: once for the first
diff --git a/source4/lib/registry/man/regpatch.1.xml b/source4/lib/registry/man/regpatch.1.xml
index c04bad9e66..d9dcdcbf80 100644
--- a/source4/lib/registry/man/regpatch.1.xml
+++ b/source4/lib/registry/man/regpatch.1.xml
@@ -49,7 +49,7 @@
<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>.
+ creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
</para></listitem>
</varlistentry>
diff --git a/source4/lib/registry/man/regshell.1.xml b/source4/lib/registry/man/regshell.1.xml
index edec729120..9f16d8cc24 100644
--- a/source4/lib/registry/man/regshell.1.xml
+++ b/source4/lib/registry/man/regshell.1.xml
@@ -48,7 +48,7 @@
<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>.
+ creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
</para></listitem>
</varlistentry>
diff --git a/source4/lib/registry/man/regtree.1.xml b/source4/lib/registry/man/regtree.1.xml
index aa31855a2b..93f15e1fb2 100644
--- a/source4/lib/registry/man/regtree.1.xml
+++ b/source4/lib/registry/man/regtree.1.xml
@@ -48,7 +48,7 @@
<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>.
+ creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
</para></listitem>
</varlistentry>
diff --git a/source4/lib/registry/patchfile.c b/source4/lib/registry/patchfile.c
index 12847eedd8..50c8f54397 100644
--- a/source4/lib/registry/patchfile.c
+++ b/source4/lib/registry/patchfile.c
@@ -1,8 +1,9 @@
/*
Unix SMB/CIFS implementation.
- Reading .REG files
+ Reading registry patch files
- Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Jelmer Vernooij 2004-2007
+ Copyright (C) Wilco Baan Hofman 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,153 +20,191 @@
*/
#include "includes.h"
+#include "lib/registry/patchfile.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;
+_PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
- diff->numkeys++;
- return NULL;
-}
+_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
/*
* Generate difference between two keys
*/
-static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *oldkey, struct registry_key *newkey)
+WERROR reg_generate_diff_key(struct registry_key *oldkey,
+ struct registry_key *newkey,
+ const char *path,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data)
{
int i;
struct registry_key *t1, *t2;
- struct registry_value *v1, *v2;
- WERROR error1, error2;
+ char *tmppath;
+ const char *keyname1;
+ WERROR error, error1, error2;
TALLOC_CTX *mem_ctx = talloc_init("writediff");
+ uint32_t old_num_subkeys, old_num_values,
+ new_num_subkeys, new_num_values;
- /* 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 (oldkey != NULL) {
+ error = reg_key_get_info(mem_ctx, oldkey, NULL, &old_num_subkeys, &old_num_values,
+ NULL);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error occured while getting key info: %s\n",
+ win_errstr(error)));
+ return error;
+ }
+ } else {
+ old_num_subkeys = 0;
+ old_num_values = 0;
+ }
- if (W_ERROR_IS_OK(error2))
+ /* Subkeys that were deleted */
+ for (i = 0; i < old_num_subkeys; i++) {
+ error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &keyname1,
+ NULL, NULL);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Error occured while getting subkey by index: %s\n",
+ win_errstr(error2)));
continue;
+ }
+
+ if (newkey != NULL) {
+ error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
+
+ if (W_ERROR_IS_OK(error2))
+ continue;
+ } else {
+ error2 = WERR_DEST_NOT_FOUND;
+ t2 = NULL;
+ }
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ win_errstr(error2)));
+ talloc_free(mem_ctx);
return error2;
}
/* newkey didn't have such a subkey, add del diff */
- 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++;
+ tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+ callbacks->del_key(callback_data, tmppath);
+ talloc_free(tmppath);
}
- 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;
+ if (newkey != NULL) {
+ error = reg_key_get_info(mem_ctx, newkey, NULL, &new_num_subkeys, &new_num_values,
+ NULL);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error occured while getting key info: %s\n",
+ win_errstr(error)));
+ return error;
+ }
+ } else {
+ new_num_subkeys = 0;
+ new_num_values = 0;
}
/* Subkeys that were added */
- for(i = 0; 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);
+ for(i = 0; i < new_num_subkeys; i++) {
+ error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &keyname1,
+ NULL, NULL);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Error occured while getting subkey by index: %s\n",
+ win_errstr(error1)));
+ talloc_free(mem_ctx);
+ return error1;
+ }
+
+ if (oldkey != NULL) {
+ error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
+
+ if (W_ERROR_IS_OK(error2))
+ continue;
+ } else {
+ t1 = NULL;
+ error2 = WERR_DEST_NOT_FOUND;
+ }
- if (W_ERROR_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)));
+ DEBUG(0, ("Error occured while getting subkey by name: %s\n",
+ win_errstr(error2)));
+ talloc_free(mem_ctx);
return error2;
}
/* oldkey didn't have such a subkey, add add diff */
- 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);
- }
+ tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+ callbacks->add_key(callback_data, tmppath);
- 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;
+ W_ERROR_NOT_OK_RETURN(
+ reg_open_key(mem_ctx, newkey, keyname1, &t2));
+
+ reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
+ talloc_free(tmppath);
}
/* Values that were changed */
- for(i = 0; 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);
+ for(i = 0; i < new_num_values; i++) {
+ const char *name;
+ uint32_t type1, type2;
+ DATA_BLOB contents1, contents2;
+
+ error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
+ &name, &type1, &contents1);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Unable to get key by index: %s\n",
+ win_errstr(error1)));
+ talloc_free(mem_ctx);
+ return error1;
+ }
+
+ if (oldkey != NULL) {
+ error2 = reg_key_get_value_by_name(mem_ctx, oldkey, name,
+ &type2, &contents2);
+ } else
+ error2 = WERR_DEST_NOT_FOUND;
if(!W_ERROR_IS_OK(error2) &&
!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting value by name: %s\n",
+ win_errstr(error2)));
+ talloc_free(mem_ctx);
return error2;
}
- if (W_ERROR_IS_OK(error2) && data_blob_cmp(&v1->data, &v2->data) == 0)
+ if (W_ERROR_IS_OK(error2) && data_blob_cmp(&contents1, &contents2) == 0)
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;
+ callbacks->set_value(callback_data, path, name, type1, contents1);
}
/* 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);
+ for (i = 0; i < old_num_values; i++) {
+ const char *name;
+ error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
+ NULL, NULL);
+ if (!W_ERROR_IS_OK(error1)) {
+ DEBUG(0, ("Error ocurred getting value by index: %s\n",
+ win_errstr(error1)));
+ talloc_free(mem_ctx);
+ return error1;
+ }
+
+ error2 = reg_key_get_value_by_name(mem_ctx, newkey, name, NULL,
+ NULL);
if (W_ERROR_IS_OK(error2))
continue;
if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
- DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
+ DEBUG(0, ("Error occured while getting value by name: %s\n",
+ win_errstr(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;
+ callbacks->del_value(callback_data, path, name);
}
talloc_free(mem_ctx);
@@ -175,244 +214,206 @@ static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *
/**
* 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)
+_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
+ struct registry_context *ctx2,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data)
{
- 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;
+ for(i = HKEY_FIRST; i <= HKEY_LAST; i++) {
+ struct registry_key *r1 = NULL, *r2 = NULL;
error = reg_get_predefined_key(ctx1, i, &r1);
- if (!W_ERROR_IS_OK(error)) {
+ if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_predef_name(i)));
- continue;
}
error = reg_get_predefined_key(ctx2, i, &r2);
- if (!W_ERROR_IS_OK(error)) {
+ if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_predef_name(i)));
- 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);
+ if (r1 == NULL && r2 == NULL)
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;
- }
+ error = reg_generate_diff_key(r1, r2, reg_get_predef_name(i), callbacks, callback_data);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Unable to determine diff: %s\n", win_errstr(error)));
+ return error;
}
-
- fdprintf(xf, "\n");
}
-
- close(xf);
-
+ if (callbacks->done != NULL) {
+ callbacks->done(callback_data);
+ }
return WERR_OK;
}
/**
* Load diff file
*/
-_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn)
+_PUBLIC_ WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data)
{
- 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);
+ char hdr[4];
+
+ fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
- DEBUG(0, ("Error opening registry patch file `%s'\n", fn));
- return NULL;
+ DEBUG(0, ("Error opening registry patch file `%s'\n", filename));
+ return WERR_GENERAL_FAILURE;
}
- diff = talloc_zero(ctx, struct reg_diff);
- if (diff == NULL) {
- close(fd);
- return NULL;
+ if (read(fd, &hdr, 4) != 4) {
+ DEBUG(0, ("Error reading registry patch file `%s'\n", filename));
+ return WERR_GENERAL_FAILURE;
}
-
- diff->format = afdgets(fd, diff, 0);
- if (!diff->format) {
- talloc_free(diff);
- close(fd);
- return NULL;
+
+ /* Reset position in file */
+ lseek(fd, 0, SEEK_SET);
+#if 0
+ if (strncmp(hdr, "CREG", 4) == 0) {
+ /* Must be a W9x CREG Config.pol file */
+ return reg_creg_diff_load(diff, fd);
+ } else if (strncmp(hdr, "regf", 4) == 0) {
+ /* Must be a REGF NTConfig.pol file */
+ return reg_regf_diff_load(diff, fd);
+ } else
+#endif
+ if (strncmp(hdr, "PReg", 4) == 0) {
+ /* Must be a GPO Registry.pol file */
+ return reg_preg_diff_load(fd, callbacks, callback_data);
+ } else {
+ /* Must be a normal .REG file */
+ return reg_dotreg_diff_load(fd, callbacks, callback_data);
}
+}
- while ((line = afdgets(fd, diff, 0))) {
- /* Ignore comments and empty lines */
- if (strlen(line) == 0 || line[0] == ';') {
- curkey = NULL;
- talloc_free(line);
- continue;
- }
+/**
+ * The reg_diff_apply functions
+ */
+static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
+{
+ struct registry_context *ctx = _ctx;
+ struct registry_key *tmp;
+ WERROR error;
- /* 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;
- }
+ error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
- /* 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;
- }
+ if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) && !W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error adding new key '%s': %s\n", key_name, win_errstr(error)));
+ return error;
+ }
+ return WERR_OK;
+}
- /* Deleting/Changing value */
- p = strchr_m(line, '=');
- if (p == NULL) {
- DEBUG(0, ("Malformed line\n"));
- talloc_free(line);
- continue;
- }
+static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
+{
+ struct registry_context *ctx = _ctx;
+ WERROR error;
- *p = '\0'; p++;
+ error = reg_key_del_abs(ctx, key_name);
- if (curkey == NULL) {
- DEBUG(0, ("Value change without key\n"));
- talloc_free(line);
- continue;
- }
+ if(!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Unable to delete key '%s'\n", key_name));
+ return error;
+ }
+
+ return WERR_OK;
+}
- 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);
+static WERROR reg_diff_apply_set_value(void *_ctx, const char *path, const char *value_name, uint32_t value_type, DATA_BLOB value)
+{
+ struct registry_context *ctx = _ctx;
+ struct registry_key *tmp;
+ WERROR error;
+
+ /* Open key */
+ error = reg_open_key_abs(ctx, ctx, path, &tmp);
- /* Delete value */
- if (strcmp(p, "-")) {
- curval->changetype = REG_DIFF_DEL_VAL;
- talloc_free(line);
- continue;
- }
-
- q = strchr_m(p, ':');
- if (q) {
- *q = '\0';
- q++;
- }
+ if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
+ DEBUG(0, ("Error opening key '%s'\n", path));
+ return error;
+ }
- curval->changetype = REG_DIFF_SET_VAL;
- reg_string_to_val(curkey->values, q?p:"REG_SZ", q?q:p, &curval->type, &curval->data);
+ /* Set value */
+ error = reg_val_set(tmp, value_name,
+ value_type, value);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error setting value '%s'\n", value_name));
+ return error;
+ }
+
+ return WERR_OK;
+}
- talloc_free(line);
+static WERROR reg_diff_apply_del_value (void *_ctx, const char *key_name, const char *value_name)
+{
+ struct registry_context *ctx = _ctx;
+ struct registry_key *tmp;
+ WERROR error;
+
+ /* Open key */
+ error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
+
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error opening key '%s'\n", key_name));
+ return error;
}
- close(fd);
+ error = reg_del_value(tmp, value_name);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error deleting value '%s'\n", value_name));
+ return error;
+ }
+
- return diff;
+ return WERR_OK;
}
-/**
- * Apply diff to a registry context
- */
-_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx)
+static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
{
- TALLOC_CTX *mem_ctx = talloc_init("apply_cmd_file");
- struct registry_key *tmp = NULL;
+ struct registry_context *ctx = _ctx;
+ struct registry_key *key;
WERROR error;
- int i, j;
+ int i;
+ uint32_t num_values;
- 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);
+ error = reg_open_key_abs(ctx, ctx, key_name, &key);
- if(!W_ERROR_IS_OK(error)) {
- DEBUG(0, ("Unable to delete key '%s'\n", diff->keys[i].name));
- return False;
- }
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error opening key '%s'\n", key_name));
+ return error;
+ }
- continue;
- }
+ W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key,
+ NULL,
+ NULL,
+ &num_values,
+ NULL));
+
+ for (i = 0; i < num_values; i++) {
+ const char *name;
+ W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i, &name,
+ NULL, NULL));
+ W_ERROR_NOT_OK_RETURN(reg_del_value(key, name));
+ }
- /* Add / change key */
- error = reg_open_key_abs(mem_ctx, ctx, diff->keys[i].name, &tmp);
+ return WERR_OK;
+}
- /* 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;
- }
- }
+/**
+ * Apply diff to a registry context
+ */
+_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
+{
+ struct reg_diff_callbacks callbacks;
- 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;
- }
- }
- }
- }
+ callbacks.add_key = reg_diff_apply_add_key;
+ callbacks.del_key = reg_diff_apply_del_key;
+ callbacks.set_value = reg_diff_apply_set_value;
+ callbacks.del_value = reg_diff_apply_del_value;
+ callbacks.del_all_values = reg_diff_apply_del_all_values;
+ callbacks.done = NULL;
- return True;
+ return reg_diff_load(filename, &callbacks, ctx);
}
diff --git a/source4/lib/registry/patchfile.h b/source4/lib/registry/patchfile.h
new file mode 100644
index 0000000000..194e2a132a
--- /dev/null
+++ b/source4/lib/registry/patchfile.h
@@ -0,0 +1,52 @@
+/*
+ Unix SMB/CIFS implementation.
+ Patchfile interface
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) Wilco Baan Hofman 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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 _PATCHFILE_H
+#define _PATCHFILE_H
+
+#include "lib/registry/registry.h"
+
+struct reg_diff_callbacks {
+ WERROR (*add_key) (void *callback_data, const char *key_name);
+ WERROR (*set_value) (void *callback_data, const char *key_name,
+ const char *value_name, uint32_t value_type, DATA_BLOB value);
+ WERROR (*del_value) (void *callback_data, const char *key_name, const char *value_name);
+ WERROR (*del_key) (void *callback_data, const char *key_name);
+ WERROR (*del_all_values) (void *callback_data, const char *key_name);
+ WERROR (*done) (void *callback_data);
+};
+
+_PUBLIC_ WERROR reg_diff_apply (const char *filename,
+ struct registry_context *ctx);
+
+_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
+ struct registry_context *ctx2,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data);
+_PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename,
+ struct reg_diff_callbacks **callbacks, void **callback_data);
+_PUBLIC_ WERROR reg_generate_diff_key(struct registry_key *oldkey,
+ struct registry_key *newkey,
+ const char *path,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data);
+
+#endif /* _PATCHFILE_H */
diff --git a/source4/lib/registry/patchfile_dotreg.c b/source4/lib/registry/patchfile_dotreg.c
new file mode 100644
index 0000000000..f11ceb1be0
--- /dev/null
+++ b/source4/lib/registry/patchfile_dotreg.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/CIFS implementation.
+ Reading .REG files
+
+ Copyright (C) Jelmer Vernooij 2004-2007
+ Copyright (C) Wilco Baan Hofman 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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.
+*/
+
+/* FIXME Newer .REG files, created by Windows XP and above use unicode UTF-16 */
+
+#include "includes.h"
+#include "lib/registry/patchfile.h"
+#include "lib/registry/registry.h"
+#include "system/filesys.h"
+
+/**
+ * @file
+ * @brief Registry patch files
+ */
+
+#define HEADER_STRING "REGEDIT4"
+
+struct dotreg_data {
+ int fd;
+};
+
+static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name)
+{
+ struct dotreg_data *data = _data;
+
+ fdprintf(data->fd, "\n[%s]\n", key_name);
+
+ return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name)
+{
+ struct dotreg_data *data = _data;
+
+ fdprintf(data->fd, "\n[-%s]\n", key_name);
+
+ return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_set_value(void *_data, const char *path,
+ const char *value_name, uint32_t value_type, DATA_BLOB value)
+{
+ struct dotreg_data *data = _data;
+
+ fdprintf(data->fd, "\"%s\"=%s:%s\n",
+ value_name, str_regtype(value_type),
+ reg_val_data_string(NULL, value_type, value));
+
+ return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_del_value(void *_data, const char *path, const char *value_name)
+{
+ struct dotreg_data *data = _data;
+
+ fdprintf(data->fd, "\"%s\"=-\n", value_name);
+
+ return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_done(void *_data)
+{
+ struct dotreg_data *data = _data;
+
+ close(data->fd);
+ talloc_free(data);
+
+ return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_del_all_values (void *callback_data, const char *key_name)
+{
+ return WERR_NOT_SUPPORTED;
+}
+
+/**
+ * Save registry diff
+ */
+_PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename,
+ struct reg_diff_callbacks **callbacks, void **callback_data)
+{
+ struct dotreg_data *data;
+
+ data = talloc_zero(ctx, struct dotreg_data);
+ *callback_data = data;
+
+ if (filename) {
+ data->fd = open(filename, O_CREAT, 0755);
+ if (data->fd == -1) {
+ DEBUG(0, ("Unable to open %s\n", filename));
+ return WERR_BADFILE;
+ }
+ } else {
+ data->fd = STDOUT_FILENO;
+ }
+
+ fdprintf(data->fd, "%s\n", HEADER_STRING);
+
+ *callbacks = talloc(ctx, struct reg_diff_callbacks);
+
+ (*callbacks)->add_key = reg_dotreg_diff_add_key;
+ (*callbacks)->del_key = reg_dotreg_diff_del_key;
+ (*callbacks)->set_value = reg_dotreg_diff_set_value;
+ (*callbacks)->del_value = reg_dotreg_diff_del_value;
+ (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values;
+ (*callbacks)->done = reg_dotreg_diff_done;
+
+ return WERR_OK;
+}
+
+/**
+ * Load diff file
+ */
+_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data)
+{
+ char *line, *p, *q;
+ char *curkey = NULL;
+ TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load");
+ WERROR error;
+ uint32_t value_type;
+ DATA_BLOB value;
+
+ line = afdgets(fd, mem_ctx, 0);
+ if (!line) {
+ DEBUG(0, ("Can't read from file.\n"));
+ talloc_free(mem_ctx);
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ while ((line = afdgets(fd, mem_ctx, 0))) {
+ /* Ignore comments and empty lines */
+ if (strlen(line) == 0 || line[0] == ';') {
+ talloc_free(line);
+
+ if (curkey) {
+ talloc_free(curkey);
+ }
+ curkey = NULL;
+ continue;
+ }
+
+ /* Start of key */
+ if (line[0] == '[') {
+ p = strchr_m(line, ']');
+ if (p[strlen(p)-1] != ']') {
+ DEBUG(0, ("Missing ']'\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ /* Deleting key */
+ if (line[1] == '-') {
+ curkey = talloc_strndup(line, line+2, strlen(line)-3);
+
+ error = callbacks->del_key(callback_data, curkey);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0,("Error deleting key %s\n", curkey));
+ talloc_free(mem_ctx);
+ return error;
+ }
+
+ talloc_free(line);
+ curkey = NULL;
+ continue;
+ }
+ curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2);
+
+ error = callbacks->add_key(callback_data, curkey);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0,("Error adding key %s\n", curkey));
+ talloc_free(mem_ctx);
+ return error;
+ }
+
+ 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;
+ }
+
+ /* Delete value */
+ if (strcmp(p, "-")) {
+ error = callbacks->del_value(callback_data, curkey, line);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error deleting value %s in key %s\n", line, curkey));
+ talloc_free(mem_ctx);
+ return error;
+ }
+
+ talloc_free(line);
+ continue;
+ }
+
+ q = strchr_m(p, ':');
+ if (q) {
+ *q = '\0';
+ q++;
+ }
+
+ reg_string_to_val(line, q?p:"REG_SZ", q?q:p, &value_type, &value);
+
+ error = callbacks->set_value(callback_data, curkey, line, value_type, value);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Error setting value for %s in %s\n", line, curkey));
+ talloc_free(mem_ctx);
+ return error;
+ }
+
+ talloc_free(line);
+ }
+
+ close(fd);
+
+ return WERR_OK;
+}
diff --git a/source4/lib/registry/patchfile_preg.c b/source4/lib/registry/patchfile_preg.c
new file mode 100644
index 0000000000..1c8d76538a
--- /dev/null
+++ b/source4/lib/registry/patchfile_preg.c
@@ -0,0 +1,270 @@
+/*
+ Unix SMB/CIFS implementation.
+ Reading Registry.pol PReg registry files
+
+ Copyright (C) Wilco Baan Hofman 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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"
+#include "pstring.h"
+
+struct preg_data {
+ int fd;
+};
+
+static WERROR preg_read_utf16(int fd, char *c)
+{
+ uint16_t v;
+
+ if (read(fd, &v, 2) < 2) {
+ return WERR_GENERAL_FAILURE;
+ }
+ push_codepoint(c, v);
+ return WERR_OK;
+}
+
+/* FIXME These functions need to be implemented */
+static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
+{
+ struct preg_data *data = _data;
+ return WERR_OK;
+}
+
+static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
+{
+ struct preg_data *data = _data;
+ return WERR_OK;
+}
+
+static WERROR reg_preg_diff_set_value(void *_data, const char *key_name, const char *value_name, uint32_t value_type, DATA_BLOB value_data)
+{
+ struct preg_data *data = _data;
+ return WERR_OK;
+}
+
+static WERROR reg_preg_diff_del_value(void *_data, const char *key_name, const char *value_name)
+{
+ struct preg_data *data = _data;
+ return WERR_OK;
+}
+
+static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
+{
+ struct preg_data *data = _data;
+ return WERR_OK;
+}
+
+static WERROR reg_preg_diff_done(void *_data)
+{
+ struct preg_data *data = _data;
+
+ close(data->fd);
+ talloc_free(data);
+ return WERR_OK;
+}
+
+/**
+ * Save registry diff
+ */
+_PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename, struct reg_diff_callbacks **callbacks, void **callback_data)
+{
+ struct preg_data *data;
+ struct {
+ char hdr[4];
+ uint32_t version;
+ } preg_header;
+
+
+ data = talloc_zero(ctx, struct preg_data);
+ *callback_data = data;
+
+ if (filename) {
+ data->fd = open(filename, O_CREAT, 0755);
+ if (data->fd == -1) {
+ DEBUG(0, ("Unable to open %s\n", filename));
+ return WERR_BADFILE;
+ }
+ } else {
+ data->fd = STDOUT_FILENO;
+ }
+ snprintf(preg_header.hdr, 4, "PReg");
+ SIVAL(&preg_header, 4, 1);
+ write(data->fd, (uint8_t *)&preg_header,8);
+
+ *callbacks = talloc(ctx, struct reg_diff_callbacks);
+
+ (*callbacks)->add_key = reg_preg_diff_add_key;
+ (*callbacks)->del_key = reg_preg_diff_del_key;
+ (*callbacks)->set_value = reg_preg_diff_set_value;
+ (*callbacks)->del_value = reg_preg_diff_del_value;
+ (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
+ (*callbacks)->done = reg_preg_diff_done;
+
+ return WERR_OK;
+}
+/**
+ * Load diff file
+ */
+_PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data)
+{
+ struct {
+ char hdr[4];
+ uint32_t version;
+ } preg_header;
+ pstring buf;
+ char *buf_ptr = buf;
+ TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
+
+
+ /* Read first 8 bytes (the header) */
+ if (read(fd, &preg_header, 8) != 8) {
+ DEBUG(0, ("Could not read PReg file: %s\n",
+ strerror(errno)));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
+ DEBUG(0, ("This file is not a valid preg registry file\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ if (preg_header.version > 1) {
+ DEBUG(0, ("Warning: file format version is higher than expected.\n"));
+ }
+
+ /* Read the entries */
+ while(1) {
+ char *key, *value_name;
+ uint32_t value_type, length;
+ DATA_BLOB data;
+
+ if (!W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr))) {
+ break;
+ }
+ if (*buf_ptr != '[') {
+ DEBUG(0, ("Error in PReg file.\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* Get the path */
+ buf_ptr = buf;
+ while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr != ';' && buf_ptr-buf < sizeof(buf)) {
+ buf_ptr++;
+ }
+ key = talloc_asprintf(mem_ctx, "\\%s", buf);
+
+ /* Get the name */
+ buf_ptr = buf;
+ while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr != ';' && buf_ptr-buf < sizeof(buf)) {
+ buf_ptr++;
+ }
+ value_name = talloc_strdup(mem_ctx, buf);
+
+ /* Get the type */
+ if (read(fd, &value_type, 4) < 4) {
+ DEBUG(0, ("Error while reading PReg\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ /* Read past delimiter */
+ buf_ptr = buf;
+ if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr == ';') && buf_ptr-buf < sizeof(buf)) {
+ DEBUG(0, ("Error in PReg file.\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ /* Get data length */
+ if (read(fd, &length, 4) < 4) {
+ DEBUG(0, ("Error while reading PReg\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ /* Read past delimiter */
+ buf_ptr = buf;
+ if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr == ';') && buf_ptr-buf < sizeof(buf)) {
+ DEBUG(0, ("Error in PReg file.\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ /* Get the data */
+ buf_ptr = buf;
+ if (length < sizeof(buf) && read(fd, buf_ptr, length) != length) {
+ DEBUG(0, ("Error while reading PReg\n"));
+ close(fd);
+ return WERR_GENERAL_FAILURE;
+ }
+ data.length = length;
+ data.data = talloc_memdup(mem_ctx, buf, length);
+
+ /* Check if delimiter is in place (whine if it isn't) */
+ buf_ptr = buf;
+ if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr == ']') && buf_ptr-buf < sizeof(buf)) {
+ DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",*buf_ptr, *buf_ptr));
+ }
+
+ if (strcasecmp(value_name, "**DelVals") == 0) {
+ callbacks->del_all_values(callback_data, key);
+ } else if (strncasecmp(value_name, "**Del.",6) == 0) {
+ char *p = value_name+6;
+
+ callbacks->del_value(callback_data, key, p);
+ } else if (strcasecmp(value_name, "**DeleteValues") == 0) {
+ char *p, *q;
+
+ p = (char *) data.data;
+
+ while ((q = strchr_m(p, ';'))) {
+ *q = '\0';
+ q++;
+
+ callbacks->del_value(callback_data, key, p);
+
+ p = q;
+ }
+ callbacks->del_value(callback_data, key, p);
+ } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
+ char *p, *q, *full_key;
+
+ p = (char *) data.data;
+
+ while ((q = strchr_m(p, ';'))) {
+ *q = '\0';
+ q++;
+
+ full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
+ callbacks->del_key(callback_data, full_key);
+ talloc_free(full_key);
+
+ p = q;
+ }
+ full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
+ callbacks->del_key(callback_data, full_key);
+ talloc_free(full_key);
+ } else {
+ callbacks->add_key(callback_data, key);
+ callbacks->set_value(callback_data, key, value_name, value_type, data);
+ }
+ talloc_free(key);
+ talloc_free(value_name);
+ talloc_free(data.data);
+ }
+ close(fd);
+ return WERR_OK;
+}
diff --git a/source4/lib/registry/reg_backend_dir.c b/source4/lib/registry/reg_backend_dir.c
deleted file mode 100644
index c2dd3dad00..0000000000
--- a/source4/lib/registry/reg_backend_dir.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- 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 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "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(&reg_backend_dir);
-}
diff --git a/source4/lib/registry/reg_backend_ldb.c b/source4/lib/registry/reg_backend_ldb.c
deleted file mode 100644
index ca9327c174..0000000000
--- a/source4/lib/registry/reg_backend_ldb.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- 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 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "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(&reg_backend_ldb);
-}
diff --git a/source4/lib/registry/reg_backend_nt4.c b/source4/lib/registry/reg_backend_nt4.c
deleted file mode 100644
index 74261c57a9..0000000000
--- a/source4/lib/registry/reg_backend_nt4.c
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
- Samba CIFS implementation
- Registry backend for REGF files
- Copyright (C) 2005 Jelmer Vernooij, jelmer@samba.org
- Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "includes.h"
-#include "lib/registry/registry.h"
-#include "system/filesys.h"
-#include "system/time.h"
-#include "lib/registry/tdr_regf.h"
-#include "librpc/gen_ndr/ndr_security.h"
-
-/* TODO:
- * - Return error codes that make more sense
- * - Locking
- */
-
-/*
- * Read HBIN blocks into memory
- */
-
-struct regf_data {
- int fd;
- struct hbin_block **hbins;
- struct regf_hdr *header;
-};
-
-static struct hbin_block *hbin_by_offset (const struct regf_data *data, uint32_t offset, uint32_t *rel_offset)
-{
- int i;
-
- for (i = 0; data->hbins[i]; i++) {
- if (offset >= data->hbins[i]->offset_from_first &&
- offset < data->hbins[i]->offset_from_first+
- data->hbins[i]->offset_to_next) {
- if (rel_offset)
- *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
- return data->hbins[i];
- }
- }
-
- return NULL;
-}
-
-/*
- * Validate a regf header
- * For now, do nothing, but we should check the checksum
- */
-static uint32_t regf_hdr_checksum(const uint8_t *buffer)
-{
- uint32_t checksum = 0, x;
- int i;
-
- for (i = 0; i < 0x01FB; i+= 4) {
- x = IVAL(buffer, i);
- checksum ^= x;
- }
-
- return checksum;
-}
-
-static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
-{
- DATA_BLOB ret;
- struct hbin_block *hbin;
- uint32_t rel_offset;
- ret.data = NULL;
- ret.length = 0;
-
- hbin = hbin_by_offset(data, offset, &rel_offset);
-
- if (hbin == NULL) {
- DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));
- return ret;
- }
-
- ret.length = IVAL(hbin->data, rel_offset);
- if (!(ret.length & 0x80000000)) {
- DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
- return ret;
- }
-
- /* remove high bit */
- ret.length = (ret.length ^ 0xffffffff) + 1;
-
- ret.length -= 4; /* 4 bytes for the length... */
- ret.data = hbin->data +
- (offset - hbin->offset_from_first - 0x20) + 4;
-
- return ret;
-}
-
-static BOOL hbin_get_tdr (struct regf_data *regf, uint32_t offset, TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
-{
- struct tdr_pull pull;
-
- ZERO_STRUCT(pull);
-
- pull.data = hbin_get(regf, offset);
- if (!pull.data.data) {
- DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
- return False;
- }
-
- if (NT_STATUS_IS_ERR(pull_fn(&pull, ctx, p))) {
- DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
- return False;
- }
-
- return True;
-}
-
-/* Allocate some new data */
-static DATA_BLOB hbin_alloc (struct regf_data *data, uint32_t size, uint32_t *offset)
-{
- DATA_BLOB ret;
- uint32_t rel_offset = -1; /* Relative offset ! */
- struct hbin_block *hbin = NULL;
- int i;
-
- *offset = 0;
-
- if (size == 0)
- return data_blob(NULL, 0);
-
- size += 4; /* Need to include uint32 for the length */
-
- /* Allocate as a multiple of 8 */
- size = (size + 7) & ~7;
-
- ret.data = NULL;
- ret.length = 0;
-
- for (i = 0; (hbin = data->hbins[i]); i++) {
- int j;
- uint32_t my_size;
- for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
- uint32_t header = IVAL(hbin->data, j + 4);
- my_size = IVAL(hbin->data, j);
-
- if (my_size == 0x0) {
- DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
- return ret;
- }
-
- if (my_size % 8 != 0) {
- DEBUG(0, ("Encountered non-aligned block!\n"));
- }
-
- if (my_size & 0x80000000) { /* Used... */
- my_size = (my_size ^ 0xffffffff) + 1;
- } else if (my_size == size) { /* exact match */
- rel_offset = j;
- DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", size));
- break;
- } else if (my_size > size) { /* data will remain */
- rel_offset = j;
- SIVAL(hbin->data, rel_offset+size, my_size-size);
- DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", my_size, size));
- break;
- }
-
- if (header == 0xffffffff &&
- hbin->offset_to_next-rel_offset >= size) {
- rel_offset = j;
-
- DEBUG(4, ("Found free block of size %d at end of HBIN\n", size));
- /* Mark new free block size */
- SIVAL(hbin->data, rel_offset+size,hbin->offset_to_next - rel_offset - size - 0x20);
- SIVAL(hbin->data, rel_offset+size+0x4, 0xffffffff);
- break;
- }
-
- if (header == 0xffffffff) {
- break;
- }
- }
-
- if (rel_offset != -1)
- break;
- }
-
- /* No space available in previous hbins,
- * allocate new one */
- if (data->hbins[i] == NULL) {
- DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size));
- data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
- hbin = talloc(data->hbins, struct hbin_block);
- data->hbins[i] = hbin;
- data->hbins[i+1] = NULL;
-
- hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
- hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
- hbin->offset_to_next = 0x1000;
- hbin->unknown[0] = 0;
- hbin->unknown[0] = 0;
- unix_to_nt_time(&hbin->last_change, time(NULL));
- hbin->block_size = hbin->offset_to_next;
- hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
-
- rel_offset = 0x0;
- SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
- SIVAL(hbin->data, size + 0x4, 0xffffffff);
- }
-
- /* Set size and mark as used */
- SIVAL(hbin->data, rel_offset, size | 0x80000000);
-
- ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
- ret.length = size - 0x4;
- if (offset) {
- uint32_t new_rel_offset;
- *offset = hbin->offset_from_first + rel_offset + 0x20;
- SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
- SMB_ASSERT(new_rel_offset == rel_offset);
- }
-
- return ret;
-}
-
-/* Store a data blob. Return the offset at which it was stored */
-static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
-{
- uint32_t ret;
- DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
-
- memcpy(dest.data, blob.data, blob.length);
-
- return ret;
-}
-
-static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
-{
- struct tdr_push *push = talloc_zero(data, struct tdr_push);
- uint32_t ret;
-
- if (NT_STATUS_IS_ERR(push_fn(push, p))) {
- DEBUG(0, ("Error during push\n"));
- return -1;
- }
-
- ret = hbin_store(data, push->data);
-
- talloc_free(push);
-
- return ret;
-}
-
-
-/* Free existing data */
-static void hbin_free (struct regf_data *data, uint32_t offset)
-{
- uint32_t size;
- uint32_t rel_offset;
- struct hbin_block *hbin;
-
- SMB_ASSERT (offset > 0);
-
- hbin = hbin_by_offset(data, offset, &rel_offset);
-
- if (hbin == NULL)
- return;
-
- /* Get original size */
- size = IVAL(hbin->data, rel_offset);
-
- if (!(size & 0x80000000)) {
- DEBUG(1, ("Trying to free already freed block at 0x%04x\n", offset));
- return;
- }
-
- /* Mark block as free */
- SIVAL(hbin->data, rel_offset, size &~ 0x80000000);
-}
-
-/* Store a data blob data was already stored, but hsa changed in size
- * Will try to save it at the current location if possible, otherwise
- * does a free + store */
-static uint32_t hbin_store_resize (struct regf_data *data, uint32_t orig_offset, DATA_BLOB blob)
-{
- uint32_t rel_offset;
- struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
- uint32_t my_size;
- uint32_t orig_size;
- uint32_t needed_size;
- uint32_t possible_size;
- int i;
-
- SMB_ASSERT(orig_offset > 0);
-
- if (!hbin)
- return hbin_store(data, blob);
-
- /* Get original size */
- orig_size = IVAL(hbin->data, rel_offset);
-
- needed_size = blob.length + 4; /* Add uint32 containing length */
- needed_size = (needed_size + 7) & ~7; /* Align */
-
- /* Fits into current allocated block */
- if (orig_size >= needed_size) {
- memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
- return orig_offset;
- }
-
- possible_size = orig_size;
-
- /* Check if it can be combined with the next few free records */
- for (i = rel_offset;
- i < hbin->offset_to_next - 0x20;
- i += my_size) {
- uint32_t header;
- if (IVAL(hbin->data, i) & 0x80000000) /* Used */
- break;
-
- my_size = IVAL(hbin->data, i);
- header = IVAL(hbin->data, i + 4);
- if (header == 0xffffffff) {
- possible_size = hbin->offset_to_next - 0x20 - rel_offset;
- } else if (my_size == 0x0) {
- DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
- break;
- } else {
- possible_size += my_size;
- }
-
- if (possible_size >= blob.length) {
- SIVAL(hbin->data, rel_offset, possible_size);
- memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
- return orig_offset;
- }
-
- if (header == 0xffffffff)
- break;
- }
-
- hbin_free(data, orig_offset);
- return hbin_store(data, blob);
-}
-
-static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn, uint32_t orig_offset, void *p)
-{
- struct tdr_push *push = talloc_zero(regf, struct tdr_push);
- uint32_t ret;
-
- if (NT_STATUS_IS_ERR(push_fn(push, p))) {
- DEBUG(0, ("Error during push\n"));
- return -1;
- }
-
- ret = hbin_store_resize(regf, orig_offset, push->data);
-
- talloc_free(push);
-
- return ret;
-}
-
-static WERROR regf_num_subkeys (const struct registry_key *key, uint32_t *count)
-{
- struct nk_block *nk = key->backend_data;
-
- *count = nk->num_subkeys;
-
- return WERR_OK;
-}
-
-static WERROR regf_num_values (const struct registry_key *key, uint32_t *count)
-{
- struct nk_block *nk = key->backend_data;
-
- *count = nk->num_values;
-
- return WERR_OK;
-}
-
-static struct registry_key *regf_get_key (TALLOC_CTX *ctx, struct regf_data *regf, uint32_t offset)
-{
- struct registry_key *ret;
- struct nk_block *nk;
-
- ret = talloc_zero(ctx, struct registry_key);
- nk = talloc(ret, struct nk_block);
- if (!hbin_get_tdr(regf, offset, nk, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
- DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
- return NULL;
- }
-
- if (strcmp(nk->header, "nk") != 0) {
- DEBUG(0, ("Expected nk record, got %s\n", nk->header));
- talloc_free(ret);
- return NULL;
- }
-
- ret->name = talloc_steal(ret, nk->key_name);
- ret->last_mod = nk->last_change;
-
- if (nk->clsname_offset != -1) {
- DATA_BLOB data = hbin_get(regf, nk->clsname_offset);
- ret->class_name = talloc_strndup(ret, (char*)data.data, nk->clsname_length);
- }
- ret->backend_data = nk;
-
- return ret;
-}
-
-static WERROR regf_get_value (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_value **ret)
-{
- struct nk_block *nk = key->backend_data;
- struct vk_block *vk;
- struct regf_data *regf = key->hive->backend_data;
- uint32_t vk_offset;
- DATA_BLOB data;
-
- if (idx >= nk->num_values)
- return WERR_NO_MORE_ITEMS;
-
- data = hbin_get(regf, nk->values_offset);
- if (!data.data) {
- DEBUG(0, ("Unable to find value list\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- if (data.length < nk->num_values * 4) {
- DEBUG(1, ("Value counts mismatch\n"));
- }
-
- vk_offset = IVAL(data.data, idx * 4);
-
- *ret = talloc_zero(ctx, struct registry_value);
- if (!(*ret))
- return WERR_NOMEM;
-
- vk = talloc(*ret, struct vk_block);
- if (!vk)
- return WERR_NOMEM;
-
- if (!hbin_get_tdr(regf, vk_offset, vk, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
- DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
- return WERR_GENERAL_FAILURE;
- }
-
- (*ret)->name = talloc_steal(*ret, vk->data_name);
- (*ret)->data_type = vk->data_type;
- if (vk->data_length & 0x80000000) {
- vk->data_length &=~0x80000000;
- (*ret)->data.data = (uint8_t *)&vk->data_offset;
- (*ret)->data.length = vk->data_length;
- } else {
- (*ret)->data = hbin_get(regf, vk->data_offset);
- }
-
- if ((*ret)->data.length < vk->data_length) {
- DEBUG(1, ("Read data less than indicated data length!\n"));
- }
-
- return WERR_OK;
-}
-
-static WERROR regf_get_subkey_by_index (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_key **ret)
-{
- DATA_BLOB data;
- struct nk_block *nk = key->backend_data;
- uint32_t key_off=0;
-
- if (idx >= nk->num_subkeys)
- return WERR_NO_MORE_ITEMS;
-
- data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
- if (!data.data) {
- DEBUG(0, ("Unable to find subkey list\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- if (!strncmp((char *)data.data, "li", 2)) {
- struct li_block li;
- struct tdr_pull pull;
-
- DEBUG(10, ("Subkeys in LI list\n"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
- DEBUG(0, ("Error parsing LI list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(li.header, "li",2));
-
- if (li.key_count != nk->num_subkeys) {
- DEBUG(0, ("Subkey counts don't match\n"));
- return WERR_GENERAL_FAILURE;
- }
- key_off = li.nk_offset[idx];
-
- } else if (!strncmp((char *)data.data, "lf", 2)) {
- struct lf_block lf;
- struct tdr_pull pull;
-
- DEBUG(10, ("Subkeys in LF list\n"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
- DEBUG(0, ("Error parsing LF list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(lf.header, "lf",2));
-
- if (lf.key_count != nk->num_subkeys) {
- DEBUG(0, ("Subkey counts don't match\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- key_off = lf.hr[idx].nk_offset;
- } else if (!strncmp((char *)data.data, "lh", 2)) {
- struct lh_block lh;
- struct tdr_pull pull;
-
- DEBUG(10, ("Subkeys in LH list"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
- DEBUG(0, ("Error parsing LH list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
- if (lh.key_count != nk->num_subkeys) {
- DEBUG(0, ("Subkey counts don't match\n"));
- return WERR_GENERAL_FAILURE;
- }
- key_off = lh.hr[idx].nk_offset;
- } else if (!strncmp((char *)data.data, "ri", 2)) {
- struct ri_block ri;
- struct tdr_pull pull;
- uint16_t i;
- uint16_t sublist_count = 0;
-
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
- DEBUG(0, ("Error parsing RI list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(ri.header, "ri",2));
-
- for (i = 0; i < ri.key_count; i++) {
- DATA_BLOB list_data;
-
- /* Get sublist data blob */
- list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
- if (!list_data.data) {
- DEBUG(0, ("Error getting RI list."));
- return WERR_GENERAL_FAILURE;
- }
-
- ZERO_STRUCT(pull);
- pull.data = list_data;
-
- if (!strncmp((char *)list_data.data, "li", 2)) {
- struct li_block li;
-
- if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
- DEBUG(0, ("Error parsing LI list from RI\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(li.header, "li",2));
-
- /* Advance to next sublist if necessary */
- if (idx >= sublist_count + li.key_count) {
- sublist_count += li.key_count;
- continue;
- }
- key_off = li.nk_offset[idx - sublist_count];
- sublist_count += li.key_count;
- break;
- } else if (!strncmp((char *)list_data.data, "lh", 2)) {
- struct lh_block lh;
-
- if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
- DEBUG(0, ("Error parsing LH list from RI\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
-
- /* Advance to next sublist if necessary */
- if (idx >= sublist_count + lh.key_count) {
- sublist_count += lh.key_count;
- continue;
- }
- key_off = lh.hr[idx - sublist_count].nk_offset;
- sublist_count += lh.key_count;
- break;
- } else {
- DEBUG(0,("Unknown sublist in ri block\n"));
- SMB_ASSERT(0);
- }
-
- }
-
- if (idx > sublist_count) {
- return WERR_NO_MORE_ITEMS;
- }
-
- } else {
- DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1]));
- return WERR_GENERAL_FAILURE;
- }
-
- *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
-
- return WERR_OK;
-}
-
-static WERROR regf_match_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, uint32_t offset, const char *name, uint32_t *ret)
-{
- DATA_BLOB subkey_data;
- struct nk_block subkey;
- struct tdr_pull pull;
-
- subkey_data = hbin_get(key->hive->backend_data, offset);
- if (!subkey_data.data) {
- DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- ZERO_STRUCT(pull);
- pull.data = subkey_data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_nk_block(&pull, ctx, &subkey))) {
- DEBUG(0, ("Error parsing NK structure.\n"));
- return WERR_GENERAL_FAILURE;
- }
- if (strncmp(subkey.header, "nk", 2)) {
- DEBUG(0, ("Not an NK structure.\n"));
- return WERR_GENERAL_FAILURE;
- }
- if (!strcasecmp(subkey.key_name, name)) {
- *ret = offset;
- } else {
- *ret = 0;
- }
- return WERR_OK;
-}
-
-static WERROR regf_get_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, const char *name, struct registry_key **ret)
-{
- DATA_BLOB data;
- struct nk_block *nk = key->backend_data;
- uint32_t key_off = 0;
-
- data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
- if (!data.data) {
- DEBUG(0, ("Unable to find subkey list\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- if (!strncmp((char *)data.data, "li",2)) {
- struct li_block li;
- struct tdr_pull pull;
- uint16_t i;
-
- DEBUG(10, ("Subkeys in LI list\n"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
- DEBUG(0, ("Error parsing LI list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(li.header, "li",2));
-
- if (li.key_count != nk->num_subkeys) {
- DEBUG(0, ("Subkey counts don't match\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- for (i = 0; i < li.key_count; i++) {
- W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, li.nk_offset[i], name, &key_off));
- if (key_off) {
- break;
- }
- }
- if (!key_off) {
- return WERR_DEST_NOT_FOUND;
- }
- } else if (!strncmp((char *)data.data, "lf",2)) {
- struct lf_block lf;
- struct tdr_pull pull;
- uint16_t i;
-
- DEBUG(10, ("Subkeys in LF list\n"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
- DEBUG(0, ("Error parsing LF list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(lf.header, "lf",2));
-
- if (lf.key_count != nk->num_subkeys) {
- DEBUG(0, ("Subkey counts don't match\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- for (i = 0; i < lf.key_count; i++) {
- if (strncmp(lf.hr[i].hash, name, 4)) {
- continue;
- }
- W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lf.hr[i].nk_offset, name, &key_off));
- if (key_off) {
- break;
- }
- }
- if (!key_off) {
- return WERR_DEST_NOT_FOUND;
- }
- } else if (!strncmp((char *)data.data, "lh",2)) {
- struct lh_block lh;
- struct tdr_pull pull;
- uint16_t i;
- uint32_t hash = 0;
- char *hash_name;
-
- DEBUG(10, ("Subkeys in LH list\n"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
- DEBUG(0, ("Error parsing LH list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
- if (lh.key_count != nk->num_subkeys) {
- DEBUG(0, ("Subkey counts don't match\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- /* Compute hash for the name */
- hash_name = strupper_talloc(nk, name);
- for (i = 0; *(hash_name + i) != 0; i++) {
- hash *= 37;
- hash += *(hash_name + i);
- }
- for (i = 0; i < lh.key_count; i++) {
- if (lh.hr[i].base37 != hash) {
- continue;
- }
- W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lh.hr[i].nk_offset, name, &key_off));
- if (key_off) {
- break;
- }
- }
- if (!key_off) {
- return WERR_DEST_NOT_FOUND;
- }
- } else if (!strncmp((char *)data.data, "ri", 2)) {
- struct ri_block ri;
- struct tdr_pull pull;
- uint16_t i, j;
-
- DEBUG(10, ("Subkeys in RI list\n"));
- ZERO_STRUCT(pull);
- pull.data = data;
-
- if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
- DEBUG(0, ("Error parsing RI list\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(ri.header, "ri",2));
-
-
- for (i = 0; i < ri.key_count; i++) {
- DATA_BLOB list_data;
-
- /* Get sublist data blob */
- list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
- if (!list_data.data) {
- DEBUG(0, ("Error getting RI list."));
- return WERR_GENERAL_FAILURE;
- }
-
- ZERO_STRUCT(pull);
- pull.data = list_data;
-
- if (!strncmp((char *)list_data.data, "li", 2)) {
- struct li_block li;
-
- if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
- DEBUG(0, ("Error parsing LI list from RI\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(li.header, "li",2));
-
- for (j = 0; j < li.key_count; j++) {
- W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
- li.nk_offset[j], name, &key_off));
- if (key_off) {
- break;
- }
- }
- } else if (!strncmp((char *)list_data.data, "lh", 2)) {
- struct lh_block lh;
- uint32_t hash = 0;
- char *hash_name;
-
- if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
- DEBUG(0, ("Error parsing LH list from RI\n"));
- return WERR_GENERAL_FAILURE;
- }
- SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
- /* Compute hash for the name */
- hash_name = strupper_talloc(nk, name);
- for (j = 0; *(hash_name + j) != 0; j++) {
- hash *= 37;
- hash += *(hash_name + j);
- }
- for (j = 0; j < lh.key_count; j++) {
- if (lh.hr[j].base37 != hash) {
- continue;
- }
- W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
- lh.hr[j].nk_offset, name, &key_off));
- if (key_off) {
- break;
- }
- }
- }
- if (key_off) {
- break;
- }
-
- }
- if (!key_off) {
- return WERR_DEST_NOT_FOUND;
- }
- } else {
- DEBUG(0, ("Unknown subkey list type.\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
- return WERR_OK;
-}
-
-static WERROR regf_set_sec_desc (const struct registry_key *key, const struct security_descriptor *sec_desc)
-{
- /* FIXME */
- return WERR_NOT_SUPPORTED;
-}
-
-static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **sd)
-{
- struct nk_block *nk = key->backend_data;
- struct sk_block sk;
- struct regf_data *regf = key->hive->backend_data;
- DATA_BLOB data;
-
- if (!hbin_get_tdr(regf, nk->sk_offset, ctx, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
- DEBUG(0, ("Unable to find security descriptor\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- if (strcmp(sk.header, "sk") != 0) {
- DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
- return WERR_GENERAL_FAILURE;
- }
-
- *sd = talloc(ctx, struct security_descriptor);
- if (!*sd)
- return WERR_NOMEM;
-
- data.data = sk.sec_desc;
- data.length = sk.rec_size;
- if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
- DEBUG(0, ("Error parsing security descriptor\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- return WERR_OK;
-}
-
-static uint32_t lf_add_entry (struct regf_data *regf, uint32_t list_offset, const char *name, uint32_t key_offset)
-{
- uint32_t ret;
- struct lf_block lf;
-
- ZERO_STRUCT(lf);
-
- /* Add to subkeys list */
- if (list_offset == -1) { /* Need to create subkeys list */
- lf.header = "lf";
- } else {
- if (!hbin_get_tdr(regf, list_offset, regf, (tdr_pull_fn_t)tdr_pull_lf_block, &lf)) {
- DEBUG(0, ("Can't get subkeys list\n"));
- return -1;
- }
- }
-
- lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
- lf.hr[lf.key_count].nk_offset = key_offset;
- lf.hr[lf.key_count].hash = talloc_strndup(regf, name, 4);
- lf.key_count++;
-
- ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
-
- talloc_free(lf.hr);
-
- return ret;
-}
-
-static WERROR regf_del_value (const struct registry_key *parent, const char *name)
-{
- /* FIXME */
- return WERR_NOT_SUPPORTED;
-}
-
-
-static WERROR regf_del_key (const struct registry_key *parent, const char *name)
-{
- struct nk_block *nk = parent->backend_data;
-
- SMB_ASSERT(nk);
-
- if (nk->subkeys_offset == -1)
- return WERR_BADFILE;
-
- /* FIXME */
-
- return WERR_NOT_SUPPORTED;
-}
-
-static WERROR regf_add_key (TALLOC_CTX *ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **ret)
-{
- struct nk_block *parent_nk = parent->backend_data, nk;
- struct regf_data *regf = parent->hive->backend_data;
- uint32_t offset;
-
- nk.header = "nk";
- nk.type = REG_SUB_KEY;
- unix_to_nt_time(&nk.last_change, time(NULL));
- nk.uk1 = 0;
- nk.parent_offset = 0; /* FIXME */
- nk.num_subkeys = 0;
- nk.uk2 = 0;
- nk.subkeys_offset = -1;
- nk.unknown_offset = -1;
- nk.num_values = 0;
- nk.sk_offset = 0;
- memset(nk.unk3, 0, 5);
- nk.clsname_offset = -1;
- nk.clsname_length = 0;
- nk.key_name = name;
-
- offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
-
- parent_nk->subkeys_offset = lf_add_entry(regf, parent_nk->subkeys_offset, name, nk.parent_offset);
-
- parent_nk->num_subkeys++;
-
- hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, nk.parent_offset, parent_nk);
-
- *ret = regf_get_key(ctx, regf, offset);
-
- /* FIXME: Set sec desc ! */
- return WERR_OK;
-}
-
-static WERROR regf_set_value (const struct registry_key *key, const char *name, uint32_t type, const DATA_BLOB data)
-{
- /* FIXME */
-
- return WERR_NOT_SUPPORTED;
-}
-
-#if 0 /* Unused */
-
-static WERROR regf_save_hbin(struct registry_hive *hive, struct hbin_block *hbin)
-{
- struct regf_data *regf = hive->backend_data;
-
- /* go to right offset */
- if (lseek(regf->fd, SEEK_SET, regf->header->data_offset + hbin->offset_from_first) == -1) {
- DEBUG(0, ("Error lseeking in regf file\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, (tdr_push_fn_t)tdr_push_hbin_block, hbin))) {
- DEBUG(0, ("Error writing HBIN block\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- return WERR_OK;
-}
-
-#endif
-
-static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
-{
- struct regf_data *regf;
- struct regf_hdr *regf_hdr;
- struct tdr_pull pull;
- int i;
-
- regf = (struct regf_data *)talloc_zero(h, struct regf_data);
- h->backend_data = regf;
-
- DEBUG(5, ("Attempting to load registry file\n"));
-
- /* Get the header */
- regf->fd = open(h->location, O_RDWR);
-
- if (regf->fd == -1) {
- DEBUG(0,("Could not load file: %s, %s\n", h->location,
- strerror(errno)));
- return WERR_GENERAL_FAILURE;
- }
-
- ZERO_STRUCT(pull);
- pull.data.data = (uint8_t*)fd_load(regf->fd, &pull.data.length, regf);
-
- if (pull.data.data == NULL) {
- DEBUG(0, ("Error reading data\n"));
- return WERR_GENERAL_FAILURE;
- }
-
- regf_hdr = talloc(regf, struct regf_hdr);
- if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(&pull, regf_hdr, regf_hdr))) {
- return WERR_GENERAL_FAILURE;
- }
-
- regf->header = regf_hdr;
-
- if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
- DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
- regf_hdr->REGF_ID, h->location));
- }
-
- DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n",
- regf_hdr->description, regf_hdr->version.major,
- regf_hdr->version.minor, regf_hdr->version.release,
- regf_hdr->version.build));
-
- /*
- * Validate the header ...
- */
- if (regf_hdr_checksum(pull.data.data) != regf_hdr->chksum) {
- DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
- h->location, regf_hdr->chksum, regf_hdr_checksum(pull.data.data)));
- return WERR_GENERAL_FAILURE;
- }
-
- pull.offset = 0x1000;
-
- i = 0;
- /* Read in all hbin blocks */
- regf->hbins = talloc_array(regf, struct hbin_block *, 1);
- regf->hbins[0] = NULL;
-
- while (pull.offset < pull.data.length && pull.offset < regf->header->last_block) {
- struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
-
- if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(&pull, hbin, hbin))) {
- DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
- return WERR_FOOBAR;
- }
-
- if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
- DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
- return WERR_FOOBAR;
- }
-
- regf->hbins[i] = hbin;
- i++;
- regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
- regf->hbins[i] = NULL;
- }
-
- DEBUG(1, ("%d HBIN blocks read\n", i));
-
- *key = regf_get_key(h, regf, 0x20);
-
- return WERR_OK;
-}
-
-static struct hive_operations reg_backend_nt4 = {
- .name = "nt4",
- .open_hive = nt_open_hive,
- .num_subkeys = regf_num_subkeys,
- .num_values = regf_num_values,
- .get_subkey_by_index = regf_get_subkey_by_index,
- .get_subkey_by_name = regf_get_subkey_by_name,
- .get_value_by_index = regf_get_value,
- .key_get_sec_desc = regf_get_sec_desc,
- .key_set_sec_desc = regf_set_sec_desc,
- .add_key = regf_add_key,
- .set_value = regf_set_value,
- .del_key = regf_del_key,
- .del_value = regf_del_value,
-};
-
-NTSTATUS registry_nt4_init(void)
-{
- return registry_register(&reg_backend_nt4);
-}
diff --git a/source4/lib/registry/reg_backend_w95.c b/source4/lib/registry/reg_backend_w95.c
deleted file mode 100644
index a0b6e0164a..0000000000
--- a/source4/lib/registry/reg_backend_w95.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- 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 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "includes.h"
-#include "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(&reg_backend_w95);
-}
diff --git a/source4/lib/registry/regf.c b/source4/lib/registry/regf.c
new file mode 100644
index 0000000000..7fa71033d9
--- /dev/null
+++ b/source4/lib/registry/regf.c
@@ -0,0 +1,1923 @@
+/*
+ Samba CIFS implementation
+ Registry backend for REGF files
+ Copyright (C) 2005-2007 Jelmer Vernooij, jelmer@samba.org
+ Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "includes.h"
+#include "lib/registry/hive.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "lib/registry/tdr_regf.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/winreg.h"
+
+static struct hive_operations reg_backend_regf;
+
+/**
+ * There are several places on the web where the REGF format is explained;
+ *
+ * TODO: Links
+ */
+
+/* TODO:
+ * - Return error codes that make more sense
+ * - Locking
+ * - do more things in-memory
+ */
+
+/*
+ * Read HBIN blocks into memory
+ */
+
+struct regf_data {
+ int fd;
+ struct hbin_block **hbins;
+ struct regf_hdr *header;
+};
+
+static WERROR regf_save_hbin(struct regf_data *data);
+
+struct regf_key_data {
+ struct hive_key key;
+ struct regf_data *hive;
+ uint32_t offset;
+ struct nk_block *nk;
+};
+
+static struct hbin_block *hbin_by_offset(const struct regf_data *data,
+ uint32_t offset, uint32_t *rel_offset)
+{
+ int i;
+
+ for (i = 0; data->hbins[i]; i++) {
+ if (offset >= data->hbins[i]->offset_from_first &&
+ offset < data->hbins[i]->offset_from_first+
+ data->hbins[i]->offset_to_next) {
+ if (rel_offset != NULL)
+ *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
+ return data->hbins[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Validate a regf header
+ * For now, do nothing, but we should check the checksum
+ */
+static uint32_t regf_hdr_checksum(const uint8_t *buffer)
+{
+ uint32_t checksum = 0, x;
+ int i;
+
+ for (i = 0; i < 0x01FB; i+= 4) {
+ x = IVAL(buffer, i);
+ checksum ^= x;
+ }
+
+ return checksum;
+}
+
+/**
+ * Obtain the contents of a HBIN block
+ */
+static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
+{
+ DATA_BLOB ret;
+ struct hbin_block *hbin;
+ uint32_t rel_offset;
+
+ ret.data = NULL;
+ ret.length = 0;
+
+ hbin = hbin_by_offset(data, offset, &rel_offset);
+
+ if (hbin == NULL) {
+ DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));
+ return ret;
+ }
+
+ ret.length = IVAL(hbin->data, rel_offset);
+ if (!(ret.length & 0x80000000)) {
+ DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
+ return ret;
+ }
+
+ /* remove high bit */
+ ret.length = (ret.length ^ 0xffffffff) + 1;
+
+ ret.length -= 4; /* 4 bytes for the length... */
+ ret.data = hbin->data +
+ (offset - hbin->offset_from_first - 0x20) + 4;
+
+ return ret;
+}
+
+static bool hbin_get_tdr (struct regf_data *regf, uint32_t offset,
+ TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
+{
+ struct tdr_pull pull;
+
+ ZERO_STRUCT(pull);
+
+ pull.data = hbin_get(regf, offset);
+ if (!pull.data.data) {
+ DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(pull_fn(&pull, ctx, p))) {
+ DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
+ return false;
+ }
+
+ return true;
+}
+
+/* Allocate some new data */
+static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size,
+ uint32_t *offset)
+{
+ DATA_BLOB ret;
+ uint32_t rel_offset = -1; /* Relative offset ! */
+ struct hbin_block *hbin = NULL;
+ int i;
+
+ *offset = 0;
+
+ if (size == 0)
+ return data_blob(NULL, 0);
+
+ size += 4; /* Need to include int32 for the length */
+
+ /* Allocate as a multiple of 8 */
+ size = (size + 7) & ~7;
+
+ ret.data = NULL;
+ ret.length = 0;
+
+ for (i = 0; (hbin = data->hbins[i]); i++) {
+ int j;
+ int32_t my_size;
+ for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
+ my_size = IVALS(hbin->data, j);
+
+ if (my_size == 0x0) {
+ DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
+ return ret;
+ }
+
+ if (my_size % 8 != 0) {
+ DEBUG(0, ("Encountered non-aligned block!\n"));
+ }
+
+ if (my_size < 0) { /* Used... */
+ my_size = -my_size;
+ } else if (my_size == size) { /* exact match */
+ rel_offset = j;
+ DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", size));
+ break;
+ } else if (my_size > size) { /* data will remain */
+ rel_offset = j;
+ /* Split this block and mark the next block as free */
+ SIVAL(hbin->data, rel_offset+size, my_size-size);
+ DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", my_size, size));
+ break;
+ }
+ }
+
+ if (rel_offset != -1)
+ break;
+ }
+
+ /* No space available in previous hbins,
+ * allocate new one */
+ if (data->hbins[i] == NULL) {
+ DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size));
+ data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
+ hbin = talloc(data->hbins, struct hbin_block);
+ SMB_ASSERT(hbin != NULL);
+
+ data->hbins[i] = hbin;
+ data->hbins[i+1] = NULL;
+
+ hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
+ hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
+ hbin->offset_to_next = 0x1000;
+ hbin->unknown[0] = 0;
+ hbin->unknown[0] = 0;
+ unix_to_nt_time(&hbin->last_change, time(NULL));
+ hbin->block_size = hbin->offset_to_next;
+ hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
+
+ rel_offset = 0x0;
+ SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
+ }
+
+ /* Set size and mark as used */
+ SIVAL(hbin->data, rel_offset, -size);
+
+ ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
+ ret.length = size - 0x4;
+ if (offset) {
+ uint32_t new_rel_offset;
+ *offset = hbin->offset_from_first + rel_offset + 0x20;
+ SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
+ SMB_ASSERT(new_rel_offset == rel_offset);
+ }
+
+ return ret;
+}
+
+/* Store a data blob. Return the offset at which it was stored */
+static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
+{
+ uint32_t ret;
+ DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
+
+ memcpy(dest.data, blob.data, blob.length);
+
+ return ret;
+}
+
+static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
+{
+ struct tdr_push *push = talloc_zero(data, struct tdr_push);
+ uint32_t ret;
+
+ if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+ DEBUG(0, ("Error during push\n"));
+ return -1;
+ }
+
+ ret = hbin_store(data, push->data);
+
+ talloc_free(push);
+
+ return ret;
+}
+
+
+/* Free existing data */
+static void hbin_free (struct regf_data *data, uint32_t offset)
+{
+ int32_t size;
+ uint32_t rel_offset;
+ int32_t next_size;
+ struct hbin_block *hbin;
+
+ SMB_ASSERT (offset > 0);
+
+ hbin = hbin_by_offset(data, offset, &rel_offset);
+
+ if (hbin == NULL)
+ return;
+
+ /* Get original size */
+ size = IVALS(hbin->data, rel_offset);
+
+ if (size > 0) {
+ DEBUG(1, ("Trying to free already freed block at 0x%04x\n", offset));
+ return;
+ }
+ /* Mark as unused */
+ size = -size;
+
+ /* If the next block is free, merge into big free block */
+ if (rel_offset + size < hbin->offset_to_next) {
+ next_size = IVALS(hbin->data, rel_offset+size);
+ if (next_size > 0) {
+ size += next_size;
+ }
+ }
+
+ /* Write block size */
+ SIVALS(hbin->data, rel_offset, size);
+}
+
+/**
+ * Store a data blob data was already stored, but has changed in size
+ * Will try to save it at the current location if possible, otherwise
+ * does a free + store */
+static uint32_t hbin_store_resize(struct regf_data *data,
+ uint32_t orig_offset, DATA_BLOB blob)
+{
+ uint32_t rel_offset;
+ struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
+ int32_t my_size;
+ int32_t orig_size;
+ int32_t needed_size;
+ int32_t possible_size;
+ int i;
+
+ SMB_ASSERT(orig_offset > 0);
+
+ if (!hbin)
+ return hbin_store(data, blob);
+
+ /* Get original size */
+ orig_size = -IVALS(hbin->data, rel_offset);
+
+ needed_size = blob.length + 4; /* Add int32 containing length */
+ needed_size = (needed_size + 7) & ~7; /* Align */
+
+ /* Fits into current allocated block */
+ if (orig_size >= needed_size) {
+ memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
+ /* If the difference in size is greater than 0x4, split the block
+ * and free/merge it */
+ if (orig_size - needed_size > 0x4) {
+ SIVALS(hbin->data, rel_offset, -needed_size);
+ SIVALS(hbin->data, rel_offset + needed_size, needed_size-orig_size);
+ hbin_free(data, orig_offset + needed_size);
+ }
+ return orig_offset;
+ }
+
+ possible_size = orig_size;
+
+ /* Check if it can be combined with the next few free records */
+ for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {
+ if (IVALS(hbin->data, i) < 0) /* Used */
+ break;
+
+ my_size = IVALS(hbin->data, i);
+
+ if (my_size == 0x0) {
+ DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
+ break;
+ } else {
+ possible_size += my_size;
+ }
+
+ if (possible_size >= blob.length) {
+ SIVAL(hbin->data, rel_offset, -possible_size);
+ memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
+ return orig_offset;
+ }
+ }
+
+ hbin_free(data, orig_offset);
+ return hbin_store(data, blob);
+}
+
+static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn,
+ uint32_t orig_offset, void *p)
+{
+ struct tdr_push *push = talloc_zero(regf, struct tdr_push);
+ uint32_t ret;
+
+ if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+ DEBUG(0, ("Error during push\n"));
+ return -1;
+ }
+
+ ret = hbin_store_resize(regf, orig_offset, push->data);
+
+ talloc_free(push);
+
+ return ret;
+}
+
+static uint32_t regf_create_lh_hash(const char *name)
+{
+ char *hash_name;
+ uint32_t ret = 0;
+ uint16_t i;
+
+ hash_name = strupper_talloc(NULL, name);
+ for (i = 0; *(hash_name + i) != 0; i++) {
+ ret *= 37;
+ ret += *(hash_name + i);
+ }
+ talloc_free(hash_name);
+ return ret;
+}
+
+static WERROR regf_get_info (TALLOC_CTX *mem_ctx,
+ const struct hive_key *key,
+ const char **classname,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_mod_time)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+
+ if (num_subkeys != NULL)
+ *num_subkeys = private_data->nk->num_subkeys;
+
+ if (num_values != NULL)
+ *num_values = private_data->nk->num_values;
+
+ if (classname != NULL) {
+ if (private_data->nk->clsname_offset != -1) {
+ DATA_BLOB data = hbin_get(private_data->hive,
+ private_data->nk->clsname_offset);
+ *classname = talloc_strndup(mem_ctx,
+ (char*)data.data, private_data->nk->clsname_length);
+ } else
+ *classname = NULL;
+ }
+
+ /* TODO: Last mod time */
+
+ return WERR_OK;
+}
+
+static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,
+ struct regf_data *regf,
+ uint32_t offset)
+{
+ struct nk_block *nk;
+ struct regf_key_data *ret;
+
+ ret = talloc_zero(ctx, struct regf_key_data);
+ ret->key.ops = &reg_backend_regf;
+ ret->hive = talloc_reference(ret, regf);
+ ret->offset = offset;
+ nk = talloc(ret, struct nk_block);
+ if (nk == NULL)
+ return NULL;
+
+ ret->nk = nk;
+
+ if (!hbin_get_tdr(regf, offset, nk, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
+ DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
+ return NULL;
+ }
+
+ if (strcmp(nk->header, "nk") != 0) {
+ DEBUG(0, ("Expected nk record, got %s\n", nk->header));
+ talloc_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+static WERROR regf_get_value(TALLOC_CTX *ctx, const struct hive_key *key,
+ int idx, const char **name,
+ uint32_t *data_type, DATA_BLOB *data)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+ struct vk_block *vk;
+ struct regf_data *regf = private_data->hive;
+ uint32_t vk_offset;
+ DATA_BLOB tmp;
+
+ if (idx >= private_data->nk->num_values)
+ return WERR_NO_MORE_ITEMS;
+
+ tmp = hbin_get(regf, private_data->nk->values_offset);
+ if (!tmp.data) {
+ DEBUG(0, ("Unable to find value list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (tmp.length < private_data->nk->num_values * 4) {
+ DEBUG(1, ("Value counts mismatch\n"));
+ }
+
+ vk_offset = IVAL(tmp.data, idx * 4);
+
+ vk = talloc(NULL, struct vk_block);
+ W_ERROR_HAVE_NO_MEMORY(vk);
+
+ if (!hbin_get_tdr(regf, vk_offset, vk, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
+ DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
+ talloc_free(vk);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* FIXME: name character set ?*/
+ if (name != NULL)
+ *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
+
+ if (data_type != NULL)
+ *data_type = vk->data_type;
+
+ if (vk->data_length & 0x80000000) {
+ vk->data_length &=~0x80000000;
+ data->data = (uint8_t *)&vk->data_offset;
+ data->length = vk->data_length;
+ } else {
+ *data = hbin_get(regf, vk->data_offset);
+ }
+
+ if (data->length < vk->data_length) {
+ DEBUG(1, ("Read data less than indicated data length!\n"));
+ }
+
+ talloc_free(vk);
+
+ return WERR_OK;
+}
+
+static WERROR regf_get_value_by_name (TALLOC_CTX *mem_ctx,
+ struct hive_key *key, const char *name,
+ uint32_t *type, DATA_BLOB *data)
+{
+ int i;
+ const char *vname;
+ WERROR error;
+
+ /* FIXME: Do binary search? Is this list sorted at all? */
+
+ for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i,
+ &vname, type, data)); i++) {
+ if (!strcmp(vname, name))
+ return WERR_OK;
+ }
+
+ if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
+ return WERR_NOT_FOUND;
+
+ return error;
+}
+
+
+static WERROR regf_get_subkey_by_index (TALLOC_CTX *ctx,
+ const struct hive_key *key,
+ uint32_t idx, const char **name,
+ const char **classname,
+ NTTIME *last_mod_time)
+{
+ DATA_BLOB data;
+ struct regf_key_data *ret;
+ const struct regf_key_data *private_data = (const struct regf_key_data *)key;
+ struct nk_block *nk = private_data->nk;
+ uint32_t key_off=0;
+
+ if (idx >= nk->num_subkeys)
+ return WERR_NO_MORE_ITEMS;
+
+ data = hbin_get(private_data->hive, nk->subkeys_offset);
+ if (!data.data) {
+ DEBUG(0, ("Unable to find subkey list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (!strncmp((char *)data.data, "li", 2)) {
+ struct li_block li;
+ struct tdr_pull pull;
+
+ DEBUG(10, ("Subkeys in LI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+ if (li.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ key_off = li.nk_offset[idx];
+
+ } else if (!strncmp((char *)data.data, "lf", 2)) {
+ struct lf_block lf;
+ struct tdr_pull pull;
+
+ DEBUG(10, ("Subkeys in LF list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
+ DEBUG(0, ("Error parsing LF list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+ if (lf.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ key_off = lf.hr[idx].nk_offset;
+ } else if (!strncmp((char *)data.data, "lh", 2)) {
+ struct lh_block lh;
+ struct tdr_pull pull;
+
+ DEBUG(10, ("Subkeys in LH list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+ if (lh.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ key_off = lh.hr[idx].nk_offset;
+ } else if (!strncmp((char *)data.data, "ri", 2)) {
+ struct ri_block ri;
+ struct tdr_pull pull;
+ uint16_t i;
+ uint16_t sublist_count = 0;
+
+ DEBUG(10, ("Subkeys in RI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
+ DEBUG(0, ("Error parsing RI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(ri.header, "ri", 2));
+
+ for (i = 0; i < ri.key_count; i++) {
+ DATA_BLOB list_data;
+
+ /* Get sublist data blob */
+ list_data = hbin_get(private_data->hive, ri.offset[i]);
+ if (!list_data.data) {
+ DEBUG(0, ("Error getting RI list."));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data = list_data;
+
+ if (!strncmp((char *)list_data.data, "li", 2)) {
+ struct li_block li;
+
+ DEBUG(10, ("Subkeys in RI->LI list\n"));
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+ /* Advance to next sublist if necessary */
+ if (idx >= sublist_count + li.key_count) {
+ sublist_count += li.key_count;
+ continue;
+ }
+ key_off = li.nk_offset[idx - sublist_count];
+ sublist_count += li.key_count;
+ break;
+ } else if (!strncmp((char *)list_data.data, "lh", 2)) {
+ struct lh_block lh;
+
+ DEBUG(10, ("Subkeys in RI->LH list\n"));
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+ /* Advance to next sublist if necessary */
+ if (idx >= sublist_count + lh.key_count) {
+ sublist_count += lh.key_count;
+ continue;
+ }
+ key_off = lh.hr[idx - sublist_count].nk_offset;
+ sublist_count += lh.key_count;
+ break;
+ } else {
+ DEBUG(0,("Unknown sublist in ri block\n"));
+
+ return WERR_GENERAL_FAILURE;
+ }
+
+ }
+
+ if (idx > sublist_count) {
+ return WERR_NO_MORE_ITEMS;
+ }
+
+ } else {
+ DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n",
+ nk->subkeys_offset, data.data[0], data.data[1]));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ret = regf_get_key (ctx, private_data->hive, key_off);
+
+ if (classname != NULL) {
+ if (ret->nk->clsname_offset != -1) {
+ DATA_BLOB db = hbin_get(ret->hive,
+ ret->nk->clsname_offset);
+ *classname = talloc_strndup(ctx,
+ (char*)db.data, ret->nk->clsname_length);
+ } else
+ *classname = NULL;
+ }
+
+ if (last_mod_time != NULL)
+ *last_mod_time = ret->nk->last_change;
+
+ if (name != NULL)
+ *name = talloc_steal(ctx, ret->nk->key_name);
+
+ talloc_free(ret);
+
+ return WERR_OK;
+}
+
+static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx,
+ const struct hive_key *key, uint32_t offset,
+ const char *name, uint32_t *ret)
+{
+ DATA_BLOB subkey_data;
+ struct nk_block subkey;
+ struct tdr_pull pull;
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+
+ subkey_data = hbin_get(private_data->hive, offset);
+ if (!subkey_data.data) {
+ DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data = subkey_data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_nk_block(&pull, ctx, &subkey))) {
+ DEBUG(0, ("Error parsing NK structure.\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (strncmp(subkey.header, "nk", 2)) {
+ DEBUG(0, ("Not an NK structure.\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (!strcasecmp(subkey.key_name, name)) {
+ *ret = offset;
+ } else {
+ *ret = 0;
+ }
+ return WERR_OK;
+}
+
+static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
+ const struct hive_key *key,
+ const char *name,
+ struct hive_key **ret)
+{
+ DATA_BLOB data;
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+ struct nk_block *nk = private_data->nk;
+ uint32_t key_off = 0;
+
+ data = hbin_get(private_data->hive, nk->subkeys_offset);
+ if (!data.data) {
+ DEBUG(0, ("Unable to find subkey list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (!strncmp((char *)data.data, "li", 2)) {
+ struct li_block li;
+ struct tdr_pull pull;
+ uint16_t i;
+
+ DEBUG(10, ("Subkeys in LI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+ if (li.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ for (i = 0; i < li.key_count; i++) {
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, li.nk_offset[i], name, &key_off));
+ if (key_off != 0)
+ break;
+ }
+ if (key_off == 0)
+ return WERR_NOT_FOUND;
+ } else if (!strncmp((char *)data.data, "lf", 2)) {
+ struct lf_block lf;
+ struct tdr_pull pull;
+ uint16_t i;
+
+ DEBUG(10, ("Subkeys in LF list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
+ DEBUG(0, ("Error parsing LF list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+ if (lf.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ for (i = 0; i < lf.key_count; i++) {
+ if (strncmp(lf.hr[i].hash, name, 4)) {
+ continue;
+ }
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lf.hr[i].nk_offset, name, &key_off));
+ if (key_off != 0)
+ break;
+ }
+ if (key_off == 0)
+ return WERR_NOT_FOUND;
+ } else if (!strncmp((char *)data.data, "lh", 2)) {
+ struct lh_block lh;
+ struct tdr_pull pull;
+ uint16_t i;
+ uint32_t hash;
+
+ DEBUG(10, ("Subkeys in LH list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+ if (lh.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ hash = regf_create_lh_hash(name);
+ for (i = 0; i < lh.key_count; i++) {
+ if (lh.hr[i].base37 != hash) {
+ continue;
+ }
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lh.hr[i].nk_offset, name, &key_off));
+ if (key_off != 0)
+ break;
+ }
+ if (key_off == 0)
+ return WERR_NOT_FOUND;
+ } else if (!strncmp((char *)data.data, "ri", 2)) {
+ struct ri_block ri;
+ struct tdr_pull pull;
+ uint16_t i, j;
+
+ DEBUG(10, ("Subkeys in RI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
+ DEBUG(0, ("Error parsing RI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(ri.header, "ri", 2));
+
+ for (i = 0; i < ri.key_count; i++) {
+ DATA_BLOB list_data;
+
+ /* Get sublist data blob */
+ list_data = hbin_get(private_data->hive, ri.offset[i]);
+ if (list_data.data == NULL) {
+ DEBUG(0, ("Error getting RI list."));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data = list_data;
+
+ if (!strncmp((char *)list_data.data, "li", 2)) {
+ struct li_block li;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+ for (j = 0; j < li.key_count; j++) {
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
+ li.nk_offset[j], name, &key_off));
+ if (key_off)
+ break;
+ }
+ } else if (!strncmp((char *)list_data.data, "lh", 2)) {
+ struct lh_block lh;
+ uint32_t hash;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+ hash = regf_create_lh_hash(name);
+ for (j = 0; j < lh.key_count; j++) {
+ if (lh.hr[j].base37 != hash) {
+ continue;
+ }
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
+ lh.hr[j].nk_offset, name, &key_off));
+ if (key_off)
+ break;
+ }
+ }
+ if (key_off)
+ break;
+ }
+ if (!key_off)
+ return WERR_NOT_FOUND;
+ } else {
+ DEBUG(0, ("Unknown subkey list type.\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ *ret = (struct hive_key *)regf_get_key (ctx, private_data->hive, key_off);
+ return WERR_OK;
+}
+
+static WERROR regf_set_sec_desc (struct hive_key *key,
+ const struct security_descriptor *sec_desc)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+ struct sk_block cur_sk, sk, new_sk;
+ struct regf_data *regf = private_data->hive;
+ struct nk_block root;
+ DATA_BLOB data;
+ uint32_t sk_offset, cur_sk_offset;
+ bool update_cur_sk = false;
+
+ /* Get the root nk */
+ hbin_get_tdr(regf, regf->header->data_offset, regf,
+ (tdr_pull_fn_t) tdr_pull_nk_block, &root);
+
+ /* Push the security descriptor to a blob */
+ if (NT_STATUS_IS_ERR(ndr_push_struct_blob(&data, regf, sec_desc,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
+ DEBUG(0, ("Unable to push security descriptor\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* Get the current security descriptor for the key */
+ if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf,
+ (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
+ DEBUG(0, ("Unable to find security descriptor for current key\n"));
+ return WERR_BADFILE;
+ }
+ /* If there's no change, change nothing. */
+ if (memcmp(data.data, cur_sk.sec_desc, MIN(data.length, cur_sk.rec_size)) == 0) {
+ return WERR_OK;
+ }
+
+ /* Delete the current sk if only this key is using it */
+ if (cur_sk.ref_cnt == 1) {
+ /* Get the previous security descriptor for the key */
+ if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf,
+ (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+ DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
+ return WERR_BADFILE;
+ }
+ /* Change and store the previous security descriptor */
+ sk.next_offset = cur_sk.next_offset;
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, cur_sk.prev_offset, &sk);
+
+ /* Get the next security descriptor for the key */
+ if (!hbin_get_tdr(regf, cur_sk.next_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+ DEBUG(0, ("Unable to find next security descriptor for current key\n"));
+ return WERR_BADFILE;
+ }
+ /* Change and store the next security descriptor */
+ sk.prev_offset = cur_sk.prev_offset;
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, cur_sk.next_offset, &sk);
+
+ hbin_free(regf, private_data->nk->sk_offset);
+ } else {
+ /* This key will no longer be referring to this sk */
+ cur_sk.ref_cnt--;
+ update_cur_sk = true;
+ }
+
+ sk_offset = root.sk_offset;
+
+ do {
+ cur_sk_offset = sk_offset;
+ if (!hbin_get_tdr(regf, sk_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+ DEBUG(0, ("Unable to find security descriptor\n"));
+ return WERR_BADFILE;
+ }
+ if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
+ private_data->nk->sk_offset = sk_offset;
+ sk.ref_cnt++;
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, sk_offset, &sk);
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, private_data->offset, private_data->nk);
+ return WERR_OK;
+ }
+ sk_offset = sk.next_offset;
+ } while (sk_offset != root.sk_offset);
+
+ ZERO_STRUCT(new_sk);
+ new_sk.header = "sk";
+ new_sk.prev_offset = cur_sk_offset;
+ new_sk.next_offset = root.sk_offset;
+ new_sk.ref_cnt = 1;
+ new_sk.rec_size = data.length;
+ new_sk.sec_desc = data.data;
+
+ sk_offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_sk_block, &new_sk);
+ if (sk_offset == -1) {
+ DEBUG(0, ("Error storing sk block\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ private_data->nk->sk_offset = sk_offset;
+
+ if (update_cur_sk) {
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, private_data->nk->sk_offset, &cur_sk);
+ }
+
+ /* Get the previous security descriptor for the key */
+ if (!hbin_get_tdr(regf, new_sk.prev_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+ DEBUG(0, ("Unable to find security descriptor for previous key\n"));
+ return WERR_BADFILE;
+ }
+ /* Change and store the previous security descriptor */
+ sk.next_offset = sk_offset;
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, cur_sk.prev_offset, &sk);
+
+ /* Get the next security descriptor for the key (always root, as we append) */
+ if (!hbin_get_tdr(regf, new_sk.next_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+ DEBUG(0, ("Unable to find security descriptor for current key\n"));
+ return WERR_BADFILE;
+ }
+ /* Change and store the next security descriptor (always root, as we append) */
+ sk.prev_offset = sk_offset;
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, root.sk_offset, &sk);
+
+
+ /* Store the nk. */
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, private_data->offset, private_data->nk);
+ return WERR_OK;
+}
+
+static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key,
+ struct security_descriptor **sd)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+ struct sk_block sk;
+ struct regf_data *regf = private_data->hive;
+ DATA_BLOB data;
+
+ if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+ DEBUG(0, ("Unable to find security descriptor\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (strcmp(sk.header, "sk") != 0) {
+ DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ *sd = talloc(ctx, struct security_descriptor);
+ W_ERROR_HAVE_NO_MEMORY(*sd);
+
+ data.data = sk.sec_desc;
+ data.length = sk.rec_size;
+ if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
+ DEBUG(0, ("Error parsing security descriptor\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset,
+ const char *name, uint32_t key_offset, uint32_t *ret)
+{
+ DATA_BLOB data;
+
+ /* Create a new key if necessary */
+ if (list_offset == -1) {
+ if (regf->header->version.major != 1) {
+ DEBUG(0, ("Can't store keys in unknown registry format\n"));
+ return WERR_NOT_SUPPORTED;
+ }
+ if (regf->header->version.minor < 3) {
+ /* Store LI */
+ struct li_block li;
+ ZERO_STRUCT(li);
+ li.header = "li";
+ li.key_count = 1;
+
+ li.nk_offset = talloc_array(regf, uint32_t, 1);
+ W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
+ li.nk_offset[0] = key_offset;
+
+ *ret = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_li_block, &li);
+
+ talloc_free(li.nk_offset);
+ } else if (regf->header->version.minor == 3 || regf->header->version.minor == 4) {
+ /* Store LF */
+ struct lf_block lf;
+ ZERO_STRUCT(lf);
+ lf.header = "lf";
+ lf.key_count = 1;
+
+ lf.hr = talloc_array(regf, struct hash_record, 1);
+ W_ERROR_HAVE_NO_MEMORY(lf.hr);
+ lf.hr[0].nk_offset = key_offset;
+ lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
+ W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
+
+ *ret = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_lf_block, &lf);
+
+ talloc_free(lf.hr);
+ } else if (regf->header->version.minor == 5) {
+ /* Store LH */
+ struct lh_block lh;
+ ZERO_STRUCT(lh);
+ lh.header = "lh";
+ lh.key_count = 1;
+
+ lh.hr = talloc_array(regf, struct lh_hash, 1);
+ W_ERROR_HAVE_NO_MEMORY(lh.hr);
+ lh.hr[0].nk_offset = key_offset;
+ lh.hr[0].base37 = regf_create_lh_hash(name);
+
+ *ret = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_lh_block, &lh);
+
+ talloc_free(lh.hr);
+ }
+ return WERR_OK;
+ }
+
+ data = hbin_get(regf, list_offset);
+ if (!data.data) {
+ DEBUG(0, ("Unable to find subkey list\n"));
+ return WERR_BADFILE;
+ }
+
+ if (!strncmp((char *)data.data, "li", 2)) {
+ struct tdr_pull pull;
+ struct li_block li;
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, regf, &li))) {
+ DEBUG(0, ("Error parsing LI list\n"));
+ return WERR_BADFILE;
+ }
+
+ if (strncmp(li.header, "li", 2) != 0) {
+ abort();
+ DEBUG(0, ("LI header corrupt\n"));
+ return WERR_BADFILE;
+ }
+
+ li.nk_offset = talloc_realloc(regf, li.nk_offset, uint32_t, li.key_count+1);
+ W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
+ li.nk_offset[li.key_count] = key_offset;
+ li.key_count++;
+ *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_li_block, list_offset, &li);
+
+ talloc_free(li.nk_offset);
+ } else if (!strncmp((char *)data.data, "lf", 2)) {
+ struct tdr_pull pull;
+ struct lf_block lf;
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, regf, &lf))) {
+ DEBUG(0, ("Error parsing LF list\n"));
+ return WERR_BADFILE;
+ }
+ SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+ lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
+ W_ERROR_HAVE_NO_MEMORY(lf.hr);
+ lf.hr[lf.key_count].nk_offset = key_offset;
+ lf.hr[lf.key_count].hash = talloc_strndup(lf.hr, name, 4);
+ W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
+ lf.key_count++;
+ *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
+
+ talloc_free(lf.hr);
+ } else if (!strncmp((char *)data.data, "lh", 2)) {
+ struct tdr_pull pull;
+ struct lh_block lh;
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, regf, &lh))) {
+ DEBUG(0, ("Error parsing LH list\n"));
+ return WERR_BADFILE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+ lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash, lh.key_count+1);
+ W_ERROR_HAVE_NO_MEMORY(lh.hr);
+ lh.hr[lh.key_count].nk_offset = key_offset;
+ lh.hr[lh.key_count].base37 = regf_create_lh_hash(name);
+ lh.key_count++;
+ *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lh_block, list_offset, &lh);
+
+ talloc_free(lh.hr);
+ } else if (!strncmp((char *)data.data, "ri", 2)) {
+ /* FIXME */
+ DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
+ return WERR_NOT_SUPPORTED;
+ } else {
+ DEBUG(0, ("Cannot add to unknown subkey list\n"));
+ return WERR_BADFILE;
+ }
+
+ return WERR_OK;
+}
+
+static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
+ uint32_t key_offset, uint32_t *ret)
+{
+ DATA_BLOB data;
+
+ data = hbin_get(regf, list_offset);
+ if (!data.data) {
+ DEBUG(0, ("Unable to find subkey list\n"));
+ return WERR_BADFILE;
+ }
+
+ if (strncmp((char *)data.data, "li", 2) == 0) {
+ struct li_block li;
+ struct tdr_pull pull;
+ uint16_t i;
+ bool found_offset = false;
+
+ DEBUG(10, ("Subkeys in LI list\n"));
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, regf, &li))) {
+ DEBUG(0, ("Error parsing LI list\n"));
+ return WERR_BADFILE;
+ }
+
+ SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+ for (i = 0; i < li.key_count; i++) {
+ if (found_offset) {
+ li.nk_offset[i-1] = li.nk_offset[i];
+ }
+ if (li.nk_offset[i] == key_offset) {
+ found_offset = true;
+ continue;
+ }
+ }
+ if (!found_offset) {
+ DEBUG(0, ("Subkey not found\n"));
+ return WERR_NOT_FOUND;
+ }
+ li.key_count--;
+
+ /* If the there are no entries left, free the subkey list */
+ if (li.key_count == 0) {
+ hbin_free(regf, list_offset);
+ *ret = -1;
+ }
+
+ /* Store li block */
+ *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_li_block, list_offset, &li);
+ } else if (strncmp((char *)data.data, "lf", 2) == 0) {
+ struct lf_block lf;
+ struct tdr_pull pull;
+ uint16_t i;
+ bool found_offset = false;
+
+ DEBUG(10, ("Subkeys in LF list\n"));
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, regf, &lf))) {
+ DEBUG(0, ("Error parsing LF list\n"));
+ return WERR_BADFILE;
+ }
+
+ SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+ for (i = 0; i < lf.key_count; i++) {
+ if (found_offset) {
+ lf.hr[i-1] = lf.hr[i];
+ continue;
+ }
+ if (lf.hr[i].nk_offset == key_offset) {
+ found_offset = 1;
+ continue;
+ }
+ }
+ if (!found_offset) {
+ DEBUG(0, ("Subkey not found\n"));
+ return WERR_NOT_FOUND;
+ }
+ lf.key_count--;
+
+ /* If the there are no entries left, free the subkey list */
+ if (lf.key_count == 0) {
+ hbin_free(regf, list_offset);
+ *ret = -1;
+ return WERR_OK;
+ }
+
+ /* Store lf block */
+ *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_lf_block, list_offset, &lf);
+ } else if (strncmp((char *)data.data, "lh", 2) == 0) {
+ struct lh_block lh;
+ struct tdr_pull pull;
+ uint16_t i;
+ bool found_offset = false;
+
+ DEBUG(10, ("Subkeys in LH list\n"));
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, regf, &lh))) {
+ DEBUG(0, ("Error parsing LF list\n"));
+ return WERR_BADFILE;
+ }
+
+ SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+ for (i = 0; i < lh.key_count; i++) {
+ if (found_offset) {
+ lh.hr[i-1] = lh.hr[i];
+ continue;
+ }
+ if (lh.hr[i].nk_offset == key_offset) {
+ found_offset = 1;
+ continue;
+ }
+ }
+ if (!found_offset) {
+ DEBUG(0, ("Subkey not found\n"));
+ return WERR_NOT_FOUND;
+ }
+ lh.key_count--;
+
+ /* If the there are no entries left, free the subkey list */
+ if (lh.key_count == 0) {
+ hbin_free(regf, list_offset);
+ *ret = -1;
+ return WERR_OK;
+ }
+
+ /* Store lh block */
+ *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_lh_block, list_offset, &lh);
+ } else if (strncmp((char *)data.data, "ri", 2) == 0) {
+ /* FIXME */
+ DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
+ return WERR_NOT_SUPPORTED;
+ } else {
+ DEBUG (0, ("Unknown header found in subkey list.\n"));
+ return WERR_BADFILE;
+ }
+ return WERR_OK;
+}
+
+static WERROR regf_del_value (struct hive_key *key, const char *name)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+ struct regf_data *regf = private_data->hive;
+ struct nk_block *nk = private_data->nk;
+ struct vk_block vk;
+ uint32_t vk_offset;
+ bool found_offset = false;
+ DATA_BLOB values;
+ uint32_t i;
+
+ if (nk->values_offset == -1) {
+ return WERR_NOT_FOUND;
+ }
+
+ values = hbin_get(regf, nk->values_offset);
+
+ for (i = 0; i < nk->num_values; i++) {
+ if (found_offset) {
+ ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
+ } else {
+ vk_offset = IVAL(values.data, i * 4);
+ if (!hbin_get_tdr(regf, vk_offset, private_data,
+ (tdr_pull_fn_t)tdr_pull_vk_block, &vk)) {
+ DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
+ return WERR_BADFILE;
+ }
+ if (strcmp(vk.data_name, name) == 0) {
+ hbin_free(regf, vk_offset);
+ found_offset = true;
+ }
+ }
+ }
+ if (!found_offset) {
+ return WERR_NOT_FOUND;
+ } else {
+ nk->num_values--;
+ values.length = (nk->num_values)*4;
+ }
+
+ /* Store values list and nk */
+ if (nk->num_values == 0) {
+ hbin_free(regf, nk->values_offset);
+ nk->values_offset = -1;
+ } else {
+ nk->values_offset = hbin_store_resize(regf, nk->values_offset, values);
+ }
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, private_data->offset, nk);
+
+ return regf_save_hbin(private_data->hive);
+}
+
+
+static WERROR regf_del_key(const struct hive_key *parent, const char *name)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)parent;
+ struct regf_key_data *key;
+ struct nk_block *parent_nk;
+ WERROR error;
+
+ SMB_ASSERT(private_data);
+
+ parent_nk = private_data->nk;
+
+ if (parent_nk->subkeys_offset == -1) {
+ DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
+ return WERR_NOT_FOUND;
+ }
+
+ /* Find the key */
+ if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
+ (struct hive_key **)&key))) {
+ DEBUG(0, ("Key '%s' not found\n", name));
+ return WERR_NOT_FOUND;
+ }
+
+ if (key->nk->subkeys_offset != -1 ||
+ key->nk->values_offset != -1) {
+ DEBUG(0, ("Key '%s' is not empty.\n", name));
+ return WERR_FILE_EXISTS;
+ }
+
+ /* Delete it from the subkey list. */
+ error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset,
+ key->offset, &parent_nk->subkeys_offset);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
+ return error;
+ }
+
+ /* Re-store parent key */
+ parent_nk->num_subkeys--;
+ hbin_store_tdr_resize(private_data->hive,
+ (tdr_push_fn_t) tdr_push_nk_block,
+ private_data->offset, parent_nk);
+
+ if (key->nk->clsname_offset != -1) {
+ hbin_free(private_data->hive, key->nk->clsname_offset);
+ }
+ hbin_free(private_data->hive, key->offset);
+
+ return regf_save_hbin(private_data->hive);
+}
+
+static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent,
+ const char *name, const char *classname,
+ struct security_descriptor *sec_desc,
+ struct hive_key **ret)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)parent;
+ struct nk_block *parent_nk = private_data->nk, nk;
+ struct nk_block *root;
+ struct regf_data *regf = private_data->hive;
+ uint32_t offset;
+ WERROR error;
+
+ nk.header = "nk";
+ nk.type = REG_SUB_KEY;
+ unix_to_nt_time(&nk.last_change, time(NULL));
+ nk.uk1 = 0;
+ nk.parent_offset = private_data->offset;
+ nk.num_subkeys = 0;
+ nk.uk2 = 0;
+ nk.subkeys_offset = -1;
+ nk.unknown_offset = -1;
+ nk.num_values = 0;
+ nk.values_offset = -1;
+ memset(nk.unk3, 0, 5);
+ nk.clsname_offset = -1; /* FIXME: fill in */
+ nk.clsname_length = 0;
+ nk.key_name = name;
+
+ /* Get the security descriptor of the root key */
+ root = talloc_zero(ctx, struct nk_block);
+ W_ERROR_HAVE_NO_MEMORY(root);
+
+ if (!hbin_get_tdr(regf, regf->header->data_offset, root,
+ (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
+ DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
+ return WERR_GENERAL_FAILURE;
+ }
+ nk.sk_offset = root->sk_offset;
+ talloc_free(root);
+
+ /* Store the new nk key */
+ offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
+
+ error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset, &parent_nk->subkeys_offset);
+ if (!W_ERROR_IS_OK(error)) {
+ hbin_free(regf, offset);
+ return error;
+ }
+
+ parent_nk->num_subkeys++;
+
+ /* Since the subkey offset of the parent can change, store it again */
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
+ nk.parent_offset, parent_nk);
+
+ *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
+
+ return regf_save_hbin(private_data->hive);
+}
+
+static WERROR regf_set_value(struct hive_key *key, const char *name,
+ uint32_t type, const DATA_BLOB data)
+{
+ const struct regf_key_data *private_data =
+ (const struct regf_key_data *)key;
+ struct regf_data *regf = private_data->hive;
+ struct nk_block *nk = private_data->nk;
+ struct vk_block vk;
+ uint32_t i;
+ uint32_t tmp_vk_offset, vk_offset, old_vk_offset = -1;
+ DATA_BLOB values;
+
+ ZERO_STRUCT(vk);
+
+ /* find the value offset, if it exists */
+ if (nk->values_offset != -1) {
+ values = hbin_get(regf, nk->values_offset);
+
+ for (i = 0; i < nk->num_values; i++) {
+ tmp_vk_offset = IVAL(values.data, i * 4);
+ if (!hbin_get_tdr(regf, tmp_vk_offset, private_data,
+ (tdr_pull_fn_t)tdr_pull_vk_block, &vk)) {
+ DEBUG(0, ("Unable to get VK block at %d\n", tmp_vk_offset));
+ return WERR_GENERAL_FAILURE;
+ }
+ if (strcmp(vk.data_name, name) == 0) {
+ old_vk_offset = tmp_vk_offset;
+ break;
+ }
+ }
+ /* Free data, if any */
+ if (!(vk.data_length & 0x80000000)) {
+ hbin_free(regf, vk.data_offset);
+ }
+ }
+ if (old_vk_offset == -1) {
+ vk.header = "vk";
+ vk.name_length = strlen(name);
+ if (name != NULL && name[0] != 0) {
+ vk.flag = 1;
+ vk.data_name = name;
+ } else {
+ vk.data_name = NULL;
+ vk.flag = 0;
+ }
+ }
+ /* Set the type and data */
+ vk.data_length = data.length;
+ vk.data_type = type;
+ if (type == REG_DWORD) {
+ vk.data_length |= 0x80000000;
+ vk.data_offset = *(uint32_t *)data.data;
+ } else {
+ /* Store data somewhere */
+ vk.data_offset = hbin_store(regf, data);
+ }
+ if (old_vk_offset == -1) {
+ /* Store new vk */
+ vk_offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_vk_block, &vk);
+ } else {
+ /* Store vk at offset */
+ vk_offset = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_vk_block, old_vk_offset ,&vk);
+ }
+
+ /* Re-allocate the value list */
+ if (nk->values_offset == -1) {
+ nk->values_offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_uint32, &vk_offset);
+ nk->num_values = 1;
+ } else {
+
+ /* Change if we're changing, otherwise we're adding the value */
+ if (old_vk_offset != -1) {
+ /* Find and overwrite the offset. */
+ for (i = 0; i < nk->num_values; i++) {
+ if (IVAL(values.data, i * 4) == old_vk_offset) {
+ SIVAL(values.data, i * 4, vk_offset);
+ break;
+ }
+ }
+ } else {
+ /* Create a new value list */
+ DATA_BLOB value_list;
+
+ value_list.length = (nk->num_values+1)*4;
+ value_list.data = (void *)talloc_array(private_data, uint32_t, nk->num_values+1);
+ W_ERROR_HAVE_NO_MEMORY(value_list.data);
+ memcpy(value_list.data, values.data, nk->num_values * 4);
+
+ SIVAL(value_list.data, nk->num_values * 4, vk_offset);
+ nk->num_values++;
+ nk->values_offset = hbin_store_resize(regf, nk->values_offset, value_list);
+ }
+
+ }
+ hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, private_data->offset, nk);
+ return regf_save_hbin(private_data->hive);
+}
+
+static WERROR regf_save_hbin(struct regf_data *regf)
+{
+ struct tdr_push *push = talloc_zero(regf, struct tdr_push);
+ int i;
+
+ W_ERROR_HAVE_NO_MEMORY(push);
+
+ if (lseek(regf->fd, 0, SEEK_SET) == -1) {
+ DEBUG(0, ("Error lseeking in regf file\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* Recompute checksum */
+ if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
+ DEBUG(0, ("Failed to push regf header\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ regf->header->chksum = regf_hdr_checksum(push->data.data);
+ talloc_free(push);
+
+ if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
+ (tdr_push_fn_t)tdr_push_regf_hdr, regf->header))) {
+ DEBUG(0, ("Error writing registry file header\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
+ DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ for (i = 0; regf->hbins[i]; i++) {
+ if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
+ (tdr_push_fn_t)tdr_push_hbin_block,
+ regf->hbins[i]))) {
+ DEBUG(0, ("Error writing HBIN block\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ }
+
+ return WERR_OK;
+}
+
+WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, const char *location,
+ int minor_version, struct hive_key **key)
+{
+ struct regf_data *regf;
+ struct regf_hdr *regf_hdr;
+ struct tdr_pull pull;
+ int i;
+ struct nk_block nk;
+ WERROR error;
+
+ regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
+
+ W_ERROR_HAVE_NO_MEMORY(regf);
+
+ DEBUG(5, ("Attempting to create registry file\n"));
+
+ /* Get the header */
+ regf->fd = creat(location, 0644);
+
+ if (regf->fd == -1) {
+ DEBUG(0,("Could not create file: %s, %s\n", location,
+ strerror(errno)));
+ talloc_free(regf);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ regf_hdr = talloc_zero(regf, struct regf_hdr);
+ W_ERROR_HAVE_NO_MEMORY(regf_hdr);
+ regf_hdr->REGF_ID = "regf";
+ unix_to_nt_time(&regf_hdr->modtime, time(NULL));
+ regf_hdr->version.major = 1;
+ regf_hdr->version.minor = minor_version;
+ regf_hdr->last_block = 0x1000; /* Block size */
+ regf_hdr->description = talloc_strdup(regf_hdr, "registry created by Samba 4");
+ W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
+ regf_hdr->chksum = 0;
+
+ regf->header = regf_hdr;
+
+ pull.offset = 0x1000;
+
+ i = 0;
+ /* Create all hbin blocks */
+ regf->hbins = talloc_array(regf, struct hbin_block *, 1);
+ W_ERROR_HAVE_NO_MEMORY(regf->hbins);
+ regf->hbins[0] = NULL;
+
+ regf_hdr->data_offset = -1; /* FIXME */
+
+ nk.header = "nk";
+ nk.type = REG_SUB_KEY;
+ unix_to_nt_time(&nk.last_change, time(NULL));
+ nk.uk1 = 0;
+ nk.parent_offset = -1;
+ nk.num_subkeys = 0;
+ nk.uk2 = 0;
+ nk.subkeys_offset = -1;
+ nk.unknown_offset = -1;
+ nk.num_values = 0;
+ nk.values_offset = -1;
+ memset(nk.unk3, 0, 5);
+ nk.clsname_offset = -1; /* FIXME: fill in */
+ nk.clsname_length = 0;
+ nk.key_name = "";
+
+ nk.sk_offset = -1; /* FIXME: fill in */
+
+ /* Store the new nk key */
+ regf->header->data_offset = hbin_store_tdr(regf,
+ (tdr_push_fn_t)tdr_push_nk_block, &nk);
+
+ *key = (struct hive_key *)regf_get_key(parent_ctx, regf, regf->header->data_offset);
+
+ /* We can drop our own reference now that *key will have created one */
+ talloc_free(regf);
+
+ error = regf_save_hbin(regf);
+ if (!W_ERROR_IS_OK(error)) {
+ return error;
+ }
+
+ return WERR_OK;
+}
+
+WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx,
+ const char *location, struct hive_key **key)
+{
+ struct regf_data *regf;
+ struct regf_hdr *regf_hdr;
+ struct tdr_pull pull;
+ int i;
+
+ regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
+
+ W_ERROR_HAVE_NO_MEMORY(regf);
+
+ DEBUG(5, ("Attempting to load registry file\n"));
+
+ /* Get the header */
+ regf->fd = open(location, O_RDWR);
+
+ if (regf->fd == -1) {
+ DEBUG(0,("Could not load file: %s, %s\n", location,
+ strerror(errno)));
+ talloc_free(regf);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data.data = (uint8_t*)fd_load(regf->fd, &pull.data.length, regf);
+
+ if (pull.data.data == NULL) {
+ DEBUG(0, ("Error reading data\n"));
+ talloc_free(regf);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ regf_hdr = talloc(regf, struct regf_hdr);
+ W_ERROR_HAVE_NO_MEMORY(regf_hdr);
+
+ if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(&pull, regf_hdr, regf_hdr))) {
+ talloc_free(regf);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ regf->header = regf_hdr;
+
+ if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
+ DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
+ regf_hdr->REGF_ID, location));
+ talloc_free(regf);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* Validate the header ... */
+ if (regf_hdr_checksum(pull.data.data) != regf_hdr->chksum) {
+ DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
+ location, regf_hdr->chksum,
+ regf_hdr_checksum(pull.data.data)));
+ talloc_free(regf);
+ return WERR_GENERAL_FAILURE;
+ }
+
+ pull.offset = 0x1000;
+
+ i = 0;
+ /* Read in all hbin blocks */
+ regf->hbins = talloc_array(regf, struct hbin_block *, 1);
+ W_ERROR_HAVE_NO_MEMORY(regf->hbins);
+
+ regf->hbins[0] = NULL;
+
+ while (pull.offset < pull.data.length && pull.offset <= regf->header->last_block) {
+ struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
+
+ W_ERROR_HAVE_NO_MEMORY(hbin);
+
+ if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(&pull, hbin, hbin))) {
+ DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
+ talloc_free(regf);
+ return WERR_FOOBAR;
+ }
+
+ if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
+ DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
+ talloc_free(regf);
+ return WERR_FOOBAR;
+ }
+
+ regf->hbins[i] = hbin;
+ i++;
+ regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
+ regf->hbins[i] = NULL;
+ }
+
+ DEBUG(1, ("%d HBIN blocks read\n", i));
+
+ *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
+ regf->header->data_offset);
+
+ /* We can drop our own reference now that *key will have created one */
+ talloc_free(regf);
+
+ return WERR_OK;
+}
+
+static struct hive_operations reg_backend_regf = {
+ .name = "regf",
+ .get_key_info = regf_get_info,
+ .enum_key = regf_get_subkey_by_index,
+ .get_key_by_name = regf_get_subkey_by_name,
+ .get_value_by_name = regf_get_value_by_name,
+ .enum_value = regf_get_value,
+ .get_sec_desc = regf_get_sec_desc,
+ .set_sec_desc = regf_set_sec_desc,
+ .add_key = regf_add_key,
+ .set_value = regf_set_value,
+ .del_key = regf_del_key,
+ .delete_value = regf_del_value,
+};
diff --git a/source4/lib/registry/regf.idl b/source4/lib/registry/regf.idl
index 46af4ffdc5..ffd7072b7a 100644
--- a/source4/lib/registry/regf.idl
+++ b/source4/lib/registry/regf.idl
@@ -45,8 +45,8 @@ interface regf
uint32 data_offset;
uint32 last_block;
[value(1)] uint32 uk7; /* 1 */
- [charset(UTF16)] uint16 description[0x40];
- uint32 padding[83]; /* Padding */
+ [charset(UTF16)] uint16 description[0x20];
+ uint32 padding[99]; /* Padding */
/* Checksum of first 0x200 bytes XOR-ed */
uint32 chksum;
};
@@ -66,7 +66,7 @@ interface regf
uint8 data[offset_to_next-0x20];
/* data is filled with:
uint32 length;
- Negative if in used, positive otherwise
+ Negative if in use, positive otherwise
Always a multiple of 8
uint8_t data[length];
Free space marker if 0xffffffff
diff --git a/source4/lib/registry/registry.h b/source4/lib/registry/registry.h
index 09d61c6b4f..acfe056616 100644
--- a/source4/lib/registry/registry.h
+++ b/source4/lib/registry/registry.h
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
Registry interface
Copyright (C) Gerald Carter 2002.
- Copyright (C) Jelmer Vernooij 2003-2004.
+ Copyright (C) Jelmer Vernooij 2003-2007.
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
@@ -21,9 +21,12 @@
#ifndef _REGISTRY_H /* _REGISTRY_H */
#define _REGISTRY_H
+struct registry_context;
+
#include "core.h"
#include "talloc/talloc.h"
#include "librpc/gen_ndr/security.h"
+#include "lib/registry/hive.h"
/* Handles for the predefined keys */
#define HKEY_CLASSES_ROOT 0x80000000
@@ -36,6 +39,9 @@
#define HKEY_PERFORMANCE_TEXT 0x80000050
#define HKEY_PERFORMANCE_NLSTEXT 0x80000060
+#define HKEY_FIRST HKEY_CLASSES_ROOT
+#define HKEY_LAST HKEY_PERFORMANCE_NLSTEXT
+
struct reg_predefined_key {
uint32_t handle;
const char *name;
@@ -52,17 +58,16 @@ extern const struct reg_predefined_key reg_predefined_keys[];
#define REGISTRY_INTERFACE_VERSION 1
+struct reg_key_operations;
+
/* 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_context *context;
};
+#include "lib/registry/patchfile.h"
+
struct registry_value
{
const char *name;
@@ -74,109 +79,87 @@ struct registry_value
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_context;
-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
-{
+struct registry_operations {
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;
+ WERROR (*get_key_info) (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char **classname,
+ uint32_t *numsubkeys,
+ uint32_t *numvalues,
+ NTTIME *last_change_time);
+
+ WERROR (*flush_key) (struct registry_key *key);
+
+ WERROR (*get_predefined_key) (const struct registry_context *ctx,
+ uint32_t key_id,
+ struct registry_key **key);
+
+ WERROR (*open_key) (TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
+ const char *path,
+ struct registry_key **key);
+
+ WERROR (*create_key) (TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
+ const char *name,
+ const char *key_class,
+ struct security_descriptor *security,
+ struct registry_key **key);
+
+ WERROR (*delete_key) (struct registry_key *key, const char *name);
+
+ WERROR (*delete_value) (struct registry_key *key, const char *name);
+
+ WERROR (*enum_key) (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key, uint32_t idx,
+ const char **name,
+ const char **keyclass,
+ NTTIME *last_changed_time);
+
+ WERROR (*enum_value) (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key, uint32_t idx,
+ const char **name,
+ uint32_t *type,
+ DATA_BLOB *data);
+
+ WERROR (*get_security) (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ struct security_descriptor **security);
+
+ WERROR (*set_security) (struct registry_key *key,
+ const struct security_descriptor *security);
+
+ WERROR (*load_key) (struct registry_key *key,
+ const char *key_name,
+ const char *path);
+
+ WERROR (*unload_key) (struct registry_key *key, const char *name);
+
+ WERROR (*notify_value_change) (struct registry_key *key,
+ reg_value_notification_function fn);
+
+ WERROR (*get_value) (TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char *name,
+ uint32_t *type,
+ DATA_BLOB *data);
+
+ WERROR (*set_value) (struct registry_key *key,
+ const char *name,
+ uint32_t type,
+ const DATA_BLOB data);
+};
+
+/**
+ * Handle to a full registry
+ * contains zero or more hives
+ */
+struct registry_context {
+ const struct registry_operations *ops;
};
struct auth_session_info;
@@ -186,60 +169,110 @@ struct event_context;
#define _PUBLIC_
#endif
+/**
+ * Open the locally defined registry.
+ */
_PUBLIC_ WERROR reg_open_local (TALLOC_CTX *mem_ctx,
struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials);
+_PUBLIC_ WERROR reg_open_samba (TALLOC_CTX *mem_ctx,
+ struct registry_context **ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials);
+
+/**
+ * Open the registry on a remote machine.
+ */
_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);
-_PUBLIC_ NTSTATUS registry_register(const void *_hive_ops);
-_PUBLIC_ NTSTATUS registry_init(void);
-_PUBLIC_ BOOL reg_has_backend(const char *backend);
-_PUBLIC_ int reg_list_predefs(TALLOC_CTX *mem_ctx, char ***predefs, uint32_t **hkeys);
+_PUBLIC_ WERROR reg_open_wine(struct registry_context **ctx, const char *path);
+
_PUBLIC_ const char *reg_get_predef_name(uint32_t hkey);
-_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, const char *name, struct registry_key **key);
-_PUBLIC_ WERROR reg_get_predefined_key(struct registry_context *ctx, uint32_t hkey, struct registry_key **key);
-_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);
-_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, struct registry_key **result);
-_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_value **val);
-_PUBLIC_ WERROR reg_key_num_subkeys(const struct registry_key *key, uint32_t *count);
-_PUBLIC_ WERROR reg_key_num_values(const struct registry_key *key, uint32_t *count);
-_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_key **subkey);
-WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_key **subkey);
-_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_value **val);
+_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx,
+ const char *name,
+ struct registry_key **key);
+_PUBLIC_ WERROR reg_get_predefined_key(const struct registry_context *ctx,
+ uint32_t hkey,
+ struct registry_key **key);
+
+_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent,
+ const char *name, struct registry_key **result);
+
+_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key, uint32_t idx,
+ const char **name,
+ uint32_t *type,
+ DATA_BLOB *data);
+_PUBLIC_ WERROR reg_key_get_info(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char **class_name,
+ uint32_t *num_subkeys,
+ uint32_t *num_values,
+ NTTIME *last_change_time);
+_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ int idx,
+ const char **name,
+ const char **classname,
+ NTTIME *last_mod_time);
+WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char *name,
+ struct registry_key **subkey);
+_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx,
+ const struct registry_key *key,
+ const char *name,
+ uint32_t *type,
+ DATA_BLOB *data);
_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name);
-_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);
-_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, uint32_t type, DATA_BLOB data);
+_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx,
+ struct registry_key *parent, const char *name,
+ const char *classname,
+ struct security_descriptor *desc,
+ struct registry_key **newkey);
+_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value,
+ uint32_t type, DATA_BLOB data);
_PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **secdesc);
-_PUBLIC_ WERROR reg_del_value(const struct registry_key *key, const char *valname);
-_PUBLIC_ WERROR reg_key_flush(const struct registry_key *key);
-_PUBLIC_ WERROR reg_key_subkeysizes(const struct registry_key *key, uint32_t *max_subkeylen, uint32_t *max_subkeysize);
-_PUBLIC_ WERROR reg_key_valuesizes(const struct registry_key *key, uint32_t *max_valnamelen, uint32_t *max_valbufsize);
+_PUBLIC_ WERROR reg_del_value(struct registry_key *key, const char *valname);
+_PUBLIC_ WERROR reg_key_flush(struct registry_key *key);
+WERROR reg_create_key (TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
-/* Utility functions */
+ const char *name,
+ const char *key_class,
+ struct security_descriptor *security,
+ struct registry_key **key);
+
+
+
+/* Utility functions */
_PUBLIC_ const char *str_regtype(int type);
-_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data);
-_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val) ;
+_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type,
+ const DATA_BLOB data);
+_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name,
+ uint32_t type, const DATA_BLOB 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);
-char *reg_path_win2unix(char *path) ;
-char *reg_path_unix2win(char *path) ;
WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result);
WERROR reg_key_del_abs(struct registry_context *ctx, const char *path);
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);
+WERROR reg_load_key(struct registry_context *ctx, struct registry_key *key,
+ const char *name, const char *filename);
+WERROR reg_mount_hive(struct registry_context *rctx,
+ struct hive_key *hive_key,
+ uint32_t key_id,
+ const char **elements);
-/* Patch files */
-
-_PUBLIC_ struct reg_diff *reg_generate_diff(TALLOC_CTX *mem_ctx, struct registry_context *ctx1, struct registry_context *ctx2);
-_PUBLIC_ WERROR reg_diff_save(const struct reg_diff *diff, const char *filename);
-_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn);
-_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx);
+struct registry_key *reg_import_hive_key(struct registry_context *ctx,
+ struct hive_key *hive,
+ uint32_t predef_key,
+ const char **elements);
-NTSTATUS registry_rpc_init(void);
#endif /* _REGISTRY_H */
diff --git a/source4/lib/registry/reg_backend_rpc.c b/source4/lib/registry/rpc.c
index 50489aced2..59d41d591a 100644
--- a/source4/lib/registry/reg_backend_rpc.c
+++ b/source4/lib/registry/rpc.c
@@ -1,7 +1,7 @@
/*
Samba Unix/Linux SMB implementation
RPC backend for the registry library
- Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org
+ Copyright (C) 2003-2007 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
@@ -20,7 +20,23 @@
#include "registry.h"
#include "librpc/gen_ndr/ndr_winreg_c.h"
-static struct hive_operations reg_backend_rpc;
+struct rpc_key {
+ struct registry_key key;
+ struct policy_handle pol;
+ struct dcerpc_pipe *pipe;
+
+ uint32_t num_values;
+ uint32_t num_subkeys;
+ uint32_t max_valnamelen;
+ uint32_t max_valdatalen;
+};
+
+struct rpc_registry_context {
+ struct registry_context context;
+ struct dcerpc_pipe *pipe;
+};
+
+static struct registry_operations reg_backend_rpc;
/**
* This is the RPC backend for the registry library.
@@ -58,57 +74,46 @@ 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 }
+ { 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)
+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;
+ struct rpc_registry_context *rctx = talloc_get_type(ctx,
+ struct rpc_registry_context);
+ struct rpc_key *mykeydata;
- for(n = 0; known_hives[n].hkey; n++)
- {
- if(known_hives[n].hkey == hkey_type) break;
+ for(n = 0; known_hives[n].hkey; n++) {
+ if(known_hives[n].hkey == hkey_type)
+ break;
}
- if(!known_hives[n].open) {
+ if (known_hives[n].open == NULL) {
DEBUG(1, ("No such hive %d\n", hkey_type));
return WERR_NO_MORE_ITEMS;
}
- h = talloc(ctx, struct registry_hive);
- h->functions = &reg_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 = talloc(ctx, struct rpc_key);
+ mykeydata->pipe = rctx->pipe;
mykeydata->num_values = -1;
mykeydata->num_subkeys = -1;
- return known_hives[n].open((struct dcerpc_pipe *)ctx->backend_data, *k, &(mykeydata->pol));
+ return known_hives[n].open(mykeydata->pipe, *k, &(mykeydata->pol));
}
#if 0
@@ -136,44 +141,44 @@ static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k)
}
#endif
-static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *h, const char *name, struct registry_key **key)
+static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, struct registry_key *h,
+ const char *name, struct registry_key **key)
{
- struct rpc_key_data *mykeydata;
+ struct rpc_key *mykeydata = talloc_get_type(h, struct rpc_key),
+ *newkeydata;
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;
+ mykeydata = talloc(mem_ctx, struct rpc_key);
/* 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);
+ r.in.parent_handle = &mykeydata->pol;
init_winreg_String(&r.in.keyname, name);
r.in.unknown = 0x00000000;
r.in.access_mask = 0x02000000;
- r.out.handle = &mykeydata->pol;
+ r.out.handle = &newkeydata->pol;
- dcerpc_winreg_OpenKey((struct dcerpc_pipe *)(h->hive->backend_data), mem_ctx, &r);
+ dcerpc_winreg_OpenKey(mykeydata->pipe, 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)
+static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx,
+ const struct registry_key *parent,
+ uint32_t n,
+ const char **value_name,
+ uint32_t *type,
+ DATA_BLOB *data)
{
- struct rpc_key_data *mykeydata = parent->backend_data;
+ struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
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) {
+ if (mykeydata->num_values == -1) {
error = rpc_query_key(parent);
if(!W_ERROR_IS_OK(error)) return error;
}
@@ -187,13 +192,13 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_
r.in.handle = &mykeydata->pol;
r.in.enum_index = n;
r.in.name = &name;
- r.in.type = &type;
+ 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);
+ status = dcerpc_winreg_EnumValue(mykeydata->pipe, mem_ctx, &r);
if(NT_STATUS_IS_ERR(status)) {
DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status)));
return WERR_GENERAL_FAILURE;
@@ -201,20 +206,23 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_
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);
+ *value_name = talloc_strdup(mem_ctx, r.out.name->name);
+ *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)
+static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx,
+ const struct registry_key *parent,
+ uint32_t n,
+ const char **name,
+ const char **keyclass,
+ NTTIME *last_changed_time)
{
struct winreg_EnumKey r;
- struct rpc_key_data *mykeydata = parent->backend_data;
+ struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
NTSTATUS status;
struct winreg_StringBuf namebuf, classbuf;
NTTIME change_time = 0;
@@ -233,40 +241,47 @@ static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry
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);
+ status = dcerpc_winreg_EnumKey(mykeydata->pipe, 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);
+ *name = talloc_strdup(mem_ctx, r.out.name->name);
+ *keyclass = talloc_strdup(mem_ctx, r.out.keyclass->name);
+ *last_changed_time = *r.out.last_changed_time;
}
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)
+static WERROR rpc_add_key(TALLOC_CTX *mem_ctx,
+ struct registry_key *parent, const char *name,
+ const char *key_class,
+ struct security_descriptor *sec,
+ struct registry_key **key)
{
NTSTATUS status;
struct winreg_CreateKey r;
+ struct rpc_key *parentkd = talloc_get_type(parent, struct rpc_key);
+ struct rpc_key *rpck = talloc(mem_ctx, struct rpc_key);
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.handle = &parentkd->pol;
+ r.out.new_handle = &rpck->pol;
r.in.options = 0;
- r.in.access_mask = access_mask;
+ r.in.access_mask = SEC_STD_ALL;
r.in.secdesc = NULL;
- status = dcerpc_winreg_CreateKey((struct dcerpc_pipe *)(parent->hive->backend_data), mem_ctx, &r);
+ status = dcerpc_winreg_CreateKey(parentkd->pipe, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(rpck);
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;
+ rpck->pipe = talloc_reference(rpck, parentkd->pipe);
+ *key = (struct registry_key *)rpck;
}
return r.out.result;
@@ -276,14 +291,14 @@ static WERROR rpc_query_key(const struct registry_key *k)
{
NTSTATUS status;
struct winreg_QueryInfoKey r;
- struct rpc_key_data *mykeydata = k->backend_data;
+ struct rpc_key *mykeydata = talloc_get_type(k, struct rpc_key);
TALLOC_CTX *mem_ctx = talloc_init("query_key");
r.in.classname = talloc(mem_ctx, struct winreg_String);
init_winreg_String(r.in.classname, NULL);
r.in.handle = &mykeydata->pol;
- status = dcerpc_winreg_QueryInfoKey((struct dcerpc_pipe *)(k->hive->backend_data), mem_ctx, &r);
+ status = dcerpc_winreg_QueryInfoKey(mykeydata->pipe, mem_ctx, &r);
talloc_free(mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
@@ -301,26 +316,29 @@ static WERROR rpc_query_key(const struct registry_key *k)
return r.out.result;
}
-static WERROR rpc_del_key(const struct registry_key *parent, const char *name)
+static WERROR rpc_del_key(struct registry_key *parent, const char *name)
{
NTSTATUS status;
- struct rpc_key_data *mykeydata = parent->backend_data;
+ struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
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);
+ status = dcerpc_winreg_DeleteKey(mykeydata->pipe, mem_ctx, &r);
talloc_free(mem_ctx);
return r.out.result;
}
-static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count)
+static WERROR rpc_get_info(TALLOC_CTX *mem_ctx, const struct registry_key *key,
+ const char **classname,
+ uint32_t *numsubkeys,
+ uint32_t *numvalue)
{
- struct rpc_key_data *mykeydata = key->backend_data;
+ struct rpc_key *mykeydata = talloc_get_type(key, struct rpc_key);
WERROR error;
if(mykeydata->num_values == -1) {
@@ -328,42 +346,34 @@ static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count)
if(!W_ERROR_IS_OK(error)) return error;
}
- *count = mykeydata->num_values;
+ /* FIXME: *classname = talloc_strdup(mem_ctx, mykeydata->classname); */
+ *numvalue = mykeydata->num_values;
+ *numsubkeys = mykeydata->num_subkeys;
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 = {
+static struct registry_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,
+ .enum_key = rpc_get_subkey_by_index,
+ .enum_value = rpc_get_value_by_index,
+ .create_key = rpc_add_key,
+ .delete_key = rpc_del_key,
+ .get_key_info = rpc_get_info,
};
-_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)
+_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;
+ struct rpc_registry_context *rctx;
+
+ dcerpc_init();
- *ctx = talloc(NULL, struct registry_context);
+ rctx = talloc(NULL, struct rpc_registry_context);
/* Default to local smbd if no connection is specified */
if (!location) {
@@ -374,7 +384,7 @@ _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_sessi
&p, location,
&ndr_table_winreg,
credentials, ev);
- (*ctx)->backend_data = p;
+ rctx->pipe = p;
if(NT_STATUS_IS_ERR(status)) {
DEBUG(1, ("Unable to open '%s': %s\n", location, nt_errstr(status)));
@@ -383,13 +393,7 @@ _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_sessi
return ntstatus_to_werror(status);
}
- (*ctx)->get_predefined_key = rpc_get_predefined_key;
+ *ctx = (struct registry_context *)rctx;
return WERR_OK;
}
-
-NTSTATUS registry_rpc_init(void)
-{
- dcerpc_init();
- return registry_register(&reg_backend_rpc);
-}
diff --git a/source4/lib/registry/reg_samba.c b/source4/lib/registry/samba.c
index 560e1ded31..244c467a2c 100644
--- a/source4/lib/registry/reg_samba.c
+++ b/source4/lib/registry/samba.c
@@ -1,6 +1,6 @@
/*
Unix SMB/CIFS implementation.
- Copyright (C) Jelmer Vernooij 2004.
+ Copyright (C) Jelmer Vernooij 2004-2007.
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
@@ -24,31 +24,52 @@
* @brief Samba-specific registry functions
*/
-static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey, struct registry_key **k)
+WERROR mount_samba_hive(struct registry_context *ctx,
+ struct auth_session_info *auth_info,
+ struct cli_credentials *creds,
+ const char *name,
+ uint32_t hive_id)
{
WERROR error;
- const char *conf;
- char *backend;
+ struct hive_key *hive;
const char *location;
- const char *hivename = reg_get_predef_name(hkey);
- *k = NULL;
+ location = talloc_asprintf(ctx, "%s/%s.ldb", lp_private_dir(), name);
- conf = lp_parm_string(-1, "registry", hivename);
-
- if (!conf) {
- return WERR_NOT_SUPPORTED;
- }
+ error = reg_open_hive(ctx, location, auth_info, creds, &hive);
+ if (!W_ERROR_IS_OK(error))
+ return error;
+
+ return reg_mount_hive(ctx, hive, hive_id, NULL);
+}
+
+
+_PUBLIC_ WERROR reg_open_samba (TALLOC_CTX *mem_ctx,
+ struct registry_context **ctx,
+ struct auth_session_info *session_info,
+ struct cli_credentials *credentials)
+{
+ WERROR result;
- location = strchr(conf, ':');
- if (location) {
- backend = talloc_strndup(ctx, conf, (int)(location - conf));
- location++;
- } else {
- backend = talloc_strdup(ctx, "ldb");
- location = conf;
+ result = reg_open_local(mem_ctx, ctx, session_info, credentials);
+ if (!W_ERROR_IS_OK(result)) {
+ return result;
}
+ mount_samba_hive(*ctx, session_info, credentials,
+ "hklm", HKEY_LOCAL_MACHINE);
+
+ mount_samba_hive(*ctx, session_info, credentials,
+ "hkcr", HKEY_CLASSES_ROOT);
+
+ /* FIXME: Should be mounted from NTUSER.DAT in the home directory of the
+ * current user */
+ mount_samba_hive(*ctx, session_info, credentials,
+ "hkcu", HKEY_CURRENT_USER);
+
+ mount_samba_hive(*ctx, session_info, credentials,
+ "hku", HKEY_USERS);
+
/* FIXME: Different hive backend for HKEY_CLASSES_ROOT: merged view of HKEY_LOCAL_MACHINE\Software\Classes
* and HKEY_CURRENT_USER\Software\Classes */
@@ -59,23 +80,6 @@ static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey,
/* 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;
}
diff --git a/source4/lib/registry/tests/diff.c b/source4/lib/registry/tests/diff.c
new file mode 100644
index 0000000000..220da88601
--- /dev/null
+++ b/source4/lib/registry/tests/diff.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of registry diff functionality
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/registry/registry.h"
+#include "lib/cmdline/popt_common.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/winreg.h"
+
+static bool test_generate_diff(struct torture_context *test)
+{
+ /* WERROR reg_generate_diff(struct registry_context *ctx1,
+ struct registry_context *ctx2,
+ const struct reg_diff_callbacks *callbacks,
+ void *callback_data)
+ */
+ return true;
+}
+
+
+static bool test_diff_load(struct torture_context *test)
+{
+ /* WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data) */
+
+ return true;
+}
+
+static bool test_diff_apply(struct torture_context *test)
+{
+ /*
+_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
+ */
+
+ return true;
+}
+
+static const char *added_key = NULL;
+
+static WERROR test_add_key (void *callback_data, const char *key_name)
+{
+ added_key = talloc_strdup(callback_data, key_name);
+
+ return WERR_OK;
+}
+
+static bool test_generate_diff_key_add(struct torture_context *test)
+{
+ struct reg_diff_callbacks cb;
+ struct registry_key rk;
+
+ return true;
+
+ ZERO_STRUCT(cb);
+
+ cb.add_key = test_add_key;
+
+ if (W_ERROR_IS_OK(reg_generate_diff_key(&rk, NULL, "bla", &cb, test)))
+ return false;
+
+ torture_assert_str_equal(test, added_key, "bla", "key added");
+
+ return true;
+}
+
+static bool test_generate_diff_key_null(struct torture_context *test)
+{
+ struct reg_diff_callbacks cb;
+
+ ZERO_STRUCT(cb);
+
+ if (!W_ERROR_IS_OK(reg_generate_diff_key(NULL, NULL, "", &cb, NULL)))
+ return false;
+
+ return true;
+}
+
+struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "DIFF");
+ torture_suite_add_simple_test(suite, "test_generate_diff_key_add", test_generate_diff_key_add);
+ torture_suite_add_simple_test(suite, "test_generate_diff_key_null", test_generate_diff_key_null);
+ torture_suite_add_simple_test(suite, "test_diff_apply", test_diff_apply);
+ torture_suite_add_simple_test(suite, "test_generate_diff", test_generate_diff);
+ torture_suite_add_simple_test(suite, "test_diff_load", test_diff_load);
+ return suite;
+}
diff --git a/source4/lib/registry/tests/generic.c b/source4/lib/registry/tests/generic.c
index 1f0c89e058..6595f86b18 100644
--- a/source4/lib/registry/tests/generic.c
+++ b/source4/lib/registry/tests/generic.c
@@ -3,7 +3,7 @@
local testing of registry library
- Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Jelmer Vernooij 2005-2007
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
@@ -25,6 +25,10 @@
#include "torture/torture.h"
#include "librpc/gen_ndr/winreg.h"
+struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx);
+
static bool test_str_regtype(struct torture_context *ctx)
{
torture_assert_str_equal(ctx, str_regtype(1), "REG_SZ", "REG_SZ failed");
@@ -38,7 +42,8 @@ static bool test_reg_val_data_string_dword(struct torture_context *ctx)
{
uint32_t d = 0x20;
DATA_BLOB db = { (uint8_t *)&d, sizeof(d) };
- torture_assert_str_equal(ctx, "0x20", reg_val_data_string(ctx, REG_DWORD, &db), "dword failed");
+ torture_assert_str_equal(ctx, "0x20",
+ reg_val_data_string(ctx, REG_DWORD, db), "dword failed");
return true;
}
@@ -46,9 +51,9 @@ static bool test_reg_val_data_string_sz(struct torture_context *ctx)
{
DATA_BLOB db;
db.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "bla", 3, (void **)&db.data);
- torture_assert_str_equal(ctx, "bla", reg_val_data_string(ctx, REG_SZ, &db), "sz failed");
+ torture_assert_str_equal(ctx, "bla", reg_val_data_string(ctx, REG_SZ, db), "sz failed");
db.length = 4;
- torture_assert_str_equal(ctx, "bl", reg_val_data_string(ctx, REG_SZ, &db), "sz failed");
+ torture_assert_str_equal(ctx, "bl", reg_val_data_string(ctx, REG_SZ, db), "sz failed");
return true;
}
@@ -56,7 +61,9 @@ static bool test_reg_val_data_string_binary(struct torture_context *ctx)
{
uint8_t x[] = { 0x1, 0x2, 0x3, 0x4 };
DATA_BLOB db = { x, 4 };
- torture_assert_str_equal(ctx, "01020304", reg_val_data_string(ctx, REG_BINARY, &db), "binary failed");
+ torture_assert_str_equal(ctx, "01020304",
+ reg_val_data_string(ctx, REG_BINARY, db),
+ "binary failed");
return true;
}
@@ -64,18 +71,20 @@ static bool test_reg_val_data_string_binary(struct torture_context *ctx)
static bool test_reg_val_data_string_empty(struct torture_context *ctx)
{
DATA_BLOB db = { NULL, 0 };
- torture_assert_str_equal(ctx, "", reg_val_data_string(ctx, REG_BINARY, &db), "empty failed");
+ torture_assert_str_equal(ctx, "",
+ reg_val_data_string(ctx, REG_BINARY, db), "empty failed");
return true;
}
static bool test_reg_val_description(struct torture_context *ctx)
{
- struct registry_value val;
- val.name = "camel";
- val.data_type = REG_SZ;
- val.data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "stationary traveller",
- strlen("stationary traveller"), (void **)&val.data.data);
- torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller", reg_val_description(ctx, &val),
+ DATA_BLOB data;
+ data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16,
+ "stationary traveller",
+ strlen("stationary traveller"),
+ (void **)&data.data);
+ torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller",
+ reg_val_description(ctx, "camel", REG_SZ, data),
"reg_val_description failed");
return true;
}
@@ -83,12 +92,11 @@ static bool test_reg_val_description(struct torture_context *ctx)
static bool test_reg_val_description_nullname(struct torture_context *ctx)
{
- struct registry_value val;
- val.name = NULL;
- val.data_type = REG_SZ;
- val.data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "west berlin",
- strlen("west berlin"), (void **)&val.data.data);
- torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin", reg_val_description(ctx, &val),
+ DATA_BLOB data;
+ data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "west berlin",
+ strlen("west berlin"), (void **)&data.data);
+ torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin",
+ reg_val_description(ctx, NULL, REG_SZ, data),
"description with null name failed");
return true;
}
@@ -98,12 +106,22 @@ struct torture_suite *torture_registry(TALLOC_CTX *mem_ctx)
struct torture_suite *suite = torture_suite_create(mem_ctx,
"REGISTRY");
torture_suite_add_simple_test(suite, "str_regtype", test_str_regtype);
- torture_suite_add_simple_test(suite, "reg_val_data_string dword", test_reg_val_data_string_dword);
- torture_suite_add_simple_test(suite, "reg_val_data_string sz", test_reg_val_data_string_sz);
- torture_suite_add_simple_test(suite, "reg_val_data_string binary", test_reg_val_data_string_binary);
- torture_suite_add_simple_test(suite, "reg_val_data_string empty", test_reg_val_data_string_empty);
- torture_suite_add_simple_test(suite, "reg_val_description", test_reg_val_description);
- torture_suite_add_simple_test(suite, "reg_val_description null", test_reg_val_description_nullname);
+ torture_suite_add_simple_test(suite, "reg_val_data_string dword",
+ test_reg_val_data_string_dword);
+ torture_suite_add_simple_test(suite, "reg_val_data_string sz",
+ test_reg_val_data_string_sz);
+ torture_suite_add_simple_test(suite, "reg_val_data_string binary",
+ test_reg_val_data_string_binary);
+ torture_suite_add_simple_test(suite, "reg_val_data_string empty",
+ test_reg_val_data_string_empty);
+ torture_suite_add_simple_test(suite, "reg_val_description",
+ test_reg_val_description);
+ torture_suite_add_simple_test(suite, "reg_val_description null",
+ test_reg_val_description_nullname);
+
+ torture_suite_add_suite(suite, torture_registry_hive(mem_ctx));
+ torture_suite_add_suite(suite, torture_registry_registry(mem_ctx));
+ torture_suite_add_suite(suite, torture_registry_diff(mem_ctx));
return suite;
}
diff --git a/source4/lib/registry/tests/hive.c b/source4/lib/registry/tests/hive.c
new file mode 100644
index 0000000000..a04bc1168e
--- /dev/null
+++ b/source4/lib/registry/tests/hive.c
@@ -0,0 +1,383 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of registry library - hives
+
+ Copyright (C) Jelmer Vernooij 2005-2007
+
+ 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 "torture/torture.h"
+#include "librpc/gen_ndr/winreg.h"
+#include "system/filesys.h"
+
+NTSTATUS torture_temp_dir(struct torture_context *tctx, const char *prefix,
+ const char **tempdir);
+
+static bool test_del_nonexistant_key(struct torture_context *tctx,
+ const void *test_data)
+{
+ const struct hive_key *root = test_data;
+ WERROR error = hive_key_del(root, "bla");
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+ "invalid return code");
+
+ return true;
+}
+
+static bool test_keyinfo_root(struct torture_context *tctx,
+ const void *test_data)
+{
+ uint32_t num_subkeys, num_values;
+ const struct hive_key *root = test_data;
+ WERROR error;
+
+ /* This is a new backend. There should be no subkeys and no
+ * values */
+ error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values,
+ NULL);
+ torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()");
+
+ torture_assert_int_equal(tctx, num_subkeys, 0, "New key has non-zero subkey count");
+
+ torture_assert_werr_ok(tctx, error, "reg_key_num_values");
+
+ torture_assert_int_equal(tctx, num_values, 0, "New key has non-zero value count");
+
+ return true;
+}
+
+static bool test_keyinfo_nums(struct torture_context *tctx,
+ const void *test_data)
+{
+ uint32_t num_subkeys, num_values;
+ const struct hive_key *root = test_data;
+ WERROR error;
+ struct hive_key *subkey;
+ uint32_t data = 42;
+
+ error = hive_key_add_name(tctx, root, "Nested Keyll", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_set_value(root, "Answer", REG_DWORD,
+ data_blob_talloc(tctx, &data, sizeof(data)));
+ torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+ /* This is a new backend. There should be no subkeys and no
+ * values */
+ error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values,
+ NULL);
+ torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()");
+
+ torture_assert_int_equal(tctx, num_subkeys, 1, "subkey count");
+
+ torture_assert_werr_ok(tctx, error, "reg_key_num_values");
+
+ torture_assert_int_equal(tctx, num_values, 1, "value count");
+
+ return true;
+}
+
+static bool test_add_subkey(struct torture_context *tctx,
+ const void *test_data)
+{
+ WERROR error;
+ struct hive_key *subkey;
+ const struct hive_key *root = test_data;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_key_del(root, "Nested Key");
+ torture_assert_werr_ok(tctx, error, "reg_key_del");
+
+ return true;
+}
+
+static bool test_flush_key(struct torture_context *tctx,
+ const void *test_data)
+{
+ const struct hive_key *root = test_data;
+
+ torture_assert_werr_ok(tctx, hive_key_flush(root), "flush key");
+
+ return true;
+}
+
+static bool test_del_key(struct torture_context *tctx, const void *test_data)
+{
+ WERROR error;
+ struct hive_key *subkey;
+ const struct hive_key *root = test_data;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_key_del(root, "Nested Key");
+ torture_assert_werr_ok(tctx, error, "reg_key_del");
+
+ error = hive_key_del(root, "Nested Key");
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "reg_key_del");
+
+ return true;
+}
+
+static bool test_set_value(struct torture_context *tctx,
+ const void *test_data)
+{
+ WERROR error;
+ struct hive_key *subkey;
+ const struct hive_key *root = test_data;
+ TALLOC_CTX *mem_ctx = tctx;
+ uint32_t data = 42;
+
+ error = hive_key_add_name(mem_ctx, root, "YA Nested Key", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_set_value(subkey, "Answer", REG_DWORD,
+ data_blob_talloc(mem_ctx, &data, sizeof(data)));
+ torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+ return true;
+}
+
+static bool test_get_value(struct torture_context *tctx, const void *test_data)
+{
+ WERROR error;
+ struct hive_key *subkey;
+ const struct hive_key *root = test_data;
+ TALLOC_CTX *mem_ctx = tctx;
+ uint32_t data = 42;
+ uint32_t type;
+ DATA_BLOB value;
+
+ error = hive_key_add_name(mem_ctx, root, "EYA Nested Key", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+ "getting missing value");
+
+ error = hive_set_value(subkey, "Answer", REG_DWORD,
+ data_blob_talloc(mem_ctx, &data, sizeof(data)));
+ torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+ error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
+ torture_assert_werr_ok(tctx, error, "getting value");
+
+ torture_assert(tctx, memcmp(value.data, &data, 4) == 0, "value data");
+
+ torture_assert_int_equal(tctx, value.length, 4, "value length");
+ torture_assert_int_equal(tctx, type, REG_DWORD, "value type");
+
+ return true;
+}
+
+static bool test_del_value(struct torture_context *tctx, const void *test_data)
+{
+ WERROR error;
+ struct hive_key *subkey;
+ const struct hive_key *root = test_data;
+ TALLOC_CTX *mem_ctx = tctx;
+ uint32_t data = 42;
+ uint32_t type;
+ DATA_BLOB value;
+
+ error = hive_key_add_name(mem_ctx, root, "EEYA Nested Key", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_set_value(subkey, "Answer", REG_DWORD,
+ data_blob_talloc(mem_ctx, &data, sizeof(data)));
+ torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+ error = hive_del_value(subkey, "Answer");
+ torture_assert_werr_ok(tctx, error, "deleting value");
+
+ error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "getting value");
+
+ error = hive_del_value(subkey, "Answer");
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "deleting value");
+
+ return true;
+}
+
+static bool test_list_values(struct torture_context *tctx,
+ const void *test_data)
+{
+ WERROR error;
+ struct hive_key *subkey;
+ const struct hive_key *root = test_data;
+ TALLOC_CTX *mem_ctx = tctx;
+ uint32_t data = 42;
+ uint32_t type;
+ DATA_BLOB value;
+ const char *name;
+
+ error = hive_key_add_name(mem_ctx, root, "AYAYA Nested Key", NULL,
+ NULL, &subkey);
+ torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+ error = hive_set_value(subkey, "Answer", REG_DWORD,
+ data_blob_talloc(mem_ctx, &data, sizeof(data)));
+ torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+ error = hive_get_value_by_index(mem_ctx, subkey, 0, &name, &type, &value);
+ torture_assert_werr_ok(tctx, error, "getting value");
+
+ torture_assert_str_equal(tctx, name, "Answer", "value name");
+ torture_assert(tctx, memcmp(value.data, &data, 4) == 0, "value data");
+
+ torture_assert_int_equal(tctx, value.length, 4, "value length");
+ torture_assert_int_equal(tctx, type, REG_DWORD, "value type");
+
+ error = hive_get_value_by_index(mem_ctx, subkey, 1, &name, &type, &value);
+ torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
+ "getting missing value");
+
+ return true;
+}
+
+static void tcase_add_tests(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "del_nonexistant_key",
+ test_del_nonexistant_key);
+ torture_tcase_add_simple_test(tcase, "add_subkey", test_add_subkey);
+ torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key);
+ torture_tcase_add_simple_test(tcase, "get_info", test_keyinfo_root);
+ torture_tcase_add_simple_test(tcase, "get_info_nums", test_keyinfo_nums);
+ torture_tcase_add_simple_test(tcase, "set_value", test_set_value);
+ torture_tcase_add_simple_test(tcase, "get_value", test_get_value);
+ torture_tcase_add_simple_test(tcase, "list_values", test_list_values);
+ torture_tcase_add_simple_test(tcase, "del_key", test_del_key);
+ torture_tcase_add_simple_test(tcase, "del_value", test_del_value);
+}
+
+static bool hive_setup_dir(struct torture_context *tctx, void **data)
+{
+ struct hive_key *key;
+ WERROR error;
+ const char *dirname;
+ NTSTATUS status;
+
+ status = torture_temp_dir(tctx, "hive-dir", &dirname);
+ if (!NT_STATUS_IS_OK(status))
+ return false;
+
+ rmdir(dirname);
+
+ error = reg_create_directory(tctx, dirname, &key);
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to initialize dir hive\n");
+ return false;
+ }
+
+ *data = key;
+
+ return true;
+}
+
+static bool hive_setup_ldb(struct torture_context *tctx, void **data)
+{
+ struct hive_key *key;
+ WERROR error;
+ const char *dirname;
+ NTSTATUS status;
+
+ status = torture_temp_dir(tctx, "hive-ldb", &dirname);
+ if (!NT_STATUS_IS_OK(status))
+ return false;
+
+ rmdir(dirname);
+
+ error = reg_open_ldb_file(tctx, dirname, NULL, NULL, &key);
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to initialize ldb hive\n");
+ return false;
+ }
+
+ *data = key;
+
+ return true;
+}
+
+static bool hive_setup_regf(struct torture_context *tctx, void **data)
+{
+ struct hive_key *key;
+ WERROR error;
+ const char *dirname;
+ NTSTATUS status;
+
+ status = torture_temp_dir(tctx, "hive-dir", &dirname);
+ if (!NT_STATUS_IS_OK(status))
+ return false;
+
+ rmdir(dirname);
+
+ error = reg_create_regf_file(tctx, dirname, 5, &key);
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to create new regf file\n");
+ return false;
+ }
+
+ *data = key;
+
+ return true;
+}
+
+static bool test_dir_refuses_null_location(struct torture_context *tctx)
+{
+ torture_assert_werr_equal(tctx, WERR_INVALID_PARAM,
+ reg_open_directory(NULL, NULL, NULL),
+ "reg_open_directory accepts NULL location");
+ return true;
+}
+
+struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx)
+{
+ struct torture_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "HIVE");
+
+ torture_suite_add_simple_test(suite, "dir-refuses-null-location",
+ test_dir_refuses_null_location);
+
+
+ tcase = torture_suite_add_tcase(suite, "dir");
+ torture_tcase_set_fixture(tcase, hive_setup_dir, NULL);
+ tcase_add_tests(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "ldb");
+ torture_tcase_set_fixture(tcase, hive_setup_ldb, NULL);
+ tcase_add_tests(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "regf");
+ torture_tcase_set_fixture(tcase, hive_setup_regf, NULL);
+ tcase_add_tests(tcase);
+
+ return suite;
+}
diff --git a/source4/lib/registry/tests/registry.c b/source4/lib/registry/tests/registry.c
new file mode 100644
index 0000000000..851f74fa3c
--- /dev/null
+++ b/source4/lib/registry/tests/registry.c
@@ -0,0 +1,486 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of registry library - registry backend
+
+ Copyright (C) Jelmer Vernooij 2005-2007
+
+ 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 "torture/torture.h"
+#include "librpc/gen_ndr/winreg.h"
+#include "system/filesys.h"
+
+NTSTATUS torture_temp_dir(struct torture_context *tctx, const char *prefix,
+ const char **tempdir);
+
+/**
+ * Test obtaining a predefined key.
+ */
+static bool test_get_predefined(struct torture_context *tctx,
+ const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root;
+ WERROR error;
+
+ error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+ torture_assert_werr_ok(tctx, error,
+ "getting predefined key failed");
+ return true;
+}
+
+/**
+ * Test creating a new subkey
+ */
+static bool test_create_subkey(struct torture_context *tctx,
+ const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *newkey;
+ WERROR error;
+
+ error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+ torture_assert_werr_ok(tctx, error,
+ "getting predefined key failed");
+
+ error = reg_key_add_name(rctx, root, "Bad Bentheim", NULL, NULL, &newkey);
+ torture_assert_werr_ok(tctx, error, "Creating key return code");
+ torture_assert(tctx, newkey != NULL, "Creating new key");
+
+ return true;
+}
+
+/**
+ * Test creating a new nested subkey
+ */
+static bool test_create_nested_subkey(struct torture_context *tctx,
+ const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *newkey1, *newkey2;
+ WERROR error;
+
+ error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+ torture_assert_werr_ok(tctx, error,
+ "getting predefined key failed");
+
+ error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL,
+ &newkey1);
+ torture_assert_werr_ok(tctx, error, "Creating key return code");
+ torture_assert(tctx, newkey2 != NULL, "Creating new key");
+
+ error = reg_key_add_name(rctx, root, "Hamburg\\Hamburg", NULL, NULL,
+ &newkey2);
+ torture_assert_werr_ok(tctx, error, "Creating key return code");
+ torture_assert(tctx, newkey2 != NULL, "Creating new key");
+
+ return true;
+}
+
+/**
+ * Test creating a new subkey
+ */
+static bool test_key_add_abs_top(struct torture_context *tctx,
+ const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root;
+ WERROR error;
+
+ error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT", 0, NULL, &root);
+ torture_assert_werr_equal(tctx, error, WERR_ALREADY_EXISTS, "create top level");
+
+ return true;
+}
+
+/**
+ * Test creating a new subkey
+ */
+static bool test_key_add_abs(struct torture_context *tctx,
+ const void *_data)
+{
+ WERROR error;
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *result1, *result2;
+
+ error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT\\bloe", 0, NULL, &result1);
+ torture_assert_werr_ok(tctx, error, "create lowest");
+
+ error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT\\bloe\\bla", 0, NULL, &result1);
+ torture_assert_werr_ok(tctx, error, "create nested");
+
+ error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+ torture_assert_werr_ok(tctx, error,
+ "getting predefined key failed");
+
+ error = reg_open_key(tctx, root, "bloe", &result2);
+ torture_assert_werr_ok(tctx, error, "opening key");
+
+ error = reg_open_key(tctx, root, "bloe\\bla", &result2);
+ torture_assert_werr_ok(tctx, error, "opening key");
+
+ return true;
+}
+
+
+static bool test_del_key(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *newkey;
+ WERROR error;
+
+ error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+ torture_assert_werr_ok(tctx, error,
+ "getting predefined key failed");
+
+ error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL, &newkey);
+
+ torture_assert_werr_ok(tctx, error, "Creating key return code");
+ torture_assert(tctx, newkey != NULL, "Creating new key");
+
+ error = reg_key_del(root, "Hamburg");
+ torture_assert_werr_ok(tctx, error, "Delete key");
+
+ error = reg_key_del(root, "Hamburg");
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+ "Delete missing key");
+
+ return true;
+}
+
+/**
+ * Convenience function for opening the HKEY_CLASSES_ROOT hive and
+ * creating a single key for testing purposes.
+ */
+static bool create_test_key(struct torture_context *tctx,
+ const struct registry_context *rctx,
+ const char *name,
+ struct registry_key **root,
+ struct registry_key **subkey)
+{
+ WERROR error;
+
+ error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, root);
+ torture_assert_werr_ok(tctx, error,
+ "getting predefined key failed");
+
+ error = reg_key_add_name(rctx, *root, name, NULL, NULL, subkey);
+ torture_assert_werr_ok(tctx, error, "Creating key return code");
+
+ return true;
+}
+
+
+static bool test_flush_key(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *subkey;
+ WERROR error;
+
+ if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
+ return false;
+
+ error = reg_key_flush(subkey);
+ torture_assert_werr_ok(tctx, error, "flush key");
+
+ return true;
+}
+
+static bool test_query_key(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *subkey;
+ WERROR error;
+ NTTIME last_changed_time;
+ uint32_t num_subkeys, num_values;
+ const char *classname;
+
+ if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
+ return false;
+
+ error = reg_key_get_info(tctx, subkey, &classname,
+ &num_subkeys, &num_values,
+ &last_changed_time);
+
+ torture_assert_werr_ok(tctx, error, "get info key");
+ torture_assert(tctx, classname == NULL, "classname");
+ torture_assert_int_equal(tctx, num_subkeys, 0, "num subkeys");
+ torture_assert_int_equal(tctx, num_values, 0, "num values");
+
+ return true;
+}
+
+static bool test_query_key_nums(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *root, *subkey1, *subkey2;
+ WERROR error;
+ uint32_t num_subkeys, num_values;
+ uint32_t data = 42;
+
+ if (!create_test_key(tctx, rctx, "Berlin", &root, &subkey1))
+ return false;
+
+ error = reg_key_add_name(rctx, subkey1, "Bentheim", NULL, NULL, &subkey2);
+ torture_assert_werr_ok(tctx, error, "Creating key return code");
+
+ error = reg_val_set(subkey1, "Answer", REG_DWORD,
+ data_blob_talloc(tctx, &data, sizeof(data)));
+ torture_assert_werr_ok(tctx, error, "set value");
+
+ error = reg_key_get_info(tctx, subkey1, NULL, &num_subkeys,
+ &num_values, NULL);
+
+ torture_assert_werr_ok(tctx, error, "get info key");
+ torture_assert_int_equal(tctx, num_subkeys, 1, "num subkeys");
+ torture_assert_int_equal(tctx, num_values, 1, "num values");
+
+ return true;
+}
+
+/**
+ * Test that the subkeys of a key can be enumerated, that
+ * the returned parameters for get_subkey_by_index are optional and
+ * that enumerating the parents of a non-top-level node works.
+ */
+static bool test_list_subkeys(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *subkey = NULL, *root;
+ WERROR error;
+ NTTIME last_mod_time;
+ const char *classname, *name;
+
+ if (!create_test_key(tctx, rctx, "Goettingen", &root, &subkey))
+ return false;
+
+ error = reg_key_get_subkey_by_index(tctx, root, 0, &name, &classname,
+ &last_mod_time);
+
+ torture_assert_werr_ok(tctx, error, "Enum keys return code");
+ torture_assert_str_equal(tctx, name, "Goettingen", "Enum keys data");
+
+
+ error = reg_key_get_subkey_by_index(tctx, root, 0, NULL, NULL, NULL);
+
+ torture_assert_werr_ok(tctx, error, "Enum keys with NULL arguments return code");
+
+ error = reg_key_get_subkey_by_index(tctx, root, 1, NULL, NULL, NULL);
+
+ torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
+ "Invalid error for no more items");
+
+ error = reg_key_get_subkey_by_index(tctx, subkey, 0, NULL, NULL, NULL);
+
+ torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
+ "Invalid error for no more items");
+
+ return true;
+}
+
+/**
+ * Test setting a value
+ */
+static bool test_set_value(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *subkey = NULL, *root;
+ WERROR error;
+ uint32_t data = 42;
+
+ if (!create_test_key(tctx, rctx, "Dusseldorf", &root, &subkey))
+ return false;
+
+ error = reg_val_set(subkey, "Answer", REG_DWORD,
+ data_blob_talloc(tctx, &data, sizeof(data)));
+ torture_assert_werr_ok (tctx, error, "setting value");
+
+ return true;
+}
+
+/**
+ * Test getting a value
+ */
+static bool test_get_value(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *subkey = NULL, *root;
+ WERROR error;
+ DATA_BLOB data;
+ uint32_t value = 42;
+ uint32_t type;
+
+ if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
+ return false;
+
+ error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
+ &data);
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+ "getting missing value");
+
+ error = reg_val_set(subkey, __FUNCTION__, REG_DWORD,
+ data_blob_talloc(tctx, &value, 4));
+ torture_assert_werr_ok (tctx, error, "setting value");
+
+ error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
+ &data);
+ torture_assert_werr_ok(tctx, error, "getting value");
+
+ torture_assert_int_equal(tctx, 4, data.length, "value length ok");
+ torture_assert(tctx, memcmp(data.data, &value, 4) == 0, "value content ok");
+ torture_assert_int_equal(tctx, REG_DWORD, type, "value type");
+
+ return true;
+}
+
+/**
+ * Test unsetting a value
+ */
+static bool test_del_value(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *subkey = NULL, *root;
+ WERROR error;
+ DATA_BLOB data;
+ uint32_t value = 42;
+ uint32_t type;
+
+ if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
+ return false;
+
+ error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
+ &data);
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+ "getting missing value");
+
+ error = reg_val_set(subkey, __FUNCTION__, REG_DWORD,
+ data_blob_talloc(tctx, &value, 4));
+ torture_assert_werr_ok (tctx, error, "setting value");
+
+ error = reg_del_value(subkey, __FUNCTION__);
+ torture_assert_werr_ok (tctx, error, "unsetting value");
+
+ error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, &data);
+ torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
+ "getting missing value");
+
+ return true;
+}
+
+/**
+ * Test listing values
+ */
+static bool test_list_values(struct torture_context *tctx, const void *_data)
+{
+ const struct registry_context *rctx = _data;
+ struct registry_key *subkey = NULL, *root;
+ WERROR error;
+ DATA_BLOB data;
+ uint32_t value = 42;
+ uint32_t type;
+ const char *name;
+
+ if (!create_test_key(tctx, rctx, "Bonn", &root, &subkey))
+ return false;
+
+ error = reg_val_set(subkey, "bar", REG_DWORD,
+ data_blob_talloc(tctx, &value, 4));
+ torture_assert_werr_ok (tctx, error, "setting value");
+
+ error = reg_key_get_value_by_index(tctx, subkey, 0, &name, &type, &data);
+ torture_assert_werr_ok(tctx, error, "getting value");
+
+ torture_assert_str_equal(tctx, name, "bar", "value name");
+ torture_assert_int_equal(tctx, 4, data.length, "value length");
+ torture_assert(tctx, memcmp(data.data, &value, 4) == 0, "value content");
+ torture_assert_int_equal(tctx, REG_DWORD, type, "value type");
+
+ error = reg_key_get_value_by_index(tctx, subkey, 1, &name, &type, &data);
+ torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
+ "getting missing value");
+
+ return true;
+}
+
+static bool setup_local_registry(struct torture_context *tctx, void **data)
+{
+ struct registry_context *rctx;
+ WERROR error;
+ const char *tempdir;
+ NTSTATUS status;
+ struct hive_key *hive_key;
+
+ error = reg_open_local(tctx, &rctx, NULL, NULL);
+ if (!W_ERROR_IS_OK(error))
+ return false;
+
+ status = torture_temp_dir(tctx, "registry-local", &tempdir);
+ if (!NT_STATUS_IS_OK(status))
+ return false;
+
+ error = reg_open_ldb_file(tctx,
+ talloc_asprintf(tctx, "%s/classes_root.ldb", tempdir),
+ NULL,
+ NULL,
+ &hive_key);
+ if (!W_ERROR_IS_OK(error))
+ return false;
+
+ error = reg_mount_hive(rctx, hive_key, HKEY_CLASSES_ROOT, NULL);
+ if (!W_ERROR_IS_OK(error))
+ return false;
+
+ *data = rctx;
+
+ return true;
+}
+
+static void tcase_add_tests(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "list_subkeys", test_list_subkeys);
+ torture_tcase_add_simple_test(tcase, "get_predefined_key",
+ test_get_predefined);
+ torture_tcase_add_simple_test(tcase, "create_key", test_create_subkey);
+ torture_tcase_add_simple_test(tcase, "create_key",
+ test_create_nested_subkey);
+ torture_tcase_add_simple_test(tcase, "key_add_abs", test_key_add_abs);
+ torture_tcase_add_simple_test(tcase, "key_add_abs_top", test_key_add_abs_top);
+ torture_tcase_add_simple_test(tcase, "set_value", test_set_value);
+ torture_tcase_add_simple_test(tcase, "get_value", test_get_value);
+ torture_tcase_add_simple_test(tcase, "list_values", test_list_values);
+ torture_tcase_add_simple_test(tcase, "del_key", test_del_key);
+ torture_tcase_add_simple_test(tcase, "del_value", test_del_value);
+ torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key);
+ torture_tcase_add_simple_test(tcase, "query_key", test_query_key);
+ torture_tcase_add_simple_test(tcase, "query_key_nums", test_query_key_nums);
+}
+
+struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx)
+{
+ struct torture_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "REGISTRY");
+
+ tcase = torture_suite_add_tcase(suite, "local");
+ torture_tcase_set_fixture(tcase, setup_local_registry, NULL);
+ tcase_add_tests(tcase);
+
+ return suite;
+}
diff --git a/source4/lib/registry/tools/common.c b/source4/lib/registry/tools/common.c
new file mode 100644
index 0000000000..c8b0945c2c
--- /dev/null
+++ b/source4/lib/registry/tools/common.c
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+ Popt routines specifically for registry
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "auth/credentials/credentials.h"
+#include "lib/registry/registry.h"
+
+struct registry_context *reg_common_open_remote(const char *remote, struct cli_credentials *creds)
+{
+ struct registry_context *h;
+ WERROR error;
+
+ error = reg_open_remote(&h, NULL, creds, remote, NULL);
+
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to open remote registry at %s:%s \n", remote, win_errstr(error));
+ return NULL;
+ }
+
+ return h;
+}
+
+struct registry_key *reg_common_open_file(const char *path, struct cli_credentials *creds)
+{
+ struct hive_key *hive_root;
+ struct registry_context *h;
+ WERROR error;
+
+ error = reg_open_hive(NULL, path, NULL, creds, &hive_root);
+
+ if(!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to open '%s': %s \n", path, win_errstr(error));
+ return NULL;
+ }
+
+ error = reg_open_local(NULL, &h, NULL, creds);
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to initialize local registry: %s\n", win_errstr(error));
+ return NULL;
+ }
+
+ return reg_import_hive_key(h, hive_root, -1, NULL);
+}
+
+struct registry_context *reg_common_open_local(struct cli_credentials *creds)
+{
+ WERROR error;
+ struct registry_context *h;
+
+ error = reg_open_samba(NULL, &h, NULL, creds);
+
+ if(!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to open local registry:%s \n", win_errstr(error));
+ return NULL;
+ }
+
+ return h;
+}
diff --git a/source4/lib/registry/tools/regdiff.c b/source4/lib/registry/tools/regdiff.c
index 6eb8a78caf..8030457f5c 100644
--- a/source4/lib/registry/tools/regdiff.c
+++ b/source4/lib/registry/tools/regdiff.c
@@ -2,7 +2,8 @@
Unix SMB/CIFS implementation.
simple registry frontend
- Copyright (C) Jelmer Vernooij 2004-2005
+ Copyright (C) Jelmer Vernooij 2004-2007
+ Copyright (C) Wilco Baan Hofman 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,63 +23,115 @@
#include "lib/registry/registry.h"
#include "lib/events/events.h"
#include "lib/cmdline/popt_common.h"
+#include "lib/registry/tools/common.h"
-int main(int argc, char **argv)
+enum reg_backend { REG_UNKNOWN, REG_LOCAL, REG_REMOTE, REG_NULL };
+
+static struct registry_context *open_backend(poptContext pc, enum reg_backend backend, const char *remote_host)
+{
+ WERROR error;
+ struct registry_context *ctx;
+
+ switch (backend) {
+ case REG_UNKNOWN:
+ poptPrintUsage(pc, stderr, 0);
+ return NULL;
+ case REG_LOCAL:
+ error = reg_open_samba(NULL, &ctx, NULL, cmdline_credentials);
+ break;
+ case REG_REMOTE:
+ error = reg_open_remote(&ctx, NULL, cmdline_credentials, remote_host, NULL);
+ break;
+ case REG_NULL:
+ error = reg_open_local(NULL, &ctx, NULL, cmdline_credentials);
+ break;
+ }
+
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Error: %s\n", win_errstr(error));
+ return NULL;
+ }
+
+ return ctx;
+}
+
+int main(int argc, const char **argv)
{
int opt;
poptContext pc;
char *outputfile = NULL;
+ enum reg_backend backend1 = REG_UNKNOWN, backend2 = REG_UNKNOWN;
+ const char *remote1 = NULL, *remote2 = 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 },
+ {"output", 'o', POPT_ARG_STRING, &outputfile, 0, "output file to use", NULL },
+ {"null", 'n', POPT_ARG_NONE, NULL, 'n', "Diff from NULL", NULL },
+ {"remote", 'R', POPT_ARG_STRING, NULL, 'R', "Connect to remote server" , NULL },
+ {"local", 'L', POPT_ARG_NONE, NULL, 'L', "Open local registry", NULL },
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
POPT_COMMON_VERSION
{ NULL }
};
+ TALLOC_CTX *ctx;
+ void *callback_data;
+ struct reg_diff_callbacks *callbacks;
- registry_init();
+ ctx = talloc_init("regdiff");
- pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+ pc = poptGetContext(argv[0], argc, 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);
+ if (backend1 == REG_UNKNOWN)
+ backend1 = REG_LOCAL;
+ else if (backend2 == REG_UNKNOWN)
+ backend2 = REG_LOCAL;
+ break;
+ case 'n':
+ if (backend1 == REG_UNKNOWN)
+ backend1 = REG_NULL;
+ else if (backend2 == REG_UNKNOWN)
+ backend2 = REG_NULL;
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);
+ if (backend1 == REG_UNKNOWN) {
+ backend1 = REG_REMOTE;
+ remote1 = poptGetOptArg(pc);
+ } else if (backend2 == REG_UNKNOWN) {
+ backend2 = REG_REMOTE;
+ remote2 = poptGetOptArg(pc);
+ }
break;
}
- if (!W_ERROR_IS_OK(error)) {
- fprintf(stderr, "Error: %s\n", win_errstr(error));
- return 1;
- }
}
+ h1 = open_backend(pc, backend1, remote1);
+ if (h1 == NULL)
+ return 1;
+
+ h2 = open_backend(pc, backend2, remote2);
+ if (h2 == NULL)
+ return 1;
+
poptFreeContext(pc);
- diff = reg_generate_diff(NULL, h1, h2);
- if (!diff) {
- fprintf(stderr, "Unable to generate diff between keys\n");
+ error = reg_dotreg_diff_save(ctx, outputfile, &callbacks, &callback_data);
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Problem saving registry diff to '%s': %s\n", outputfile, win_errstr(error));
return -1;
}
- reg_diff_save(diff, outputfile);
+ error = reg_generate_diff(h1, h2, callbacks, callback_data);
+ if (!W_ERROR_IS_OK(error)) {
+ fprintf(stderr, "Unable to generate diff between keys: %s\n", win_errstr(error));
+ return -1;
+ }
return 0;
}
diff --git a/source4/lib/registry/tools/regpatch.c b/source4/lib/registry/tools/regpatch.c
index 83ad5575ef..1e6d15a7af 100644
--- a/source4/lib/registry/tools/regpatch.c
+++ b/source4/lib/registry/tools/regpatch.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple registry frontend
- Copyright (C) 2004-2005 Jelmer Vernooij, jelmer@samba.org
+ Copyright (C) 2004-2007 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
@@ -22,6 +22,8 @@
#include "lib/events/events.h"
#include "lib/registry/registry.h"
#include "lib/cmdline/popt_common.h"
+#include "lib/registry/tools/common.h"
+#include "lib/registry/patchfile.h"
int main(int argc, char **argv)
{
@@ -29,12 +31,12 @@ int main(int argc, char **argv)
poptContext pc;
const char *patch;
struct registry_context *h;
+ const char *file = NULL;
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},
+ {"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL },
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
{ NULL }
@@ -45,29 +47,24 @@ int main(int argc, char **argv)
while((opt = poptGetNextOpt(pc)) != -1) {
}
- registry_init();
-
if (remote) {
- error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL);
+ h = reg_common_open_remote (remote, cmdline_credentials);
} else {
- error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
+ h = reg_common_open_local (cmdline_credentials);
}
-
- if (W_ERROR_IS_OK(error)) {
- fprintf(stderr, "Error: %s\n", win_errstr(error));
+
+ if (h == NULL)
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);
+ if (patch == NULL) {
+ poptPrintUsage(pc, stderr, 0);
return 1;
}
- reg_diff_apply(diff, h);
+ poptFreeContext(pc);
+
+ reg_diff_apply(patch, h);
return 0;
}
diff --git a/source4/lib/registry/tools/regshell.c b/source4/lib/registry/tools/regshell.c
index f431c81bf8..0887bc91f3 100644
--- a/source4/lib/registry/tools/regshell.c
+++ b/source4/lib/registry/tools/regshell.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple registry frontend
- Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Jelmer Vernooij 2004-2007
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
@@ -25,8 +25,15 @@
#include "system/time.h"
#include "lib/smbreadline/smbreadline.h"
#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/registry/tools/common.h"
-/*
+struct regshell_context {
+ struct registry_context *registry;
+ const char *path;
+ struct registry_key *current;
+};
+
+/* *
* ck/cd - change key
* ls - list values/keys
* rmval/rm - remove value
@@ -40,29 +47,40 @@
* exit
*/
-static struct registry_key *cmd_info(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_info(struct regshell_context *ctx, int argc, char **argv)
{
struct security_descriptor *sec_desc = NULL;
time_t last_mod;
WERROR error;
+ const char *classname;
+ NTTIME last_change;
+
+ error = reg_key_get_info(ctx, ctx->current, &classname, NULL, NULL, &last_change);
+ if (!W_ERROR_IS_OK(error)) {
+ printf("Error getting key info: %s\n", win_errstr(error));
+ return 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("Name: %s\n", strchr(ctx->path, '\\')?strrchr(ctx->path, '\\')+1:
+ ctx->path);
+ printf("Full path: %s\n", ctx->path);
+ printf("Key Class: %s\n", classname);
+ last_mod = nt_time_to_unix(last_change);
printf("Time Last Modified: %s\n", ctime(&last_mod));
- error = reg_get_sec_desc(mem_ctx, cur, &sec_desc);
+ error = reg_get_sec_desc(ctx, ctx->current, &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);
- }
+ return error;
+ }
+ ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
talloc_free(sec_desc);
- return cur;
+
+ return WERR_OK;
}
-static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_predef(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_key *ret = NULL;
if (argc < 2) {
@@ -70,165 +88,195 @@ static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_cont
} 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);
+ WERROR error = reg_get_predefined_key_by_name(ctx->registry, 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 error;
}
}
- return ret;
+
+ return WERR_OK;
}
-static struct registry_key *cmd_pwd(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_pwd(struct regshell_context *ctx,
+ int argc, char **argv)
{
- printf("%s\n", cur->path);
- return cur;
+ printf("%s\n", ctx->path);
+ return WERR_OK;
}
-static struct registry_key *cmd_set(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_set(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_value val;
WERROR error;
if (argc < 4) {
fprintf(stderr, "Usage: set value-name type value\n");
- return cur;
+ return WERR_INVALID_PARAM;
}
- if (!reg_string_to_val(mem_ctx, argv[2], argv[3], &val.data_type, &val.data)) {
+ if (!reg_string_to_val(ctx, argv[2], argv[3], &val.data_type,
+ &val.data)) {
fprintf(stderr, "Unable to interpret data\n");
- return cur;
+ return WERR_INVALID_PARAM;
}
- error = reg_val_set(cur, argv[1], val.data_type, val.data);
+ error = reg_val_set(ctx->current, 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 error;
}
- return cur;
+
+ return WERR_OK;
}
-static struct registry_key *cmd_ck(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_ck(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_key *new = NULL;
WERROR error;
+
if(argc < 2) {
- new = cur;
+ new = ctx->current;
} else {
- error = reg_open_key(mem_ctx, cur, argv[1], &new);
+ error = reg_open_key(ctx->registry, ctx->current, argv[1], &new);
if(!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening specified key: %s\n", win_errstr(error)));
- return NULL;
+ return error;
}
}
- printf("Current path is: %s\n", new->path);
+ ctx->path = talloc_asprintf(ctx, "%s\\%s", ctx->path, argv[1]);
+ printf("Current path is: %s\n", ctx->path);
+ ctx->current = new;
- return new;
+ return WERR_OK;
}
-static struct registry_key *cmd_print(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_print(struct regshell_context *ctx, int argc, char **argv)
{
- struct registry_value *value;
+ uint32_t value_type;
+ DATA_BLOB value_data;
WERROR error;
if (argc != 2) {
fprintf(stderr, "Usage: print <valuename>");
- return NULL;
+ return WERR_INVALID_PARAM;
}
- error = reg_key_get_value_by_name(mem_ctx, cur, argv[1], &value);
+ error = reg_key_get_value_by_name(ctx, ctx->current, argv[1],
+ &value_type, &value_data);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "No such value '%s'\n", argv[1]);
- return NULL;
+ return error;
}
- printf("%s\n%s\n", str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
- return NULL;
+ printf("%s\n%s\n", str_regtype(value_type),
+ reg_val_data_string(ctx, value_type, value_data));
+
+ return WERR_OK;
}
-static struct registry_key *cmd_ls(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_ls(struct regshell_context *ctx, 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);
+ uint32_t data_type;
+ DATA_BLOB data;
+ const char *name;
+
+ for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(ctx, ctx->current, i, &name, NULL, NULL)); i++) {
+ printf("K %s\n", name);
}
- if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
+ 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));
+ for (i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(ctx, ctx->current, i, &name, &data_type, &data)); i++) {
+ printf("V \"%s\" %s %s\n", value->name, str_regtype(data_type),
+ reg_val_data_string(ctx, data_type, data));
}
- return NULL;
+ return WERR_OK;
}
-static struct registry_key *cmd_mkkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_mkkey(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_key *tmp;
+ WERROR error;
+
if(argc < 2) {
fprintf(stderr, "Usage: mkkey <keyname>\n");
- return NULL;
+ return WERR_INVALID_PARAM;
}
+
+ error = reg_key_add_name(ctx, ctx->current, argv[1], 0, NULL, &tmp);
- if(!W_ERROR_IS_OK(reg_key_add_name(mem_ctx, cur, argv[1], 0, NULL, &tmp))) {
+ if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
- return NULL;
+ return error;
}
- return NULL;
+ return WERR_OK;
}
-static struct registry_key *cmd_rmkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_rmkey(struct regshell_context *ctx,
+ int argc, char **argv)
{
+ WERROR error;
+
if(argc < 2) {
fprintf(stderr, "Usage: rmkey <name>\n");
- return NULL;
+ return WERR_INVALID_PARAM;
}
- if(!W_ERROR_IS_OK(reg_key_del(cur, argv[1]))) {
+ error = reg_key_del(ctx->current, argv[1]);
+ if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error deleting '%s'\n", argv[1]);
+ return error;
} else {
fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
}
- return NULL;
+ return WERR_OK;
}
-static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_rmval(struct regshell_context *ctx, int argc, char **argv)
{
+ WERROR error;
+
if(argc < 2) {
fprintf(stderr, "Usage: rmval <valuename>\n");
- return NULL;
+ return WERR_INVALID_PARAM;
}
- if(!W_ERROR_IS_OK(reg_del_value(cur, argv[1]))) {
+ error = reg_del_value(ctx->current, argv[1]);
+ if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
+ return error;
} else {
fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
}
- return NULL;
+ return WERR_OK;
}
-static struct registry_key *cmd_exit(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_exit(struct regshell_context *ctx,
+ int argc, char **argv)
{
exit(0);
- return NULL;
+ return WERR_OK;
}
-static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int, char **);
+static WERROR cmd_help(struct regshell_context *ctx, 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);
+ WERROR (*handle)(struct regshell_context *ctx,
+ int argc, char **argv);
} regshell_cmds[] = {
{"ck", "cd", "Change current key", cmd_ck },
{"info", "i", "Show detailed information of a key", cmd_info },
@@ -245,17 +293,19 @@ static struct {
{NULL }
};
-static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_help(struct regshell_context *ctx,
+ 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;
+ return WERR_OK;
}
-static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *k, char *line)
+static WERROR process_cmd(struct regshell_context *ctx,
+ char *line)
{
int argc;
char **argv = NULL;
@@ -263,19 +313,19 @@ static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_con
if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
- return k;
+ return WERR_INVALID_PARAM;
}
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);
+ return regshell_cmds[i].handle(ctx, argc, argv);
}
}
fprintf(stderr, "No such command '%s'\n", argv[0]);
- return k;
+ return WERR_INVALID_PARAM;
}
#define MAX_COMPLETIONS 100
@@ -333,7 +383,7 @@ cleanup:
static char **reg_complete_key(const char *text, int start, int end)
{
struct registry_key *base;
- struct registry_key *subkey;
+ const char *subkeyname;
int i, j = 1;
int samelen = 0;
int len;
@@ -351,10 +401,11 @@ static char **reg_complete_key(const char *text, int start, int end)
len = strlen(text);
for(i = 0; j < MAX_COMPLETIONS-1; i++) {
- status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkey);
+ status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkeyname,
+ NULL, NULL);
if(W_ERROR_IS_OK(status)) {
- if(!strncmp(text, subkey->name, len)) {
- matches[j] = strdup(subkey->name);
+ if(!strncmp(text, subkeyname, len)) {
+ matches[j] = strdup(subkeyname);
j++;
if (j == 1)
@@ -381,7 +432,8 @@ static char **reg_complete_key(const char *text, int start, int end)
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));
+ asprintf(&matches[0], "%s%s", base_n,
+ talloc_strndup(mem_ctx, matches[1], samelen));
}
talloc_free(mem_ctx);
@@ -400,19 +452,17 @@ static char **reg_completion(const char *text, int start, int end)
}
}
- int main(int argc, char **argv)
+int main(int argc, char **argv)
{
int opt;
- const char *backend = NULL;
- struct registry_key *curkey = NULL;
+ const char *file = NULL;
poptContext pc;
- WERROR error;
- TALLOC_CTX *mem_ctx = talloc_init("cmd");
const char *remote = NULL;
- struct registry_context *h = NULL;
+ struct regshell_context *ctx;
+ bool ret = true;
struct poptOption long_options[] = {
POPT_AUTOHELP
- {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+ {"file", 'F', POPT_ARG_STRING, &file, 0, "open hive file", NULL },
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
@@ -425,64 +475,62 @@ static char **reg_completion(const char *text, int start, int end)
while((opt = poptGetNextOpt(pc)) != -1) {
}
- registry_init();
+ ctx = talloc_zero(NULL, struct regshell_context);
- 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);
+ if (remote != NULL) {
+ ctx->registry = reg_common_open_remote(remote, cmdline_credentials);
+ } else if (file != NULL) {
+ ctx->current = reg_common_open_file(file, cmdline_credentials);
+ ctx->registry = ctx->current->context;
+ ctx->path = talloc_strdup(ctx, "");
} else {
- error = reg_open_local(NULL, &h, NULL, cmdline_credentials);
+ ctx->registry = reg_common_open_local(cmdline_credentials);
}
- if(!W_ERROR_IS_OK(error)) {
- fprintf(stderr, "Unable to open registry\n");
+ if (ctx->registry == NULL)
return 1;
- }
- if (h) {
+ if (ctx->current == NULL) {
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);
+ err = reg_get_predefined_key(ctx->registry,
+ reg_predefined_keys[i].handle,
+ &ctx->current);
if (W_ERROR_IS_OK(err)) {
+ ctx->path = talloc_strdup(ctx, reg_predefined_keys[i].name);
break;
} else {
- curkey = NULL;
+ ctx->current = NULL;
}
}
}
- if (!curkey) {
+ if (ctx->current == NULL) {
fprintf(stderr, "Unable to access any of the predefined keys\n");
return -1;
}
poptFreeContext(pc);
- while(True) {
+ 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);
- }
+ asprintf(&prompt, "%s> ", ctx->path);
- current_key = curkey; /* No way to pass a void * pointer
- via readline :-( */
+ current_key = ctx->current; /* No way to pass a void * pointer
+ via readline :-( */
line = smb_readline(prompt, NULL, reg_completion);
- if(!line)
+ if (line == NULL)
break;
- if(line[0] != '\n') {
- struct registry_key *new = process_cmd(mem_ctx, h, curkey, line);
- if(new)curkey = new;
+ if (line[0] != '\n') {
+ ret = W_ERROR_IS_OK(process_cmd(ctx, line));
}
}
- talloc_free(mem_ctx);
+ talloc_free(ctx);
- return 0;
+ return (ret?0:1);
}
diff --git a/source4/lib/registry/tools/regtree.c b/source4/lib/registry/tools/regtree.c
index d026d2824f..8d2460a93e 100644
--- a/source4/lib/registry/tools/regtree.c
+++ b/source4/lib/registry/tools/regtree.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple registry frontend
- Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Jelmer Vernooij 2004-2007
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
@@ -20,52 +20,66 @@
#include "includes.h"
#include "lib/registry/registry.h"
+#include "lib/registry/tools/common.h"
#include "lib/events/events.h"
#include "lib/cmdline/popt_common.h"
-static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
+/**
+ * Print a registry key recursively
+ *
+ * @param level Level at which to print
+ * @param p Key to print
+ * @param fullpath Whether the full pat hshould be printed or just the last bit
+ * @param novals Whether values should not be printed
+ */
+static void print_tree(int level, struct registry_key *p,
+ const char *name,
+ bool fullpath, bool novals)
{
struct registry_key *subkey;
- struct registry_value *value;
+ const char *valuename;
+ const char *keyname;
+ uint32_t value_type;
+ DATA_BLOB value_data;
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)");
- }
+ for(i = 0; i < level; i++) putchar(' '); puts(name);
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);
+ for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, p, i, &keyname, NULL, NULL)); i++) {
+ SMB_ASSERT(strlen(keyname) > 0);
+ if (!W_ERROR_IS_OK(reg_open_key(mem_ctx, p, keyname, &subkey)))
+ continue;
+ print_tree(level+1, subkey, (fullpath && strlen(name))?
+ talloc_asprintf(mem_ctx, "%s\\%s", name, keyname):
+ keyname, 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)));
+ DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n",
+ name, win_errstr(error)));
}
- if(!novals) {
+ 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++) {
+ for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx,
+ p, i, &valuename, &value_type, &value_data)); i++) {
int j;
char *desc;
- for(j = 0; j < l+1; j++) putchar(' ');
- desc = reg_val_description(mem_ctx, value);
+ for(j = 0; j < level+1; j++) putchar(' ');
+ desc = reg_val_description(mem_ctx, valuename, value_type,
+ value_data);
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)));
+ DEBUG(0, ("Error occured while fetching values for '%s': %s\n",
+ name, win_errstr(error)));
}
}
@@ -79,21 +93,22 @@ static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
int main(int argc, char **argv)
{
int opt, i;
- const char *backend = NULL;
+ const char *file = NULL;
const char *remote = NULL;
poptContext pc;
struct registry_context *h = NULL;
- struct registry_key *root = NULL;
+ struct registry_key *start_key = NULL;
WERROR error;
- int fullpath = 0, no_values = 0;
+ bool fullpath = false, no_values = false;
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},
+ {"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL },
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL },
+ {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
{"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
{ NULL }
};
@@ -102,48 +117,35 @@ int main(int argc, char **argv)
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;
- }
+ if (remote != NULL) {
+ h = reg_common_open_remote(remote, cmdline_credentials);
+ } else if (file != NULL) {
+ start_key = reg_common_open_file(file, cmdline_credentials);
} 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;
- }
-
+ h = reg_common_open_local(cmdline_credentials);
}
+ if (h == NULL && start_key == NULL)
+ return 1;
+
poptFreeContext(pc);
error = WERR_OK;
- if (root != NULL) {
- print_tree(0, root, fullpath, no_values);
+ if (start_key != NULL) {
+ print_tree(0, start_key, "", 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);
+ error = reg_get_predefined_key(h, reg_predefined_keys[i].handle,
+ &start_key);
if (!W_ERROR_IS_OK(error)) {
- fprintf(stderr, "Skipping %s\n", reg_predefined_keys[i].name);
+ fprintf(stderr, "Skipping %s: %s\n", reg_predefined_keys[i].name,
+ win_errstr(error));
continue;
}
- SMB_ASSERT(root);
- print_tree(0, root, fullpath, no_values);
+ SMB_ASSERT(start_key != NULL);
+ print_tree(0, start_key, reg_predefined_keys[i].name, fullpath,
+ no_values);
}
}
diff --git a/source4/lib/registry/common/reg_util.c b/source4/lib/registry/util.c
index 696336161e..47716f89cf 100644
--- a/source4/lib/registry/common/reg_util.c
+++ b/source4/lib/registry/util.c
@@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
Transparent registry backend handling
- Copyright (C) Jelmer Vernooij 2003-2004.
+ Copyright (C) Jelmer Vernooij 2003-2007.
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
@@ -50,27 +50,30 @@ _PUBLIC_ const char *str_regtype(int type)
return "Unknown";
}
-_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data)
+_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type,
+ const DATA_BLOB data)
{
char *ret = NULL;
- if(data->length == 0) return talloc_strdup(mem_ctx, "");
+ 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);
+ 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);
+ ret = data_blob_hex_string(mem_ctx, &data);
return ret;
case REG_DWORD:
- if (*(int *)data->data == 0)
+ if (*(int *)data.data == 0)
return talloc_strdup(mem_ctx, "0");
- return talloc_asprintf(mem_ctx, "0x%x", *(int *)data->data);
+ return talloc_asprintf(mem_ctx, "0x%x", *(int *)data.data);
case REG_MULTI_SZ:
/* FIXME */
@@ -84,9 +87,13 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB
}
/** Generate a string that describes a registry value */
-_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val)
+_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name,
+ uint32_t data_type,
+ const DATA_BLOB data)
{
- 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));
+ return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>",
+ str_regtype(data_type),
+ reg_val_data_string(mem_ctx, data_type, 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)
@@ -136,29 +143,6 @@ _PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const
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)
{
@@ -167,14 +151,16 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co
int predeflength;
char *predefname;
- if(strchr(name, '\\')) predeflength = strchr(name, '\\')-name;
- else predeflength = strlen(name);
+ if (strchr(name, '\\') != NULL)
+ 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)) {
+ if (!W_ERROR_IS_OK(error)) {
return error;
}
@@ -186,7 +172,9 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co
}
}
-static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, struct registry_key **parent, const char **name)
+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;
@@ -195,14 +183,14 @@ static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
return WERR_FOOBAR;
}
- parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-1-path);
+ parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-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);
+ *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1);
return WERR_OK;
}
@@ -228,20 +216,27 @@ WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
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)
+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;
+ return WERR_ALREADY_EXISTS;
}
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);
+ if (!W_ERROR_IS_OK(error)) {
+ DEBUG(2, ("Opening parent of %s failed with %s\n", path,
+ win_errstr(error)));
+ return error;
}
+ error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result);
+
return error;
}
diff --git a/source4/lib/registry/reg_backend_wine.c b/source4/lib/registry/wine.c
index 7184a602d1..2cb0b9955e 100644
--- a/source4/lib/registry/reg_backend_wine.c
+++ b/source4/lib/registry/wine.c
@@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
Registry interface
- Copyright (C) Jelmer Vernooij 2004.
+ Copyright (C) Jelmer Vernooij 2007.
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
@@ -26,8 +26,6 @@ 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,