From 444a86792471c0bef33dde15c7a4a33e16a951b4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 10 Dec 2004 20:07:04 +0000 Subject: r4132: - Bunch of rather large fixes in the registry - Added some README files Not everything works yet, e.g. the EnumValue test appears to be broken. (This used to be commit c169e86c1f52763b83e77e509f89cb91f9b69071) --- source4/lib/registry/README | 30 + source4/lib/registry/common/reg_interface.c | 182 +- source4/lib/registry/config.mk | 17 +- source4/lib/registry/reg_backend_dir.c | 148 ++ .../lib/registry/reg_backend_dir/reg_backend_dir.c | 148 -- source4/lib/registry/reg_backend_gconf.c | 193 +++ .../registry/reg_backend_gconf/reg_backend_gconf.c | 193 --- source4/lib/registry/reg_backend_ldb.c | 219 +++ .../lib/registry/reg_backend_ldb/reg_backend_ldb.c | 219 --- source4/lib/registry/reg_backend_nt4.c | 1747 ++++++++++++++++++++ .../lib/registry/reg_backend_nt4/reg_backend_nt4.c | 1747 -------------------- source4/lib/registry/reg_backend_rpc.c | 398 +++++ .../lib/registry/reg_backend_rpc/reg_backend_rpc.c | 405 ----- source4/lib/registry/reg_backend_w95.c | 356 ++++ .../lib/registry/reg_backend_w95/reg_backend_w95.c | 356 ---- source4/lib/registry/reg_backend_wine.c | 48 + .../registry/reg_backend_wine/reg_backend_wine.c | 33 - source4/lib/registry/reg_samba.c | 62 + source4/lib/registry/tools/regdiff.c | 76 +- source4/lib/registry/tools/regpatch.c | 25 +- source4/lib/registry/tools/regshell.c | 87 +- source4/lib/registry/tools/regtree.c | 38 +- 22 files changed, 3418 insertions(+), 3309 deletions(-) create mode 100644 source4/lib/registry/README create mode 100644 source4/lib/registry/reg_backend_dir.c delete mode 100644 source4/lib/registry/reg_backend_dir/reg_backend_dir.c create mode 100644 source4/lib/registry/reg_backend_gconf.c delete mode 100644 source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c create mode 100644 source4/lib/registry/reg_backend_ldb.c delete mode 100644 source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c create mode 100644 source4/lib/registry/reg_backend_nt4.c delete mode 100644 source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c create mode 100644 source4/lib/registry/reg_backend_rpc.c delete mode 100644 source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c create mode 100644 source4/lib/registry/reg_backend_w95.c delete mode 100644 source4/lib/registry/reg_backend_w95/reg_backend_w95.c create mode 100644 source4/lib/registry/reg_backend_wine.c delete mode 100644 source4/lib/registry/reg_backend_wine/reg_backend_wine.c create mode 100644 source4/lib/registry/reg_samba.c (limited to 'source4/lib') diff --git a/source4/lib/registry/README b/source4/lib/registry/README new file mode 100644 index 0000000000..757029cdc2 --- /dev/null +++ b/source4/lib/registry/README @@ -0,0 +1,30 @@ +This is the registry library. The registry is basically a bunch of hives +(HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, etc) that can be loaded from +different places. + +The various registry backends provide support for loading/saving specific types +of hives: + - ldb + - w95 (USER.DAT-style files) + - nt4 (NTUSER.DAT-style files) + - gconf (GNOME configuration) + - rpc (Remote individual hives) + +Instead of opening individual hives, one can also open a 'complete' registry by +using one of these three functions: + + - reg_open_local() - load local registry, see below + - reg_open_remote() - connect to remote registry over RPC + - reg_open_wine() (not working yet) + +reg_open_local() loads a set of hives based on smb.conf settings. +Lines in smb.conf should have the following syntax: + +registry: = : + +So an example usage could be: + +registry:HKEY_CURRENT_USER = nt4:NTUSER.DAT +registry:HKEY_LOCAL_MACHINE = ldb:tdb://registry.tdb + +WERR_NOT_SUPPORTED will be returned for all hives that haven't been set. diff --git a/source4/lib/registry/common/reg_interface.c b/source4/lib/registry/common/reg_interface.c index f7d3af0705..740d849db1 100644 --- a/source4/lib/registry/common/reg_interface.c +++ b/source4/lib/registry/common/reg_interface.c @@ -30,32 +30,25 @@ static struct reg_init_function_entry *backends = NULL; static struct reg_init_function_entry *reg_find_backend_entry(const char *name); -#define reg_make_path(mem_ctx, parent, name) (((parent)->hive->root == (parent))?talloc_strdup(mem_ctx, name):talloc_asprintf(mem_ctx, "%s\\%s", parent->path, name)) - /* Register new backend */ -NTSTATUS registry_register(const void *_function) +NTSTATUS registry_register(const void *_hive_ops) { - const struct registry_operations *functions = _function; + const struct hive_operations *hive_ops = _hive_ops; struct reg_init_function_entry *entry = backends; - if (!functions || !functions->name) { - DEBUG(0, ("Invalid arguments while registering registry backend\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(5,("Attempting to register registry backend %s\n", functions->name)); + DEBUG(5,("Attempting to register registry backend %s\n", hive_ops->name)); /* Check for duplicates */ - if (reg_find_backend_entry(functions->name)) { - DEBUG(0,("There already is a registry backend registered with the name %s!\n", functions->name)); + 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 = malloc_p(struct reg_init_function_entry); - entry->functions = functions; + entry = talloc_p(NULL, struct reg_init_function_entry); + entry->hive_functions = hive_ops; DLIST_ADD(backends, entry); - DEBUG(5,("Successfully added registry backend '%s'\n", functions->name)); + DEBUG(5,("Successfully added registry backend '%s'\n", hive_ops->name)); return NT_STATUS_OK; } @@ -67,7 +60,7 @@ static struct reg_init_function_entry *reg_find_backend_entry(const char *name) entry = backends; while(entry) { - if (strcmp(entry->functions->name, name) == 0) return entry; + if (strcmp(entry->hive_functions->name, name) == 0) return entry; entry = entry->next; } @@ -80,85 +73,83 @@ BOOL reg_has_backend(const char *backend) return reg_find_backend_entry(backend) != NULL?True:False; } -WERROR reg_create(struct registry_context **_ret) +static struct { + uint32 hkey; + const char *name; +} hkey_names[] = { - TALLOC_CTX *mem_ctx; - struct registry_context *ret; - mem_ctx = talloc_init("registry handle"); - ret = talloc_p(mem_ctx, struct registry_context); - ret->mem_ctx = mem_ctx; - ZERO_STRUCTP(ret); - *_ret = ret; - return WERR_OK; -} - -WERROR reg_list_available_hives(TALLOC_CTX *mem_ctx, const char *backend, const char *location, const char *credentials, char ***hives) + {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_PT, "HKEY_PT" }, + {HKEY_PN, "HKEY_PN" }, + { 0, NULL } +}; + +int reg_list_hives(TALLOC_CTX *mem_ctx, char ***hives, uint32_t **hkeys) { - struct reg_init_function_entry *entry; - - entry = reg_find_backend_entry(backend); - - if (!entry) { - DEBUG(0, ("No such registry backend '%s' loaded!\n", backend)); - return WERR_GENERAL_FAILURE; - } + int i; + *hives = talloc_array_p(mem_ctx, char *, ARRAY_SIZE(hkey_names)); + *hkeys = talloc_array_p(mem_ctx, uint32_t, ARRAY_SIZE(hkey_names)); - if(!entry->functions->list_available_hives) { - return WERR_NOT_SUPPORTED; + for (i = 0; hkey_names[i].name; i++) { + (*hives)[i] = talloc_strdup(mem_ctx, hkey_names[i].name); + (*hkeys)[i] = hkey_names[i].hkey; } - return entry->functions->list_available_hives(mem_ctx, location, credentials, hives); + return i; } -WERROR reg_open(struct registry_context **ret, const char *backend, const char *location, const char *credentials) +const char *reg_get_hkey_name(uint32_t hkey) { - WERROR error = reg_create(ret), reterror = WERR_NO_MORE_ITEMS; - char **hives; - int i, j; - TALLOC_CTX *mem_ctx = talloc_init("reg_open"); - - if(!W_ERROR_IS_OK(error)) return error; - - error = reg_list_available_hives(mem_ctx, backend, location, credentials, &hives); - - if(W_ERROR_EQUAL(error, WERR_NOT_SUPPORTED)) { - return reg_import_hive(*ret, backend, location, credentials, NULL); + int i; + for (i = 0; hkey_names[i].name; i++) { + if (hkey_names[i].hkey == hkey) return hkey_names[i].name; } - - if(!W_ERROR_IS_OK(error)) return error; - j = 0; - for(i = 0; hives[i]; i++) - { - error = reg_import_hive(*ret, backend, location, credentials, hives[i]); - if (W_ERROR_IS_OK(error)) { - reterror = WERR_OK; - (*ret)->hives[j]->name = talloc_strdup((*ret)->mem_ctx, hives[i]); - j++; - } else if (!W_ERROR_IS_OK(reterror)) reterror = error; + return NULL; +} + +WERROR reg_get_hive_by_name(struct registry_context *ctx, const char *name, struct registry_key **key) +{ + int i; + + for (i = 0; hkey_names[i].name; i++) { + if (!strcmp(hkey_names[i].name, name)) return reg_get_hive(ctx, hkey_names[i].hkey, key); } - return reterror; + DEBUG(1, ("No hive with name '%s'\n", name)); + + return WERR_BADFILE; } WERROR reg_close (struct registry_context *ctx) { - int i; - for (i = 0; i < ctx->num_hives; i++) { - if (ctx->hives[i]->functions->close_hive) { - ctx->hives[i]->functions->close_hive(ctx->hives[i]); - } - } talloc_destroy(ctx); return WERR_OK; } +WERROR reg_get_hive(struct registry_context *ctx, uint32_t hkey, struct registry_key **key) +{ + WERROR ret = ctx->get_hive(ctx, hkey, key); + + if (W_ERROR_IS_OK(ret)) { + (*key)->name = talloc_strdup(*key, reg_get_hkey_name(hkey)); + (*key)->path = ""; + } + + return ret; +} + /* Open a registry file/host/etc */ -WERROR reg_import_hive(struct registry_context *h, const char *backend, const char *location, const char *credentials, const char *hivename) +WERROR reg_open_hive(struct registry_context *parent_ctx, const char *backend, const char *location, const char *credentials, struct registry_key **root) { struct registry_hive *ret; - TALLOC_CTX *mem_ctx; struct reg_init_function_entry *entry; WERROR werr; @@ -169,24 +160,21 @@ WERROR reg_import_hive(struct registry_context *h, const char *backend, const ch return WERR_GENERAL_FAILURE; } - if(!entry->functions->open_hive) { + if(!entry->hive_functions || !entry->hive_functions->open_hive) { return WERR_NOT_SUPPORTED; } - - mem_ctx = h->mem_ctx; - ret = talloc_p(mem_ctx, struct registry_hive); - ret->location = location?talloc_strdup(mem_ctx, location):NULL; - ret->backend_hivename = hivename?talloc_strdup(mem_ctx, hivename):NULL; - ret->credentials = credentials?talloc_strdup(mem_ctx, credentials):NULL; - ret->functions = entry->functions; + ret = talloc_p(parent_ctx, struct registry_hive); + ret->location = location?talloc_strdup(ret, location):NULL; + ret->functions = entry->hive_functions; ret->backend_data = NULL; - ret->reg_ctx = h; - ret->name = NULL; + ret->reg_ctx = parent_ctx; - werr = entry->functions->open_hive(mem_ctx, ret, &ret->root); + werr = entry->hive_functions->open_hive(ret, &ret->root); - if(!W_ERROR_IS_OK(werr)) return werr; + if(!W_ERROR_IS_OK(werr)) { + return werr; + } if(!ret->root) { DEBUG(0, ("Backend %s didn't provide root key!\n", backend)); @@ -195,12 +183,9 @@ WERROR reg_import_hive(struct registry_context *h, const char *backend, const ch ret->root->hive = ret; ret->root->name = NULL; - ret->root->path = talloc_strdup(mem_ctx, ""); - - /* Add hive to context */ - h->num_hives++; - h->hives = talloc_realloc_p(h, h->hives, struct registry_hive *, h->num_hives); - h->hives[h->num_hives-1] = ret; + ret->root->path = talloc_strdup(ret, ""); + + *root = ret->root; return WERR_OK; } @@ -217,7 +202,7 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co else hivelength = strlen(name); hivename = strndup(name, hivelength); - error = reg_get_hive(handle, hivename, &hive); + error = reg_get_hive_by_name(handle, hivename, &hive); SAFE_FREE(hivename); if(!W_ERROR_IS_OK(error)) { @@ -272,7 +257,8 @@ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char return WERR_NOT_SUPPORTED; } - fullname = reg_make_path(mem_ctx, parent, name); + + fullname = ((parent->hive->root == parent)?talloc_strdup(mem_ctx, name):talloc_asprintf(mem_ctx, "%s\\%s", parent->path, name)); error = parent->hive->functions->open_key(mem_ctx, parent->hive, fullname, result); @@ -499,7 +485,7 @@ WERROR reg_key_add_name_recursive_abs(struct registry_context *handle, const cha else hivelength = strlen(name); hivename = strndup(name, hivelength); - error = reg_get_hive(handle, hivename, &hive); + error = reg_get_hive_by_name(handle, hivename, &hive); SAFE_FREE(hivename); if(!W_ERROR_IS_OK(error)) return error; @@ -578,19 +564,7 @@ WERROR reg_val_set(struct registry_key *key, const char *value, int type, void * return WERR_NOT_SUPPORTED; } -WERROR reg_get_hive(struct registry_context *h, const char *name, struct registry_key **key) -{ - int i; - for(i = 0; i < h->num_hives; i++) - { - if(!strcmp(h->hives[i]->name, name)) { - *key = h->hives[i]->root; - return WERR_OK; - } - } - return WERR_NO_MORE_ITEMS; -} WERROR reg_del_value(struct registry_value *val) { diff --git a/source4/lib/registry/config.mk b/source4/lib/registry/config.mk index b91ec647a0..af9fb83bab 100644 --- a/source4/lib/registry/config.mk +++ b/source4/lib/registry/config.mk @@ -6,7 +6,7 @@ INIT_FUNCTION = registry_nt4_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ - lib/registry/reg_backend_nt4/reg_backend_nt4.o + lib/registry/reg_backend_nt4.o # End MODULE registry_nt4 ################################################ @@ -16,7 +16,7 @@ INIT_OBJ_FILES = \ INIT_FUNCTION = registry_w95_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ - lib/registry/reg_backend_w95/reg_backend_w95.o + lib/registry/reg_backend_w95.o # End MODULE registry_w95 ################################################ @@ -26,7 +26,7 @@ INIT_OBJ_FILES = \ INIT_FUNCTION = registry_dir_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ - lib/registry/reg_backend_dir/reg_backend_dir.o + lib/registry/reg_backend_dir.o # End MODULE registry_dir ################################################ @@ -36,18 +36,20 @@ INIT_OBJ_FILES = \ INIT_FUNCTION = registry_rpc_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ - lib/registry/reg_backend_rpc/reg_backend_rpc.o + lib/registry/reg_backend_rpc.o REQUIRED_SUBSYSTEMS = RPC_NDR_WINREG # End MODULE registry_rpc ################################################ + + ################################################ # Start MODULE registry_gconf [MODULE::registry_gconf] INIT_FUNCTION = registry_gconf_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ - lib/registry/reg_backend_gconf/reg_backend_gconf.o + lib/registry/reg_backend_gconf.o REQUIRED_SUBSYSTEMS = EXT_LIB_gconf # End MODULE registry_gconf ################################################ @@ -58,7 +60,7 @@ REQUIRED_SUBSYSTEMS = EXT_LIB_gconf INIT_FUNCTION = registry_ldb_init SUBSYSTEM = REGISTRY INIT_OBJ_FILES = \ - lib/registry/reg_backend_ldb/reg_backend_ldb.o + lib/registry/reg_backend_ldb.o REQUIRED_SUBSYSTEMS = \ LIBLDB # End MODULE registry_ldb @@ -70,7 +72,8 @@ REQUIRED_SUBSYSTEMS = \ INIT_OBJ_FILES = \ lib/registry/common/reg_interface.o ADD_OBJ_FILES = \ - lib/registry/common/reg_util.o + lib/registry/common/reg_util.o \ + lib/registry/reg_samba.o REQUIRED_SUBSYSTEMS = \ LIBBASIC # End MODULE registry_ldb diff --git a/source4/lib/registry/reg_backend_dir.c b/source4/lib/registry/reg_backend_dir.c new file mode 100644 index 0000000000..5c3ed3c44c --- /dev/null +++ b/source4/lib/registry/reg_backend_dir.c @@ -0,0 +1,148 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "registry.h" +#include "system/dir.h" + +static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, uint32_t access_mask, SEC_DESC *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(struct registry_key *k) +{ + return (rmdir((char *)k->backend_data) == 0)?WERR_OK:WERR_GENERAL_FAILURE; +} + +static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **subkey) +{ + DIR *d; + char *fullpath; + 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", h->location, name); + fullpath = reg_path_win2unix(fullpath); + + d = opendir(fullpath); + if(!d) { + DEBUG(3,("Unable to open '%s': %s\n", fullpath, strerror(errno))); + return WERR_BADFILE; + } + closedir(d); + ret = talloc_p(mem_ctx, struct registry_key); + ret->hive = h; + ret->path = fullpath; + *subkey = ret; + return WERR_OK; +} + +static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, 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( strcmp(e->d_name, ".") && + strcmp(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)) { + i++; + if(i == idx) { + (*key) = talloc_p(mem_ctx, struct registry_key); + (*key)->name = e->d_name; + (*key)->path = NULL; + (*key)->backend_data = talloc_strdup(mem_ctx, thispath); + SAFE_FREE(thispath); + closedir(d); + return WERR_OK; + } + } + + 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_p(h, struct registry_key); + (*key)->backend_data = talloc_strdup(*key, h->location); + return WERR_OK; +} + +static WERROR reg_dir_set_value(struct registry_key *p, const char *name, int type, void *data, int len) +{ + /* FIXME */ + return WERR_NOT_SUPPORTED; +} + +static WERROR reg_dir_del_value(struct registry_value *v) +{ + /* FIXME*/ + return WERR_NOT_SUPPORTED; +} + +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, + .set_value = reg_dir_set_value, + .del_value = reg_dir_del_value, +}; + +NTSTATUS registry_dir_init(void) +{ + return registry_register(®_backend_dir); +} diff --git a/source4/lib/registry/reg_backend_dir/reg_backend_dir.c b/source4/lib/registry/reg_backend_dir/reg_backend_dir.c deleted file mode 100644 index 8712e7ce7c..0000000000 --- a/source4/lib/registry/reg_backend_dir/reg_backend_dir.c +++ /dev/null @@ -1,148 +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 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "registry.h" -#include "system/dir.h" - -static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, uint32_t access_mask, SEC_DESC *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(struct registry_key *k) -{ - return (rmdir((char *)k->backend_data) == 0)?WERR_OK:WERR_GENERAL_FAILURE; -} - -static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **subkey) -{ - DIR *d; - char *fullpath; - 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", h->location, name); - fullpath = reg_path_win2unix(fullpath); - - d = opendir(fullpath); - if(!d) { - DEBUG(3,("Unable to open '%s': %s\n", fullpath, strerror(errno))); - return WERR_BADFILE; - } - closedir(d); - ret = talloc_p(mem_ctx, struct registry_key); - ret->hive = h; - ret->path = fullpath; - *subkey = ret; - return WERR_OK; -} - -static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, 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( strcmp(e->d_name, ".") && - strcmp(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)) { - i++; - if(i == idx) { - (*key) = talloc_p(mem_ctx, struct registry_key); - (*key)->name = e->d_name; - (*key)->path = NULL; - (*key)->backend_data = talloc_strdup(mem_ctx, thispath); - SAFE_FREE(thispath); - closedir(d); - return WERR_OK; - } - } - - SAFE_FREE(thispath); - } - } - - closedir(d); - - return WERR_NO_MORE_ITEMS; -} - -static WERROR reg_dir_open(TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **key) -{ - if(!h->location) return WERR_INVALID_PARAM; - - *key = talloc_p(mem_ctx, struct registry_key); - (*key)->backend_data = talloc_strdup(mem_ctx, h->location); - return WERR_OK; -} - -static WERROR reg_dir_set_value(struct registry_key *p, const char *name, int type, void *data, int len) -{ - /* FIXME */ - return WERR_NOT_SUPPORTED; -} - -static WERROR reg_dir_del_value(struct registry_value *v) -{ - /* FIXME*/ - return WERR_NOT_SUPPORTED; -} - -static struct registry_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, - .set_value = reg_dir_set_value, - .del_value = reg_dir_del_value, -}; - -NTSTATUS registry_dir_init(void) -{ - return registry_register(®_backend_dir); -} diff --git a/source4/lib/registry/reg_backend_gconf.c b/source4/lib/registry/reg_backend_gconf.c new file mode 100644 index 0000000000..2fed2417b7 --- /dev/null +++ b/source4/lib/registry/reg_backend_gconf.c @@ -0,0 +1,193 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "registry.h" +#include + +static WERROR gerror_to_werror(GError *error) +{ + if(error == NULL) return WERR_OK; + /* FIXME */ + return WERR_FOOBAR; +} + +static WERROR reg_open_gconf_hive(struct registry_hive *h, struct registry_key **k) +{ + g_type_init(); + h->backend_data = (void *)gconf_client_get_default(); + if(!h->backend_data) return WERR_FOOBAR; + + *k = talloc_p(h, struct registry_key); + (*k)->name = talloc_strdup(*k, ""); + (*k)->path = talloc_strdup(*k, ""); + (*k)->backend_data = talloc_strdup(*k, "/"); + return WERR_OK; +} + +static WERROR gconf_open_key (TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **key) +{ + struct registry_key *ret; + char *fullpath; + + fullpath = talloc_asprintf(mem_ctx, "/%s", reg_path_win2unix(talloc_strdup(mem_ctx, name))); + + /* Check if key exists */ + if(!gconf_client_dir_exists((GConfClient *)h->backend_data, fullpath, NULL)) { + return WERR_DEST_NOT_FOUND; + } + + ret = talloc_p(mem_ctx, struct registry_key); + ret->backend_data = fullpath; + + *key = ret; + return WERR_OK; +} + +static WERROR gconf_get_value_by_id(TALLOC_CTX *mem_ctx, struct registry_key *p, int idx, struct registry_value **val) +{ + GSList *entries; + GSList *cur; + GConfEntry *entry; + GConfValue *value; + struct registry_value *newval; + char *fullpath = p->backend_data; + int i; + cur = entries = gconf_client_all_entries((GConfClient*)p->hive->backend_data, fullpath, NULL); + + for(i = 0; i < idx && cur; i++) cur = cur->next; + + if(!cur) return WERR_NO_MORE_ITEMS; + + entry = cur->data; + value = gconf_entry_get_value(entry); + + newval = talloc_p(mem_ctx, struct registry_value); + newval->name = talloc_strdup(mem_ctx, strrchr(gconf_entry_get_key(entry), '/')+1); + if(value) { + switch(value->type) { + case GCONF_VALUE_INVALID: + newval->data_type = REG_NONE; + break; + + case GCONF_VALUE_STRING: + newval->data_type = REG_SZ; + newval->data_blk = talloc_strdup(mem_ctx, gconf_value_get_string(value)); + newval->data_len = strlen(newval->data_blk); + break; + + case GCONF_VALUE_INT: + newval->data_type = REG_DWORD; + newval->data_blk = talloc_p(mem_ctx, long); + *((long *)newval->data_blk) = gconf_value_get_int(value); + newval->data_len = sizeof(long); + break; + + case GCONF_VALUE_FLOAT: + newval->data_blk = talloc_p(mem_ctx, double); + newval->data_type = REG_BINARY; + *((double *)newval->data_blk) = gconf_value_get_float(value); + newval->data_len = sizeof(double); + break; + + case GCONF_VALUE_BOOL: + newval->data_blk = talloc_p(mem_ctx, BOOL); + newval->data_type = REG_BINARY; + *((BOOL *)newval->data_blk) = gconf_value_get_bool(value); + newval->data_len = sizeof(BOOL); + break; + + default: + newval->data_type = REG_NONE; + DEBUG(0, ("Not implemented..\n")); + break; + } + } else newval->data_type = REG_NONE; + + g_slist_free(entries); + *val = newval; + return WERR_OK; +} + +static WERROR gconf_get_subkey_by_id(TALLOC_CTX *mem_ctx, struct registry_key *p, int idx, struct registry_key **sub) +{ + GSList *dirs; + GSList *cur; + int i; + char *fullpath = p->backend_data; + cur = dirs = gconf_client_all_dirs((GConfClient*)p->hive->backend_data, fullpath,NULL); + + for(i = 0; i < idx && cur; i++) cur = cur->next; + + if(!cur) return WERR_NO_MORE_ITEMS; + + *sub = talloc_p(mem_ctx, struct registry_key); + (*sub)->name = talloc_strdup(mem_ctx, strrchr((char *)cur->data, '/')+1); + (*sub)->backend_data = talloc_strdup(mem_ctx, cur->data); + + g_slist_free(dirs); + return WERR_OK; +} + +static WERROR gconf_set_value(struct registry_key *key, const char *valname, int type, void *data, int len) +{ + GError *error = NULL; + char *valpath; + asprintf(&valpath, "%s/%s", key->path, valname); + + switch(type) { + case REG_SZ: + case REG_EXPAND_SZ: + gconf_client_set_string((GConfClient *)key->hive->backend_data, valpath, data, &error); + SAFE_FREE(valpath); + return gerror_to_werror(error); + + case REG_DWORD: + gconf_client_set_int((GConfClient *)key->hive->backend_data, valpath, + *((int *)data), &error); + SAFE_FREE(valpath); + return gerror_to_werror(error); + default: + DEBUG(0, ("Unsupported type: %d\n", type)); + SAFE_FREE(valpath); + return WERR_NOT_SUPPORTED; + } + + return WERR_NOT_SUPPORTED; +} + +static struct hive_operations reg_backend_gconf = { + .name = "gconf", + .open_hive = reg_open_gconf_hive, + .open_key = gconf_open_key, + .get_subkey_by_index = gconf_get_subkey_by_id, + .get_value_by_index = gconf_get_value_by_id, + .set_value = gconf_set_value, + + /* Note: + * since GConf uses schemas for what keys and values are allowed, there + * is no way of 'emulating' add_key and del_key here. + */ +}; + +NTSTATUS registry_gconf_init(void) +{ + return registry_register(®_backend_gconf); +} diff --git a/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c b/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c deleted file mode 100644 index fd258ca285..0000000000 --- a/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c +++ /dev/null @@ -1,193 +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 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "registry.h" -#include - -static WERROR gerror_to_werror(GError *error) -{ - if(error == NULL) return WERR_OK; - /* FIXME */ - return WERR_FOOBAR; -} - -static WERROR reg_open_gconf_hive(TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **k) -{ - g_type_init(); - h->backend_data = (void *)gconf_client_get_default(); - if(!h->backend_data) return WERR_FOOBAR; - - *k = talloc_p(mem_ctx, struct registry_key); - (*k)->name = talloc_strdup(mem_ctx, ""); - (*k)->path = talloc_strdup(mem_ctx, ""); - (*k)->backend_data = talloc_strdup(mem_ctx, "/"); - return WERR_OK; -} - -static WERROR gconf_open_key (TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **key) -{ - struct registry_key *ret; - char *fullpath; - - fullpath = talloc_asprintf(mem_ctx, "/%s", reg_path_win2unix(talloc_strdup(mem_ctx, name))); - - /* Check if key exists */ - if(!gconf_client_dir_exists((GConfClient *)h->backend_data, fullpath, NULL)) { - return WERR_DEST_NOT_FOUND; - } - - ret = talloc_p(mem_ctx, struct registry_key); - ret->backend_data = fullpath; - - *key = ret; - return WERR_OK; -} - -static WERROR gconf_get_value_by_id(TALLOC_CTX *mem_ctx, struct registry_key *p, int idx, struct registry_value **val) -{ - GSList *entries; - GSList *cur; - GConfEntry *entry; - GConfValue *value; - struct registry_value *newval; - char *fullpath = p->backend_data; - int i; - cur = entries = gconf_client_all_entries((GConfClient*)p->hive->backend_data, fullpath, NULL); - - for(i = 0; i < idx && cur; i++) cur = cur->next; - - if(!cur) return WERR_NO_MORE_ITEMS; - - entry = cur->data; - value = gconf_entry_get_value(entry); - - newval = talloc_p(mem_ctx, struct registry_value); - newval->name = talloc_strdup(mem_ctx, strrchr(gconf_entry_get_key(entry), '/')+1); - if(value) { - switch(value->type) { - case GCONF_VALUE_INVALID: - newval->data_type = REG_NONE; - break; - - case GCONF_VALUE_STRING: - newval->data_type = REG_SZ; - newval->data_blk = talloc_strdup(mem_ctx, gconf_value_get_string(value)); - newval->data_len = strlen(newval->data_blk); - break; - - case GCONF_VALUE_INT: - newval->data_type = REG_DWORD; - newval->data_blk = talloc_p(mem_ctx, long); - *((long *)newval->data_blk) = gconf_value_get_int(value); - newval->data_len = sizeof(long); - break; - - case GCONF_VALUE_FLOAT: - newval->data_blk = talloc_p(mem_ctx, double); - newval->data_type = REG_BINARY; - *((double *)newval->data_blk) = gconf_value_get_float(value); - newval->data_len = sizeof(double); - break; - - case GCONF_VALUE_BOOL: - newval->data_blk = talloc_p(mem_ctx, BOOL); - newval->data_type = REG_BINARY; - *((BOOL *)newval->data_blk) = gconf_value_get_bool(value); - newval->data_len = sizeof(BOOL); - break; - - default: - newval->data_type = REG_NONE; - DEBUG(0, ("Not implemented..\n")); - break; - } - } else newval->data_type = REG_NONE; - - g_slist_free(entries); - *val = newval; - return WERR_OK; -} - -static WERROR gconf_get_subkey_by_id(TALLOC_CTX *mem_ctx, struct registry_key *p, int idx, struct registry_key **sub) -{ - GSList *dirs; - GSList *cur; - int i; - char *fullpath = p->backend_data; - cur = dirs = gconf_client_all_dirs((GConfClient*)p->hive->backend_data, fullpath,NULL); - - for(i = 0; i < idx && cur; i++) cur = cur->next; - - if(!cur) return WERR_NO_MORE_ITEMS; - - *sub = talloc_p(mem_ctx, struct registry_key); - (*sub)->name = talloc_strdup(mem_ctx, strrchr((char *)cur->data, '/')+1); - (*sub)->backend_data = talloc_strdup(mem_ctx, cur->data); - - g_slist_free(dirs); - return WERR_OK; -} - -static WERROR gconf_set_value(struct registry_key *key, const char *valname, int type, void *data, int len) -{ - GError *error = NULL; - char *valpath; - asprintf(&valpath, "%s/%s", key->path, valname); - - switch(type) { - case REG_SZ: - case REG_EXPAND_SZ: - gconf_client_set_string((GConfClient *)key->hive->backend_data, valpath, data, &error); - SAFE_FREE(valpath); - return gerror_to_werror(error); - - case REG_DWORD: - gconf_client_set_int((GConfClient *)key->hive->backend_data, valpath, - *((int *)data), &error); - SAFE_FREE(valpath); - return gerror_to_werror(error); - default: - DEBUG(0, ("Unsupported type: %d\n", type)); - SAFE_FREE(valpath); - return WERR_NOT_SUPPORTED; - } - - return WERR_NOT_SUPPORTED; -} - -static struct registry_operations reg_backend_gconf = { - .name = "gconf", - .open_hive = reg_open_gconf_hive, - .open_key = gconf_open_key, - .get_subkey_by_index = gconf_get_subkey_by_id, - .get_value_by_index = gconf_get_value_by_id, - .set_value = gconf_set_value, - - /* Note: - * since GConf uses schemas for what keys and values are allowed, there - * is no way of 'emulating' add_key and del_key here. - */ -}; - -NTSTATUS registry_gconf_init(void) -{ - return registry_register(®_backend_gconf); -} diff --git a/source4/lib/registry/reg_backend_ldb.c b/source4/lib/registry/reg_backend_ldb.c new file mode 100644 index 0000000000..7eaf6194a5 --- /dev/null +++ b/source4/lib/registry/reg_backend_ldb.c @@ -0,0 +1,219 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "registry.h" +#include "lib/ldb/include/ldb.h" + +static char *reg_path_to_ldb(TALLOC_CTX *mem_ctx, const char *path, const char *add) +{ + char *ret = talloc_strdup(mem_ctx, ""); + char *mypath = strdup(path); + char *end = mypath, *begin; + + if(add) + ret = talloc_asprintf_append(ret, "%s", add); + + while(end) { + char *keyname; + begin = strrchr(end, '\\'); + + if(begin) keyname = begin + 1; + else keyname = mypath; + + if(strlen(keyname)) + ret = talloc_asprintf_append(ret, "key=%s,", keyname); + + if(begin) { + *begin = '\0'; + end = begin-1; + } else { + end = NULL; + } + } + + SAFE_FREE(mypath); + + ret[strlen(ret)-1] = '\0'; + + if(strlen(ret) == 0) return NULL; + + return ret; +} + + +static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx, struct registry_key *k, int idx, struct registry_key **subkey) +{ + struct ldb_context *c = k->hive->backend_data; + int ret; + struct ldb_message **msg; + struct ldb_message_element *el; + + ret = ldb_search(c, (char *)k->backend_data, LDB_SCOPE_ONELEVEL, "(key=*)", NULL,&msg); + + if(ret < 0) { + DEBUG(0, ("Error getting subkeys for '%s': %s\n", (char *)k->backend_data, ldb_errstring(c))); + return WERR_FOOBAR; + } + + if(idx >= ret) return WERR_NO_MORE_ITEMS; + + el = ldb_msg_find_element(msg[idx], "key"); + + *subkey = talloc_p(mem_ctx, struct registry_key); + (*subkey)->name = talloc_strdup(mem_ctx, el->values[0].data); + (*subkey)->backend_data = talloc_strdup(mem_ctx, msg[idx]->dn); + + ldb_search_free(c, msg); + return WERR_OK; +} + +static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, struct registry_key *k, int idx, struct registry_value **value) +{ + struct ldb_context *c = k->hive->backend_data; + int ret; + struct ldb_message **msg; + struct ldb_message_element *el; + + ret = ldb_search(c, (char *)k->backend_data, LDB_SCOPE_ONELEVEL, "(value=*)", NULL,&msg); + + if(ret < 0) { + DEBUG(0, ("Error getting values for '%s': %s\n", (char *)k->backend_data, ldb_errstring(c))); + return WERR_FOOBAR; + } + + if(idx >= ret) return WERR_NO_MORE_ITEMS; + + el = ldb_msg_find_element(msg[idx], "value"); + + *value = talloc_p(mem_ctx, struct registry_value); + (*value)->name = talloc_strdup(mem_ctx, el->values[0].data); + (*value)->backend_data = talloc_strdup(mem_ctx, msg[idx]->dn); + + ldb_search_free(c, msg); + return WERR_OK; +} + +static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **key) +{ + struct ldb_context *c = h->backend_data; + struct ldb_message **msg; + char *ldap_path; + int ret; + ldap_path = reg_path_to_ldb(mem_ctx, name, NULL); + + ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL,&msg); + + if(ret == 0) { + return WERR_NO_MORE_ITEMS; + } else if(ret < 0) { + DEBUG(0, ("Error opening key '%s': %s\n", ldap_path, ldb_errstring(c))); + return WERR_FOOBAR; + } + + *key = talloc_p(mem_ctx, struct registry_key); + (*key)->name = talloc_strdup(mem_ctx, strrchr(name, '\\')); + (*key)->backend_data = talloc_strdup(mem_ctx, msg[0]->dn); + + ldb_search_free(c, msg); + + return WERR_OK; +} + +static WERROR ldb_open_hive(struct registry_hive *hive, struct registry_key **k) +{ + struct ldb_context *c; + + if (!hive->location) return WERR_INVALID_PARAM; + c = ldb_connect(hive->location, 0, NULL); + + if(!c) { + DEBUG(1, ("ldb_open_hive: %s\n", ldb_errstring(hive->backend_data))); + return WERR_FOOBAR; + } + ldb_set_debug_stderr(c); + hive->backend_data = c; + + hive->root = talloc_zero_p(hive, struct registry_key); + hive->root->name = talloc_strdup(hive->root, ""); + + return WERR_OK; +} + +static WERROR ldb_add_key (TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, uint32_t access_mask, SEC_DESC *sd, struct registry_key **newkey) +{ + struct ldb_context *ctx = parent->hive->backend_data; + struct ldb_message msg; + int ret; + + ZERO_STRUCT(msg); + + msg.dn = reg_path_to_ldb(mem_ctx, parent->path, talloc_asprintf(mem_ctx, "key=%s,", name)); + + ldb_msg_add_string(ctx, &msg, "key", talloc_strdup(mem_ctx, name)); + + ret = ldb_add(ctx, &msg); + if (ret < 0) { + DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(parent->hive->backend_data))); + return WERR_FOOBAR; + } + + *newkey = talloc_zero_p(mem_ctx, struct registry_key); + (*newkey)->backend_data = msg.dn; + (*newkey)->name = talloc_strdup(mem_ctx, name); + + return WERR_OK; +} + +static WERROR ldb_del_key (struct registry_key *key) +{ + int ret; + + ret = ldb_delete(key->hive->backend_data, key->backend_data); + + if (ret < 0) { + DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(key->hive->backend_data))); + return WERR_FOOBAR; + } + + return WERR_OK; +} + +static WERROR ldb_close_hive (struct registry_hive *hive) +{ + ldb_close (hive->backend_data); + 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, + .close_hive = ldb_close_hive, + .open_key = ldb_open_key, + .get_value_by_index = ldb_get_value_by_id, + .get_subkey_by_index = ldb_get_subkey_by_id, +}; + +NTSTATUS registry_ldb_init(void) +{ + return registry_register(®_backend_ldb); +} diff --git a/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c b/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c deleted file mode 100644 index 380a8010f2..0000000000 --- a/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c +++ /dev/null @@ -1,219 +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 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "registry.h" -#include "lib/ldb/include/ldb.h" - -static char *reg_path_to_ldb(TALLOC_CTX *mem_ctx, const char *path, const char *add) -{ - char *ret = talloc_strdup(mem_ctx, ""); - char *mypath = strdup(path); - char *end = mypath, *begin; - - if(add) - ret = talloc_asprintf_append(ret, "%s", add); - - while(end) { - char *keyname; - begin = strrchr(end, '\\'); - - if(begin) keyname = begin + 1; - else keyname = mypath; - - if(strlen(keyname)) - ret = talloc_asprintf_append(ret, "key=%s,", keyname); - - if(begin) { - *begin = '\0'; - end = begin-1; - } else { - end = NULL; - } - } - - SAFE_FREE(mypath); - - ret[strlen(ret)-1] = '\0'; - - if(strlen(ret) == 0) return NULL; - - return ret; -} - - -static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx, struct registry_key *k, int idx, struct registry_key **subkey) -{ - struct ldb_context *c = k->hive->backend_data; - int ret; - struct ldb_message **msg; - struct ldb_message_element *el; - - ret = ldb_search(c, (char *)k->backend_data, LDB_SCOPE_ONELEVEL, "(key=*)", NULL,&msg); - - if(ret < 0) { - DEBUG(0, ("Error getting subkeys for '%s': %s\n", (char *)k->backend_data, ldb_errstring(c))); - return WERR_FOOBAR; - } - - if(idx >= ret) return WERR_NO_MORE_ITEMS; - - el = ldb_msg_find_element(msg[idx], "key"); - - *subkey = talloc_p(mem_ctx, struct registry_key); - (*subkey)->name = talloc_strdup(mem_ctx, el->values[0].data); - (*subkey)->backend_data = talloc_strdup(mem_ctx, msg[idx]->dn); - - ldb_search_free(c, msg); - return WERR_OK; -} - -static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, struct registry_key *k, int idx, struct registry_value **value) -{ - struct ldb_context *c = k->hive->backend_data; - int ret; - struct ldb_message **msg; - struct ldb_message_element *el; - - ret = ldb_search(c, (char *)k->backend_data, LDB_SCOPE_ONELEVEL, "(value=*)", NULL,&msg); - - if(ret < 0) { - DEBUG(0, ("Error getting values for '%s': %s\n", (char *)k->backend_data, ldb_errstring(c))); - return WERR_FOOBAR; - } - - if(idx >= ret) return WERR_NO_MORE_ITEMS; - - el = ldb_msg_find_element(msg[idx], "value"); - - *value = talloc_p(mem_ctx, struct registry_value); - (*value)->name = talloc_strdup(mem_ctx, el->values[0].data); - (*value)->backend_data = talloc_strdup(mem_ctx, msg[idx]->dn); - - ldb_search_free(c, msg); - return WERR_OK; -} - -static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **key) -{ - struct ldb_context *c = h->backend_data; - struct ldb_message **msg; - char *ldap_path; - int ret; - ldap_path = reg_path_to_ldb(mem_ctx, name, NULL); - - ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL,&msg); - - if(ret == 0) { - return WERR_NO_MORE_ITEMS; - } else if(ret < 0) { - DEBUG(0, ("Error opening key '%s': %s\n", ldap_path, ldb_errstring(c))); - return WERR_FOOBAR; - } - - *key = talloc_p(mem_ctx, struct registry_key); - (*key)->name = talloc_strdup(mem_ctx, strrchr(name, '\\')); - (*key)->backend_data = talloc_strdup(mem_ctx, msg[0]->dn); - - ldb_search_free(c, msg); - - return WERR_OK; -} - -static WERROR ldb_open_hive(TALLOC_CTX *mem_ctx, struct registry_hive *hive, struct registry_key **k) -{ - struct ldb_context *c; - - if (!hive->location) return WERR_INVALID_PARAM; - c = ldb_connect(hive->location, 0, NULL); - - if(!c) { - DEBUG(1, ("ldb_open_hive: %s\n", ldb_errstring(hive->backend_data))); - return WERR_FOOBAR; - } - ldb_set_debug_stderr(c); - hive->backend_data = c; - - hive->root = talloc_zero_p(mem_ctx, struct registry_key); - hive->root->name = talloc_strdup(mem_ctx, ""); - - return WERR_OK; -} - -static WERROR ldb_add_key (TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, uint32_t access_mask, SEC_DESC *sd, struct registry_key **newkey) -{ - struct ldb_context *ctx = parent->hive->backend_data; - struct ldb_message msg; - int ret; - - ZERO_STRUCT(msg); - - msg.dn = reg_path_to_ldb(mem_ctx, parent->path, talloc_asprintf(mem_ctx, "key=%s,", name)); - - ldb_msg_add_string(ctx, &msg, "key", talloc_strdup(mem_ctx, name)); - - ret = ldb_add(ctx, &msg); - if (ret < 0) { - DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(parent->hive->backend_data))); - return WERR_FOOBAR; - } - - *newkey = talloc_zero_p(mem_ctx, struct registry_key); - (*newkey)->backend_data = msg.dn; - (*newkey)->name = talloc_strdup(mem_ctx, name); - - return WERR_OK; -} - -static WERROR ldb_del_key (struct registry_key *key) -{ - int ret; - - ret = ldb_delete(key->hive->backend_data, key->backend_data); - - if (ret < 0) { - DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(key->hive->backend_data))); - return WERR_FOOBAR; - } - - return WERR_OK; -} - -static WERROR ldb_close_hive (struct registry_hive *hive) -{ - ldb_close (hive->backend_data); - return WERR_OK; -} - -static struct registry_operations reg_backend_ldb = { - .name = "ldb", - .add_key = ldb_add_key, - .del_key = ldb_del_key, - .open_hive = ldb_open_hive, - .close_hive = ldb_close_hive, - .open_key = ldb_open_key, - .get_value_by_index = ldb_get_value_by_id, - .get_subkey_by_index = ldb_get_subkey_by_id, -}; - -NTSTATUS registry_ldb_init(void) -{ - return registry_register(®_backend_ldb); -} diff --git a/source4/lib/registry/reg_backend_nt4.c b/source4/lib/registry/reg_backend_nt4.c new file mode 100644 index 0000000000..117d8d1b81 --- /dev/null +++ b/source4/lib/registry/reg_backend_nt4.c @@ -0,0 +1,1747 @@ +/* + Samba Unix/Linux SMB client utility libeditreg.c + Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com + Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/************************************************************************* + + A utility to edit a Windows NT/2K etc registry file. + + Many of the ideas in here come from other people and software. + I first looked in Wine in misc/registry.c and was also influenced by + http://www.wednesday.demon.co.uk/dosreg.html + + Which seems to contain comments from someone else. I reproduce them here + incase the site above disappears. It actually comes from + http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt. + + The goal here is to read the registry into memory, manipulate it, and then + write it out if it was changed by any actions of the user. + +The windows NT registry has 2 different blocks, where one can occur many +times... + +the "regf"-Block +================ + +"regf" is obviously the abbreviation for "Registry file". "regf" is the +signature of the header-block which is always 4kb in size, although only +the first 64 bytes seem to be used and a checksum is calculated over +the first 0x200 bytes only! + +Offset Size Contents +0x00000000 D-Word ID: ASCII-"regf" = 0x66676572 +0x00000004 D-Word ???? //see struct REG_HANDLE +0x00000008 D-Word ???? Always the same value as at 0x00000004 +0x0000000C Q-Word last modify date in WinNT date-format +0x00000014 D-Word 1 +0x00000018 D-Word 3 +0x0000001C D-Word 0 +0x00000020 D-Word 1 +0x00000024 D-Word Offset of 1st key record +0x00000028 D-Word Size of the data-blocks (Filesize-4kb) +0x0000002C D-Word 1 +0x000001FC D-Word Sum of all D-Words from 0x00000000 to +0x000001FB //XOR of all words. Nigel + +I have analyzed more registry files (from multiple machines running +NT 4.0 german version) and could not find an explanation for the values +marked with ???? the rest of the first 4kb page is not important... + +the "hbin"-Block +================ +I don't know what "hbin" stands for, but this block is always a multiple +of 4kb in size. + +Inside these hbin-blocks the different records are placed. The memory- +management looks like a C-compiler heap management to me... + +hbin-Header +=========== +Offset Size Contents +0x0000 D-Word ID: ASCII-"hbin" = 0x6E696268 +0x0004 D-Word Offset from the 1st hbin-Block +0x0008 D-Word Offset to the next hbin-Block +0x001C D-Word Block-size + +The values in 0x0008 and 0x001C should be the same, so I don't know +if they are correct or swapped... + +From offset 0x0020 inside a hbin-block data is stored with the following +format: + +Offset Size Contents +0x0000 D-Word Data-block size //this size must be a +multiple of 8. Nigel +0x0004 ???? Data + +If the size field is negative (bit 31 set), the corresponding block +is free and has a size of -blocksize! + +That does not seem to be true. All block lengths seem to be negative! +(Richard Sharpe) + +The data is stored as one record per block. Block size is a multiple +of 4 and the last block reaches the next hbin-block, leaving no room. + +(That also seems incorrect, in that the block size if a multiple of 8. +That is, the block, including the 4 byte header, is always a multiple of +8 bytes. Richard Sharpe.) + +Records in the hbin-blocks +========================== + +nk-Record + + The nk-record can be treated as a combination of tree-record and + key-record of the win 95 registry. + +lf-Record + + The lf-record is the counterpart to the RGKN-record (the + hash-function) + +vk-Record + + The vk-record consists information to a single value (value key). + +sk-Record + + sk (? Security Key ?) is the ACL of the registry. + +Value-Lists + + The value-lists contain information about which values are inside a + sub-key and don't have a header. + +Datas + + The datas of the registry are (like the value-list) stored without a + header. + +All offset-values are relative to the first hbin-block and point to the +block-size field of the record-entry. to get the file offset, you have to add +the header size (4kb) and the size field (4 bytes)... + +the nk-Record +============= +Offset Size Contents +0x0000 Word ID: ASCII-"nk" = 0x6B6E +0x0002 Word for the root-key: 0x2C, otherwise 0x20 //key symbolic links 0x10. Nigel +0x0004 Q-Word write-date/time in windows nt notation +0x0010 D-Word Offset of Owner/Parent key +0x0014 D-Word number of sub-Keys +0x001C D-Word Offset of the sub-key lf-Records +0x0024 D-Word number of values +0x0028 D-Word Offset of the Value-List +0x002C D-Word Offset of the sk-Record + +0x0030 D-Word Offset of the Class-Name //see NK structure for the use of these fields. Nigel +0x0044 D-Word Unused (data-trash) //some kind of run time index. Does not appear to be important. Nigel +0x0048 Word name-length +0x004A Word class-name length +0x004C ???? key-name + +the Value-List +============== +Offset Size Contents +0x0000 D-Word Offset 1st Value +0x0004 D-Word Offset 2nd Value +0x???? D-Word Offset nth Value + +To determine the number of values, you have to look at the owner-nk-record! + +The vk-Record +============= +Offset Size Contents +0x0000 Word ID: ASCII-"vk" = 0x6B76 +0x0002 Word name length +0x0004 D-Word length of the data //if top bit is set when offset contains data. Nigel +0x0008 D-Word Offset of Data +0x000C D-Word Type of value +0x0010 Word Flag +0x0012 Word Unused (data-trash) +0x0014 ???? Name + +If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default) + +If the data-size is lower 5, the data-offset value is used to store the data itself! + +The data-types +============== +Wert Beteutung +0x0001 RegSZ: character string (in UNICODE!) +0x0002 ExpandSZ: string with "%var%" expanding (UNICODE!) +0x0003 RegBin: raw-binary value +0x0004 RegDWord: Dword +0x0007 RegMultiSZ: multiple strings, seperated with 0 + (UNICODE!) + +The "lf"-record +=============== +Offset Size Contents +0x0000 Word ID: ASCII-"lf" = 0x666C +0x0002 Word number of keys +0x0004 ???? Hash-Records + +Hash-Record +=========== +Offset Size Contents +0x0000 D-Word Offset of corresponding "nk"-Record +0x0004 D-Word ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv! + +Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the +key-name you have to change the hash-value too! + +//These hashrecords must be sorted low to high within the lf record. Nigel. + +The "sk"-block +============== +(due to the complexity of the SAM-info, not clear jet) +(This is just a self-relative security descriptor in the data. R Sharpe.) + + +Offset Size Contents +0x0000 Word ID: ASCII-"sk" = 0x6B73 +0x0002 Word Unused +0x0004 D-Word Offset of previous "sk"-Record +0x0008 D-Word Offset of next "sk"-Record +0x000C D-Word usage-counter +0x0010 D-Word Size of "sk"-record in bytes +???? //standard self +relative security desciptor. Nigel +???? ???? Security and auditing settings... +???? + +The usage counter counts the number of references to this +"sk"-record. You can use one "sk"-record for the entire registry! + +Windows nt date/time format +=========================== +The time-format is a 64-bit integer which is incremented every +0,0000001 seconds by 1 (I don't know how accurate it realy is!) +It starts with 0 at the 1st of january 1601 0:00! All values are +stored in GMT time! The time-zone is important to get the real +time! + +Common values for win95 and win-nt +================================== +Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF). +If a value has no name (length=0, flag(bit 0)=0), it is treated as the +"Default" entry... +If a value has no data (length=0), it is displayed as empty. + +simplyfied win-3.?? registry: +============================= + ++-----------+ +| next rec. |---+ +----->+------------+ +| first sub | | | | Usage cnt. | +| name | | +-->+------------+ | | length | +| value | | | | next rec. | | | text |------->+-------+ ++-----------+ | | | name rec. |--+ +------------+ | xxxxx | + +------------+ | | value rec. |-------->+------------+ +-------+ + v | +------------+ | Usage cnt. | ++-----------+ | | length | +| next rec. | | | text |------->+-------+ +| first sub |------+ +------------+ | xxxxx | +| name | +-------+ +| value | ++-----------+ + +Greatly simplyfied structure of the nt-registry: +================================================ + ++---------------------------------------------------------------+ +| | +v | ++---------+ +---------->+-----------+ +----->+---------+ | +| "nk" | | | lf-rec. | | | nk-rec. | | +| ID | | | # of keys | | | parent |---+ +| Date | | | 1st key |--+ | .... | +| parent | | +-----------+ +---------+ +| suk-keys|-----+ +| values |--------------------->+----------+ +| SK-rec. |---------------+ | 1. value |--> +----------+ +| class |--+ | +----------+ | vk-rec. | ++---------+ | | | .... | + v | | data |--> +-------+ + +------------+ | +----------+ | xxxxx | + | Class name | | +-------+ + +------------+ | + v + +---------+ +---------+ + +----->| next sk |--->| Next sk |--+ + | +---| prev sk |<---| prev sk | | + | | | .... | | ... | | + | | +---------+ +---------+ | + | | ^ | + | | | | + | +--------------------+ | + +----------------------------------+ + +--------------------------------------------------------------------------- + +Hope this helps.... (Although it was "fun" for me to uncover this things, + it took me several sleepless nights ;) + + B.D. + +*************************************************************************/ + +#include "includes.h" +#include "registry.h" +#include "system/shmem.h" + +#define REG_KEY_LIST_SIZE 10 +#define FLAG_HAS_NAME 0x01 +/*FIXME*/ + +/* + * Structures for dealing with the on-disk format of the registry + */ + +const char *def_owner_sid_str = NULL; + +/* + * These definitions are for the in-memory registry structure. + * It is a tree structure that mimics what you see with tools like regedit + */ + + +/* + * Definition of a Key. It has a name, classname, date/time last modified, + * sub-keys, values, and a security descriptor + */ + +#define REG_ROOT_KEY 1 +#define REG_SUB_KEY 2 +#define REG_SYM_LINK 3 + +/* + * All of the structures below actually have a four-byte length before them + * which always seems to be negative. The following macro retrieves that + * size as an integer + */ + +#define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1)) + +typedef uint_t DWORD; +typedef unsigned short WORD; + +typedef struct sk_struct SK_HDR; +/* + * This structure keeps track of the output format of the registry + */ +#define REG_OUTBLK_HDR 1 +#define REG_OUTBLK_HBIN 2 + +typedef struct regf_block { + DWORD REGF_ID; /* regf */ + DWORD uk1; + DWORD uk2; + DWORD tim1, tim2; + DWORD uk3; /* 1 */ + DWORD uk4; /* 3 */ + DWORD uk5; /* 0 */ + DWORD uk6; /* 1 */ + DWORD first_key; /* offset */ + uint_t dblk_size; + DWORD uk7[116]; /* 1 */ + DWORD chksum; +} REGF_HDR; + +typedef struct hbin_sub_struct { + DWORD dblocksize; + char data[1]; +} HBIN_SUB_HDR; + +typedef struct hbin_struct { + DWORD HBIN_ID; /* hbin */ + DWORD off_from_first; + DWORD off_to_next; + DWORD uk1; + DWORD uk2; + DWORD uk3; + DWORD uk4; + DWORD blk_size; + HBIN_SUB_HDR hbin_sub_hdr; +} HBIN_HDR; + +typedef struct nk_struct { + WORD NK_ID; + WORD type; + DWORD t1, t2; + DWORD uk1; + DWORD own_off; + DWORD subk_num; + DWORD uk2; + DWORD lf_off; + DWORD uk3; + DWORD val_cnt; + DWORD val_off; + DWORD sk_off; + DWORD clsnam_off; + DWORD unk4[4]; + DWORD unk5; + WORD nam_len; + WORD clsnam_len; + char key_nam[1]; /* Actual length determined by nam_len */ +} NK_HDR; + +struct sk_struct { + WORD SK_ID; + WORD uk1; + DWORD prev_off; + DWORD next_off; + DWORD ref_cnt; + DWORD rec_size; + char sec_desc[1]; +}; + +typedef struct key_sec_desc_s { + struct key_sec_desc_s *prev, *next; + int ref_cnt; + int state; + int offset; + SK_HDR *sk_hdr; /* This means we must keep the registry in memory */ + SEC_DESC *sec_desc; +} KEY_SEC_DESC; + +/* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */ +typedef struct sk_map_s { + int sk_off; + KEY_SEC_DESC *key_sec_desc; +} SK_MAP; + +typedef struct vk_struct { + WORD VK_ID; + WORD nam_len; + DWORD dat_len; /* If top-bit set, offset contains the data */ + DWORD dat_off; + DWORD dat_type; + WORD flag; /* =1, has name, else no name (=Default). */ + WORD unk1; + char dat_name[1]; /* Name starts here ... */ +} VK_HDR; + +typedef DWORD VL_TYPE[1]; /* Value list is an array of vk rec offsets */ + +typedef struct hash_struct { + DWORD nk_off; + char hash[4]; +} HASH_REC; + + +typedef struct lf_struct { + WORD LF_ID; + WORD key_count; + struct hash_struct hr[1]; /* Array of hash records, depending on key_count */} LF_HDR; + + + +/* + * This structure keeps track of the output format of the registry + */ +#define REG_OUTBLK_HDR 1 +#define REG_OUTBLK_HBIN 2 + +typedef struct hbin_blk_s { + int type, size; + struct hbin_blk_s *next; + char *data; /* The data block */ + uint_t file_offset; /* Offset in file */ + uint_t free_space; /* Amount of free space in block */ + uint_t fsp_off; /* Start of free space in block */ + int complete, stored; +} HBIN_BLK; + +typedef struct regf_struct_s { + int reg_type; + int fd; + struct stat sbuf; + char *base; + BOOL modified; + NTTIME last_mod_time; + NK_HDR *first_key; + int sk_count, sk_map_size; + SK_MAP *sk_map; + const char *owner_sid_str; + SEC_DESC *def_sec_desc; + /* + * These next pointers point to the blocks used to contain the + * keys when we are preparing to write them to a file + */ + HBIN_BLK *blk_head, *blk_tail, *free_space; +} REGF; + +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 + +/* + * Create an ACE + */ +static BOOL nt_create_ace(SEC_ACE *ace, int type, int flags, uint32_t perms, const char *sid) +{ + DOM_SID s; + SEC_ACCESS access; + access.mask = perms; + if(!string_to_sid(&s, sid))return False; + init_sec_ace(ace, &s, type, access, flags); + return True; +} + +/* + * Create a default ACL + */ +static SEC_ACL *nt_create_default_acl(struct registry_hive *regf) +{ + SEC_ACE aces[8]; + + if(!nt_create_ace(&aces[0], 0x00, 0x0, 0xF003F, regf->owner_sid_str)) return NULL; + if(!nt_create_ace(&aces[1], 0x00, 0x0, 0xF003F, "S-1-5-18")) return NULL; + if(!nt_create_ace(&aces[2], 0x00, 0x0, 0xF003F, "S-1-5-32-544")) return NULL; + if(!nt_create_ace(&aces[3], 0x00, 0x0, 0x20019, "S-1-5-12")) return NULL; + if(!nt_create_ace(&aces[4], 0x00, 0x0B, GENERIC_RIGHT_ALL_ACCESS, regf->owner_sid_str)) return NULL; + if(!nt_create_ace(&aces[5], 0x00, 0x0B, 0x10000000, "S-1-5-18")) return NULL; + if(!nt_create_ace(&aces[6], 0x00, 0x0B, 0x10000000, "S-1-5-32-544")) return NULL; + if(!nt_create_ace(&aces[7], 0x00, 0x0B, 0x80000000, "S-1-5-12")) return NULL; + + return make_sec_acl(regf->mem_ctx, 2, 8, aces); +} + +/* + * Create a default security descriptor. We pull in things from env + * if need be + */ +static SEC_DESC *nt_create_def_sec_desc(struct registry_hive *regf) +{ + SEC_DESC *tmp; + + tmp = malloc_p(SEC_DESC); + + tmp->revision = 1; + tmp->type = SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT; + if (!string_to_sid(tmp->owner_sid, "S-1-5-32-544")) goto error; + if (!string_to_sid(tmp->grp_sid, "S-1-5-18")) goto error; + tmp->sacl = NULL; + tmp->dacl = nt_create_default_acl(regf); + + return tmp; + + error: + if (tmp) nt_delete_sec_desc(tmp); + return NULL; +} + +/* + * We will implement inheritence that is based on what the parent's SEC_DESC + * says, but the Owner and Group SIDs can be overwridden from the command line + * and additional ACEs can be applied from the command line etc. + */ +static KEY_SEC_DESC *nt_inherit_security(struct registry_key *key) +{ + + if (!key) return NULL; + return key->security; +} + +/* + * Create an initial security descriptor and init other structures, if needed + * We assume that the initial security stuff is empty ... + */ +static KEY_SEC_DESC *nt_create_init_sec(struct registry_hive *h) +{ + REGF *regf = h->backend_data; + KEY_SEC_DESC *tsec = NULL; + + tsec = malloc_p(KEY_SEC_DESC); + + tsec->ref_cnt = 1; + tsec->state = SEC_DESC_NBK; + tsec->offset = 0; + + tsec->sec_desc = regf->def_sec_desc; + + return tsec; +} +#endif + +/* + * Get the starting record for NT Registry file + */ + +/* + * Where we keep all the regf stuff for one registry. + * This is the structure that we use to tie the in memory tree etc + * together. By keeping separate structs, we can operate on different + * registries at the same time. + * Currently, the SK_MAP is an array of mapping structure. + * Since we only need this on input and output, we fill in the structure + * as we go on input. On output, we know how many SK items we have, so + * we can allocate the structure as we need to. + * If you add stuff here that is dynamically allocated, add the + * appropriate free statements below. + */ + +#define REG_HANDLE_REGTYPE_NONE 0 +#define REG_HANDLE_REGTYPE_NT 1 +#define REG_HANDLE_REGTYPE_W9X 2 + +#define TTTONTTIME(r, t1, t2) (r)->last_mod_time = (t1) | (((uint64_t)(t2)) << 32) + +#define REGF_HDR_BLKSIZ 0x1000 + +#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4) +#define LOCN(base, f) ((base) + OFF(f)) + +/* Get the header of the registry. Return a pointer to the structure + * If the mmap'd area has not been allocated, then mmap the input file + */ +static REGF_HDR *nt_get_regf_hdr(struct registry_hive *h) +{ + REGF *regf = h->backend_data; + SMB_REG_ASSERT(regf); + + if (!regf->base) { /* Try to mmap etc the file */ + + if ((regf->fd = open(h->location, O_RDONLY, 0000)) <0) { + return NULL; /* What about errors? */ + } + + if (fstat(regf->fd, ®f->sbuf) < 0) { + return NULL; + } + + regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0); + + if ((int)regf->base == 1) { + DEBUG(0,("Could not mmap file: %s, %s\n", h->location, + strerror(errno))); + return NULL; + } + } + + /* + * At this point, regf->base != NULL, and we should be able to read the + * header + */ + + SMB_REG_ASSERT(regf->base != NULL); + + return (REGF_HDR *)regf->base; +} + +/* + * Validate a regf header + * For now, do nothing, but we should check the checksum + */ +static int valid_regf_hdr(REGF_HDR *regf_hdr) +{ + if (!regf_hdr) return 0; + + return 1; +} + +#if 0 + +/* + * Process an SK header ... + * Every time we see a new one, add it to the map. Otherwise, just look it up. + * We will do a simple linear search for the moment, since many KEYs have the + * same security descriptor. + * We allocate the map in increments of 10 entries. + */ + +/* + * Create a new entry in the map, and increase the size of the map if needed + */ +static SK_MAP *alloc_sk_map_entry(struct registry_hive *h, KEY_SEC_DESC *tmp, int sk_off) +{ + REGF *regf = h->backend_data; + if (!regf->sk_map) { /* Allocate a block of 10 */ + regf->sk_map = malloc_array_p(SK_MAP, 10); + regf->sk_map_size = 10; + regf->sk_count = 1; + (regf->sk_map)[0].sk_off = sk_off; + (regf->sk_map)[0].key_sec_desc = tmp; + } + else { /* Simply allocate a new slot, unless we have to expand the list */ + int ndx = regf->sk_count; + if (regf->sk_count >= regf->sk_map_size) { + regf->sk_map = (SK_MAP *)realloc(regf->sk_map, + (regf->sk_map_size + 10)*sizeof(SK_MAP)); + if (!regf->sk_map) { + free(tmp); + return NULL; + } + /* + * ndx already points at the first entry of the new block + */ + regf->sk_map_size += 10; + } + (regf->sk_map)[ndx].sk_off = sk_off; + (regf->sk_map)[ndx].key_sec_desc = tmp; + regf->sk_count++; + } + return regf->sk_map; +} + +/* + * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not + * found + */ +KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off) +{ + int i; + + if (!sk_map) return NULL; + + for (i = 0; i < count; i++) { + + if (sk_map[i].sk_off == sk_off) + return sk_map[i].key_sec_desc; + + } + + return NULL; + +} + +/* + * Allocate a KEY_SEC_DESC if we can't find one in the map + */ +static KEY_SEC_DESC *lookup_create_sec_key(struct registry_hive *h, SK_MAP *sk_map, int sk_off) +{ + REGF *regf = h->backend_data; + KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off); + + if (tmp) { + return tmp; + } + else { /* Allocate a new one */ + tmp = malloc_p(KEY_SEC_DESC); + memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */ + tmp->state = SEC_DESC_RES; + if (!alloc_sk_map_entry(h, tmp, sk_off)) { + return NULL; + } + return tmp; + } +} + +static SEC_DESC *process_sec_desc(struct registry_hive *regf, SEC_DESC *sec_desc) +{ + SEC_DESC *tmp = NULL; + + tmp = malloc_p(SEC_DESC); + + tmp->revision = SVAL(&sec_desc->revision,0); + tmp->type = SVAL(&sec_desc->type,0); + DEBUG(2, ("SEC_DESC Rev: %0X, Type: %0X\n", tmp->revision, tmp->type)); + DEBUGADD(2, ("SEC_DESC Owner Off: %0X\n", IVAL(&sec_desc->off_owner_sid,0))); + DEBUGADD(2, ("SEC_DESC Group Off: %0X\n", IVAL(&sec_desc->off_grp_sid,0))); + DEBUGADD(2, ("SEC_DESC DACL Off: %0X\n", IVAL(&sec_desc->off_dacl,0))); + tmp->owner_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_owner_sid,0))); + if (!tmp->owner_sid) { + free(tmp); + return NULL; + } + tmp->grp_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_grp_sid,0))); + if (!tmp->grp_sid) { + free(tmp); + return NULL; + } + + /* Now pick up the SACL and DACL */ + + DEBUG(0, ("%d, %d\n", IVAL(&sec_desc->off_sacl,0), IVAL(&sec_desc->off_dacl,0))); + + if (sec_desc->off_sacl) + tmp->sacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_sacl,0))); + else + tmp->sacl = NULL; + + if (sec_desc->off_dacl) + tmp->dacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_dacl,0))); + else + tmp->dacl = NULL; + + return tmp; +} + +static KEY_SEC_DESC *process_sk(struct registry_hive *regf, SK_HDR *sk_hdr, int sk_off, int size) +{ + KEY_SEC_DESC *tmp = NULL; + int sk_next_off, sk_prev_off, sk_size; + SEC_DESC *sec_desc; + + if (!sk_hdr) return NULL; + + if (SVAL(&sk_hdr->SK_ID,0) != str_to_dword("sk")) { + DEBUG(0, ("Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr, + regf->regfile_name)); + return NULL; + } + + if (-size < (sk_size = IVAL(&sk_hdr->rec_size,0))) { + DEBUG(0, ("Incorrect SK record size: %d vs %d. %s\n", + -size, sk_size, regf->regfile_name)); + return NULL; + } + + /* + * Now, we need to look up the SK Record in the map, and return it + * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can + * use that + */ + + if (regf->sk_map && + ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL) + && (tmp->state == SEC_DESC_OCU)) { + tmp->ref_cnt++; + return tmp; + } + + /* Here, we have an item in the map that has been reserved, or tmp==NULL. */ + + SMB_REG_ASSERT(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON)); + + /* + * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the + * new KEY_SEC_DESC to the mapping structure, since the offset supplied is + * the actual offset of structure. The same offset will be used by + * all future references to this structure + * We could put all this unpleasantness in a function. + */ + + if (!tmp) { + tmp = malloc_p(KEY_SEC_DESC); + memset(tmp, 0, sizeof(KEY_SEC_DESC)); + + /* + * Allocate an entry in the SK_MAP ... + * We don't need to free tmp, because that is done for us if the + * sm_map entry can't be expanded when we need more space in the map. + */ + + if (!alloc_sk_map_entry(regf, tmp, sk_off)) { + return NULL; + } + } + + tmp->ref_cnt++; + tmp->state = SEC_DESC_OCU; + + /* + * Now, process the actual sec desc and plug the values in + */ + + sec_desc = (SEC_DESC *)&sk_hdr->sec_desc[0]; + tmp->sec_desc = process_sec_desc(regf, sec_desc); + + /* + * Now forward and back links. Here we allocate an entry in the sk_map + * if it does not exist, and mark it reserved + */ + + sk_prev_off = IVAL(&sk_hdr->prev_off,0); + tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off); + SMB_REG_ASSERT(tmp->prev != NULL); + sk_next_off = IVAL(&sk_hdr->next_off,0); + tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off); + SMB_REG_ASSERT(tmp->next != NULL); + + return tmp; +} +#endif + +/* + * Process a VK header and return a value + */ +static WERROR vk_to_val(TALLOC_CTX *mem_ctx, struct registry_key *parent, VK_HDR *vk_hdr, int size, struct registry_value **value) +{ + REGF *regf = parent->hive->backend_data; + int nam_len, dat_len, flag, dat_type, dat_off, vk_id; + struct registry_value *tmp = NULL; + + if (!vk_hdr) return WERR_INVALID_PARAM; + + if ((vk_id = SVAL(&vk_hdr->VK_ID,0)) != str_to_dword("vk")) { + DEBUG(0, ("Unrecognized VK header ID: %0X, block: %0X, %s\n", + vk_id, (int)vk_hdr, parent->hive->location)); + return WERR_GENERAL_FAILURE; + } + + nam_len = SVAL(&vk_hdr->nam_len,0); + flag = SVAL(&vk_hdr->flag,0); + dat_type = IVAL(&vk_hdr->dat_type,0); + dat_len = IVAL(&vk_hdr->dat_len,0); /* If top bit, offset contains data */ + dat_off = IVAL(&vk_hdr->dat_off,0); + + tmp = talloc_p(mem_ctx, struct registry_value); + tmp->data_type = dat_type; + + if (flag & FLAG_HAS_NAME) { + tmp->name = talloc_strndup(mem_ctx, vk_hdr->dat_name, nam_len); + } else { + tmp->name = NULL; + } + + /* + * Allocate space and copy the data as a BLOB + */ + + if (dat_len&0x7FFFFFFF) { + + char *dtmp = (char *)talloc(mem_ctx, dat_len&0x7FFFFFFF); + + if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */ + char *dat_ptr = LOCN(regf->base, dat_off); + memcpy(dtmp, dat_ptr, dat_len); + } + else { /* The data is in the offset or type */ + /* + * FIXME. + * Some registry files seem to have weird fields. If top bit is set, + * but len is 0, the type seems to be the value ... + * Not sure how to handle this last type for the moment ... + */ + dat_len = dat_len & 0x7FFFFFFF; + memcpy(dtmp, &dat_off, dat_len); + } + + + if(tmp->data_type == REG_SZ) { + char *ret; + dat_len = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, dtmp, dat_len, (void **)&ret); + dtmp = ret; + } + + + tmp->data_blk = dtmp; + tmp->data_len = dat_len; + } + + *value = tmp; + return WERR_OK; +} + +#if 0 /* unused */ + +static BOOL vl_verify(VL_TYPE vl, int count, int size) +{ + if(!vl) return False; + if (-size < (count+1)*sizeof(int)){ + DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size)); + return False; + } + return True; +} + +#endif + +static WERROR lf_verify(struct registry_hive *h, LF_HDR *lf_hdr, int size) +{ + int lf_id; + if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) { + DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n", + lf_id, (int)lf_hdr, h->location)); + return WERR_INVALID_PARAM; + } + return WERR_OK; +} + +static WERROR lf_num_entries(struct registry_hive *h, LF_HDR *lf_hdr, int size, int *count) +{ + WERROR error; + + error = lf_verify(h, lf_hdr, size); + if(!W_ERROR_IS_OK(error)) return error; + + SMB_REG_ASSERT(size < 0); + + *count = SVAL(&lf_hdr->key_count,0); + DEBUG(2, ("Key Count: %u\n", *count)); + if (*count <= 0) return WERR_INVALID_PARAM; + + return WERR_OK; +} + + +static WERROR nk_to_key(TALLOC_CTX *, struct registry_hive *regf, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **); + + + +/* + * Process an LF Header and return a list of sub-keys + */ +static WERROR lf_get_entry(TALLOC_CTX *mem_ctx, struct registry_key *parent, LF_HDR *lf_hdr, int size, int n, struct registry_key **key) +{ + REGF *regf = parent->hive->backend_data; + int count, nk_off; + NK_HDR *nk_hdr; + WERROR error; + + if (!lf_hdr) return WERR_INVALID_PARAM; + + error = lf_verify(parent->hive, lf_hdr, size); + if(!W_ERROR_IS_OK(error)) return error; + + SMB_REG_ASSERT(size < 0); + + count = SVAL(&lf_hdr->key_count,0); + DEBUG(2, ("Key Count: %u\n", count)); + if (count <= 0) return WERR_GENERAL_FAILURE; + if (n >= count) return WERR_NO_MORE_ITEMS; + + nk_off = IVAL(&lf_hdr->hr[n].nk_off,0); + DEBUG(2, ("NK Offset: %0X\n", nk_off)); + nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off); + return nk_to_key(mem_ctx, parent->hive, nk_hdr, BLK_SIZE(nk_hdr), parent, key); +} + +static WERROR nk_to_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **key) +{ + REGF *regf = h->backend_data; + struct registry_key *tmp = NULL, *own; + int namlen, clsname_len, sk_off, own_off; + uint_t nk_id; + SK_HDR *sk_hdr; + int type; + char key_name[1024]; + + if (!nk_hdr) return WERR_INVALID_PARAM; + + if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) { + DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n", + nk_id, (int)nk_hdr, parent->hive->location)); + return WERR_INVALID_PARAM; + } + + SMB_REG_ASSERT(size < 0); + + namlen = SVAL(&nk_hdr->nam_len,0); + clsname_len = SVAL(&nk_hdr->clsnam_len,0); + + /* + * The value of -size should be ge + * (sizeof(NK_HDR) - 1 + namlen) + * The -1 accounts for the fact that we included the first byte of + * the name in the structure. clsname_len is the length of the thing + * pointed to by clsnam_off + */ + + if (-size < (sizeof(NK_HDR) - 1 + namlen)) { + DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr)); + DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n", + sizeof(NK_HDR), namlen, clsname_len)); + return WERR_GENERAL_FAILURE; + } + + DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", namlen, clsname_len)); + + /* Fish out the key name and process the LF list */ + + SMB_REG_ASSERT(namlen < sizeof(key_name)); + + strncpy(key_name, nk_hdr->key_nam, namlen); + key_name[namlen] = '\0'; + + type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY); + if(type == REG_ROOT_KEY && parent) { + DEBUG(0,("Root key encountered below root level!\n")); + return WERR_GENERAL_FAILURE; + } + + tmp = talloc_p(mem_ctx, struct registry_key); + tmp->name = talloc_strdup(mem_ctx, key_name); + tmp->backend_data = nk_hdr; + + DEBUG(2, ("Key name: %s\n", key_name)); + + /* + * Fish out the class name, it is in UNICODE, while the key name is + * ASCII :-) + */ + + if (clsname_len) { /* Just print in Ascii for now */ + void *clsnamep; + int clsnam_off; + + clsnam_off = IVAL(&nk_hdr->clsnam_off,0); + clsnamep = LOCN(regf->base, clsnam_off); + DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off)); + + pull_ucs2_talloc(mem_ctx, &tmp->class_name, clsnamep); + + DEBUGADD(2,(" Class Name: %s\n", tmp->class_name)); + + } + + /* + * Process the owner offset ... + */ + + own_off = IVAL(&nk_hdr->own_off,0); + own = (struct registry_key *)LOCN(regf->base, own_off); + DEBUG(2, ("Owner Offset: %0X\n", own_off)); + + DEBUGADD(2, (" Owner locn: %0X, Our locn: %0X\n", + (uint_t)own, (uint_t)nk_hdr)); + + /* + * We should verify that the owner field is correct ... + * for now, we don't worry ... + */ + + /* + * Also handle the SK header ... + */ + + sk_off = IVAL(&nk_hdr->sk_off,0); + sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off); + DEBUG(2, ("SK Offset: %0X\n", sk_off)); + + if (sk_off != -1) { + +#if 0 + tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr)); +#endif + + } + + *key = tmp; + return WERR_OK; +} + +#if 0 /* unused */ + +/* + * Allocate a new hbin block, set up the header for the block etc + */ +static HBIN_BLK *nt_create_hbin_blk(struct registry_hive *h, int size) +{ + REGF *regf = h->backend_data; + HBIN_BLK *tmp; + HBIN_HDR *hdr; + + if (!regf || !size) return NULL; + + /* Round size up to multiple of REGF_HDR_BLKSIZ */ + + size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1); + + tmp = malloc_p(HBIN_BLK); + memset(tmp, 0, sizeof(HBIN_BLK)); + + tmp->data = malloc(size); + + memset(tmp->data, 0, size); /* Make it pristine */ + + tmp->size = size; + /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/ + + tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR)); + tmp->fsp_off = size - tmp->free_space; + + /* + * Now, build the header in the data block + */ + hdr = (HBIN_HDR *)tmp->data; + hdr->HBIN_ID = str_to_dword("hbin"); + hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ; + hdr->off_to_next = tmp->size; + hdr->blk_size = tmp->size; + + /* + * Now link it in + */ + + regf->blk_tail->next = tmp; + regf->blk_tail = tmp; + if (!regf->free_space) regf->free_space = tmp; + + return tmp; +} + +/* + * Allocate a unit of space ... and return a pointer as function param + * and the block's offset as a side effect + */ +static void *nt_alloc_regf_space(struct registry_hive *h, int size, uint_t *off) +{ + REGF *regf = h->backend_data; + int tmp = 0; + void *ret = NULL; + HBIN_BLK *blk; + + if (!regf || !size || !off) return NULL; + + SMB_REG_ASSERT(regf->blk_head != NULL); + + /* + * round up size to include header and then to 8-byte boundary + */ + size = (size + 4 + 7) & ~7; + + /* + * Check if there is space, if none, grab a block + */ + if (!regf->free_space) { + if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) + return NULL; + } + + /* + * Now, chain down the list of blocks looking for free space + */ + + for (blk = regf->free_space; blk != NULL; blk = blk->next) { + if (blk->free_space <= size) { + tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ; + ret = blk->data + blk->fsp_off; + blk->free_space -= size; + blk->fsp_off += size; + + /* Insert the header */ + ((HBIN_SUB_HDR *)ret)->dblocksize = -size; + + /* + * Fix up the free space ptr + * If it is NULL, we fix it up next time + */ + + if (!blk->free_space) + regf->free_space = blk->next; + + *off = tmp; + return (((char *)ret)+4);/* The pointer needs to be to the data struct */ + } + } + + /* + * If we got here, we need to add another block, which might be + * larger than one block -- deal with that later + */ + if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) { + blk = regf->free_space; + tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ; + ret = blk->data + blk->fsp_off; + blk->free_space -= size; + blk->fsp_off += size; + + /* Insert the header */ + ((HBIN_SUB_HDR *)ret)->dblocksize = -size; + + /* + * Fix up the free space ptr + * If it is NULL, we fix it up next time + */ + + if (!blk->free_space) + regf->free_space = blk->next; + + *off = tmp; + return (((char *)ret) + 4);/* The pointer needs to be to the data struct */ + } + + return NULL; +} + +/* + * Store a SID at the location provided + */ +static int nt_store_SID(struct registry_hive *regf, DOM_SID *sid, uint8_t *locn) +{ + int i; + uint8_t *p = locn; + + if (!regf || !sid || !locn) return 0; + + *p = sid->sid_rev_num; p++; + *p = sid->num_auths; p++; + + for (i=0; i < 6; i++) { + *p = sid->id_auth[i]; p++; + } + + for (i=0; i < sid->num_auths; i++) { + SIVAL(p, 0, sid->sub_auths[i]); p+=4; + } + + return p - locn; + +} + +static int nt_store_ace(struct registry_hive *regf, SEC_ACE *ace, uint8_t *locn) +{ + int size = 0; + SEC_ACE *reg_ace = (SEC_ACE *)locn; + uint8_t *p; + + if (!regf || !ace || !locn) return 0; + + reg_ace->type = ace->type; + reg_ace->flags = ace->flags; + + /* Deal with the length when we have stored the SID */ + + p = (uint8_t *)®_ace->info.mask; + + SIVAL(p, 0, ace->info.mask); p += 4; + + size = nt_store_SID(regf, &ace->trustee, p); + + size += 8; /* Size of the fixed header */ + + p = (uint8_t *)®_ace->size; + + SSVAL(p, 0, size); + + return size; +} + +/* + * Store an ACL at the location provided + */ +static int nt_store_acl(struct registry_hive *regf, SEC_ACL *acl, uint8_t *locn) { + int size = 0, i; + uint8_t *p = locn, *s; + + if (!regf || !acl || !locn) return 0; + + /* + * Now store the header and then the ACEs ... + */ + + SSVAL(p, 0, acl->revision); + + p += 2; s = p; /* Save this for the size field */ + + p += 2; + + SIVAL(p, 0, acl->num_aces); + + p += 4; + + for (i = 0; i < acl->num_aces; i++) { + size = nt_store_ace(regf, &acl->ace[i], p); + p += size; + } + + size = s - locn; + SSVAL(s, 0, size); + return size; +} + +/* + * Flatten and store the Sec Desc + * Windows lays out the DACL first, but since there is no SACL, it might be + * that first, then the owner, then the group SID. So, we do it that way + * too. + */ +static uint_t nt_store_sec_desc(struct registry_hive *regf, SEC_DESC *sd, char *locn) +{ + SEC_DESC *rsd = (SEC_DESC *)locn; + uint_t size = 0, off = 0; + + if (!regf || !sd || !locn) return 0; + + /* + * Now, fill in the first two fields, then lay out the various fields + * as needed + */ + + rsd->revision = SEC_DESC_REVISION; + rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE; + + off = 4 * sizeof(DWORD) + 4; + + if (sd->sacl){ + size = nt_store_acl(regf, sd->sacl, (char *)(locn + off)); + rsd->off_sacl = off; + } + else + rsd->off_sacl = 0; + + off += size; + + if (sd->dacl) { + rsd->off_dacl = off; + size = nt_store_acl(regf, sd->dacl, (char *)(locn + off)); + } + else { + rsd->off_dacl = 0; + } + + off += size; + + /* Now the owner and group SIDs */ + + if (sd->owner_sid) { + rsd->off_owner_sid = off; + size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off)); + } + else { + rsd->off_owner_sid = 0; + } + + off += size; + + if (sd->grp_sid) { + rsd->off_grp_sid = off; + size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off)); + } + else { + rsd->off_grp_sid = 0; + } + + off += size; + + return size; +} + +/* + * Store the security information + * + * If it has already been stored, just get its offset from record + * otherwise, store it and record its offset + */ +static uint_t nt_store_security(struct registry_hive *regf, KEY_SEC_DESC *sec) +{ + int size = 0; + uint_t sk_off; + SK_HDR *sk_hdr; + + if (sec->offset) return sec->offset; + + /* + * OK, we don't have this one in the file yet. We must compute the + * size taken by the security descriptor as a self-relative SD, which + * means making one pass over each structure and figuring it out + */ + +/* FIXME size = sec_desc_size(sec->sec_desc); */ + + /* Allocate that much space */ + + sk_hdr = nt_alloc_regf_space(regf, size, &sk_off); + sec->sk_hdr = sk_hdr; + + if (!sk_hdr) return 0; + + /* Now, lay out the sec_desc in the space provided */ + + sk_hdr->SK_ID = str_to_dword("sk"); + + /* + * We can't deal with the next and prev offset in the SK_HDRs until the + * whole tree has been stored, then we can go and deal with them + */ + + sk_hdr->ref_cnt = sec->ref_cnt; + sk_hdr->rec_size = size; /* Is this correct */ + + /* Now, lay out the sec_desc */ + + if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc)) + return 0; + + return sk_off; + +} + +/* + * Store a KEY in the file ... + * + * We store this depth first, and defer storing the lf struct until + * all the sub-keys have been stored. + * + * We store the NK hdr, any SK header, class name, and VK structure, then + * recurse down the LF structures ... + * + * We return the offset of the NK struct + * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ... + */ +static int nt_store_reg_key(struct registry_hive *regf, struct registry_key *key) +{ + NK_HDR *nk_hdr; + uint_t nk_off, sk_off, size; + + if (!regf || !key) return 0; + + size = sizeof(NK_HDR) + strlen(key->name) - 1; + nk_hdr = nt_alloc_regf_space(regf, size, &nk_off); + if (!nk_hdr) goto error; + + key->offset = nk_off; /* We will need this later */ + + /* + * Now fill in each field etc ... + */ + + nk_hdr->NK_ID = str_to_dword("nk"); + if (key->type == REG_ROOT_KEY) + nk_hdr->type = 0x2C; + else + nk_hdr->type = 0x20; + + /* FIXME: Fill in the time of last update */ + + if (key->type != REG_ROOT_KEY) + nk_hdr->own_off = key->owner->offset; + + if (key->sub_keys) + nk_hdr->subk_num = key->sub_keys->key_count; + + /* + * Now, process the Sec Desc and then store its offset + */ + + sk_off = nt_store_security(regf, key->security); + nk_hdr->sk_off = sk_off; + + /* + * Then, store the val list and store its offset + */ + if (key->values) { + nk_hdr->val_cnt = key->values->val_count; + nk_hdr->val_off = nt_store_val_list(regf, key->values); + } + else { + nk_hdr->val_off = -1; + nk_hdr->val_cnt = 0; + } + + /* + * Finally, store the subkeys, and their offsets + */ + +error: + return 0; +} + +/* + * Store the registry header ... + * We actually create the registry header block and link it to the chain + * of output blocks. + */ +static REGF_HDR *nt_get_reg_header(struct registry_hive *h) { + REGF *regf = h->backend_data; + HBIN_BLK *tmp = NULL; + + tmp = malloc_p(HBIN_BLK); + + memset(tmp, 0, sizeof(HBIN_BLK)); + tmp->type = REG_OUTBLK_HDR; + tmp->size = REGF_HDR_BLKSIZ; + tmp->data = malloc(REGF_HDR_BLKSIZ); + if (!tmp->data) goto error; + + memset(tmp->data, 0, REGF_HDR_BLKSIZ); /* Make it pristine, unlike Windows */ + regf->blk_head = regf->blk_tail = tmp; + + return (REGF_HDR *)tmp->data; + +error: + if (tmp) free(tmp); + return NULL; +} + +#endif + +static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key) +{ + REGF *regf; + REGF_HDR *regf_hdr; + uint_t regf_id, hbin_id; + HBIN_HDR *hbin_hdr; + + regf = (REGF *)talloc_p(h, REGF); + memset(regf, 0, sizeof(REGF)); + regf->owner_sid_str = NULL; /* FIXME: Fill in */ + h->backend_data = regf; + + DEBUG(5, ("Attempting to load registry file\n")); + + /* Get the header */ + + if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) { + DEBUG(0, ("Unable to get header\n")); + return WERR_GENERAL_FAILURE; + } + + /* Now process that header and start to read the rest in */ + + if ((regf_id = IVAL(®f_hdr->REGF_ID,0)) != str_to_dword("regf")) { + DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n", + regf_id, h->location)); + return WERR_GENERAL_FAILURE; + } + + /* + * Validate the header ... + */ + if (!valid_regf_hdr(regf_hdr)) { + DEBUG(0, ("Registry file header does not validate: %s\n", + h->location)); + return WERR_GENERAL_FAILURE; + } + + /* Update the last mod date, and then go get the first NK record and on */ + + TTTONTTIME(regf, IVAL(®f_hdr->tim1,0), IVAL(®f_hdr->tim2,0)); + + /* + * The hbin hdr seems to be just uninteresting garbage. Check that + * it is there, but that is all. + */ + + hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ); + + if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) { + DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", + hbin_id, h->location)); + return WERR_GENERAL_FAILURE; + } + + /* + * Get a pointer to the first key from the hreg_hdr + */ + + DEBUG(2, ("First Key: %0X\n", + IVAL(®f_hdr->first_key, 0))); + + regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(®f_hdr->first_key,0)); + DEBUGADD(2, ("First Key Offset: %0X\n", + IVAL(®f_hdr->first_key, 0))); + + DEBUGADD(2, ("Data Block Size: %d\n", + IVAL(®f_hdr->dblk_size, 0))); + + DEBUGADD(2, ("Offset to next hbin block: %0X\n", + IVAL(&hbin_hdr->off_to_next, 0))); + + DEBUGADD(2, ("HBIN block size: %0X\n", + IVAL(&hbin_hdr->blk_size, 0))); + + /* + * Unmap the registry file, as we might want to read in another + * tree etc. + */ + + h->backend_data = regf; + + return nk_to_key(h, h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key); +} + + +static WERROR nt_num_subkeys(struct registry_key *k, int *num) +{ + REGF *regf = k->hive->backend_data; + LF_HDR *lf_hdr; + int lf_off; + NK_HDR *nk_hdr = k->backend_data; + lf_off = IVAL(&nk_hdr->lf_off,0); + DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); + if(lf_off == -1) { + *num = 0; + return WERR_OK; + } + lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); + + return lf_num_entries(k->hive, lf_hdr, BLK_SIZE(lf_hdr), num); +} + +static WERROR nt_num_values(struct registry_key *k, int *count) +{ + NK_HDR *nk_hdr = k->backend_data; + *count = IVAL(&nk_hdr->val_cnt,0); + return WERR_OK; +} + +static WERROR nt_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_value **value) +{ + VL_TYPE *vl; + int val_off, vk_off; + int val_count; + VK_HDR *vk_hdr; + REGF *regf = k->hive->backend_data; + NK_HDR *nk_hdr = k->backend_data; + val_count = IVAL(&nk_hdr->val_cnt,0); + val_off = IVAL(&nk_hdr->val_off,0); + vl = (VL_TYPE *)LOCN(regf->base, val_off); + DEBUG(2, ("Val List Offset: %0X\n", val_off)); + if(n < 0) return WERR_INVALID_PARAM; + if(n >= val_count) return WERR_NO_MORE_ITEMS; + + vk_off = IVAL(&vl[n],0); + vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off); + return vk_to_val(mem_ctx, k, vk_hdr, BLK_SIZE(vk_hdr), value); +} + +static WERROR nt_key_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_key **subkey) +{ + REGF *regf = k->hive->backend_data; + int lf_off; + NK_HDR *nk_hdr = k->backend_data; + LF_HDR *lf_hdr; + lf_off = IVAL(&nk_hdr->lf_off,0); + DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); + + /* + * No more subkeys if lf_off == -1 + */ + + if (lf_off != -1) { + lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); + return lf_get_entry(mem_ctx, k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey); + } + + return WERR_NO_MORE_ITEMS; +} + +static struct hive_operations reg_backend_nt4 = { + .name = "nt4", + .open_hive = nt_open_hive, + .num_subkeys = nt_num_subkeys, + .num_values = nt_num_values, + .get_subkey_by_index = nt_key_by_index, + .get_value_by_index = nt_value_by_index, + + /* TODO: + .add_key + .add_value + .del_key + .del_value + .update_value + */ +}; + +NTSTATUS registry_nt4_init(void) +{ + return registry_register(®_backend_nt4); +} diff --git a/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c b/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c deleted file mode 100644 index 381f0c3bcf..0000000000 --- a/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c +++ /dev/null @@ -1,1747 +0,0 @@ -/* - Samba Unix/Linux SMB client utility libeditreg.c - Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com - Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/************************************************************************* - - A utility to edit a Windows NT/2K etc registry file. - - Many of the ideas in here come from other people and software. - I first looked in Wine in misc/registry.c and was also influenced by - http://www.wednesday.demon.co.uk/dosreg.html - - Which seems to contain comments from someone else. I reproduce them here - incase the site above disappears. It actually comes from - http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt. - - The goal here is to read the registry into memory, manipulate it, and then - write it out if it was changed by any actions of the user. - -The windows NT registry has 2 different blocks, where one can occur many -times... - -the "regf"-Block -================ - -"regf" is obviously the abbreviation for "Registry file". "regf" is the -signature of the header-block which is always 4kb in size, although only -the first 64 bytes seem to be used and a checksum is calculated over -the first 0x200 bytes only! - -Offset Size Contents -0x00000000 D-Word ID: ASCII-"regf" = 0x66676572 -0x00000004 D-Word ???? //see struct REG_HANDLE -0x00000008 D-Word ???? Always the same value as at 0x00000004 -0x0000000C Q-Word last modify date in WinNT date-format -0x00000014 D-Word 1 -0x00000018 D-Word 3 -0x0000001C D-Word 0 -0x00000020 D-Word 1 -0x00000024 D-Word Offset of 1st key record -0x00000028 D-Word Size of the data-blocks (Filesize-4kb) -0x0000002C D-Word 1 -0x000001FC D-Word Sum of all D-Words from 0x00000000 to -0x000001FB //XOR of all words. Nigel - -I have analyzed more registry files (from multiple machines running -NT 4.0 german version) and could not find an explanation for the values -marked with ???? the rest of the first 4kb page is not important... - -the "hbin"-Block -================ -I don't know what "hbin" stands for, but this block is always a multiple -of 4kb in size. - -Inside these hbin-blocks the different records are placed. The memory- -management looks like a C-compiler heap management to me... - -hbin-Header -=========== -Offset Size Contents -0x0000 D-Word ID: ASCII-"hbin" = 0x6E696268 -0x0004 D-Word Offset from the 1st hbin-Block -0x0008 D-Word Offset to the next hbin-Block -0x001C D-Word Block-size - -The values in 0x0008 and 0x001C should be the same, so I don't know -if they are correct or swapped... - -From offset 0x0020 inside a hbin-block data is stored with the following -format: - -Offset Size Contents -0x0000 D-Word Data-block size //this size must be a -multiple of 8. Nigel -0x0004 ???? Data - -If the size field is negative (bit 31 set), the corresponding block -is free and has a size of -blocksize! - -That does not seem to be true. All block lengths seem to be negative! -(Richard Sharpe) - -The data is stored as one record per block. Block size is a multiple -of 4 and the last block reaches the next hbin-block, leaving no room. - -(That also seems incorrect, in that the block size if a multiple of 8. -That is, the block, including the 4 byte header, is always a multiple of -8 bytes. Richard Sharpe.) - -Records in the hbin-blocks -========================== - -nk-Record - - The nk-record can be treated as a combination of tree-record and - key-record of the win 95 registry. - -lf-Record - - The lf-record is the counterpart to the RGKN-record (the - hash-function) - -vk-Record - - The vk-record consists information to a single value (value key). - -sk-Record - - sk (? Security Key ?) is the ACL of the registry. - -Value-Lists - - The value-lists contain information about which values are inside a - sub-key and don't have a header. - -Datas - - The datas of the registry are (like the value-list) stored without a - header. - -All offset-values are relative to the first hbin-block and point to the -block-size field of the record-entry. to get the file offset, you have to add -the header size (4kb) and the size field (4 bytes)... - -the nk-Record -============= -Offset Size Contents -0x0000 Word ID: ASCII-"nk" = 0x6B6E -0x0002 Word for the root-key: 0x2C, otherwise 0x20 //key symbolic links 0x10. Nigel -0x0004 Q-Word write-date/time in windows nt notation -0x0010 D-Word Offset of Owner/Parent key -0x0014 D-Word number of sub-Keys -0x001C D-Word Offset of the sub-key lf-Records -0x0024 D-Word number of values -0x0028 D-Word Offset of the Value-List -0x002C D-Word Offset of the sk-Record - -0x0030 D-Word Offset of the Class-Name //see NK structure for the use of these fields. Nigel -0x0044 D-Word Unused (data-trash) //some kind of run time index. Does not appear to be important. Nigel -0x0048 Word name-length -0x004A Word class-name length -0x004C ???? key-name - -the Value-List -============== -Offset Size Contents -0x0000 D-Word Offset 1st Value -0x0004 D-Word Offset 2nd Value -0x???? D-Word Offset nth Value - -To determine the number of values, you have to look at the owner-nk-record! - -The vk-Record -============= -Offset Size Contents -0x0000 Word ID: ASCII-"vk" = 0x6B76 -0x0002 Word name length -0x0004 D-Word length of the data //if top bit is set when offset contains data. Nigel -0x0008 D-Word Offset of Data -0x000C D-Word Type of value -0x0010 Word Flag -0x0012 Word Unused (data-trash) -0x0014 ???? Name - -If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default) - -If the data-size is lower 5, the data-offset value is used to store the data itself! - -The data-types -============== -Wert Beteutung -0x0001 RegSZ: character string (in UNICODE!) -0x0002 ExpandSZ: string with "%var%" expanding (UNICODE!) -0x0003 RegBin: raw-binary value -0x0004 RegDWord: Dword -0x0007 RegMultiSZ: multiple strings, seperated with 0 - (UNICODE!) - -The "lf"-record -=============== -Offset Size Contents -0x0000 Word ID: ASCII-"lf" = 0x666C -0x0002 Word number of keys -0x0004 ???? Hash-Records - -Hash-Record -=========== -Offset Size Contents -0x0000 D-Word Offset of corresponding "nk"-Record -0x0004 D-Word ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv! - -Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the -key-name you have to change the hash-value too! - -//These hashrecords must be sorted low to high within the lf record. Nigel. - -The "sk"-block -============== -(due to the complexity of the SAM-info, not clear jet) -(This is just a self-relative security descriptor in the data. R Sharpe.) - - -Offset Size Contents -0x0000 Word ID: ASCII-"sk" = 0x6B73 -0x0002 Word Unused -0x0004 D-Word Offset of previous "sk"-Record -0x0008 D-Word Offset of next "sk"-Record -0x000C D-Word usage-counter -0x0010 D-Word Size of "sk"-record in bytes -???? //standard self -relative security desciptor. Nigel -???? ???? Security and auditing settings... -???? - -The usage counter counts the number of references to this -"sk"-record. You can use one "sk"-record for the entire registry! - -Windows nt date/time format -=========================== -The time-format is a 64-bit integer which is incremented every -0,0000001 seconds by 1 (I don't know how accurate it realy is!) -It starts with 0 at the 1st of january 1601 0:00! All values are -stored in GMT time! The time-zone is important to get the real -time! - -Common values for win95 and win-nt -================================== -Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF). -If a value has no name (length=0, flag(bit 0)=0), it is treated as the -"Default" entry... -If a value has no data (length=0), it is displayed as empty. - -simplyfied win-3.?? registry: -============================= - -+-----------+ -| next rec. |---+ +----->+------------+ -| first sub | | | | Usage cnt. | -| name | | +-->+------------+ | | length | -| value | | | | next rec. | | | text |------->+-------+ -+-----------+ | | | name rec. |--+ +------------+ | xxxxx | - +------------+ | | value rec. |-------->+------------+ +-------+ - v | +------------+ | Usage cnt. | -+-----------+ | | length | -| next rec. | | | text |------->+-------+ -| first sub |------+ +------------+ | xxxxx | -| name | +-------+ -| value | -+-----------+ - -Greatly simplyfied structure of the nt-registry: -================================================ - -+---------------------------------------------------------------+ -| | -v | -+---------+ +---------->+-----------+ +----->+---------+ | -| "nk" | | | lf-rec. | | | nk-rec. | | -| ID | | | # of keys | | | parent |---+ -| Date | | | 1st key |--+ | .... | -| parent | | +-----------+ +---------+ -| suk-keys|-----+ -| values |--------------------->+----------+ -| SK-rec. |---------------+ | 1. value |--> +----------+ -| class |--+ | +----------+ | vk-rec. | -+---------+ | | | .... | - v | | data |--> +-------+ - +------------+ | +----------+ | xxxxx | - | Class name | | +-------+ - +------------+ | - v - +---------+ +---------+ - +----->| next sk |--->| Next sk |--+ - | +---| prev sk |<---| prev sk | | - | | | .... | | ... | | - | | +---------+ +---------+ | - | | ^ | - | | | | - | +--------------------+ | - +----------------------------------+ - ---------------------------------------------------------------------------- - -Hope this helps.... (Although it was "fun" for me to uncover this things, - it took me several sleepless nights ;) - - B.D. - -*************************************************************************/ - -#include "includes.h" -#include "registry.h" -#include "system/shmem.h" - -#define REG_KEY_LIST_SIZE 10 -#define FLAG_HAS_NAME 0x01 -/*FIXME*/ - -/* - * Structures for dealing with the on-disk format of the registry - */ - -const char *def_owner_sid_str = NULL; - -/* - * These definitions are for the in-memory registry structure. - * It is a tree structure that mimics what you see with tools like regedit - */ - - -/* - * Definition of a Key. It has a name, classname, date/time last modified, - * sub-keys, values, and a security descriptor - */ - -#define REG_ROOT_KEY 1 -#define REG_SUB_KEY 2 -#define REG_SYM_LINK 3 - -/* - * All of the structures below actually have a four-byte length before them - * which always seems to be negative. The following macro retrieves that - * size as an integer - */ - -#define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1)) - -typedef uint_t DWORD; -typedef unsigned short WORD; - -typedef struct sk_struct SK_HDR; -/* - * This structure keeps track of the output format of the registry - */ -#define REG_OUTBLK_HDR 1 -#define REG_OUTBLK_HBIN 2 - -typedef struct regf_block { - DWORD REGF_ID; /* regf */ - DWORD uk1; - DWORD uk2; - DWORD tim1, tim2; - DWORD uk3; /* 1 */ - DWORD uk4; /* 3 */ - DWORD uk5; /* 0 */ - DWORD uk6; /* 1 */ - DWORD first_key; /* offset */ - uint_t dblk_size; - DWORD uk7[116]; /* 1 */ - DWORD chksum; -} REGF_HDR; - -typedef struct hbin_sub_struct { - DWORD dblocksize; - char data[1]; -} HBIN_SUB_HDR; - -typedef struct hbin_struct { - DWORD HBIN_ID; /* hbin */ - DWORD off_from_first; - DWORD off_to_next; - DWORD uk1; - DWORD uk2; - DWORD uk3; - DWORD uk4; - DWORD blk_size; - HBIN_SUB_HDR hbin_sub_hdr; -} HBIN_HDR; - -typedef struct nk_struct { - WORD NK_ID; - WORD type; - DWORD t1, t2; - DWORD uk1; - DWORD own_off; - DWORD subk_num; - DWORD uk2; - DWORD lf_off; - DWORD uk3; - DWORD val_cnt; - DWORD val_off; - DWORD sk_off; - DWORD clsnam_off; - DWORD unk4[4]; - DWORD unk5; - WORD nam_len; - WORD clsnam_len; - char key_nam[1]; /* Actual length determined by nam_len */ -} NK_HDR; - -struct sk_struct { - WORD SK_ID; - WORD uk1; - DWORD prev_off; - DWORD next_off; - DWORD ref_cnt; - DWORD rec_size; - char sec_desc[1]; -}; - -typedef struct key_sec_desc_s { - struct key_sec_desc_s *prev, *next; - int ref_cnt; - int state; - int offset; - SK_HDR *sk_hdr; /* This means we must keep the registry in memory */ - SEC_DESC *sec_desc; -} KEY_SEC_DESC; - -/* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */ -typedef struct sk_map_s { - int sk_off; - KEY_SEC_DESC *key_sec_desc; -} SK_MAP; - -typedef struct vk_struct { - WORD VK_ID; - WORD nam_len; - DWORD dat_len; /* If top-bit set, offset contains the data */ - DWORD dat_off; - DWORD dat_type; - WORD flag; /* =1, has name, else no name (=Default). */ - WORD unk1; - char dat_name[1]; /* Name starts here ... */ -} VK_HDR; - -typedef DWORD VL_TYPE[1]; /* Value list is an array of vk rec offsets */ - -typedef struct hash_struct { - DWORD nk_off; - char hash[4]; -} HASH_REC; - - -typedef struct lf_struct { - WORD LF_ID; - WORD key_count; - struct hash_struct hr[1]; /* Array of hash records, depending on key_count */} LF_HDR; - - - -/* - * This structure keeps track of the output format of the registry - */ -#define REG_OUTBLK_HDR 1 -#define REG_OUTBLK_HBIN 2 - -typedef struct hbin_blk_s { - int type, size; - struct hbin_blk_s *next; - char *data; /* The data block */ - uint_t file_offset; /* Offset in file */ - uint_t free_space; /* Amount of free space in block */ - uint_t fsp_off; /* Start of free space in block */ - int complete, stored; -} HBIN_BLK; - -typedef struct regf_struct_s { - int reg_type; - int fd; - struct stat sbuf; - char *base; - BOOL modified; - NTTIME last_mod_time; - NK_HDR *first_key; - int sk_count, sk_map_size; - SK_MAP *sk_map; - const char *owner_sid_str; - SEC_DESC *def_sec_desc; - /* - * These next pointers point to the blocks used to contain the - * keys when we are preparing to write them to a file - */ - HBIN_BLK *blk_head, *blk_tail, *free_space; -} REGF; - -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 - -/* - * Create an ACE - */ -static BOOL nt_create_ace(SEC_ACE *ace, int type, int flags, uint32_t perms, const char *sid) -{ - DOM_SID s; - SEC_ACCESS access; - access.mask = perms; - if(!string_to_sid(&s, sid))return False; - init_sec_ace(ace, &s, type, access, flags); - return True; -} - -/* - * Create a default ACL - */ -static SEC_ACL *nt_create_default_acl(struct registry_hive *regf) -{ - SEC_ACE aces[8]; - - if(!nt_create_ace(&aces[0], 0x00, 0x0, 0xF003F, regf->owner_sid_str)) return NULL; - if(!nt_create_ace(&aces[1], 0x00, 0x0, 0xF003F, "S-1-5-18")) return NULL; - if(!nt_create_ace(&aces[2], 0x00, 0x0, 0xF003F, "S-1-5-32-544")) return NULL; - if(!nt_create_ace(&aces[3], 0x00, 0x0, 0x20019, "S-1-5-12")) return NULL; - if(!nt_create_ace(&aces[4], 0x00, 0x0B, GENERIC_RIGHT_ALL_ACCESS, regf->owner_sid_str)) return NULL; - if(!nt_create_ace(&aces[5], 0x00, 0x0B, 0x10000000, "S-1-5-18")) return NULL; - if(!nt_create_ace(&aces[6], 0x00, 0x0B, 0x10000000, "S-1-5-32-544")) return NULL; - if(!nt_create_ace(&aces[7], 0x00, 0x0B, 0x80000000, "S-1-5-12")) return NULL; - - return make_sec_acl(regf->mem_ctx, 2, 8, aces); -} - -/* - * Create a default security descriptor. We pull in things from env - * if need be - */ -static SEC_DESC *nt_create_def_sec_desc(struct registry_hive *regf) -{ - SEC_DESC *tmp; - - tmp = malloc_p(SEC_DESC); - - tmp->revision = 1; - tmp->type = SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT; - if (!string_to_sid(tmp->owner_sid, "S-1-5-32-544")) goto error; - if (!string_to_sid(tmp->grp_sid, "S-1-5-18")) goto error; - tmp->sacl = NULL; - tmp->dacl = nt_create_default_acl(regf); - - return tmp; - - error: - if (tmp) nt_delete_sec_desc(tmp); - return NULL; -} - -/* - * We will implement inheritence that is based on what the parent's SEC_DESC - * says, but the Owner and Group SIDs can be overwridden from the command line - * and additional ACEs can be applied from the command line etc. - */ -static KEY_SEC_DESC *nt_inherit_security(struct registry_key *key) -{ - - if (!key) return NULL; - return key->security; -} - -/* - * Create an initial security descriptor and init other structures, if needed - * We assume that the initial security stuff is empty ... - */ -static KEY_SEC_DESC *nt_create_init_sec(struct registry_hive *h) -{ - REGF *regf = h->backend_data; - KEY_SEC_DESC *tsec = NULL; - - tsec = malloc_p(KEY_SEC_DESC); - - tsec->ref_cnt = 1; - tsec->state = SEC_DESC_NBK; - tsec->offset = 0; - - tsec->sec_desc = regf->def_sec_desc; - - return tsec; -} -#endif - -/* - * Get the starting record for NT Registry file - */ - -/* - * Where we keep all the regf stuff for one registry. - * This is the structure that we use to tie the in memory tree etc - * together. By keeping separate structs, we can operate on different - * registries at the same time. - * Currently, the SK_MAP is an array of mapping structure. - * Since we only need this on input and output, we fill in the structure - * as we go on input. On output, we know how many SK items we have, so - * we can allocate the structure as we need to. - * If you add stuff here that is dynamically allocated, add the - * appropriate free statements below. - */ - -#define REG_HANDLE_REGTYPE_NONE 0 -#define REG_HANDLE_REGTYPE_NT 1 -#define REG_HANDLE_REGTYPE_W9X 2 - -#define TTTONTTIME(r, t1, t2) (r)->last_mod_time = (t1) | (((uint64_t)(t2)) << 32) - -#define REGF_HDR_BLKSIZ 0x1000 - -#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4) -#define LOCN(base, f) ((base) + OFF(f)) - -/* Get the header of the registry. Return a pointer to the structure - * If the mmap'd area has not been allocated, then mmap the input file - */ -static REGF_HDR *nt_get_regf_hdr(struct registry_hive *h) -{ - REGF *regf = h->backend_data; - SMB_REG_ASSERT(regf); - - if (!regf->base) { /* Try to mmap etc the file */ - - if ((regf->fd = open(h->location, O_RDONLY, 0000)) <0) { - return NULL; /* What about errors? */ - } - - if (fstat(regf->fd, ®f->sbuf) < 0) { - return NULL; - } - - regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0); - - if ((int)regf->base == 1) { - DEBUG(0,("Could not mmap file: %s, %s\n", h->location, - strerror(errno))); - return NULL; - } - } - - /* - * At this point, regf->base != NULL, and we should be able to read the - * header - */ - - SMB_REG_ASSERT(regf->base != NULL); - - return (REGF_HDR *)regf->base; -} - -/* - * Validate a regf header - * For now, do nothing, but we should check the checksum - */ -static int valid_regf_hdr(REGF_HDR *regf_hdr) -{ - if (!regf_hdr) return 0; - - return 1; -} - -#if 0 - -/* - * Process an SK header ... - * Every time we see a new one, add it to the map. Otherwise, just look it up. - * We will do a simple linear search for the moment, since many KEYs have the - * same security descriptor. - * We allocate the map in increments of 10 entries. - */ - -/* - * Create a new entry in the map, and increase the size of the map if needed - */ -static SK_MAP *alloc_sk_map_entry(struct registry_hive *h, KEY_SEC_DESC *tmp, int sk_off) -{ - REGF *regf = h->backend_data; - if (!regf->sk_map) { /* Allocate a block of 10 */ - regf->sk_map = malloc_array_p(SK_MAP, 10); - regf->sk_map_size = 10; - regf->sk_count = 1; - (regf->sk_map)[0].sk_off = sk_off; - (regf->sk_map)[0].key_sec_desc = tmp; - } - else { /* Simply allocate a new slot, unless we have to expand the list */ - int ndx = regf->sk_count; - if (regf->sk_count >= regf->sk_map_size) { - regf->sk_map = (SK_MAP *)realloc(regf->sk_map, - (regf->sk_map_size + 10)*sizeof(SK_MAP)); - if (!regf->sk_map) { - free(tmp); - return NULL; - } - /* - * ndx already points at the first entry of the new block - */ - regf->sk_map_size += 10; - } - (regf->sk_map)[ndx].sk_off = sk_off; - (regf->sk_map)[ndx].key_sec_desc = tmp; - regf->sk_count++; - } - return regf->sk_map; -} - -/* - * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not - * found - */ -KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off) -{ - int i; - - if (!sk_map) return NULL; - - for (i = 0; i < count; i++) { - - if (sk_map[i].sk_off == sk_off) - return sk_map[i].key_sec_desc; - - } - - return NULL; - -} - -/* - * Allocate a KEY_SEC_DESC if we can't find one in the map - */ -static KEY_SEC_DESC *lookup_create_sec_key(struct registry_hive *h, SK_MAP *sk_map, int sk_off) -{ - REGF *regf = h->backend_data; - KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off); - - if (tmp) { - return tmp; - } - else { /* Allocate a new one */ - tmp = malloc_p(KEY_SEC_DESC); - memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */ - tmp->state = SEC_DESC_RES; - if (!alloc_sk_map_entry(h, tmp, sk_off)) { - return NULL; - } - return tmp; - } -} - -static SEC_DESC *process_sec_desc(struct registry_hive *regf, SEC_DESC *sec_desc) -{ - SEC_DESC *tmp = NULL; - - tmp = malloc_p(SEC_DESC); - - tmp->revision = SVAL(&sec_desc->revision,0); - tmp->type = SVAL(&sec_desc->type,0); - DEBUG(2, ("SEC_DESC Rev: %0X, Type: %0X\n", tmp->revision, tmp->type)); - DEBUGADD(2, ("SEC_DESC Owner Off: %0X\n", IVAL(&sec_desc->off_owner_sid,0))); - DEBUGADD(2, ("SEC_DESC Group Off: %0X\n", IVAL(&sec_desc->off_grp_sid,0))); - DEBUGADD(2, ("SEC_DESC DACL Off: %0X\n", IVAL(&sec_desc->off_dacl,0))); - tmp->owner_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_owner_sid,0))); - if (!tmp->owner_sid) { - free(tmp); - return NULL; - } - tmp->grp_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_grp_sid,0))); - if (!tmp->grp_sid) { - free(tmp); - return NULL; - } - - /* Now pick up the SACL and DACL */ - - DEBUG(0, ("%d, %d\n", IVAL(&sec_desc->off_sacl,0), IVAL(&sec_desc->off_dacl,0))); - - if (sec_desc->off_sacl) - tmp->sacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_sacl,0))); - else - tmp->sacl = NULL; - - if (sec_desc->off_dacl) - tmp->dacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_dacl,0))); - else - tmp->dacl = NULL; - - return tmp; -} - -static KEY_SEC_DESC *process_sk(struct registry_hive *regf, SK_HDR *sk_hdr, int sk_off, int size) -{ - KEY_SEC_DESC *tmp = NULL; - int sk_next_off, sk_prev_off, sk_size; - SEC_DESC *sec_desc; - - if (!sk_hdr) return NULL; - - if (SVAL(&sk_hdr->SK_ID,0) != str_to_dword("sk")) { - DEBUG(0, ("Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr, - regf->regfile_name)); - return NULL; - } - - if (-size < (sk_size = IVAL(&sk_hdr->rec_size,0))) { - DEBUG(0, ("Incorrect SK record size: %d vs %d. %s\n", - -size, sk_size, regf->regfile_name)); - return NULL; - } - - /* - * Now, we need to look up the SK Record in the map, and return it - * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can - * use that - */ - - if (regf->sk_map && - ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL) - && (tmp->state == SEC_DESC_OCU)) { - tmp->ref_cnt++; - return tmp; - } - - /* Here, we have an item in the map that has been reserved, or tmp==NULL. */ - - SMB_REG_ASSERT(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON)); - - /* - * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the - * new KEY_SEC_DESC to the mapping structure, since the offset supplied is - * the actual offset of structure. The same offset will be used by - * all future references to this structure - * We could put all this unpleasantness in a function. - */ - - if (!tmp) { - tmp = malloc_p(KEY_SEC_DESC); - memset(tmp, 0, sizeof(KEY_SEC_DESC)); - - /* - * Allocate an entry in the SK_MAP ... - * We don't need to free tmp, because that is done for us if the - * sm_map entry can't be expanded when we need more space in the map. - */ - - if (!alloc_sk_map_entry(regf, tmp, sk_off)) { - return NULL; - } - } - - tmp->ref_cnt++; - tmp->state = SEC_DESC_OCU; - - /* - * Now, process the actual sec desc and plug the values in - */ - - sec_desc = (SEC_DESC *)&sk_hdr->sec_desc[0]; - tmp->sec_desc = process_sec_desc(regf, sec_desc); - - /* - * Now forward and back links. Here we allocate an entry in the sk_map - * if it does not exist, and mark it reserved - */ - - sk_prev_off = IVAL(&sk_hdr->prev_off,0); - tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off); - SMB_REG_ASSERT(tmp->prev != NULL); - sk_next_off = IVAL(&sk_hdr->next_off,0); - tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off); - SMB_REG_ASSERT(tmp->next != NULL); - - return tmp; -} -#endif - -/* - * Process a VK header and return a value - */ -static WERROR vk_to_val(TALLOC_CTX *mem_ctx, struct registry_key *parent, VK_HDR *vk_hdr, int size, struct registry_value **value) -{ - REGF *regf = parent->hive->backend_data; - int nam_len, dat_len, flag, dat_type, dat_off, vk_id; - struct registry_value *tmp = NULL; - - if (!vk_hdr) return WERR_INVALID_PARAM; - - if ((vk_id = SVAL(&vk_hdr->VK_ID,0)) != str_to_dword("vk")) { - DEBUG(0, ("Unrecognized VK header ID: %0X, block: %0X, %s\n", - vk_id, (int)vk_hdr, parent->hive->location)); - return WERR_GENERAL_FAILURE; - } - - nam_len = SVAL(&vk_hdr->nam_len,0); - flag = SVAL(&vk_hdr->flag,0); - dat_type = IVAL(&vk_hdr->dat_type,0); - dat_len = IVAL(&vk_hdr->dat_len,0); /* If top bit, offset contains data */ - dat_off = IVAL(&vk_hdr->dat_off,0); - - tmp = talloc_p(mem_ctx, struct registry_value); - tmp->data_type = dat_type; - - if (flag & FLAG_HAS_NAME) { - tmp->name = talloc_strndup(mem_ctx, vk_hdr->dat_name, nam_len); - } else { - tmp->name = NULL; - } - - /* - * Allocate space and copy the data as a BLOB - */ - - if (dat_len&0x7FFFFFFF) { - - char *dtmp = (char *)talloc(mem_ctx, dat_len&0x7FFFFFFF); - - if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */ - char *dat_ptr = LOCN(regf->base, dat_off); - memcpy(dtmp, dat_ptr, dat_len); - } - else { /* The data is in the offset or type */ - /* - * FIXME. - * Some registry files seem to have weird fields. If top bit is set, - * but len is 0, the type seems to be the value ... - * Not sure how to handle this last type for the moment ... - */ - dat_len = dat_len & 0x7FFFFFFF; - memcpy(dtmp, &dat_off, dat_len); - } - - - if(tmp->data_type == REG_SZ) { - char *ret; - dat_len = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, dtmp, dat_len, (void **)&ret); - dtmp = ret; - } - - - tmp->data_blk = dtmp; - tmp->data_len = dat_len; - } - - *value = tmp; - return WERR_OK; -} - -#if 0 /* unused */ - -static BOOL vl_verify(VL_TYPE vl, int count, int size) -{ - if(!vl) return False; - if (-size < (count+1)*sizeof(int)){ - DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size)); - return False; - } - return True; -} - -#endif - -static WERROR lf_verify(struct registry_hive *h, LF_HDR *lf_hdr, int size) -{ - int lf_id; - if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) { - DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n", - lf_id, (int)lf_hdr, h->location)); - return WERR_INVALID_PARAM; - } - return WERR_OK; -} - -static WERROR lf_num_entries(struct registry_hive *h, LF_HDR *lf_hdr, int size, int *count) -{ - WERROR error; - - error = lf_verify(h, lf_hdr, size); - if(!W_ERROR_IS_OK(error)) return error; - - SMB_REG_ASSERT(size < 0); - - *count = SVAL(&lf_hdr->key_count,0); - DEBUG(2, ("Key Count: %u\n", *count)); - if (*count <= 0) return WERR_INVALID_PARAM; - - return WERR_OK; -} - - -static WERROR nk_to_key(TALLOC_CTX *, struct registry_hive *regf, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **); - - - -/* - * Process an LF Header and return a list of sub-keys - */ -static WERROR lf_get_entry(TALLOC_CTX *mem_ctx, struct registry_key *parent, LF_HDR *lf_hdr, int size, int n, struct registry_key **key) -{ - REGF *regf = parent->hive->backend_data; - int count, nk_off; - NK_HDR *nk_hdr; - WERROR error; - - if (!lf_hdr) return WERR_INVALID_PARAM; - - error = lf_verify(parent->hive, lf_hdr, size); - if(!W_ERROR_IS_OK(error)) return error; - - SMB_REG_ASSERT(size < 0); - - count = SVAL(&lf_hdr->key_count,0); - DEBUG(2, ("Key Count: %u\n", count)); - if (count <= 0) return WERR_GENERAL_FAILURE; - if (n >= count) return WERR_NO_MORE_ITEMS; - - nk_off = IVAL(&lf_hdr->hr[n].nk_off,0); - DEBUG(2, ("NK Offset: %0X\n", nk_off)); - nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off); - return nk_to_key(mem_ctx, parent->hive, nk_hdr, BLK_SIZE(nk_hdr), parent, key); -} - -static WERROR nk_to_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, NK_HDR *nk_hdr, int size, struct registry_key *parent, struct registry_key **key) -{ - REGF *regf = h->backend_data; - struct registry_key *tmp = NULL, *own; - int namlen, clsname_len, sk_off, own_off; - uint_t nk_id; - SK_HDR *sk_hdr; - int type; - char key_name[1024]; - - if (!nk_hdr) return WERR_INVALID_PARAM; - - if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) { - DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n", - nk_id, (int)nk_hdr, parent->hive->location)); - return WERR_INVALID_PARAM; - } - - SMB_REG_ASSERT(size < 0); - - namlen = SVAL(&nk_hdr->nam_len,0); - clsname_len = SVAL(&nk_hdr->clsnam_len,0); - - /* - * The value of -size should be ge - * (sizeof(NK_HDR) - 1 + namlen) - * The -1 accounts for the fact that we included the first byte of - * the name in the structure. clsname_len is the length of the thing - * pointed to by clsnam_off - */ - - if (-size < (sizeof(NK_HDR) - 1 + namlen)) { - DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr)); - DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n", - sizeof(NK_HDR), namlen, clsname_len)); - return WERR_GENERAL_FAILURE; - } - - DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", namlen, clsname_len)); - - /* Fish out the key name and process the LF list */ - - SMB_REG_ASSERT(namlen < sizeof(key_name)); - - strncpy(key_name, nk_hdr->key_nam, namlen); - key_name[namlen] = '\0'; - - type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY); - if(type == REG_ROOT_KEY && parent) { - DEBUG(0,("Root key encountered below root level!\n")); - return WERR_GENERAL_FAILURE; - } - - tmp = talloc_p(mem_ctx, struct registry_key); - tmp->name = talloc_strdup(mem_ctx, key_name); - tmp->backend_data = nk_hdr; - - DEBUG(2, ("Key name: %s\n", key_name)); - - /* - * Fish out the class name, it is in UNICODE, while the key name is - * ASCII :-) - */ - - if (clsname_len) { /* Just print in Ascii for now */ - void *clsnamep; - int clsnam_off; - - clsnam_off = IVAL(&nk_hdr->clsnam_off,0); - clsnamep = LOCN(regf->base, clsnam_off); - DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off)); - - pull_ucs2_talloc(mem_ctx, &tmp->class_name, clsnamep); - - DEBUGADD(2,(" Class Name: %s\n", tmp->class_name)); - - } - - /* - * Process the owner offset ... - */ - - own_off = IVAL(&nk_hdr->own_off,0); - own = (struct registry_key *)LOCN(regf->base, own_off); - DEBUG(2, ("Owner Offset: %0X\n", own_off)); - - DEBUGADD(2, (" Owner locn: %0X, Our locn: %0X\n", - (uint_t)own, (uint_t)nk_hdr)); - - /* - * We should verify that the owner field is correct ... - * for now, we don't worry ... - */ - - /* - * Also handle the SK header ... - */ - - sk_off = IVAL(&nk_hdr->sk_off,0); - sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off); - DEBUG(2, ("SK Offset: %0X\n", sk_off)); - - if (sk_off != -1) { - -#if 0 - tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr)); -#endif - - } - - *key = tmp; - return WERR_OK; -} - -#if 0 /* unused */ - -/* - * Allocate a new hbin block, set up the header for the block etc - */ -static HBIN_BLK *nt_create_hbin_blk(struct registry_hive *h, int size) -{ - REGF *regf = h->backend_data; - HBIN_BLK *tmp; - HBIN_HDR *hdr; - - if (!regf || !size) return NULL; - - /* Round size up to multiple of REGF_HDR_BLKSIZ */ - - size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1); - - tmp = malloc_p(HBIN_BLK); - memset(tmp, 0, sizeof(HBIN_BLK)); - - tmp->data = malloc(size); - - memset(tmp->data, 0, size); /* Make it pristine */ - - tmp->size = size; - /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/ - - tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR)); - tmp->fsp_off = size - tmp->free_space; - - /* - * Now, build the header in the data block - */ - hdr = (HBIN_HDR *)tmp->data; - hdr->HBIN_ID = str_to_dword("hbin"); - hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ; - hdr->off_to_next = tmp->size; - hdr->blk_size = tmp->size; - - /* - * Now link it in - */ - - regf->blk_tail->next = tmp; - regf->blk_tail = tmp; - if (!regf->free_space) regf->free_space = tmp; - - return tmp; -} - -/* - * Allocate a unit of space ... and return a pointer as function param - * and the block's offset as a side effect - */ -static void *nt_alloc_regf_space(struct registry_hive *h, int size, uint_t *off) -{ - REGF *regf = h->backend_data; - int tmp = 0; - void *ret = NULL; - HBIN_BLK *blk; - - if (!regf || !size || !off) return NULL; - - SMB_REG_ASSERT(regf->blk_head != NULL); - - /* - * round up size to include header and then to 8-byte boundary - */ - size = (size + 4 + 7) & ~7; - - /* - * Check if there is space, if none, grab a block - */ - if (!regf->free_space) { - if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) - return NULL; - } - - /* - * Now, chain down the list of blocks looking for free space - */ - - for (blk = regf->free_space; blk != NULL; blk = blk->next) { - if (blk->free_space <= size) { - tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ; - ret = blk->data + blk->fsp_off; - blk->free_space -= size; - blk->fsp_off += size; - - /* Insert the header */ - ((HBIN_SUB_HDR *)ret)->dblocksize = -size; - - /* - * Fix up the free space ptr - * If it is NULL, we fix it up next time - */ - - if (!blk->free_space) - regf->free_space = blk->next; - - *off = tmp; - return (((char *)ret)+4);/* The pointer needs to be to the data struct */ - } - } - - /* - * If we got here, we need to add another block, which might be - * larger than one block -- deal with that later - */ - if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) { - blk = regf->free_space; - tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ; - ret = blk->data + blk->fsp_off; - blk->free_space -= size; - blk->fsp_off += size; - - /* Insert the header */ - ((HBIN_SUB_HDR *)ret)->dblocksize = -size; - - /* - * Fix up the free space ptr - * If it is NULL, we fix it up next time - */ - - if (!blk->free_space) - regf->free_space = blk->next; - - *off = tmp; - return (((char *)ret) + 4);/* The pointer needs to be to the data struct */ - } - - return NULL; -} - -/* - * Store a SID at the location provided - */ -static int nt_store_SID(struct registry_hive *regf, DOM_SID *sid, uint8_t *locn) -{ - int i; - uint8_t *p = locn; - - if (!regf || !sid || !locn) return 0; - - *p = sid->sid_rev_num; p++; - *p = sid->num_auths; p++; - - for (i=0; i < 6; i++) { - *p = sid->id_auth[i]; p++; - } - - for (i=0; i < sid->num_auths; i++) { - SIVAL(p, 0, sid->sub_auths[i]); p+=4; - } - - return p - locn; - -} - -static int nt_store_ace(struct registry_hive *regf, SEC_ACE *ace, uint8_t *locn) -{ - int size = 0; - SEC_ACE *reg_ace = (SEC_ACE *)locn; - uint8_t *p; - - if (!regf || !ace || !locn) return 0; - - reg_ace->type = ace->type; - reg_ace->flags = ace->flags; - - /* Deal with the length when we have stored the SID */ - - p = (uint8_t *)®_ace->info.mask; - - SIVAL(p, 0, ace->info.mask); p += 4; - - size = nt_store_SID(regf, &ace->trustee, p); - - size += 8; /* Size of the fixed header */ - - p = (uint8_t *)®_ace->size; - - SSVAL(p, 0, size); - - return size; -} - -/* - * Store an ACL at the location provided - */ -static int nt_store_acl(struct registry_hive *regf, SEC_ACL *acl, uint8_t *locn) { - int size = 0, i; - uint8_t *p = locn, *s; - - if (!regf || !acl || !locn) return 0; - - /* - * Now store the header and then the ACEs ... - */ - - SSVAL(p, 0, acl->revision); - - p += 2; s = p; /* Save this for the size field */ - - p += 2; - - SIVAL(p, 0, acl->num_aces); - - p += 4; - - for (i = 0; i < acl->num_aces; i++) { - size = nt_store_ace(regf, &acl->ace[i], p); - p += size; - } - - size = s - locn; - SSVAL(s, 0, size); - return size; -} - -/* - * Flatten and store the Sec Desc - * Windows lays out the DACL first, but since there is no SACL, it might be - * that first, then the owner, then the group SID. So, we do it that way - * too. - */ -static uint_t nt_store_sec_desc(struct registry_hive *regf, SEC_DESC *sd, char *locn) -{ - SEC_DESC *rsd = (SEC_DESC *)locn; - uint_t size = 0, off = 0; - - if (!regf || !sd || !locn) return 0; - - /* - * Now, fill in the first two fields, then lay out the various fields - * as needed - */ - - rsd->revision = SEC_DESC_REVISION; - rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE; - - off = 4 * sizeof(DWORD) + 4; - - if (sd->sacl){ - size = nt_store_acl(regf, sd->sacl, (char *)(locn + off)); - rsd->off_sacl = off; - } - else - rsd->off_sacl = 0; - - off += size; - - if (sd->dacl) { - rsd->off_dacl = off; - size = nt_store_acl(regf, sd->dacl, (char *)(locn + off)); - } - else { - rsd->off_dacl = 0; - } - - off += size; - - /* Now the owner and group SIDs */ - - if (sd->owner_sid) { - rsd->off_owner_sid = off; - size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off)); - } - else { - rsd->off_owner_sid = 0; - } - - off += size; - - if (sd->grp_sid) { - rsd->off_grp_sid = off; - size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off)); - } - else { - rsd->off_grp_sid = 0; - } - - off += size; - - return size; -} - -/* - * Store the security information - * - * If it has already been stored, just get its offset from record - * otherwise, store it and record its offset - */ -static uint_t nt_store_security(struct registry_hive *regf, KEY_SEC_DESC *sec) -{ - int size = 0; - uint_t sk_off; - SK_HDR *sk_hdr; - - if (sec->offset) return sec->offset; - - /* - * OK, we don't have this one in the file yet. We must compute the - * size taken by the security descriptor as a self-relative SD, which - * means making one pass over each structure and figuring it out - */ - -/* FIXME size = sec_desc_size(sec->sec_desc); */ - - /* Allocate that much space */ - - sk_hdr = nt_alloc_regf_space(regf, size, &sk_off); - sec->sk_hdr = sk_hdr; - - if (!sk_hdr) return 0; - - /* Now, lay out the sec_desc in the space provided */ - - sk_hdr->SK_ID = str_to_dword("sk"); - - /* - * We can't deal with the next and prev offset in the SK_HDRs until the - * whole tree has been stored, then we can go and deal with them - */ - - sk_hdr->ref_cnt = sec->ref_cnt; - sk_hdr->rec_size = size; /* Is this correct */ - - /* Now, lay out the sec_desc */ - - if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc)) - return 0; - - return sk_off; - -} - -/* - * Store a KEY in the file ... - * - * We store this depth first, and defer storing the lf struct until - * all the sub-keys have been stored. - * - * We store the NK hdr, any SK header, class name, and VK structure, then - * recurse down the LF structures ... - * - * We return the offset of the NK struct - * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ... - */ -static int nt_store_reg_key(struct registry_hive *regf, struct registry_key *key) -{ - NK_HDR *nk_hdr; - uint_t nk_off, sk_off, size; - - if (!regf || !key) return 0; - - size = sizeof(NK_HDR) + strlen(key->name) - 1; - nk_hdr = nt_alloc_regf_space(regf, size, &nk_off); - if (!nk_hdr) goto error; - - key->offset = nk_off; /* We will need this later */ - - /* - * Now fill in each field etc ... - */ - - nk_hdr->NK_ID = str_to_dword("nk"); - if (key->type == REG_ROOT_KEY) - nk_hdr->type = 0x2C; - else - nk_hdr->type = 0x20; - - /* FIXME: Fill in the time of last update */ - - if (key->type != REG_ROOT_KEY) - nk_hdr->own_off = key->owner->offset; - - if (key->sub_keys) - nk_hdr->subk_num = key->sub_keys->key_count; - - /* - * Now, process the Sec Desc and then store its offset - */ - - sk_off = nt_store_security(regf, key->security); - nk_hdr->sk_off = sk_off; - - /* - * Then, store the val list and store its offset - */ - if (key->values) { - nk_hdr->val_cnt = key->values->val_count; - nk_hdr->val_off = nt_store_val_list(regf, key->values); - } - else { - nk_hdr->val_off = -1; - nk_hdr->val_cnt = 0; - } - - /* - * Finally, store the subkeys, and their offsets - */ - -error: - return 0; -} - -/* - * Store the registry header ... - * We actually create the registry header block and link it to the chain - * of output blocks. - */ -static REGF_HDR *nt_get_reg_header(struct registry_hive *h) { - REGF *regf = h->backend_data; - HBIN_BLK *tmp = NULL; - - tmp = malloc_p(HBIN_BLK); - - memset(tmp, 0, sizeof(HBIN_BLK)); - tmp->type = REG_OUTBLK_HDR; - tmp->size = REGF_HDR_BLKSIZ; - tmp->data = malloc(REGF_HDR_BLKSIZ); - if (!tmp->data) goto error; - - memset(tmp->data, 0, REGF_HDR_BLKSIZ); /* Make it pristine, unlike Windows */ - regf->blk_head = regf->blk_tail = tmp; - - return (REGF_HDR *)tmp->data; - -error: - if (tmp) free(tmp); - return NULL; -} - -#endif - -static WERROR nt_open_hive (TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **key) -{ - REGF *regf; - REGF_HDR *regf_hdr; - uint_t regf_id, hbin_id; - HBIN_HDR *hbin_hdr; - - regf = (REGF *)talloc_p(mem_ctx, REGF); - memset(regf, 0, sizeof(REGF)); - regf->owner_sid_str = h->credentials; - h->backend_data = regf; - - DEBUG(5, ("Attempting to load registry file\n")); - - /* Get the header */ - - if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) { - DEBUG(0, ("Unable to get header\n")); - return WERR_GENERAL_FAILURE; - } - - /* Now process that header and start to read the rest in */ - - if ((regf_id = IVAL(®f_hdr->REGF_ID,0)) != str_to_dword("regf")) { - DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n", - regf_id, h->location)); - return WERR_GENERAL_FAILURE; - } - - /* - * Validate the header ... - */ - if (!valid_regf_hdr(regf_hdr)) { - DEBUG(0, ("Registry file header does not validate: %s\n", - h->location)); - return WERR_GENERAL_FAILURE; - } - - /* Update the last mod date, and then go get the first NK record and on */ - - TTTONTTIME(regf, IVAL(®f_hdr->tim1,0), IVAL(®f_hdr->tim2,0)); - - /* - * The hbin hdr seems to be just uninteresting garbage. Check that - * it is there, but that is all. - */ - - hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ); - - if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) { - DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", - hbin_id, h->location)); - return WERR_GENERAL_FAILURE; - } - - /* - * Get a pointer to the first key from the hreg_hdr - */ - - DEBUG(2, ("First Key: %0X\n", - IVAL(®f_hdr->first_key, 0))); - - regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(®f_hdr->first_key,0)); - DEBUGADD(2, ("First Key Offset: %0X\n", - IVAL(®f_hdr->first_key, 0))); - - DEBUGADD(2, ("Data Block Size: %d\n", - IVAL(®f_hdr->dblk_size, 0))); - - DEBUGADD(2, ("Offset to next hbin block: %0X\n", - IVAL(&hbin_hdr->off_to_next, 0))); - - DEBUGADD(2, ("HBIN block size: %0X\n", - IVAL(&hbin_hdr->blk_size, 0))); - - /* - * Unmap the registry file, as we might want to read in another - * tree etc. - */ - - h->backend_data = regf; - - return nk_to_key(mem_ctx, h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key); -} - - -static WERROR nt_num_subkeys(struct registry_key *k, int *num) -{ - REGF *regf = k->hive->backend_data; - LF_HDR *lf_hdr; - int lf_off; - NK_HDR *nk_hdr = k->backend_data; - lf_off = IVAL(&nk_hdr->lf_off,0); - DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); - if(lf_off == -1) { - *num = 0; - return WERR_OK; - } - lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); - - return lf_num_entries(k->hive, lf_hdr, BLK_SIZE(lf_hdr), num); -} - -static WERROR nt_num_values(struct registry_key *k, int *count) -{ - NK_HDR *nk_hdr = k->backend_data; - *count = IVAL(&nk_hdr->val_cnt,0); - return WERR_OK; -} - -static WERROR nt_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_value **value) -{ - VL_TYPE *vl; - int val_off, vk_off; - int val_count; - VK_HDR *vk_hdr; - REGF *regf = k->hive->backend_data; - NK_HDR *nk_hdr = k->backend_data; - val_count = IVAL(&nk_hdr->val_cnt,0); - val_off = IVAL(&nk_hdr->val_off,0); - vl = (VL_TYPE *)LOCN(regf->base, val_off); - DEBUG(2, ("Val List Offset: %0X\n", val_off)); - if(n < 0) return WERR_INVALID_PARAM; - if(n >= val_count) return WERR_NO_MORE_ITEMS; - - vk_off = IVAL(&vl[n],0); - vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off); - return vk_to_val(mem_ctx, k, vk_hdr, BLK_SIZE(vk_hdr), value); -} - -static WERROR nt_key_by_index(TALLOC_CTX *mem_ctx, struct registry_key *k, int n, struct registry_key **subkey) -{ - REGF *regf = k->hive->backend_data; - int lf_off; - NK_HDR *nk_hdr = k->backend_data; - LF_HDR *lf_hdr; - lf_off = IVAL(&nk_hdr->lf_off,0); - DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); - - /* - * No more subkeys if lf_off == -1 - */ - - if (lf_off != -1) { - lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); - return lf_get_entry(mem_ctx, k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey); - } - - return WERR_NO_MORE_ITEMS; -} - -static struct registry_operations reg_backend_nt4 = { - .name = "nt4", - .open_hive = nt_open_hive, - .num_subkeys = nt_num_subkeys, - .num_values = nt_num_values, - .get_subkey_by_index = nt_key_by_index, - .get_value_by_index = nt_value_by_index, - - /* TODO: - .add_key - .add_value - .del_key - .del_value - .update_value - */ -}; - -NTSTATUS registry_nt4_init(void) -{ - return registry_register(®_backend_nt4); -} diff --git a/source4/lib/registry/reg_backend_rpc.c b/source4/lib/registry/reg_backend_rpc.c new file mode 100644 index 0000000000..18563b2478 --- /dev/null +++ b/source4/lib/registry/reg_backend_rpc.c @@ -0,0 +1,398 @@ +/* + Samba Unix/Linux SMB implementation + RPC backend for the registry library + Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "registry.h" +#include "librpc/gen_ndr/ndr_winreg.h" + +static struct hive_operations reg_backend_rpc; + +/** + * This is the RPC backend for the registry library. + */ + +static void init_winreg_String(struct winreg_String *name, const char *s) +{ + name->name = s; + if (s) { + name->name_len = 2 * (strlen_m(s) + 1); + name->name_size = name->name_len; + } else { + name->name_len = 0; + name->name_size = 0; + } +} + + +#define openhive(u) static WERROR open_ ## u(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *hnd) \ +{ \ + struct winreg_Open ## u r; \ + struct winreg_OpenUnknown unknown; \ + NTSTATUS status; \ + \ + unknown.unknown0 = 0x84e0; \ + unknown.unknown1 = 0x0000; \ + r.in.unknown = &unknown; \ + r.in.access_required = SEC_FLAG_MAXIMUM_ALLOWED; \ + r.out.handle = hnd;\ + \ + status = dcerpc_winreg_Open ## u(p, mem_ctx, &r); \ + if (NT_STATUS_IS_ERR(status)) {\ + DEBUG(0,("Error executing open\n"));\ + return ntstatus_to_werror(status);\ + }\ +\ + return r.out.result;\ +} + +openhive(HKLM) +openhive(HKCU) +openhive(HKPD) +openhive(HKU) +openhive(HKCR) +openhive(HKDD) +openhive(HKCC) + +struct rpc_key_data { + struct policy_handle pol; + int num_subkeys; + int num_values; + int max_valnamelen; + int max_valdatalen; +}; + +struct { + uint32 hkey; + WERROR (*open) (struct dcerpc_pipe *p, TALLOC_CTX *, struct policy_handle *h); +} known_hives[] = { +{ HKEY_LOCAL_MACHINE, open_HKLM }, +{ HKEY_CURRENT_USER, open_HKCU }, +{ HKEY_CLASSES_ROOT, open_HKCR }, +{ HKEY_PERFORMANCE_DATA, open_HKPD }, +{ HKEY_USERS, open_HKU }, +{ HKEY_DYN_DATA, open_HKDD }, +{ HKEY_CURRENT_CONFIG, open_HKCC }, +{ 0, NULL } +}; + +static WERROR rpc_query_key(struct registry_key *k); + +static WERROR rpc_get_hive (struct registry_context *ctx, uint32 hkey_type, struct registry_key **k) +{ + int n; + struct registry_hive *h; + struct rpc_key_data *mykeydata; + + for(n = 0; known_hives[n].hkey; n++) + { + if(known_hives[n].hkey == hkey_type) break; + } + + if(!known_hives[n].open) { + DEBUG(1, ("No such hive %d\n", hkey_type)); + return WERR_NO_MORE_ITEMS; + } + + h = talloc_p(ctx, struct registry_hive); + h->functions = ®_backend_rpc; + h->location = NULL; + h->backend_data = ctx->backend_data; + h->reg_ctx = ctx; + + (*k) = h->root = talloc_p(h, struct registry_key); + (*k)->hive = h; + (*k)->backend_data = mykeydata = talloc_p(*k, struct rpc_key_data); + mykeydata->num_values = -1; + mykeydata->num_subkeys = -1; + return known_hives[n].open((struct dcerpc_pipe *)ctx->backend_data, *k, &(mykeydata->pol)); +} + +static int rpc_close (void *_h) +{ + struct registry_context *h = _h; + dcerpc_pipe_close(h->backend_data); + return 0; +} + +#if 0 +static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k) +{ + struct winreg_OpenKey r; + struct rpc_key_data *mykeydata; + + k->backend_data = mykeydata = talloc_p(mem_ctx, struct rpc_key_data); + mykeydata->num_values = -1; + mykeydata->num_subkeys = -1; + + /* Then, open the handle using the hive */ + + memset(&r, 0, sizeof(struct winreg_OpenKey)); + r.in.handle = &(((struct rpc_key_data *)k->hive->root->backend_data)->pol); + init_winreg_String(&r.in.keyname, k->path); + r.in.unknown = 0x00000000; + r.in.access_mask = 0x02000000; + r.out.handle = &mykeydata->pol; + + dcerpc_winreg_OpenKey((struct dcerpc_pipe *)k->hive->backend_data, mem_ctx, &r); + + return r.out.result; +} +#endif + +static WERROR rpc_open_rel_key(TALLOC_CTX *mem_ctx, struct registry_key *h, const char *name, struct registry_key **key) +{ + struct rpc_key_data *mykeydata; + struct winreg_OpenKey r; + + *key = talloc_p(mem_ctx, struct registry_key); + (*key)->name = talloc_strdup(mem_ctx, name); + + (*key)->backend_data = mykeydata = talloc_p(mem_ctx, struct rpc_key_data); + mykeydata->num_values = -1; + mykeydata->num_subkeys = -1; + + /* Then, open the handle using the hive */ + + memset(&r, 0, sizeof(struct winreg_OpenKey)); + r.in.handle = &(((struct rpc_key_data *)h->backend_data)->pol); + init_winreg_String(&r.in.keyname, name); + r.in.unknown = 0x00000000; + r.in.access_mask = 0x02000000; + r.out.handle = &mykeydata->pol; + + dcerpc_winreg_OpenKey((struct dcerpc_pipe *)(h->hive->backend_data), mem_ctx, &r); + + return r.out.result; +} + +static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **key) +{ + return rpc_open_rel_key(mem_ctx, h->root, name, key); +} + +static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *parent, int n, struct registry_value **value) +{ + struct rpc_key_data *mykeydata = parent->backend_data; + WERROR error; + struct winreg_EnumValue r; + uint32 type, len1, zero = 0; + NTSTATUS status; + uint8_t buf8; + uint16_t buf16; + + if(mykeydata->num_values == -1) { + error = rpc_query_key(parent); + if(!W_ERROR_IS_OK(error)) return error; + } + + len1 = mykeydata->max_valdatalen; + + r.in.handle = &mykeydata->pol; + r.in.enum_index = n; + r.in.name_in.length = 0; + r.in.name_in.size = mykeydata->max_valnamelen * 2; + r.in.name_in.name = &buf16; + r.in.type = &type; + r.in.value = &buf8; + r.in.length = &zero; + r.in.size = &len1; + r.out.type = &type; + + + status = dcerpc_winreg_EnumValue((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r); + if(NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status))); + return WERR_GENERAL_FAILURE; + } + + if(NT_STATUS_IS_OK(status) && + W_ERROR_IS_OK(r.out.result) && r.out.length) { + *value = talloc_p(mem_ctx, struct registry_value); + (*value)->parent = parent; + (*value)->name = talloc_strdup(mem_ctx, r.out.name_out.name); + (*value)->data_type = type; + (*value)->data_len = *r.out.length; + (*value)->data_blk = talloc_memdup(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, struct registry_key *parent, int n, struct registry_key **subkey) +{ + struct winreg_EnumKey r; + struct winreg_EnumKeyNameRequest keyname; + struct winreg_String classname; + struct winreg_Time tm; + struct rpc_key_data *mykeydata = parent->backend_data; + NTSTATUS status; + + r.in.handle = &mykeydata->pol; + keyname.unknown = 0x0000020a; + init_winreg_String(&keyname.key_name, NULL); + init_winreg_String(&classname, NULL); + r.in.in_name = &keyname; + r.in.class = &classname; + tm.low = tm.high = 0x7fffffff; + r.in.last_changed_time = &tm; + + r.in.enum_index = n; + r.in.unknown = r.out.unknown = 0x0414; + r.in.key_name_len = r.out.key_name_len = 0; + status = dcerpc_winreg_EnumKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r); + if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) { + return rpc_open_rel_key(mem_ctx, parent, talloc_strdup(mem_ctx, r.out.out_name->name), subkey); + } + + return r.out.result; +} + +static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, uint32_t access_mask, SEC_DESC *sec, struct registry_key **key) +{ + return WERR_NOT_SUPPORTED; +} + +static WERROR rpc_query_key(struct registry_key *k) +{ + NTSTATUS status; + struct winreg_QueryInfoKey r; + struct rpc_key_data *mykeydata = k->backend_data; + TALLOC_CTX *mem_ctx = talloc_init("query_key"); + + init_winreg_String(&r.in.class, NULL); + r.in.handle = &mykeydata->pol; + + status = dcerpc_winreg_QueryInfoKey((struct dcerpc_pipe *)(k->hive->backend_data), mem_ctx, &r); + talloc_destroy(mem_ctx); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("QueryInfoKey failed - %s\n", nt_errstr(status))); + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(r.out.result)) { + mykeydata->num_subkeys = r.out.num_subkeys; + mykeydata->num_values = r.out.num_values; + mykeydata->max_valnamelen = r.out.max_valnamelen; + mykeydata->max_valdatalen = r.out.max_valbufsize; + } + + return r.out.result; +} + +static WERROR rpc_del_key(struct registry_key *k) +{ + NTSTATUS status; + struct rpc_key_data *mykeydata = k->backend_data; + struct winreg_DeleteKey r; + struct registry_key *parent; + WERROR error; + TALLOC_CTX *mem_ctx = talloc_init("del_key"); + + error = reg_key_get_parent(mem_ctx, k, &parent); + if(!W_ERROR_IS_OK(error)) { + talloc_destroy(mem_ctx); + return error; + } + + mykeydata = parent->backend_data; + + r.in.handle = &mykeydata->pol; + init_winreg_String(&r.in.key, k->name); + + status = dcerpc_winreg_DeleteKey((struct dcerpc_pipe *)k->hive->backend_data, mem_ctx, &r); + + talloc_destroy(mem_ctx); + + return r.out.result; +} + +static WERROR rpc_num_values(struct registry_key *key, int *count) { + struct rpc_key_data *mykeydata = key->backend_data; + WERROR error; + + if(mykeydata->num_values == -1) { + error = rpc_query_key(key); + if(!W_ERROR_IS_OK(error)) return error; + } + + *count = mykeydata->num_values; + return WERR_OK; +} + +static WERROR rpc_num_subkeys(struct registry_key *key, int *count) { + struct rpc_key_data *mykeydata = key->backend_data; + WERROR error; + + if(mykeydata->num_subkeys == -1) { + error = rpc_query_key(key); + if(!W_ERROR_IS_OK(error)) return error; + } + + *count = mykeydata->num_subkeys; + return WERR_OK; +} + +static struct hive_operations reg_backend_rpc = { + .name = "rpc", + .open_key = rpc_open_key, + .get_subkey_by_index = rpc_get_subkey_by_index, + .get_value_by_index = rpc_get_value_by_index, + .add_key = rpc_add_key, + .del_key = rpc_del_key, + .num_subkeys = rpc_num_subkeys, + .num_values = rpc_num_values, +}; + +WERROR reg_open_remote (struct registry_context **ctx, const char *user, const char *pass, const char *location) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + + *ctx = talloc_p(NULL, struct registry_context); + + /* Default to local smbd if no connection is specified */ + if (!location) { + location = talloc_strdup(ctx, "ncalrpc:"); + } + + status = dcerpc_pipe_connect(&p, location, + DCERPC_WINREG_UUID, + DCERPC_WINREG_VERSION, + lp_workgroup(), + user, pass); + (*ctx)->backend_data = p; + + if(NT_STATUS_IS_ERR(status)) { + DEBUG(1, ("Unable to open '%s': %s\n", location, nt_errstr(status))); + return ntstatus_to_werror(status); + } + + (*ctx)->get_hive = rpc_get_hive; + + talloc_set_destructor(*ctx, rpc_close); + + return WERR_OK; +} + +NTSTATUS registry_rpc_init(void) +{ + return registry_register(®_backend_rpc); +} diff --git a/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c b/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c deleted file mode 100644 index 3969a763e0..0000000000 --- a/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - Samba Unix/Linux SMB implementation - RPC backend for the registry library - Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "includes.h" -#include "registry.h" -#include "librpc/gen_ndr/ndr_winreg.h" - -/** - * This is the RPC backend for the registry library. - */ - -static void init_winreg_String(struct winreg_String *name, const char *s) -{ - name->name = s; - if (s) { - name->name_len = 2 * (strlen_m(s) + 1); - name->name_size = name->name_len; - } else { - name->name_len = 0; - name->name_size = 0; - } -} - - -#define openhive(u) static WERROR open_ ## u(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *hnd) \ -{ \ - struct winreg_Open ## u r; \ - struct winreg_OpenUnknown unknown; \ - NTSTATUS status; \ - \ - unknown.unknown0 = 0x84e0; \ - unknown.unknown1 = 0x0000; \ - r.in.unknown = &unknown; \ - r.in.access_required = SEC_FLAG_MAXIMUM_ALLOWED; \ - r.out.handle = hnd;\ - \ - status = dcerpc_winreg_Open ## u(p, mem_ctx, &r); \ - if (NT_STATUS_IS_ERR(status)) {\ - DEBUG(0,("Error executing open\n"));\ - return ntstatus_to_werror(status);\ - }\ -\ - return r.out.result;\ -} - -openhive(HKLM) -openhive(HKCU) -openhive(HKPD) -openhive(HKU) -openhive(HKCR) -openhive(HKDD) -openhive(HKCC) - -struct rpc_key_data { - struct policy_handle pol; - int num_subkeys; - int num_values; - int max_valnamelen; - int max_valdatalen; -}; - -struct { - const char *name; - 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 }, -{ NULL, NULL } -}; - -static WERROR rpc_query_key(struct registry_key *k); - -static WERROR rpc_list_hives (TALLOC_CTX *mem_ctx, const char *location, const char *credentials, char ***hives) -{ - int i = 0; - *hives = talloc_p(mem_ctx, char *); - for(i = 0; known_hives[i].name; i++) { - *hives = talloc_realloc_p(mem_ctx, *hives, char *, i+2); - (*hives)[i] = talloc_strdup(mem_ctx, known_hives[i].name); - } - (*hives)[i] = NULL; - return WERR_OK; -} - -static WERROR rpc_close_hive (struct registry_hive *h) -{ - dcerpc_pipe_close(h->backend_data); - return WERR_OK; -} - -static WERROR rpc_open_hive(TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **k) -{ - NTSTATUS status; - char *user; - char *pass; - struct rpc_key_data *mykeydata; - struct dcerpc_pipe *p; - int n; - - if (!h->credentials) return WERR_INVALID_PARAM; - - /* Default to local smbd if no connection is specified */ - if (!h->location) { - h->location = talloc_strdup(mem_ctx, "ncalrpc:"); - } - - user = talloc_strdup(mem_ctx, h->credentials); - pass = strchr(user, '%'); - if (pass) { - *pass = '\0'; - pass = strdup(pass+1); - } else { - pass = strdup(""); - } - - status = dcerpc_pipe_connect(&p, h->location, - DCERPC_WINREG_UUID, - DCERPC_WINREG_VERSION, - lp_workgroup(), - user, pass); - free(pass); - - h->backend_data = p; - - if(NT_STATUS_IS_ERR(status)) { - DEBUG(1, ("Unable to open '%s': %s\n", h->location, nt_errstr(status))); - return ntstatus_to_werror(status); - } - - for(n = 0; known_hives[n].name; n++) - { - if(!strcmp(known_hives[n].name, h->backend_hivename)) break; - } - - if(!known_hives[n].name) { - DEBUG(1, ("No such hive %s\n", known_hives[n].name)); - return WERR_NO_MORE_ITEMS; - } - - *k = talloc_p(mem_ctx, struct registry_key); - (*k)->backend_data = mykeydata = talloc_p(mem_ctx, struct rpc_key_data); - mykeydata->num_values = -1; - mykeydata->num_subkeys = -1; - return known_hives[n].open((struct dcerpc_pipe *)h->backend_data, *k, &(mykeydata->pol)); -} - -#if 0 -static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k) -{ - struct winreg_OpenKey r; - struct rpc_key_data *mykeydata; - - k->backend_data = mykeydata = talloc_p(mem_ctx, struct rpc_key_data); - mykeydata->num_values = -1; - mykeydata->num_subkeys = -1; - - /* Then, open the handle using the hive */ - - memset(&r, 0, sizeof(struct winreg_OpenKey)); - r.in.handle = &(((struct rpc_key_data *)k->hive->root->backend_data)->pol); - init_winreg_String(&r.in.keyname, k->path); - r.in.unknown = 0x00000000; - r.in.access_mask = 0x02000000; - r.out.handle = &mykeydata->pol; - - dcerpc_winreg_OpenKey((struct dcerpc_pipe *)k->hive->backend_data, mem_ctx, &r); - - return r.out.result; -} -#endif - -static WERROR rpc_open_rel_key(TALLOC_CTX *mem_ctx, struct registry_key *h, const char *name, struct registry_key **key) -{ - struct rpc_key_data *mykeydata; - struct winreg_OpenKey r; - - *key = talloc_p(mem_ctx, struct registry_key); - (*key)->name = talloc_strdup(mem_ctx, name); - - (*key)->backend_data = mykeydata = talloc_p(mem_ctx, struct rpc_key_data); - mykeydata->num_values = -1; - mykeydata->num_subkeys = -1; - - /* Then, open the handle using the hive */ - - memset(&r, 0, sizeof(struct winreg_OpenKey)); - r.in.handle = &(((struct rpc_key_data *)h->backend_data)->pol); - init_winreg_String(&r.in.keyname, name); - r.in.unknown = 0x00000000; - r.in.access_mask = 0x02000000; - r.out.handle = &mykeydata->pol; - - dcerpc_winreg_OpenKey((struct dcerpc_pipe *)(h->hive->backend_data), mem_ctx, &r); - - return r.out.result; -} - -static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, struct registry_hive *h, const char *name, struct registry_key **key) -{ - return rpc_open_rel_key(mem_ctx, h->root, name, key); -} - -static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, struct registry_key *parent, int n, struct registry_value **value) -{ - struct rpc_key_data *mykeydata = parent->backend_data; - WERROR error; - struct winreg_EnumValue r; - uint32 type, len1, zero = 0; - NTSTATUS status; - uint8_t buf8; - uint16_t buf16; - - if(mykeydata->num_values == -1) { - error = rpc_query_key(parent); - if(!W_ERROR_IS_OK(error)) return error; - } - - len1 = mykeydata->max_valdatalen; - - r.in.handle = &mykeydata->pol; - r.in.enum_index = n; - r.in.name_in.length = 0; - r.in.name_in.size = mykeydata->max_valnamelen * 2; - r.in.name_in.name = &buf16; - r.in.type = &type; - r.in.value = &buf8; - r.in.length = &zero; - r.in.size = &len1; - r.out.type = &type; - - - status = dcerpc_winreg_EnumValue((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r); - if(NT_STATUS_IS_ERR(status)) { - DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status))); - return WERR_GENERAL_FAILURE; - } - - if(NT_STATUS_IS_OK(status) && - W_ERROR_IS_OK(r.out.result) && r.out.length) { - *value = talloc_p(mem_ctx, struct registry_value); - (*value)->parent = parent; - (*value)->name = talloc_strdup(mem_ctx, r.out.name_out.name); - (*value)->data_type = type; - (*value)->data_len = *r.out.length; - (*value)->data_blk = talloc_memdup(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, struct registry_key *parent, int n, struct registry_key **subkey) -{ - struct winreg_EnumKey r; - struct winreg_EnumKeyNameRequest keyname; - struct winreg_String classname; - struct winreg_Time tm; - struct rpc_key_data *mykeydata = parent->backend_data; - NTSTATUS status; - - r.in.handle = &mykeydata->pol; - keyname.unknown = 0x0000020a; - init_winreg_String(&keyname.key_name, NULL); - init_winreg_String(&classname, NULL); - r.in.in_name = &keyname; - r.in.class = &classname; - tm.low = tm.high = 0x7fffffff; - r.in.last_changed_time = &tm; - - r.in.enum_index = n; - r.in.unknown = r.out.unknown = 0x0414; - r.in.key_name_len = r.out.key_name_len = 0; - status = dcerpc_winreg_EnumKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r); - if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) { - return rpc_open_rel_key(mem_ctx, parent, talloc_strdup(mem_ctx, r.out.out_name->name), subkey); - } - - return r.out.result; -} - -static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, uint32_t access_mask, SEC_DESC *sec, struct registry_key **key) -{ - return WERR_NOT_SUPPORTED; -} - -static WERROR rpc_query_key(struct registry_key *k) -{ - NTSTATUS status; - struct winreg_QueryInfoKey r; - struct rpc_key_data *mykeydata = k->backend_data; - TALLOC_CTX *mem_ctx = talloc_init("query_key"); - - init_winreg_String(&r.in.class, NULL); - r.in.handle = &mykeydata->pol; - - status = dcerpc_winreg_QueryInfoKey((struct dcerpc_pipe *)(k->hive->backend_data), mem_ctx, &r); - talloc_destroy(mem_ctx); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("QueryInfoKey failed - %s\n", nt_errstr(status))); - return ntstatus_to_werror(status); - } - - if (W_ERROR_IS_OK(r.out.result)) { - mykeydata->num_subkeys = r.out.num_subkeys; - mykeydata->num_values = r.out.num_values; - mykeydata->max_valnamelen = r.out.max_valnamelen; - mykeydata->max_valdatalen = r.out.max_valbufsize; - } - - return r.out.result; -} - -static WERROR rpc_del_key(struct registry_key *k) -{ - NTSTATUS status; - struct rpc_key_data *mykeydata = k->backend_data; - struct winreg_DeleteKey r; - struct registry_key *parent; - WERROR error; - TALLOC_CTX *mem_ctx = talloc_init("del_key"); - - error = reg_key_get_parent(mem_ctx, k, &parent); - if(!W_ERROR_IS_OK(error)) { - talloc_destroy(mem_ctx); - return error; - } - - mykeydata = parent->backend_data; - - r.in.handle = &mykeydata->pol; - init_winreg_String(&r.in.key, k->name); - - status = dcerpc_winreg_DeleteKey((struct dcerpc_pipe *)k->hive->backend_data, mem_ctx, &r); - - talloc_destroy(mem_ctx); - - return r.out.result; -} - -static WERROR rpc_num_values(struct registry_key *key, int *count) { - struct rpc_key_data *mykeydata = key->backend_data; - WERROR error; - - if(mykeydata->num_values == -1) { - error = rpc_query_key(key); - if(!W_ERROR_IS_OK(error)) return error; - } - - *count = mykeydata->num_values; - return WERR_OK; -} - -static WERROR rpc_num_subkeys(struct registry_key *key, int *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 registry_operations reg_backend_rpc = { - .name = "rpc", - .open_hive = rpc_open_hive, - .close_hive = rpc_close_hive, - .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, - .list_available_hives = rpc_list_hives, -}; - -NTSTATUS registry_rpc_init(void) -{ - return registry_register(®_backend_rpc); -} diff --git a/source4/lib/registry/reg_backend_w95.c b/source4/lib/registry/reg_backend_w95.c new file mode 100644 index 0000000000..a94ad86c2c --- /dev/null +++ b/source4/lib/registry/reg_backend_w95.c @@ -0,0 +1,356 @@ +/* + Samba Unix/Linux SMB client utility libeditreg.c + Copyright (C) 2004 Jelmer Vernooij, jelmer@samba.org + + Backend for Windows '95 registry files. Explanation of file format + comes from http://www.cs.mun.ca/~michael/regutils/. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" +#include "registry.h" +#include "system/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 uint_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; + +#define RGKN_START_SIZE 0x2000 +#define RGKN_INC_SIZE 0x1000 + +#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_p(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 ((int)creg->base == 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_p(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_p(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_p(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, 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_p(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(struct registry_key *k, int *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, 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_p(mem_ctx, struct registry_value); + (*value)->backend_data = curval; + (*value)->name = talloc_strndup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE), curval->name_len); + + (*value)->data_len = curval->data_len; + (*value)->data_blk = talloc_memdup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE)+curval->name_len, curval->data_len); + (*value)->data_type = curval->type; + + return WERR_OK; +} + +static struct hive_operations reg_backend_w95 = { + .name = "w95", + .open_hive = w95_open_reg, + .get_value_by_index = w95_get_value_by_id, + .num_values = w95_num_values, + .get_subkey_by_index = w95_get_subkey_by_index, +}; + +NTSTATUS registry_w95_init(void) +{ + return registry_register(®_backend_w95); +} diff --git a/source4/lib/registry/reg_backend_w95/reg_backend_w95.c b/source4/lib/registry/reg_backend_w95/reg_backend_w95.c deleted file mode 100644 index 445d13a99c..0000000000 --- a/source4/lib/registry/reg_backend_w95/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 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "includes.h" -#include "registry.h" -#include "system/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 uint_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; - -#define RGKN_START_SIZE 0x2000 -#define RGKN_INC_SIZE 0x1000 - -#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 (TALLOC_CTX *mem_ctx, struct registry_hive *h, struct registry_key **root) -{ - CREG *creg; - DWORD creg_id, rgkn_id; - DWORD i; - DWORD offset; - - creg = talloc_p(mem_ctx, 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 ((int)creg->base == 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_p(mem_ctx, 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_p(mem_ctx, 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_p(mem_ctx, 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, 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_p(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(struct registry_key *k, int *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, 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_p(mem_ctx, struct registry_value); - (*value)->backend_data = curval; - (*value)->name = talloc_strndup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE), curval->name_len); - - (*value)->data_len = curval->data_len; - (*value)->data_blk = talloc_memdup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE)+curval->name_len, curval->data_len); - (*value)->data_type = curval->type; - - return WERR_OK; -} - -static struct registry_operations reg_backend_w95 = { - .name = "w95", - .open_hive = w95_open_reg, - .get_value_by_index = w95_get_value_by_id, - .num_values = w95_num_values, - .get_subkey_by_index = w95_get_subkey_by_index, -}; - -NTSTATUS registry_w95_init(void) -{ - return registry_register(®_backend_w95); -} diff --git a/source4/lib/registry/reg_backend_wine.c b/source4/lib/registry/reg_backend_wine.c new file mode 100644 index 0000000000..8a3458b52c --- /dev/null +++ b/source4/lib/registry/reg_backend_wine.c @@ -0,0 +1,48 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "lib/registry/common/registry.h" +#include "windows/registry.h" + +static WERROR wine_open_reg (struct registry_hive *h, struct registry_key **key) +{ + /* FIXME: Open h->location and mmap it */ +} + + + +static REG_OPS reg_backend_wine = { + .name = "wine", + .open_hive = wine_open_reg, + +}; + +NTSTATUS registry_wine_init(void) +{ + register_backend("registry", ®_backend_wine); + return NT_STATUS_OK; +} + +WERROR reg_open_wine(struct registry_key **ctx) +{ + /* FIXME: Open ~/.wine/system.reg, etc */ + return WERR_NOT_SUPPORTED; +} diff --git a/source4/lib/registry/reg_backend_wine/reg_backend_wine.c b/source4/lib/registry/reg_backend_wine/reg_backend_wine.c deleted file mode 100644 index 249af27e13..0000000000 --- a/source4/lib/registry/reg_backend_wine/reg_backend_wine.c +++ /dev/null @@ -1,33 +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 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "lib/registry/common/registry.h" -#include "windows/registry.h" - -static REG_OPS reg_backend_wine = { - .name = "wine", -}; - -NTSTATUS registry_wine_init(void) -{ - register_backend("registry", ®_backend_wine); - return NT_STATUS_OK; -} diff --git a/source4/lib/registry/reg_samba.c b/source4/lib/registry/reg_samba.c new file mode 100644 index 0000000000..a19029524d --- /dev/null +++ b/source4/lib/registry/reg_samba.c @@ -0,0 +1,62 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "registry.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_REGISTRY + +static WERROR reg_samba_get_hive (struct registry_context *ctx, uint32 hkey, struct registry_key **k) +{ + WERROR error; + const char *conf; + char *backend, *location; + const char *hivename = reg_get_hkey_name(hkey); + + *k = NULL; + + conf = lp_parm_string(-1, "registry", hivename); + + if (!conf) { + return WERR_NOT_SUPPORTED; + } + + backend = talloc_strdup(NULL, conf); + location = strchr(backend, ':'); + + if (location) { + *location = '\0'; + location++; + } + + error = reg_open_hive(ctx, backend, location, NULL, k); + + talloc_destroy(backend); + + return error; +} + +WERROR reg_open_local (struct registry_context **ctx) +{ + *ctx = talloc_p(NULL, struct registry_context); + (*ctx)->get_hive = reg_samba_get_hive; + + return WERR_OK; +} diff --git a/source4/lib/registry/tools/regdiff.c b/source4/lib/registry/tools/regdiff.c index 55c8f1e72f..fc2954b6af 100644 --- a/source4/lib/registry/tools/regdiff.c +++ b/source4/lib/registry/tools/regdiff.c @@ -113,21 +113,19 @@ static void writediff(struct registry_key *oldkey, struct registry_key *newkey, { int opt; poptContext pc; - const char *backend1 = NULL, *backend2 = NULL; - const char *location2; - const char *credentials1= NULL, *credentials2 = NULL; char *outputfile = NULL; FILE *fd = stdout; - struct registry_context *h1 = NULL, *h2; + struct registry_context *h1 = NULL, *h2 = NULL; int from_null = 0; int i; WERROR error, error2; struct poptOption long_options[] = { POPT_AUTOHELP - {"backend", 'b', POPT_ARG_STRING, NULL, 'b', "backend to use", NULL}, - {"credentials", 'c', POPT_ARG_STRING, NULL, 'c', "credentials", NULL}, + POPT_COMMON_CREDENTIALS {"output", 'o', POPT_ARG_STRING, &outputfile, 'o', "output file to use", NULL }, - {"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL" }, + {"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL", NULL }, + {"remote", 'R', POPT_ARG_STRING, NULL, 0, "Connect to remote server" , NULL }, + {"local", 'L', POPT_ARG_NONE, NULL, 0, "Open local registry", NULL }, POPT_TABLEEND }; @@ -141,49 +139,24 @@ static void writediff(struct registry_key *oldkey, struct registry_key *newkey, pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0); while((opt = poptGetNextOpt(pc)) != -1) { + error = WERR_OK; switch(opt) { - case 'c': - if(!credentials1 && !from_null) credentials1 = poptGetOptArg(pc); - else if(!credentials2) credentials2 = poptGetOptArg(pc); + case 'L': + if (!h1 && !from_null) error = reg_open_local(&h1); + else if (!h2) error = reg_open_local(&h2); break; - case 'b': - if(!backend1 && !from_null) backend1 = poptGetOptArg(pc); - else if(!backend2) backend2 = poptGetOptArg(pc); + case 'R': + if (!h1 && !from_null) error = reg_open_remote(&h1, cmdline_get_username(), cmdline_get_userpassword(), poptGetOptArg(pc)); + else if (!h2) error = reg_open_remote(&h2, cmdline_get_username(), cmdline_get_userpassword(), poptGetOptArg(pc)); break; } - } - setup_logging(argv[0], True); - if(!from_null) { - const char *location1; - location1 = poptGetArg(pc); - if(!location1) { - poptPrintUsage(pc, stderr, 0); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error: %s\n", win_errstr(error)); return 1; } - - if(!backend1) backend1 = "rpc"; - - error = reg_open(&h1, backend1, location1, credentials1); - if(!W_ERROR_IS_OK(error)) { - fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location1, backend1); - return 1; - } - } - - location2 = poptGetArg(pc); - if(!location2) { - poptPrintUsage(pc, stderr, 0); - return 2; - } - - if(!backend2) backend2 = "rpc"; - - error = reg_open(&h2, backend2, location2, credentials2); - if(!W_ERROR_IS_OK(error)) { - fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location2, backend2); - return 1; } + setup_logging(argv[0], True); poptFreeContext(pc); @@ -196,12 +169,25 @@ static void writediff(struct registry_key *oldkey, struct registry_key *newkey, } fprintf(fd, "REGEDIT4\n\n"); - fprintf(fd, "; Generated using regdiff\n"); + fprintf(fd, "; Generated using regdiff, part of Samba\n"); error2 = error = WERR_OK; - for(i = 0; (!h1 || i < h1->num_hives) && i < h2->num_hives; i++) { - writediff(h1?h1->hives[i]->root:NULL, h2->hives[i]->root, fd); + for(i = HKEY_CLASSES_ROOT; i <= HKEY_PN; i++) { + struct registry_key *r1, *r2; + error = reg_get_hive(h1, i, &r1); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_hkey_name(i))); + continue; + } + + error = reg_get_hive(h2, i, &r2); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_hkey_name(i))); + continue; + } + + writediff(r1, r2, fd); } fclose(fd); diff --git a/source4/lib/registry/tools/regpatch.c b/source4/lib/registry/tools/regpatch.c index be60b96019..a4a4649c96 100644 --- a/source4/lib/registry/tools/regpatch.c +++ b/source4/lib/registry/tools/regpatch.c @@ -758,16 +758,14 @@ static int nt_apply_reg_command_file(struct registry_context *r, const char *cmd { int opt; poptContext pc; - const char *location; - const char *credentials = NULL; const char *patch; - const char *backend = "rpc"; struct registry_context *h; + const char *remote = NULL; WERROR error; struct poptOption long_options[] = { POPT_AUTOHELP - {"backend", 'b', POPT_ARG_STRING, &backend, 'b', "backend to use", NULL}, - {"credentials", 'c', POPT_ARG_STRING, &credentials, 'c', "credentials (user%password", NULL}, + POPT_COMMON_CREDENTIALS + {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL}, POPT_TABLEEND }; @@ -785,25 +783,22 @@ static int nt_apply_reg_command_file(struct registry_context *r, const char *cmd setup_logging(argv[0], True); - location = poptGetArg(pc); - if(!location) { - poptPrintUsage(pc, stderr, 0); - return 1; + if (remote) { + error = reg_open_remote (&h, cmdline_get_username(), cmdline_get_userpassword(), remote); + } else { + error = reg_open_local (&h); } - error = reg_open(&h, backend, location, credentials); - if(!h) { - fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location, backend); + if (W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error: %s\n", win_errstr(error)); return 1; } - + patch = poptGetArg(pc); if(!patch) patch = "/dev/stdin"; poptFreeContext(pc); nt_apply_reg_command_file(h, patch); - talloc_destroy(h->mem_ctx); - return 0; } diff --git a/source4/lib/registry/tools/regshell.c b/source4/lib/registry/tools/regshell.c index f18b012720..3fd9dab268 100644 --- a/source4/lib/registry/tools/regshell.c +++ b/source4/lib/registry/tools/regshell.c @@ -164,15 +164,23 @@ static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_key * static struct registry_key *cmd_hive(TALLOC_CTX *mem_ctx, struct registry_key *cur, int argc, char **argv) { - int i; - for(i = 0; i < cur->hive->reg_ctx->num_hives; i++) { + if (!cur->hive->reg_ctx) { + fprintf(stderr, "Only one hive loaded\n"); + return cur; + } - if(argc == 1) { - printf("%s\n", cur->hive->reg_ctx->hives[i]->name); - } else if(!strcmp(cur->hive->reg_ctx->hives[i]->name, argv[1])) { - return cur->hive->reg_ctx->hives[i]->root; - } + if (argc == 1) { + printf("%s\n", cur->hive->root->name); + } else { + struct registry_key *newroot; + WERROR error = reg_get_hive_by_name(cur->hive->reg_ctx, argv[1], &newroot); + if (W_ERROR_IS_OK(error)) { + return newroot; + } else { + fprintf(stderr, "Can't switch to hive %s: %s\n", cur->hive->root->name, win_errstr(error)); + } } + return NULL; } @@ -274,11 +282,7 @@ static char **reg_complete_command(const char *text, int end) matches[0] = strdup(matches[1]); break; default: - matches[0] = malloc(samelen+1); - if (!matches[0]) - goto cleanup; - strncpy(matches[0], matches[1], samelen); - matches[0][samelen] = 0; + matches[0] = strndup(matches[1], samelen); } matches[count] = NULL; return matches; @@ -295,11 +299,11 @@ cleanup: static char **reg_complete_key(const char *text, int end) { struct registry_key *subkey; - int i, j = 0; + int i, j = 1; + int samelen = 0; int len; char **matches; TALLOC_CTX *mem_ctx; - /* Complete argument */ matches = malloc_array_p(char *, MAX_COMPLETIONS); if (!matches) return NULL; @@ -313,6 +317,12 @@ static char **reg_complete_key(const char *text, int end) if(!strncmp(text, subkey->name, len)) { matches[j] = strdup(subkey->name); j++; + + if (j == 1) + samelen = strlen(matches[j]); + else + while (strncmp(matches[j], matches[j-1], samelen) != 0) + samelen--; } } else if(W_ERROR_EQUAL(status, WERR_NO_MORE_ITEMS)) { break; @@ -322,8 +332,20 @@ static char **reg_complete_key(const char *text, int end) return NULL; } } - matches[j] = NULL; talloc_destroy(mem_ctx); + + if (j == 1) { /* No matches at all */ + SAFE_FREE(matches); + return NULL; + } + + if (j == 2) { /* Exact match */ + matches[0] = strdup(matches[1]); + } else { + matches[0] = strndup(matches[1], samelen); + } + + matches[j] = NULL; return matches; } @@ -341,18 +363,18 @@ static char **reg_completion(const char *text, int start, int end) int main(int argc, char **argv) { int opt; - const char *backend = "rpc"; - const char *credentials = NULL; + const char *backend = NULL; struct registry_key *curkey = NULL; poptContext pc; WERROR error; TALLOC_CTX *mem_ctx = talloc_init("cmd"); - struct registry_context *h; + const char *remote = NULL; + struct registry_context *h = NULL; struct poptOption long_options[] = { POPT_AUTOHELP - POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL}, - {"credentials", 'c', POPT_ARG_STRING, &credentials, 0, "credentials", NULL}, + {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL}, POPT_TABLEEND }; @@ -370,20 +392,31 @@ static char **reg_completion(const char *text, int start, int end) setup_logging("regtree", True); - error = reg_open(&h, backend, poptPeekArg(pc), credentials); + if (remote) { + error = reg_open_remote (&h, cmdline_get_username(), cmdline_get_userpassword(), remote); + } else if (backend) { + error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, &curkey); + } else { + error = reg_open_local(&h); + } + if(!W_ERROR_IS_OK(error)) { - fprintf(stderr, "Unable to open '%s' with backend '%s'\n", poptGetArg(pc), backend); + fprintf(stderr, "Unable to open registry\n"); return 1; } - poptFreeContext(pc); - - curkey = h->hives[0]->root; + if (h) { + /*FIXME: What if HKEY_CLASSES_ROOT is not present ? */ + reg_get_hive(h, HKEY_CLASSES_ROOT, &curkey); + } + + poptFreeContext(pc); + while(True) { char *line, *prompt; - if(curkey->hive->name) { - asprintf(&prompt, "%s:%s> ", curkey->hive->name, curkey->path); + if(curkey->hive->root->name) { + asprintf(&prompt, "%s:%s> ", curkey->hive->root->name, curkey->path); } else { asprintf(&prompt, "%s> ", curkey->path); } diff --git a/source4/lib/registry/tools/regtree.c b/source4/lib/registry/tools/regtree.c index ced7a00f94..8ff68229eb 100644 --- a/source4/lib/registry/tools/regtree.c +++ b/source4/lib/registry/tools/regtree.c @@ -36,7 +36,7 @@ static void print_tree(int l, struct registry_key *p, int fullpath, int novals) /* Hive name */ if(p->hive->root == p) { - if(p->hive->name) printf("%s\n", p->hive->name); else printf("\n"); + if(p->hive->root->name) printf("%s\n", p->hive->root->name); else printf("\n"); } else { if(!p->name) printf("\n"); if(fullpath) printf("%s\n", p->path); @@ -73,17 +73,19 @@ 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 = "rpc"; - const char *credentials = NULL; + const char *backend = NULL; + const char *remote = NULL; poptContext pc; - struct registry_context *h; + struct registry_context *h = NULL; + struct registry_key *root = NULL; WERROR error; int fullpath = 0, no_values = 0; struct poptOption long_options[] = { POPT_AUTOHELP + POPT_COMMON_CREDENTIALS {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL}, {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL}, - {"credentials", 'c', POPT_ARG_STRING, &credentials, 0, "credentials (user%password)", NULL}, + {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL }, {"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL}, POPT_TABLEEND }; @@ -102,7 +104,14 @@ static void print_tree(int l, struct registry_key *p, int fullpath, int novals) setup_logging("regtree", True); - error = reg_open(&h, backend, poptPeekArg(pc), credentials); + if (remote) { + error = reg_open_remote(&h, cmdline_get_username(), cmdline_get_userpassword(), remote); + } else if (backend) { + error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, &root); + } else { + error = reg_open_local (&h); + } + 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; @@ -110,10 +119,19 @@ static void print_tree(int l, struct registry_key *p, int fullpath, int novals) poptFreeContext(pc); error = WERR_OK; - - for(i = 0; i < h->num_hives; i++) { - print_tree(0, h->hives[i]->root, fullpath, no_values); - } + if (!h) { + print_tree(0, root, fullpath, no_values); + } else { + for(i = HKEY_CLASSES_ROOT; i < HKEY_PN; i++) { + error = reg_get_hive(h, i, &root); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Skipping %s\n", reg_get_hkey_name(i)); + continue; + } + print_tree(0, root, fullpath, no_values); + } + } + return 0; } -- cgit