diff options
Diffstat (limited to 'source4/lib/registry')
37 files changed, 14901 insertions, 0 deletions
diff --git a/source4/lib/registry/Doxyfile b/source4/lib/registry/Doxyfile new file mode 100644 index 0000000000..efc01cd355 --- /dev/null +++ b/source4/lib/registry/Doxyfile @@ -0,0 +1,24 @@ +PROJECT_NAME = REGISTRY +OUTPUT_DIRECTORY = apidocs +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +OPTIMIZE_OUTPUT_FOR_C = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +GENERATE_TODOLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +SHOW_USED_FILES = NO +SHOW_DIRECTORIES = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +INPUT = . +FILE_PATTERNS = *.c *.h *.dox +GENERATE_HTML = YES +HTML_OUTPUT = html +GENERATE_MAN = YES +ALWAYS_DETAILED_SEC = YES +JAVADOC_AUTOBRIEF = YES diff --git a/source4/lib/registry/README b/source4/lib/registry/README new file mode 100644 index 0000000000..07b2c01684 --- /dev/null +++ b/source4/lib/registry/README @@ -0,0 +1,42 @@ +This is the registry library. The registry is basically a bunch of +hives, each of which is loaded from a file. When using a local registry, +it is possible to specify where hives should be loaded from, etc. + +There are separate APIs for accessing the data in a hive and the +data in the registry itself. Each supports different backends. + +The following "full registry" backends are currently provided: + + * Remote (over DCE/RPC) + * Local (allows "mounting" hives) + * Wine (uses the wine plain-text file) + +The following hive backends are supported: + + - ldb + - regf (NTUSER.DAT-style files) + - rpc (Remote individual hives) + - directory + +reg_open_samba() loads a set of hives based on smb.conf settings. +Lines in smb.conf should have the following syntax: + +registry:<hivename> = <backend>:<location> + +So an example usage could be: + +registry:HKEY_CURRENT_USER = regf:NTUSER.DAT +registry:HKEY_LOCAL_MACHINE = ldb:tdb://registry.tdb + +WERR_NOT_SUPPORTED will be returned for all hives that haven't been set. + +On Windows the various registry hives are loaded from: + +HKEY_CURRENT_CONFIG: %SystemRoot%\System32\Config\System +HKEY_CURRENT_USER: %Profile%\NTUser.dat +HKEY_LOCAL_MACHINE\SAM: %SystemRoot%\System32\Config\Sam +HKEY_LOCAL_MACHINE\Security: %SystemRoot%\System32\Config\Security +HKEY_LOCAL_MACHINE\Software: %SystemRoot%\System32\Config\Software +HKEY_LOCAL_MACHINE\System: %SystemRoot%\System32\Config\System +HKEY_USERS\.DEFAULT: %SystemRoot%\System32\Config\Default +HKEY_LOCAL_MACHINE\HARDWARE: is autogenerated diff --git a/source4/lib/registry/TODO b/source4/lib/registry/TODO new file mode 100644 index 0000000000..b5809b84ed --- /dev/null +++ b/source4/lib/registry/TODO @@ -0,0 +1,5 @@ +- ..\..\, \bla\blie support in regshell +- finish rpc_server + +regshell: + - support for security descriptors diff --git a/source4/lib/registry/config.mk b/source4/lib/registry/config.mk new file mode 100644 index 0000000000..fd1fd01a09 --- /dev/null +++ b/source4/lib/registry/config.mk @@ -0,0 +1,114 @@ +[SUBSYSTEM::TDR_REGF] +PUBLIC_DEPENDENCIES = TDR + +TDR_REGF_OBJ_FILES = $(libregistrysrcdir)/tdr_regf.o + +# Special support for external builddirs +$(libregistrysrcdir)/regf.c: $(libregistrysrcdir)/tdr_regf.c +$(libregistrysrcdir)/tdr_regf.h: $(libregistrysrcdir)/tdr_regf.c +$(libregistrysrcdir)/tdr_regf.c: $(libregistrysrcdir)/regf.idl + @CPP="$(CPP)" $(PERL) $(pidldir)/pidl $(PIDL_ARGS) \ + --header --outputdir=$(libregistrysrcdir) \ + --tdr-parser -- $(libregistrysrcdir)/regf.idl + +clean:: + @-rm -f $(libregistrysrcdir)/regf.h $(libregistrysrcdir)/tdr_regf* + +################################################ +# Start SUBSYSTEM registry +[LIBRARY::registry] +PUBLIC_DEPENDENCIES = \ + LIBSAMBA-UTIL CHARSET TDR_REGF LIBLDB \ + RPC_NDR_WINREG LDB_WRAP +# End MODULE registry_ldb +################################################ + +PC_FILES += $(libregistrysrcdir)/registry.pc + +registry_VERSION = 0.0.1 +registry_SOVERSION = 0 + +registry_OBJ_FILES = $(addprefix $(libregistrysrcdir)/, interface.o util.o samba.o \ + patchfile_dotreg.o patchfile_preg.o patchfile.o regf.o \ + hive.o local.o ldb.o dir.o rpc.o) + +PUBLIC_HEADERS += $(libregistrysrcdir)/registry.h + +[SUBSYSTEM::registry_common] +PUBLIC_DEPENDENCIES = registry + +registry_common_OBJ_FILES = $(libregistrysrcdir)/tools/common.o + +$(eval $(call proto_header_template,$(libregistrysrcdir)/tools/common.h,$(registry_common_OBJ_FILES:.o=.c))) + +################################################ +# Start BINARY regdiff +[BINARY::regdiff] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS +# End BINARY regdiff +################################################ + +regdiff_OBJ_FILES = $(libregistrysrcdir)/tools/regdiff.o + +MANPAGES += $(libregistrysrcdir)/man/regdiff.1 + +################################################ +# Start BINARY regpatch +[BINARY::regpatch] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS \ + registry_common +# End BINARY regpatch +################################################ + +regpatch_OBJ_FILES = $(libregistrysrcdir)/tools/regpatch.o + +MANPAGES += $(libregistrysrcdir)/man/regpatch.1 + +################################################ +# Start BINARY regshell +[BINARY::regshell] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \ + SMBREADLINE registry_common +# End BINARY regshell +################################################ + +regshell_OBJ_FILES = $(libregistrysrcdir)/tools/regshell.o + +MANPAGES += $(libregistrysrcdir)/man/regshell.1 + +################################################ +# Start BINARY regtree +[BINARY::regtree] +INSTALLDIR = BINDIR +PRIVATE_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \ + registry_common +# End BINARY regtree +################################################ + +regtree_OBJ_FILES = $(libregistrysrcdir)/tools/regtree.o + +MANPAGES += $(libregistrysrcdir)/man/regtree.1 + +[SUBSYSTEM::torture_registry] +PRIVATE_DEPENDENCIES = registry + +torture_registry_OBJ_FILES = $(addprefix $(libregistrysrcdir)/tests/, generic.o hive.o diff.o registry.o) + +$(eval $(call proto_header_template,$(libregistrysrcdir)/tests/proto.h,$(torture_registry_OBJ_FILES:.o=.c))) + +[PYTHON::swig_registry] +LIBRARY_REALNAME = samba/_registry.$(SHLIBEXT) +PUBLIC_DEPENDENCIES = registry + +swig_registry_OBJ_FILES = $(libregistrysrcdir)/registry_wrap.o + +$(eval $(call python_py_module_template,samba/registry.py,lib/registry/registry.py)) + +$(swig_registry_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) diff --git a/source4/lib/registry/dir.c b/source4/lib/registry/dir.c new file mode 100644 index 0000000000..449ee0f6ee --- /dev/null +++ b/source4/lib/registry/dir.c @@ -0,0 +1,409 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "registry.h" +#include "system/dir.h" +#include "system/filesys.h" + +struct dir_key { + struct hive_key key; + const char *path; +}; + +static struct hive_operations reg_backend_dir; + +static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, + const struct hive_key *parent, + const char *name, const char *classname, + struct security_descriptor *desc, + struct hive_key **result) +{ + struct dir_key *dk = talloc_get_type(parent, struct dir_key); + char *path; + int ret; + + path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name); + ret = mkdir(path, 0700); + if (ret == 0) { + struct dir_key *key = talloc(mem_ctx, struct dir_key); + key->key.ops = ®_backend_dir; + key->path = talloc_steal(key, path); + *result = (struct hive_key *)key; + return WERR_OK; + } + + if (errno == EEXIST) + return WERR_ALREADY_EXISTS; + printf("FAILED %s BECAUSE: %s\n", path, strerror(errno)); + return WERR_GENERAL_FAILURE; +} + +static WERROR reg_dir_delete_recursive(const char *name) +{ + DIR *d; + struct dirent *e; + WERROR werr; + + d = opendir(name); + if (d == NULL) { + DEBUG(3,("Unable to open '%s': %s\n", name, + strerror(errno))); + return WERR_BADFILE; + } + + while((e = readdir(d))) { + char *path; + struct stat stbuf; + + if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) + continue; + + path = talloc_asprintf(name, "%s/%s", name, e->d_name); + if (!path) + return WERR_NOMEM; + + stat(path, &stbuf); + + if (!S_ISDIR(stbuf.st_mode)) { + if (unlink(path) < 0) { + talloc_free(path); + closedir(d); + return WERR_GENERAL_FAILURE; + } + } else { + werr = reg_dir_delete_recursive(path); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(path); + closedir(d); + return werr; + } + } + + talloc_free(path); + } + closedir(d); + + if (rmdir(name) == 0) + return WERR_OK; + else if (errno == ENOENT) + return WERR_BADFILE; + else + return WERR_GENERAL_FAILURE; +} + +static WERROR reg_dir_del_key(const struct hive_key *k, const char *name) +{ + struct dir_key *dk = talloc_get_type(k, struct dir_key); + char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name); + WERROR ret; + + ret = reg_dir_delete_recursive(child); + + talloc_free(child); + + return ret; +} + +static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, + const struct hive_key *parent, + const char *name, struct hive_key **subkey) +{ + DIR *d; + char *fullpath; + const struct dir_key *p = talloc_get_type(parent, struct dir_key); + struct dir_key *ret; + + if (name == NULL) { + DEBUG(0, ("NULL pointer passed as directory name!")); + return WERR_INVALID_PARAM; + } + + fullpath = talloc_asprintf(mem_ctx, "%s/%s", p->path, name); + + d = opendir(fullpath); + if (d == NULL) { + DEBUG(3,("Unable to open '%s': %s\n", fullpath, + strerror(errno))); + return WERR_BADFILE; + } + closedir(d); + ret = talloc(mem_ctx, struct dir_key); + ret->key.ops = ®_backend_dir; + ret->path = talloc_steal(ret, fullpath); + *subkey = (struct hive_key *)ret; + return WERR_OK; +} + +static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, + const struct hive_key *k, uint32_t idx, + const char **name, + const char **classname, + NTTIME *last_mod_time) +{ + struct dirent *e; + const struct dir_key *dk = talloc_get_type(k, struct dir_key); + int i = 0; + DIR *d; + + d = opendir(dk->path); + + if (d == NULL) + return WERR_INVALID_PARAM; + + while((e = readdir(d))) { + if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) { + struct stat stbuf; + char *thispath; + + /* Check if file is a directory */ + asprintf(&thispath, "%s/%s", dk->path, e->d_name); + stat(thispath, &stbuf); + + if (!S_ISDIR(stbuf.st_mode)) { + SAFE_FREE(thispath); + continue; + } + + if (i == idx) { + struct stat st; + *name = talloc_strdup(mem_ctx, e->d_name); + *classname = NULL; + stat(thispath, &st); + unix_to_nt_time(last_mod_time, st.st_mtime); + SAFE_FREE(thispath); + closedir(d); + return WERR_OK; + } + i++; + + SAFE_FREE(thispath); + } + } + + closedir(d); + + return WERR_NO_MORE_ITEMS; +} + +WERROR reg_open_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key) +{ + struct dir_key *dk; + + if (location == NULL) + return WERR_INVALID_PARAM; + + dk = talloc(parent_ctx, struct dir_key); + dk->key.ops = ®_backend_dir; + dk->path = talloc_strdup(dk, location); + *key = (struct hive_key *)dk; + return WERR_OK; +} + +WERROR reg_create_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key) +{ + if (mkdir(location, 0700) != 0) { + *key = NULL; + return WERR_GENERAL_FAILURE; + } + + return reg_open_directory(parent_ctx, location, key); +} + +static WERROR reg_dir_get_info(TALLOC_CTX *ctx, const struct hive_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *lastmod, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + DIR *d; + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + struct dirent *e; + struct stat st; + + SMB_ASSERT(key != NULL); + + if (classname != NULL) + *classname = NULL; + + d = opendir(dk->path); + if (d == NULL) + return WERR_INVALID_PARAM; + + if (num_subkeys != NULL) + *num_subkeys = 0; + + if (num_values != NULL) + *num_values = 0; + + if (max_subkeynamelen != NULL) + *max_subkeynamelen = 0; + + if (max_valnamelen != NULL) + *max_valnamelen = 0; + + if (max_valbufsize != NULL) + *max_valbufsize = 0; + + while((e = readdir(d))) { + if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) { + char *path = talloc_asprintf(ctx, "%s/%s", + dk->path, e->d_name); + + if (stat(path, &st) < 0) { + DEBUG(0, ("Error statting %s: %s\n", path, + strerror(errno))); + continue; + } + + if (S_ISDIR(st.st_mode)) { + if (num_subkeys != NULL) + (*num_subkeys)++; + if (max_subkeynamelen != NULL) + *max_subkeynamelen = MAX(*max_subkeynamelen, strlen(e->d_name)); + } + + if (!S_ISDIR(st.st_mode)) { + if (num_values != NULL) + (*num_values)++; + if (max_valnamelen != NULL) + *max_valnamelen = MAX(*max_valnamelen, strlen(e->d_name)); + if (max_valbufsize != NULL) + *max_valbufsize = MAX(*max_valbufsize, st.st_size); + } + + talloc_free(path); + } + } + + closedir(d); + + if (lastmod != NULL) + *lastmod = 0; + return WERR_OK; +} + +static WERROR reg_dir_set_value(struct hive_key *key, const char *name, + uint32_t type, const DATA_BLOB data) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + char *path = talloc_asprintf(dk, "%s/%s", dk->path, name); + + if (!file_save(path, data.data, data.length)) + return WERR_GENERAL_FAILURE; + + /* FIXME: Type */ + + return WERR_OK; +} + +static WERROR reg_dir_get_value(TALLOC_CTX *mem_ctx, + struct hive_key *key, const char *name, + uint32_t *type, DATA_BLOB *data) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + char *path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name); + size_t size; + char *contents; + + contents = file_load(path, &size, mem_ctx); + talloc_free(path); + if (contents == NULL) + return WERR_BADFILE; + + if (type != NULL) + *type = 4; /* FIXME */ + + data->data = (uint8_t *)contents; + data->length = size; + + return WERR_OK; +} + +static WERROR reg_dir_enum_value(TALLOC_CTX *mem_ctx, + struct hive_key *key, int idx, + const char **name, + uint32_t *type, DATA_BLOB *data) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + DIR *d; + struct dirent *e; + int i; + + d = opendir(dk->path); + if (d == NULL) { + DEBUG(3,("Unable to open '%s': %s\n", dk->path, + strerror(errno))); + return WERR_BADFILE; + } + + i = 0; + while((e = readdir(d))) { + if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) + continue; + + if (i == idx) { + if (name != NULL) + *name = talloc_strdup(mem_ctx, e->d_name); + W_ERROR_NOT_OK_RETURN(reg_dir_get_value(mem_ctx, key, + *name, type, + data)); + return WERR_OK; + } + + i++; + } + closedir(d); + + return WERR_NO_MORE_ITEMS; +} + + +static WERROR reg_dir_del_value (struct hive_key *key, const char *name) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + char *path = talloc_asprintf(key, "%s/%s", dk->path, name); + if (unlink(path) < 0) { + talloc_free(path); + if (errno == ENOENT) + return WERR_BADFILE; + return WERR_GENERAL_FAILURE; + } + talloc_free(path); + + return WERR_OK; +} + +static struct hive_operations reg_backend_dir = { + .name = "dir", + .get_key_by_name = reg_dir_open_key, + .get_key_info = reg_dir_get_info, + .add_key = reg_dir_add_key, + .del_key = reg_dir_del_key, + .enum_key = reg_dir_key_by_index, + .set_value = reg_dir_set_value, + .get_value_by_name = reg_dir_get_value, + .enum_value = reg_dir_enum_value, + .delete_value = reg_dir_del_value, +}; diff --git a/source4/lib/registry/hive.c b/source4/lib/registry/hive.c new file mode 100644 index 0000000000..5105040f30 --- /dev/null +++ b/source4/lib/registry/hive.c @@ -0,0 +1,180 @@ + +/* + Unix SMB/CIFS implementation. + Registry hive interface + Copyright (C) Jelmer Vernooij 2003-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "registry.h" +#include "system/filesys.h" +#include "param/param.h" + +/** Open a registry file/host/etc */ +_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct hive_key **root) +{ + int fd, num; + char peek[20]; + + /* Check for directory */ + if (directory_exist(location)) { + return reg_open_directory(parent_ctx, location, root); + } + + fd = open(location, O_RDWR); + if (fd == -1) { + if (errno == ENOENT) + return WERR_BADFILE; + return WERR_BADFILE; + } + + num = read(fd, peek, 20); + if (num == -1) { + return WERR_BADFILE; + } + + if (!strncmp(peek, "regf", 4)) { + close(fd); + return reg_open_regf_file(parent_ctx, location, lp_iconv_convenience(lp_ctx), root); + } else if (!strncmp(peek, "TDB file", 8)) { + close(fd); + return reg_open_ldb_file(parent_ctx, location, session_info, + credentials, ev_ctx, lp_ctx, root); + } + + return WERR_BADFILE; +} + +_PUBLIC_ WERROR hive_key_get_info(TALLOC_CTX *mem_ctx, + const struct hive_key *key, + const char **classname, uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + return key->ops->get_key_info(mem_ctx, key, classname, num_subkeys, + num_values, last_change_time, + max_subkeynamelen, + max_valnamelen, max_valbufsize); +} + +_PUBLIC_ WERROR hive_key_add_name(TALLOC_CTX *ctx, + const struct hive_key *parent_key, + const char *name, const char *classname, + struct security_descriptor *desc, + struct hive_key **key) +{ + SMB_ASSERT(strchr(name, '\\') == NULL); + + return parent_key->ops->add_key(ctx, parent_key, name, classname, + desc, key); +} + +_PUBLIC_ WERROR hive_key_del(const struct hive_key *key, const char *name) +{ + return key->ops->del_key(key, name); +} + +_PUBLIC_ WERROR hive_get_key_by_name(TALLOC_CTX *mem_ctx, + const struct hive_key *key, + const char *name, + struct hive_key **subkey) +{ + return key->ops->get_key_by_name(mem_ctx, key, name, subkey); +} + +WERROR hive_enum_key(TALLOC_CTX *mem_ctx, + const struct hive_key *key, uint32_t idx, + const char **name, + const char **classname, + NTTIME *last_mod_time) +{ + return key->ops->enum_key(mem_ctx, key, idx, name, classname, + last_mod_time); +} + +WERROR hive_key_set_value(struct hive_key *key, const char *name, uint32_t type, + const DATA_BLOB data) +{ + if (key->ops->set_value == NULL) + return WERR_NOT_SUPPORTED; + + return key->ops->set_value(key, name, type, data); +} + +WERROR hive_get_value(TALLOC_CTX *mem_ctx, + struct hive_key *key, const char *name, + uint32_t *type, DATA_BLOB *data) +{ + if (key->ops->get_value_by_name == NULL) + return WERR_NOT_SUPPORTED; + + return key->ops->get_value_by_name(mem_ctx, key, name, type, data); +} + +WERROR hive_get_value_by_index(TALLOC_CTX *mem_ctx, + struct hive_key *key, uint32_t idx, + const char **name, + uint32_t *type, DATA_BLOB *data) +{ + if (key->ops->enum_value == NULL) + return WERR_NOT_SUPPORTED; + + return key->ops->enum_value(mem_ctx, key, idx, name, type, data); +} + +WERROR hive_get_sec_desc(TALLOC_CTX *mem_ctx, + struct hive_key *key, + struct security_descriptor **security) +{ + if (key->ops->get_sec_desc == NULL) + return WERR_NOT_SUPPORTED; + + return key->ops->get_sec_desc(mem_ctx, key, security); +} + +WERROR hive_set_sec_desc(struct hive_key *key, + const struct security_descriptor *security) +{ + if (key->ops->set_sec_desc == NULL) + return WERR_NOT_SUPPORTED; + + return key->ops->set_sec_desc(key, security); +} + +WERROR hive_key_del_value(struct hive_key *key, const char *name) +{ + if (key->ops->delete_value == NULL) + return WERR_NOT_SUPPORTED; + + return key->ops->delete_value(key, name); +} + +WERROR hive_key_flush(struct hive_key *key) +{ + if (key->ops->flush_key == NULL) + return WERR_OK; + + return key->ops->flush_key(key); +} diff --git a/source4/lib/registry/interface.c b/source4/lib/registry/interface.c new file mode 100644 index 0000000000..c9b3b06447 --- /dev/null +++ b/source4/lib/registry/interface.c @@ -0,0 +1,295 @@ +/* + Unix SMB/CIFS implementation. + Transparent registry backend handling + Copyright (C) Jelmer Vernooij 2003-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/util/dlinklist.h" +#include "lib/registry/registry.h" +#include "system/filesys.h" + + +/** + * @file + * @brief Main registry functions + */ + +const struct reg_predefined_key reg_predefined_keys[] = { + {HKEY_CLASSES_ROOT,"HKEY_CLASSES_ROOT" }, + {HKEY_CURRENT_USER,"HKEY_CURRENT_USER" }, + {HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" }, + {HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA" }, + {HKEY_USERS, "HKEY_USERS" }, + {HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" }, + {HKEY_DYN_DATA, "HKEY_DYN_DATA" }, + {HKEY_PERFORMANCE_TEXT, "HKEY_PERFORMANCE_TEXT" }, + {HKEY_PERFORMANCE_NLSTEXT, "HKEY_PERFORMANCE_NLSTEXT" }, + { 0, NULL } +}; + +/** Obtain name of specific hkey. */ +_PUBLIC_ const char *reg_get_predef_name(uint32_t hkey) +{ + int i; + for (i = 0; reg_predefined_keys[i].name; i++) { + if (reg_predefined_keys[i].handle == hkey) + return reg_predefined_keys[i].name; + } + + return NULL; +} + +/** Get predefined key by name. */ +_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, + const char *name, + struct registry_key **key) +{ + int i; + + for (i = 0; reg_predefined_keys[i].name; i++) { + if (!strcasecmp(reg_predefined_keys[i].name, name)) + return reg_get_predefined_key(ctx, + reg_predefined_keys[i].handle, + key); + } + + DEBUG(1, ("No predefined key with name '%s'\n", name)); + + return WERR_BADFILE; +} + +/** Get predefined key by id. */ +_PUBLIC_ WERROR reg_get_predefined_key(struct registry_context *ctx, + uint32_t hkey, struct registry_key **key) +{ + return ctx->ops->get_predefined_key(ctx, hkey, key); +} + +/** + * Open a key + * First tries to use the open_key function from the backend + * then falls back to get_subkey_by_name and later get_subkey_by_index + */ +_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, + const char *name, struct registry_key **result) +{ + if (parent == NULL) { + DEBUG(0, ("Invalid parent key specified for open of '%s'\n", + name)); + return WERR_INVALID_PARAM; + } + + if (parent->context->ops->open_key == NULL) { + DEBUG(0, ("Registry backend doesn't have open_key!\n")); + return WERR_NOT_SUPPORTED; + } + + return parent->context->ops->open_key(mem_ctx, parent, name, result); +} + +/** + * Get value by index + */ +_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + uint32_t idx, const char **name, + uint32_t *type, DATA_BLOB *data) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->enum_value == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->enum_value(mem_ctx, key, idx, name, + type, data); +} + +/** + * Get the number of subkeys. + */ +_PUBLIC_ WERROR reg_key_get_info(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->get_key_info == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->get_key_info(mem_ctx, + key, classname, num_subkeys, + num_values, last_change_time, + max_subkeynamelen, + max_valnamelen, max_valbufsize); +} + +/** + * Get subkey by index. + */ +_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + int idx, const char **name, + const char **keyclass, + NTTIME *last_changed_time) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->enum_key == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->enum_key(mem_ctx, key, idx, name, + keyclass, last_changed_time); +} + +/** + * Get value by name. + */ +_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char *name, + uint32_t *type, + DATA_BLOB *data) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->get_value == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->get_value(mem_ctx, key, name, type, data); +} + +/** + * Delete a key. + */ +_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name) +{ + if (parent == NULL) + return WERR_INVALID_PARAM; + + if (parent->context->ops->delete_key == NULL) + return WERR_NOT_SUPPORTED; + + return parent->context->ops->delete_key(parent, name); +} + +/** + * Add a key. + */ +_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, + struct registry_key *parent, + const char *name, const char *key_class, + struct security_descriptor *desc, + struct registry_key **newkey) +{ + if (parent == NULL) + return WERR_INVALID_PARAM; + + if (parent->context->ops->create_key == NULL) { + DEBUG(1, ("Backend '%s' doesn't support method add_key\n", + parent->context->ops->name)); + return WERR_NOT_SUPPORTED; + } + + return parent->context->ops->create_key(mem_ctx, parent, name, + key_class, desc, newkey); +} + +/** + * Set a value. + */ +_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, + uint32_t type, const DATA_BLOB data) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + /* A 'real' set function has preference */ + if (key->context->ops->set_value == NULL) { + DEBUG(1, ("Backend '%s' doesn't support method set_value\n", + key->context->ops->name)); + return WERR_NOT_SUPPORTED; + } + + return key->context->ops->set_value(key, value, type, data); +} + +/** + * Get the security descriptor on a key. + */ +_PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, + const struct registry_key *key, + struct security_descriptor **secdesc) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + /* A 'real' set function has preference */ + if (key->context->ops->get_sec_desc == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->get_sec_desc(ctx, key, secdesc); +} + +/** + * Delete a value. + */ +_PUBLIC_ WERROR reg_del_value(struct registry_key *key, const char *valname) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->delete_value == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->delete_value(key, valname); +} + +/** + * Flush a key to disk. + */ +_PUBLIC_ WERROR reg_key_flush(struct registry_key *key) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->flush_key == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->flush_key(key); +} + +_PUBLIC_ WERROR reg_set_sec_desc(struct registry_key *key, + const struct security_descriptor *security) +{ + if (key == NULL) + return WERR_INVALID_PARAM; + + if (key->context->ops->set_sec_desc == NULL) + return WERR_NOT_SUPPORTED; + + return key->context->ops->set_sec_desc(key, security); +} diff --git a/source4/lib/registry/ldb.c b/source4/lib/registry/ldb.c new file mode 100644 index 0000000000..a8a9ed597e --- /dev/null +++ b/source4/lib/registry/ldb.c @@ -0,0 +1,726 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "registry.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "ldb_wrap.h" +#include "librpc/gen_ndr/winreg.h" +#include "param/param.h" + +static struct hive_operations reg_backend_ldb; + +struct ldb_key_data +{ + struct hive_key key; + struct ldb_context *ldb; + struct ldb_dn *dn; + struct ldb_message **subkeys, **values; + int subkey_count, value_count; +}; + +static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + struct ldb_message *msg, + const char **name, uint32_t *type, + DATA_BLOB *data) +{ + const struct ldb_val *val; + uint32_t value_type; + + if (name != NULL) + *name = talloc_strdup(mem_ctx, + ldb_msg_find_attr_as_string(msg, "value", + NULL)); + + value_type = ldb_msg_find_attr_as_uint(msg, "type", 0); + if (type != NULL) + *type = value_type; + val = ldb_msg_find_ldb_val(msg, "data"); + + switch (value_type) + { + case REG_SZ: + case REG_EXPAND_SZ: + data->length = convert_string_talloc(mem_ctx, iconv_convenience, CH_UTF8, CH_UTF16, + val->data, val->length, + (void **)&data->data); + break; + + case REG_DWORD: { + uint32_t tmp = strtoul((char *)val->data, NULL, 0); + *data = data_blob_talloc(mem_ctx, &tmp, 4); + } + break; + + default: + *data = data_blob_talloc(mem_ctx, val->data, val->length); + break; + } +} + +static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx, + TALLOC_CTX *mem_ctx, + const char *name, + uint32_t type, DATA_BLOB data) +{ + struct ldb_val val; + struct ldb_message *msg = talloc_zero(mem_ctx, struct ldb_message); + char *type_s; + + ldb_msg_add_string(msg, "value", talloc_strdup(mem_ctx, name)); + + switch (type) { + case REG_SZ: + case REG_EXPAND_SZ: + val.length = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, + (void *)data.data, + data.length, + (void **)&val.data); + ldb_msg_add_value(msg, "data", &val, NULL); + break; + + case REG_DWORD: + ldb_msg_add_string(msg, "data", + talloc_asprintf(mem_ctx, "0x%x", + IVAL(data.data, 0))); + break; + default: + ldb_msg_add_value(msg, "data", &data, NULL); + } + + + type_s = talloc_asprintf(mem_ctx, "%u", type); + ldb_msg_add_string(msg, "type", type_s); + + return msg; +} + +static char *reg_ldb_escape(TALLOC_CTX *mem_ctx, const char *value) +{ + struct ldb_val val; + + val.data = discard_const_p(uint8_t, value); + val.length = strlen(value); + + return ldb_dn_escape_value(mem_ctx, val); +} + +static int reg_close_ldb_key(struct ldb_key_data *key) +{ + if (key->subkeys != NULL) { + talloc_free(key->subkeys); + key->subkeys = NULL; + } + + if (key->values != NULL) { + talloc_free(key->values); + key->values = NULL; + } + return 0; +} + +static struct ldb_dn *reg_path_to_ldb(TALLOC_CTX *mem_ctx, + const struct hive_key *from, + const char *path, const char *add) +{ + TALLOC_CTX *local_ctx; + struct ldb_dn *ret; + char *mypath = talloc_strdup(mem_ctx, path); + char *begin; + struct ldb_key_data *kd = talloc_get_type(from, struct ldb_key_data); + struct ldb_context *ldb = kd->ldb; + + local_ctx = talloc_new(mem_ctx); + + if (add) { + ret = ldb_dn_new(mem_ctx, ldb, add); + } else { + ret = ldb_dn_new(mem_ctx, ldb, NULL); + } + if (!ldb_dn_validate(ret)) { + talloc_free(ret); + talloc_free(local_ctx); + return NULL; + } + + while (mypath) { + char *keyname; + + begin = strrchr(mypath, '\\'); + + if (begin) keyname = begin + 1; + else keyname = mypath; + + if(strlen(keyname)) { + if (!ldb_dn_add_base_fmt(ret, "key=%s", + reg_ldb_escape(local_ctx, + keyname))) + { + talloc_free(local_ctx); + return NULL; + } + } + + if(begin) { + *begin = '\0'; + } else { + break; + } + } + + ldb_dn_add_base(ret, kd->dn); + + talloc_free(local_ctx); + + return ret; +} + +static WERROR cache_subkeys(struct ldb_key_data *kd) +{ + struct ldb_context *c = kd->ldb; + struct ldb_result *res; + int ret; + + ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(key=*)", NULL, &res); + + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Error getting subkeys for '%s': %s\n", + ldb_dn_get_linearized(kd->dn), ldb_errstring(c))); + return WERR_FOOBAR; + } + + kd->subkey_count = res->count; + kd->subkeys = talloc_steal(kd, res->msgs); + talloc_free(res); + + return WERR_OK; +} + +static WERROR cache_values(struct ldb_key_data *kd) +{ + struct ldb_context *c = kd->ldb; + struct ldb_result *res; + int ret; + + ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, + "(value=*)", NULL, &res); + + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Error getting values for '%s': %s\n", + ldb_dn_get_linearized(kd->dn), ldb_errstring(c))); + return WERR_FOOBAR; + } + kd->value_count = res->count; + kd->values = talloc_steal(kd, res->msgs); + talloc_free(res); + return WERR_OK; +} + + +static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx, + const struct hive_key *k, uint32_t idx, + const char **name, + const char **classname, + NTTIME *last_mod_time) +{ + struct ldb_message_element *el; + struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data); + + /* Do a search if necessary */ + if (kd->subkeys == NULL) { + W_ERROR_NOT_OK_RETURN(cache_subkeys(kd)); + } + + if (idx >= kd->subkey_count) + return WERR_NO_MORE_ITEMS; + + el = ldb_msg_find_element(kd->subkeys[idx], "key"); + SMB_ASSERT(el != NULL); + SMB_ASSERT(el->num_values != 0); + + if (name != NULL) + *name = talloc_strdup(mem_ctx, (char *)el->values[0].data); + + if (classname != NULL) + *classname = NULL; /* TODO: Store properly */ + + if (last_mod_time != NULL) + *last_mod_time = 0; /* TODO: we need to add this to the + ldb backend properly */ + + return WERR_OK; +} + +static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, struct hive_key *k, + int idx, const char **name, + uint32_t *data_type, DATA_BLOB *data) +{ + struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data); + + /* Do the search if necessary */ + if (kd->values == NULL) { + W_ERROR_NOT_OK_RETURN(cache_values(kd)); + } + + if (idx >= kd->value_count) + return WERR_NO_MORE_ITEMS; + + reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm), kd->values[idx], + name, data_type, data); + + return WERR_OK; +} + +static WERROR ldb_get_value(TALLOC_CTX *mem_ctx, struct hive_key *k, + const char *name, uint32_t *data_type, + DATA_BLOB *data) +{ + struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data); + struct ldb_context *c = kd->ldb; + struct ldb_result *res; + int ret; + char *query = talloc_asprintf(mem_ctx, "(value=%s)", name); + + ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, query, NULL, &res); + + talloc_free(query); + + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Error getting values for '%s': %s\n", + ldb_dn_get_linearized(kd->dn), ldb_errstring(c))); + return WERR_FOOBAR; + } + + if (res->count == 0) + return WERR_BADFILE; + + reg_ldb_unpack_value(mem_ctx, lp_iconv_convenience(global_loadparm), res->msgs[0], NULL, data_type, data); + + return WERR_OK; +} + +static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, const struct hive_key *h, + const char *name, struct hive_key **key) +{ + struct ldb_result *res; + struct ldb_dn *ldap_path; + int ret; + struct ldb_key_data *newkd; + struct ldb_key_data *kd = talloc_get_type(h, struct ldb_key_data); + struct ldb_context *c = kd->ldb; + + ldap_path = reg_path_to_ldb(mem_ctx, h, name, NULL); + + ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL, &res); + + if (ret != LDB_SUCCESS) { + DEBUG(3, ("Error opening key '%s': %s\n", + ldb_dn_get_linearized(ldap_path), ldb_errstring(c))); + return WERR_FOOBAR; + } else if (res->count == 0) { + DEBUG(3, ("Key '%s' not found\n", + ldb_dn_get_linearized(ldap_path))); + talloc_free(res); + return WERR_BADFILE; + } + + newkd = talloc_zero(mem_ctx, struct ldb_key_data); + newkd->key.ops = ®_backend_ldb; + newkd->ldb = talloc_reference(newkd, kd->ldb); + newkd->dn = ldb_dn_copy(mem_ctx, res->msgs[0]->dn); + + *key = (struct hive_key *)newkd; + + talloc_free(res); + + return WERR_OK; +} + +WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct hive_key **k) +{ + struct ldb_key_data *kd; + struct ldb_context *wrap; + struct ldb_message *attrs_msg; + + if (location == NULL) + return WERR_INVALID_PARAM; + + wrap = ldb_wrap_connect(parent_ctx, ev_ctx, lp_ctx, + location, session_info, credentials, 0, NULL); + + if (wrap == NULL) { + DEBUG(1, (__FILE__": unable to connect\n")); + return WERR_FOOBAR; + } + + attrs_msg = ldb_msg_new(wrap); + W_ERROR_HAVE_NO_MEMORY(attrs_msg); + attrs_msg->dn = ldb_dn_new(attrs_msg, wrap, "@ATTRIBUTES"); + W_ERROR_HAVE_NO_MEMORY(attrs_msg->dn); + ldb_msg_add_string(attrs_msg, "key", "CASE_INSENSITIVE"); + ldb_msg_add_string(attrs_msg, "value", "CASE_INSENSITIVE"); + + ldb_add(wrap, attrs_msg); + + ldb_set_debug_stderr(wrap); + + kd = talloc_zero(parent_ctx, struct ldb_key_data); + kd->key.ops = ®_backend_ldb; + kd->ldb = talloc_reference(kd, wrap); + talloc_set_destructor (kd, reg_close_ldb_key); + kd->dn = ldb_dn_new(kd, wrap, "hive=NONE"); + + *k = (struct hive_key *)kd; + + return WERR_OK; +} + +static WERROR ldb_add_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent, + const char *name, const char *classname, + struct security_descriptor *sd, + struct hive_key **newkey) +{ + struct ldb_key_data *parentkd = discard_const_p(struct ldb_key_data, parent); + struct ldb_message *msg; + struct ldb_key_data *newkd; + int ret; + + msg = ldb_msg_new(mem_ctx); + + msg->dn = reg_path_to_ldb(msg, parent, name, NULL); + + ldb_msg_add_string(msg, "key", talloc_strdup(mem_ctx, name)); + if (classname != NULL) + ldb_msg_add_string(msg, "classname", + talloc_strdup(mem_ctx, classname)); + + ret = ldb_add(parentkd->ldb, msg); + if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { + return WERR_ALREADY_EXISTS; + } + + if (ret != LDB_SUCCESS) { + DEBUG(1, ("ldb_add: %s\n", ldb_errstring(parentkd->ldb))); + return WERR_FOOBAR; + } + + DEBUG(2, ("key added: %s\n", ldb_dn_get_linearized(msg->dn))); + + newkd = talloc_zero(mem_ctx, struct ldb_key_data); + newkd->ldb = talloc_reference(newkd, parentkd->ldb); + newkd->key.ops = ®_backend_ldb; + newkd->dn = talloc_steal(newkd, msg->dn); + + *newkey = (struct hive_key *)newkd; + + /* reset cache */ + talloc_free(parentkd->subkeys); + parentkd->subkeys = NULL; + + return WERR_OK; +} + +static WERROR ldb_del_value (struct hive_key *key, const char *child) +{ + int ret; + struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data); + struct ldb_dn *childdn; + + childdn = ldb_dn_copy(kd->ldb, kd->dn); + if (!ldb_dn_add_child_fmt(childdn, "value=%s", + reg_ldb_escape(childdn, child))) + { + talloc_free(childdn); + return WERR_FOOBAR; + } + + ret = ldb_delete(kd->ldb, childdn); + + talloc_free(childdn); + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + return WERR_BADFILE; + } else if (ret != LDB_SUCCESS) { + DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb))); + return WERR_FOOBAR; + } + + /* reset cache */ + talloc_free(kd->values); + kd->values = NULL; + + return WERR_OK; +} + +static WERROR ldb_del_key(const struct hive_key *key, const char *name) +{ + int i, ret; + struct ldb_key_data *parentkd = talloc_get_type(key, struct ldb_key_data); + struct ldb_dn *ldap_path; + TALLOC_CTX *mem_ctx = talloc_init("ldb_del_key"); + struct ldb_context *c = parentkd->ldb; + struct ldb_result *res_keys; + struct ldb_result *res_vals; + WERROR werr; + struct hive_key *hk; + + /* Verify key exists by opening it */ + werr = ldb_open_key(mem_ctx, key, name, &hk); + if (!W_ERROR_IS_OK(werr)) { + talloc_free(mem_ctx); + return werr; + } + + ldap_path = reg_path_to_ldb(mem_ctx, key, name, NULL); + if (!ldap_path) { + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + /* Search for subkeys */ + ret = ldb_search(c, ldap_path, LDB_SCOPE_ONELEVEL, + "(key=*)", NULL, &res_keys); + + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Error getting subkeys for '%s': %s\n", + ldb_dn_get_linearized(ldap_path), ldb_errstring(c))); + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + /* Search for values */ + ret = ldb_search(c, ldap_path, LDB_SCOPE_ONELEVEL, + "(value=*)", NULL, &res_vals); + + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Error getting values for '%s': %s\n", + ldb_dn_get_linearized(ldap_path), ldb_errstring(c))); + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + /* Start an explicit transaction */ + ret = ldb_transaction_start(c); + + if (ret != LDB_SUCCESS) { + DEBUG(0, ("ldb_transaction_start: %s\n", ldb_errstring(c))); + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + if (res_keys->count || res_vals->count) + { + /* Delete any subkeys */ + for (i = 0; i < res_keys->count; i++) + { + werr = ldb_del_key(hk, ldb_msg_find_attr_as_string( + res_keys->msgs[i], + "key", NULL)); + if (!W_ERROR_IS_OK(werr)) { + ret = ldb_transaction_cancel(c); + talloc_free(mem_ctx); + return werr; + } + } + + /* Delete any values */ + for (i = 0; i < res_vals->count; i++) + { + werr = ldb_del_value(hk, ldb_msg_find_attr_as_string( + res_vals->msgs[i], + "value", NULL)); + if (!W_ERROR_IS_OK(werr)) { + ret = ldb_transaction_cancel(c); + talloc_free(mem_ctx); + return werr; + } + } + } + + /* Delete the key itself */ + ret = ldb_delete(c, ldap_path); + + if (ret != LDB_SUCCESS) + { + DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(c))); + ret = ldb_transaction_cancel(c); + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + /* Commit the transaction */ + ret = ldb_transaction_commit(c); + + if (ret != LDB_SUCCESS) + { + DEBUG(0, ("ldb_transaction_commit: %s\n", ldb_errstring(c))); + ret = ldb_transaction_cancel(c); + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + talloc_free(mem_ctx); + + /* reset cache */ + talloc_free(parentkd->subkeys); + parentkd->subkeys = NULL; + + return WERR_OK; +} + +static WERROR ldb_set_value(struct hive_key *parent, + const char *name, uint32_t type, + const DATA_BLOB data) +{ + struct ldb_message *msg; + struct ldb_key_data *kd = talloc_get_type(parent, struct ldb_key_data); + int ret; + TALLOC_CTX *mem_ctx = talloc_init("ldb_set_value"); + + msg = reg_ldb_pack_value(kd->ldb, mem_ctx, name, type, data); + + msg->dn = ldb_dn_copy(msg, kd->dn); + if (!ldb_dn_add_child_fmt(msg->dn, "value=%s", + reg_ldb_escape(mem_ctx, name))) + { + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + ret = ldb_add(kd->ldb, msg); + if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { + int i; + for (i = 0; i < msg->num_elements; i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + ret = ldb_modify(kd->ldb, msg); + } + + if (ret != LDB_SUCCESS) { + DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(kd->ldb))); + talloc_free(mem_ctx); + return WERR_FOOBAR; + } + + /* reset cache */ + talloc_free(kd->values); + kd->values = NULL; + + talloc_free(mem_ctx); + return WERR_OK; +} + +static WERROR ldb_get_key_info(TALLOC_CTX *mem_ctx, + const struct hive_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data); + + if (kd->subkeys == NULL) { + W_ERROR_NOT_OK_RETURN(cache_subkeys(kd)); + } + + if (kd->values == NULL) { + W_ERROR_NOT_OK_RETURN(cache_values(kd)); + } + + /* FIXME */ + if (classname != NULL) + *classname = NULL; + + if (num_subkeys != NULL) { + *num_subkeys = kd->subkey_count; + } + + if (num_values != NULL) { + *num_values = kd->value_count; + } + + if (last_change_time != NULL) + *last_change_time = 0; + + if (max_subkeynamelen != NULL) { + int i; + struct ldb_message_element *el; + + *max_subkeynamelen = 0; + + for (i = 0; i < kd->subkey_count; i++) { + el = ldb_msg_find_element(kd->subkeys[i], "key"); + *max_subkeynamelen = MAX(*max_subkeynamelen, el->values[0].length); + } + } + + if (max_valnamelen != NULL || max_valbufsize != NULL) { + int i; + struct ldb_message_element *el; + W_ERROR_NOT_OK_RETURN(cache_values(kd)); + + if (max_valbufsize != NULL) + *max_valbufsize = 0; + + if (max_valnamelen != NULL) + *max_valnamelen = 0; + + for (i = 0; i < kd->value_count; i++) { + if (max_valnamelen != NULL) { + el = ldb_msg_find_element(kd->values[i], "value"); + *max_valnamelen = MAX(*max_valnamelen, el->values[0].length); + } + + if (max_valbufsize != NULL) { + DATA_BLOB data; + reg_ldb_unpack_value(mem_ctx, + lp_iconv_convenience(global_loadparm), + kd->values[i], NULL, + NULL, &data); + *max_valbufsize = MAX(*max_valbufsize, data.length); + talloc_free(data.data); + } + } + } + + return WERR_OK; +} + +static struct hive_operations reg_backend_ldb = { + .name = "ldb", + .add_key = ldb_add_key, + .del_key = ldb_del_key, + .get_key_by_name = ldb_open_key, + .enum_value = ldb_get_value_by_id, + .enum_key = ldb_get_subkey_by_id, + .set_value = ldb_set_value, + .get_value_by_name = ldb_get_value, + .delete_value = ldb_del_value, + .get_key_info = ldb_get_key_info, +}; diff --git a/source4/lib/registry/local.c b/source4/lib/registry/local.c new file mode 100644 index 0000000000..4af95e2dd6 --- /dev/null +++ b/source4/lib/registry/local.c @@ -0,0 +1,351 @@ +/* + Unix SMB/CIFS implementation. + Transparent registry backend handling + Copyright (C) Jelmer Vernooij 2003-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "lib/util/dlinklist.h" +#include "lib/registry/registry.h" +#include "system/filesys.h" + +struct reg_key_path { + uint32_t predefined_key; + const char **elements; +}; + +struct registry_local { + const struct registry_operations *ops; + + struct mountpoint { + struct reg_key_path path; + struct hive_key *key; + struct mountpoint *prev, *next; + } *mountpoints; +}; + +struct local_key { + struct registry_key global; + struct reg_key_path path; + struct hive_key *hive_key; +}; + + +struct registry_key *reg_import_hive_key(struct registry_context *ctx, + struct hive_key *hive, + uint32_t predefined_key, + const char **elements) +{ + struct local_key *local_key; + struct reg_key_path parent_path; + + parent_path.predefined_key = predefined_key; + parent_path.elements = elements; + + local_key = talloc(ctx, struct local_key); + local_key->hive_key = talloc_steal(local_key, hive); + local_key->global.context = talloc_reference(local_key, ctx); + local_key->path = parent_path; + + return (struct registry_key *)local_key; +} + + +static WERROR local_open_key(TALLOC_CTX *mem_ctx, + struct registry_key *parent, + const char *path, + struct registry_key **result) +{ + char *orig = talloc_strdup(mem_ctx, path), + *curbegin = orig, + *curend = strchr(orig, '\\'); + struct local_key *local_parent = talloc_get_type(parent, + struct local_key); + struct hive_key *curkey = local_parent->hive_key; + WERROR error; + const char **elements = NULL; + int el; + + if (local_parent->path.elements != NULL) { + elements = talloc_array(mem_ctx, const char *, + str_list_length(local_parent->path.elements) + 1); + for (el = 0; local_parent->path.elements[el] != NULL; el++) { + elements[el] = talloc_reference(elements, + local_parent->path.elements[el]); + } + elements[el] = NULL; + } else { + elements = NULL; + el = 0; + } + + while (curbegin != NULL && *curbegin) { + if (curend != NULL) + *curend = '\0'; + elements = talloc_realloc(mem_ctx, elements, const char *, el+2); + elements[el] = talloc_strdup(elements, curbegin); + el++; + elements[el] = NULL; + error = hive_get_key_by_name(mem_ctx, curkey, + curbegin, &curkey); + if (!W_ERROR_IS_OK(error)) { + DEBUG(2, ("Opening key %s failed: %s\n", curbegin, + win_errstr(error))); + talloc_free(orig); + return error; + } + if (curend == NULL) + break; + curbegin = curend + 1; + curend = strchr(curbegin, '\\'); + } + talloc_free(orig); + + *result = reg_import_hive_key(local_parent->global.context, curkey, + local_parent->path.predefined_key, + talloc_steal(curkey, elements)); + + return WERR_OK; +} + +WERROR local_get_predefined_key(struct registry_context *ctx, + uint32_t key_id, struct registry_key **key) +{ + struct registry_local *rctx = talloc_get_type(ctx, + struct registry_local); + struct mountpoint *mp; + + for (mp = rctx->mountpoints; mp != NULL; mp = mp->next) { + if (mp->path.predefined_key == key_id && + mp->path.elements == NULL) + break; + } + + if (mp == NULL) + return WERR_BADFILE; + + *key = reg_import_hive_key(ctx, mp->key, + mp->path.predefined_key, + mp->path.elements); + + return WERR_OK; +} + +static WERROR local_enum_key(TALLOC_CTX *mem_ctx, + const struct registry_key *key, uint32_t idx, + const char **name, + const char **keyclass, + NTTIME *last_changed_time) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_enum_key(mem_ctx, local->hive_key, idx, name, keyclass, + last_changed_time); +} + +static WERROR local_create_key(TALLOC_CTX *mem_ctx, + struct registry_key *parent_key, + const char *name, + const char *key_class, + struct security_descriptor *security, + struct registry_key **key) +{ + struct local_key *local_parent; + struct hive_key *hivekey; + const char **elements; + int i; + const char *last_part; + + last_part = strrchr(name, '\\'); + if (last_part == NULL) { + last_part = name; + local_parent = (struct local_key *)parent_key; + } else { + W_ERROR_NOT_OK_RETURN(reg_open_key(mem_ctx, parent_key, + talloc_strndup(mem_ctx, name, last_part-name), + (struct registry_key **)&local_parent)); + last_part++; + } + + W_ERROR_NOT_OK_RETURN(hive_key_add_name(mem_ctx, local_parent->hive_key, + last_part, key_class, security, + &hivekey)); + + if (local_parent->path.elements != NULL) { + elements = talloc_array(hivekey, const char *, + str_list_length(local_parent->path.elements)+2); + for (i = 0; local_parent->path.elements[i] != NULL; i++) { + elements[i] = talloc_reference(elements, + local_parent->path.elements[i]); + } + } else { + elements = talloc_array(hivekey, const char *, 2); + i = 0; + } + + elements[i] = talloc_strdup(elements, name); + elements[i+1] = NULL; + + *key = reg_import_hive_key(local_parent->global.context, hivekey, + local_parent->path.predefined_key, + elements); + + return WERR_OK; +} + +static WERROR local_set_value(struct registry_key *key, const char *name, + uint32_t type, const DATA_BLOB data) +{ + struct local_key *local = (struct local_key *)key; + + return hive_key_set_value(local->hive_key, name, type, data); +} + +static WERROR local_get_value(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char *name, uint32_t *type, DATA_BLOB *data) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_get_value(mem_ctx, local->hive_key, name, type, data); +} + +static WERROR local_enum_value(TALLOC_CTX *mem_ctx, + const struct registry_key *key, uint32_t idx, + const char **name, + uint32_t *type, + DATA_BLOB *data) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_get_value_by_index(mem_ctx, local->hive_key, idx, + name, type, data); +} + +static WERROR local_delete_key(struct registry_key *key, const char *name) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_key_del(local->hive_key, name); +} + +static WERROR local_delete_value(struct registry_key *key, const char *name) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_key_del_value(local->hive_key, name); +} + +static WERROR local_flush_key(struct registry_key *key) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_key_flush(local->hive_key); +} + +static WERROR local_get_key_info(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_key_get_info(mem_ctx, local->hive_key, + classname, num_subkeys, num_values, + last_change_time, max_subkeynamelen, + max_valnamelen, max_valbufsize); +} +static WERROR local_get_sec_desc(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + struct security_descriptor **security) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_get_sec_desc(mem_ctx, local->hive_key, security); +} +static WERROR local_set_sec_desc(struct registry_key *key, + const struct security_descriptor *security) +{ + const struct local_key *local = (const struct local_key *)key; + + return hive_set_sec_desc(local->hive_key, security); +} +const static struct registry_operations local_ops = { + .name = "local", + .open_key = local_open_key, + .get_predefined_key = local_get_predefined_key, + .enum_key = local_enum_key, + .create_key = local_create_key, + .set_value = local_set_value, + .get_value = local_get_value, + .enum_value = local_enum_value, + .delete_key = local_delete_key, + .delete_value = local_delete_value, + .flush_key = local_flush_key, + .get_key_info = local_get_key_info, + .get_sec_desc = local_get_sec_desc, + .set_sec_desc = local_set_sec_desc, +}; + +WERROR reg_open_local(TALLOC_CTX *mem_ctx, struct registry_context **ctx) +{ + struct registry_local *ret = talloc_zero(mem_ctx, + struct registry_local); + + W_ERROR_HAVE_NO_MEMORY(ret); + + ret->ops = &local_ops; + + *ctx = (struct registry_context *)ret; + + return WERR_OK; +} + +WERROR reg_mount_hive(struct registry_context *rctx, + struct hive_key *hive_key, + uint32_t key_id, + const char **elements) +{ + struct registry_local *reg_local = talloc_get_type(rctx, + struct registry_local); + struct mountpoint *mp = talloc(rctx, struct mountpoint); + int i = 0; + + mp->path.predefined_key = key_id; + mp->prev = mp->next = NULL; + mp->key = hive_key; + if (elements != NULL && str_list_length(elements) != 0) { + mp->path.elements = talloc_array(mp, const char *, + str_list_length(elements)); + for (i = 0; elements[i] != NULL; i++) { + mp->path.elements[i] = talloc_reference(mp->path.elements, + elements[i]); + } + mp->path.elements[i] = NULL; + } else { + mp->path.elements = NULL; + } + + DLIST_ADD(reg_local->mountpoints, mp); + + return WERR_OK; +} diff --git a/source4/lib/registry/man/regdiff.1.xml b/source4/lib/registry/man/regdiff.1.xml new file mode 100644 index 0000000000..7bcaa1502c --- /dev/null +++ b/source4/lib/registry/man/regdiff.1.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc"> +<refentry id="regdiff.1"> + +<refmeta> + <refentrytitle>regdiff</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>regdiff</refname> + <refpurpose>Diff program for Windows registry files</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>regdiff</command> + <arg choice="opt">--help</arg> + <arg choice="opt">--backend=BACKEND</arg> + <arg choice="opt">--backend=BACKEND</arg> + <arg choice="opt">--credentials=CREDENTIALS</arg> + <arg choice="opt">--credentials=CREDENTIALS</arg> + <arg choice="opt">location</arg> + <arg choice="opt">location</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>regdiff compares two Windows registry files key by key + and value by value and generates a text file that contains the + differences between the two files.</para> + + <para>A file generated by regdiff can later be applied to a + registry file by the regpatch utility. </para> + + <para>regdiff and regpatch use the same file format as + the regedit32.exe utility from Windows.</para> + +</refsect1> + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>--help</term> + <listitem><para> + Show list of available options.</para></listitem> + </varlistentry> + + <varlistentry> + <term>--backend BACKEND</term> + <listitem><para>Name of backend to load. Possible values are: + creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>. + </para> + <para> + This argument can be specified twice: once for the first + registry file and once for the second. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>--credentials=CREDENTIALS</term> + <listitem><para> + Credentials to use, if any. Password should be separated from user name by a percent sign. + </para> + <para> + This argument can be specified twice: once for the first + registry file and once for the second. + </para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>gregedit, regshell, regpatch, regtree, samba, patch, diff</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para> + + <para>This manpage and regdiff were written by Jelmer Vernooij. </para> + +</refsect1> + +</refentry> diff --git a/source4/lib/registry/man/regpatch.1.xml b/source4/lib/registry/man/regpatch.1.xml new file mode 100644 index 0000000000..d9dcdcbf80 --- /dev/null +++ b/source4/lib/registry/man/regpatch.1.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc"> +<refentry id="regpatch.1"> + +<refmeta> + <refentrytitle>regpatch</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>regpatch</refname> + <refpurpose>Applies registry patches to registry files</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>regpatch</command> + <arg choice="opt">--help</arg> + <arg choice="opt">--backend=BACKEND</arg> + <arg choice="opt">--credentials=CREDENTIALS</arg> + <arg choice="opt">location</arg> + <arg choice="opt">patch-file</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>The regpatch utility applies registry patches to Windows registry + files. The patch files should have the same format as is being used + by the regdiff utility and regedit32.exe from Windows.</para> + + <para>If no patch file is specified on the command line, + regpatch attempts to read it from standard input.</para> +</refsect1> + + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>--help</term> + <listitem><para> + Show list of available options.</para></listitem> + </varlistentry> + + <varlistentry> + <term>--backend BACKEND</term> + <listitem><para>Name of backend to load. Possible values are: + creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>--credentials=CREDENTIALS</term> + <listitem><para> + Credentials to use, if any. Password should be separated from user name by a percent sign.</para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>regdiff, regtree, regshell, gregedit, samba, diff, patch</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para> + + <para>This manpage and regpatch were written by Jelmer Vernooij. </para> + +</refsect1> + +</refentry> diff --git a/source4/lib/registry/man/regshell.1.xml b/source4/lib/registry/man/regshell.1.xml new file mode 100644 index 0000000000..9f16d8cc24 --- /dev/null +++ b/source4/lib/registry/man/regshell.1.xml @@ -0,0 +1,186 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc"> +<refentry id="regshell.1"> + +<refmeta> + <refentrytitle>regshell</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>regshell</refname> + <refpurpose>Windows registry file browser using readline</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>regshell</command> + <arg choice="opt">--help</arg> + <arg choice="opt">--backend=BACKEND</arg> + <arg choice="opt">--credentials=CREDENTIALS</arg> + <arg choice="opt">location</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para> + regshell is a utility that lets you browse thru a Windows registry + file as if you were using a regular unix shell to browse thru a + file system. + </para> + +</refsect1> + + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>--help</term> + <listitem><para> + Show list of available options.</para></listitem> + </varlistentry> + + <varlistentry> + <term>--backend BACKEND</term> + <listitem><para>Name of backend to load. Possible values are: + creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>--credentials=CREDENTIALS</term> + <listitem><para> + Credentials to use, if any. Password should be separated from user name by a percent sign.</para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>COMMANDS</title> + + <variablelist> + <varlistentry> + <term>ck|cd <keyname></term> + <listitem><para> + Go to the specified subkey. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>ch|predef [predefined-key-name]</term> + <listitem><para> + Go to the specified predefined key. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>list|ls</term> + <listitem><para> + List subkeys and values of the current key. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>mkkey|mkdir <keyname></term> + <listitem><para> + Create a key with the specified <replaceable>keyname</replaceable> as a subkey of the current key. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>rmval|rm <valname></term> + <listitem><para> + Delete the specified value. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>rmkey|rmdir <keyname></term> + <listitem><para> + Delete the specified subkey recursively. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>pwd|pwk</term> + <listitem><para>Print the full name of the current key.</para></listitem> + </varlistentry> + + <varlistentry> + <term>set|update</term> + <listitem><para>Update the value of a key value. Not implemented at the moment.</para></listitem> + </varlistentry> + + <varlistentry> + <term>help|?</term> + <listitem><para>Print a list of available commands.</para></listitem> + </varlistentry> + <varlistentry> + <term>exit|quit</term> + <listitem><para>Leave regshell.</para></listitem> + </varlistentry> + </variablelist> +</refsect1> + +<refsect1> + <title>EXAMPLES</title> + + <para>Browsing thru a nt4 registry file</para> + <screen> +<userinput>regshell -b nt4 NTUSER.DAT</userinput> +$$$PROTO.HIV> <userinput>ls</userinput> +K AppEvents +K Console +K Control Panel +K Environment +K Identities +K Keyboard Layout +K Network +K Printers +K Software +K UNICODE Program Groups +K Windows 3.1 Migration Status +$$$PROTO.HIV> <userinput>exit</userinput> +</screen> + +<para>Listing the subkeys of HKEY_CURRENT_USER\AppEvents on a remote computer:</para> +<screen> +<userinput>regshell --remote=ncacn_np:aurelia -c "jelmer%secret"</userinput> +HKEY_CURRENT_MACHINE> <userinput>predef HKEY_CURRENT_USER</userinput> +HKEY_CURRENT_USER> <userinput>cd AppEvents</userinput> +Current path is: HKEY_CURRENT_USER\AppEvents +HKEY_CURRENT_USER\AppEvents> <userinput>ls</userinput> +K EventLabels +K Schemes +HKEY_CURRENT_USER\AppEvents> <userinput>exit</userinput> +</screen> +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>regtree, regdiff, regpatch, gregedit, samba</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para> + + <para>This manpage and regshell were written by Jelmer Vernooij. </para> + +</refsect1> + +</refentry> diff --git a/source4/lib/registry/man/regtree.1.xml b/source4/lib/registry/man/regtree.1.xml new file mode 100644 index 0000000000..93f15e1fb2 --- /dev/null +++ b/source4/lib/registry/man/regtree.1.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc"> +<refentry id="regtree.1"> + +<refmeta> + <refentrytitle>regtree</refentrytitle> + <manvolnum>1</manvolnum> +</refmeta> + + +<refnamediv> + <refname>regtree</refname> + <refpurpose>Text-mode registry viewer</refpurpose> +</refnamediv> + +<refsynopsisdiv> + <cmdsynopsis> + <command>regtree</command> + <arg choice="opt">--help</arg> + <arg choice="opt">--backend=BACKEND</arg> + <arg choice="opt">--fullpath</arg> + <arg choice="opt">--no-values</arg> + <arg choice="opt">--credentials=CREDENTIALS</arg> + <arg choice="opt">location</arg> + </cmdsynopsis> +</refsynopsisdiv> + +<refsect1> + <title>DESCRIPTION</title> + + <para>The regtree utility prints out all the contents of a + Windows registry file. Subkeys are printed with one level + more indentation than their parents. </para> + +</refsect1> + + +<refsect1> + <title>OPTIONS</title> + + <variablelist> + <varlistentry> + <term>--help</term> + <listitem><para> + Show list of available options.</para></listitem> + </varlistentry> + + <varlistentry> + <term>--backend BACKEND</term> + <listitem><para>Name of backend to load. Possible values are: + creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>--credentials=CREDENTIALS</term> + <listitem><para> + Credentials to use, if any. Password should be separated from user name by a percent sign.</para></listitem> + </varlistentry> + + <varlistentry> + <term>--fullpath</term> + <listitem><para> + Print the full path to each key instead of only its name. + </para> + </listitem> + </varlistentry> + + <varlistentry><term>--no-values</term> + <listitem><para>Don't print values, just keys.</para></listitem> + </varlistentry> + </variablelist> + +</refsect1> + +<refsect1> + <title>VERSION</title> + + <para>This man page is correct for version 4.0 of the Samba suite.</para> +</refsect1> + +<refsect1> + <title>SEE ALSO</title> + + <para>gregedit, regshell, regdiff, regpatch, samba</para> + +</refsect1> + +<refsect1> + <title>AUTHOR</title> + + <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para> + + <para>This manpage and regtree were written by Jelmer Vernooij. </para> + +</refsect1> + +</refentry> diff --git a/source4/lib/registry/patchfile.c b/source4/lib/registry/patchfile.c new file mode 100644 index 0000000000..0ede3106f0 --- /dev/null +++ b/source4/lib/registry/patchfile.c @@ -0,0 +1,469 @@ +/* + Unix SMB/CIFS implementation. + Reading registry patch files + + Copyright (C) Jelmer Vernooij 2004-2007 + Copyright (C) Wilco Baan Hofman 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "system/filesys.h" +#include "param/param.h" + + +_PUBLIC_ WERROR reg_preg_diff_load(int fd, + struct smb_iconv_convenience *iconv_convenience, + const struct reg_diff_callbacks *callbacks, + void *callback_data); + +_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, + struct smb_iconv_convenience *iconv_convenience, + const struct reg_diff_callbacks *callbacks, + void *callback_data); + +/* + * Generate difference between two keys + */ +WERROR reg_generate_diff_key(struct registry_key *oldkey, + struct registry_key *newkey, + const char *path, + const struct reg_diff_callbacks *callbacks, + void *callback_data) +{ + int i; + struct registry_key *t1 = NULL, *t2 = NULL; + char *tmppath; + const char *keyname1; + WERROR error, error1, error2; + TALLOC_CTX *mem_ctx = talloc_init("writediff"); + uint32_t old_num_subkeys, old_num_values, + new_num_subkeys, new_num_values; + + if (oldkey != NULL) { + error = reg_key_get_info(mem_ctx, oldkey, NULL, + &old_num_subkeys, &old_num_values, + NULL, NULL, NULL, NULL); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error occured while getting key info: %s\n", + win_errstr(error))); + return error; + } + } else { + old_num_subkeys = 0; + old_num_values = 0; + } + + /* Subkeys that were deleted */ + for (i = 0; i < old_num_subkeys; i++) { + error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, + &keyname1, + NULL, NULL); + if (!W_ERROR_IS_OK(error1)) { + DEBUG(0, ("Error occured while getting subkey by index: %s\n", + win_errstr(error2))); + continue; + } + + if (newkey != NULL) { + error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2); + + if (W_ERROR_IS_OK(error2)) + continue; + } else { + error2 = WERR_BADFILE; + t2 = NULL; + } + + if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) { + DEBUG(0, ("Error occured while getting subkey by name: %s\n", + win_errstr(error2))); + talloc_free(mem_ctx); + return error2; + } + + /* newkey didn't have such a subkey, add del diff */ + tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1); + callbacks->del_key(callback_data, tmppath); + talloc_free(tmppath); + } + + if (newkey != NULL) { + error = reg_key_get_info(mem_ctx, newkey, NULL, + &new_num_subkeys, &new_num_values, + NULL, NULL, NULL, NULL); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error occured while getting key info: %s\n", + win_errstr(error))); + return error; + } + } else { + new_num_subkeys = 0; + new_num_values = 0; + } + + /* Subkeys that were added */ + for(i = 0; i < new_num_subkeys; i++) { + error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, + i, &keyname1, + NULL, NULL); + if (!W_ERROR_IS_OK(error1)) { + DEBUG(0, ("Error occured while getting subkey by index: %s\n", + win_errstr(error1))); + talloc_free(mem_ctx); + return error1; + } + + if (oldkey != NULL) { + error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1); + + if (W_ERROR_IS_OK(error2)) + continue; + } else { + t1 = NULL; + error2 = WERR_BADFILE; + } + + if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) { + DEBUG(0, ("Error occured while getting subkey by name: %s\n", + win_errstr(error2))); + talloc_free(mem_ctx); + return error2; + } + + /* oldkey didn't have such a subkey, add add diff */ + tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1); + callbacks->add_key(callback_data, tmppath); + + W_ERROR_NOT_OK_RETURN( + reg_open_key(mem_ctx, newkey, keyname1, &t2)); + + reg_generate_diff_key(t1, t2, tmppath, + callbacks, callback_data); + talloc_free(tmppath); + } + + /* Values that were changed */ + for(i = 0; i < new_num_values; i++) { + const char *name; + uint32_t type1, type2; + DATA_BLOB contents1, contents2; + + error1 = reg_key_get_value_by_index(mem_ctx, newkey, i, + &name, &type1, &contents1); + if (!W_ERROR_IS_OK(error1)) { + DEBUG(0, ("Unable to get key by index: %s\n", + win_errstr(error1))); + talloc_free(mem_ctx); + return error1; + } + + if (oldkey != NULL) { + error2 = reg_key_get_value_by_name(mem_ctx, oldkey, + name, &type2, + &contents2); + } else + error2 = WERR_BADFILE; + + if(!W_ERROR_IS_OK(error2) && + !W_ERROR_EQUAL(error2, WERR_BADFILE)) { + DEBUG(0, ("Error occured while getting value by name: %s\n", + win_errstr(error2))); + talloc_free(mem_ctx); + return error2; + } + + if (W_ERROR_IS_OK(error2) && + data_blob_cmp(&contents1, &contents2) == 0) + continue; + + callbacks->set_value(callback_data, path, name, + type1, contents1); + } + + /* Values that were deleted */ + for (i = 0; i < old_num_values; i++) { + const char *name; + error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name, + NULL, NULL); + if (!W_ERROR_IS_OK(error1)) { + DEBUG(0, ("Error ocurred getting value by index: %s\n", + win_errstr(error1))); + talloc_free(mem_ctx); + return error1; + } + + error2 = reg_key_get_value_by_name(mem_ctx, newkey, name, NULL, + NULL); + + if (W_ERROR_IS_OK(error2)) + continue; + + if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) { + DEBUG(0, ("Error occured while getting value by name: %s\n", + win_errstr(error2))); + return error2; + } + + callbacks->del_value(callback_data, path, name); + } + + talloc_free(mem_ctx); + return WERR_OK; +} + +/** + * Generate diff between two registry contexts + */ +_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1, + struct registry_context *ctx2, + const struct reg_diff_callbacks *callbacks, + void *callback_data) +{ + int i; + WERROR error; + + for(i = HKEY_FIRST; i <= HKEY_LAST; i++) { + struct registry_key *r1 = NULL, *r2 = NULL; + error = reg_get_predefined_key(ctx1, i, &r1); + if (!W_ERROR_IS_OK(error) && + !W_ERROR_EQUAL(error, WERR_BADFILE)) { + DEBUG(0, ("Unable to open hive %s for backend 1\n", + reg_get_predef_name(i))); + } + + error = reg_get_predefined_key(ctx2, i, &r2); + if (!W_ERROR_IS_OK(error) && + !W_ERROR_EQUAL(error, WERR_BADFILE)) { + DEBUG(0, ("Unable to open hive %s for backend 2\n", + reg_get_predef_name(i))); + } + + if (r1 == NULL && r2 == NULL) + continue; + + error = reg_generate_diff_key(r1, r2, reg_get_predef_name(i), + callbacks, callback_data); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Unable to determine diff: %s\n", + win_errstr(error))); + return error; + } + } + if (callbacks->done != NULL) { + callbacks->done(callback_data); + } + return WERR_OK; +} + +/** + * Load diff file + */ +_PUBLIC_ WERROR reg_diff_load(const char *filename, + struct smb_iconv_convenience *iconv_convenience, + const struct reg_diff_callbacks *callbacks, + void *callback_data) +{ + int fd; + char hdr[4]; + + fd = open(filename, O_RDONLY, 0); + if (fd == -1) { + DEBUG(0, ("Error opening registry patch file `%s'\n", + filename)); + return WERR_GENERAL_FAILURE; + } + + if (read(fd, &hdr, 4) != 4) { + DEBUG(0, ("Error reading registry patch file `%s'\n", + filename)); + return WERR_GENERAL_FAILURE; + } + + /* Reset position in file */ + lseek(fd, 0, SEEK_SET); +#if 0 /* These backends are not supported yet. */ + if (strncmp(hdr, "CREG", 4) == 0) { + /* Must be a W9x CREG Config.pol file */ + return reg_creg_diff_load(diff, fd); + } else if (strncmp(hdr, "regf", 4) == 0) { + /* Must be a REGF NTConfig.pol file */ + return reg_regf_diff_load(diff, fd); + } else +#endif + if (strncmp(hdr, "PReg", 4) == 0) { + /* Must be a GPO Registry.pol file */ + return reg_preg_diff_load(fd, iconv_convenience, callbacks, callback_data); + } else { + /* Must be a normal .REG file */ + return reg_dotreg_diff_load(fd, iconv_convenience, callbacks, callback_data); + } +} + +/** + * The reg_diff_apply functions + */ +static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name) +{ + struct registry_context *ctx = (struct registry_context *)_ctx; + struct registry_key *tmp; + char *buf, *buf_ptr; + WERROR error; + + /* Recursively create the path */ + buf = talloc_strdup(ctx, key_name); + buf_ptr = buf; + + while (*buf_ptr++ != '\0' ) { + if (*buf_ptr == '\\') { + *buf_ptr = '\0'; + error = reg_key_add_abs(ctx, ctx, buf, 0, NULL, &tmp); + + if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) && + !W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error adding new key '%s': %s\n", + key_name, win_errstr(error))); + return error; + } + *buf_ptr++ = '\\'; + } + } + + /* Add the key */ + error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp); + + if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) && + !W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error adding new key '%s': %s\n", + key_name, win_errstr(error))); + return error; + } + return WERR_OK; +} + +static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name) +{ + struct registry_context *ctx = (struct registry_context *)_ctx; + WERROR error; + + error = reg_key_del_abs(ctx, key_name); + + if(!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Unable to delete key '%s'\n", key_name)); + return error; + } + + return WERR_OK; +} + +static WERROR reg_diff_apply_set_value(void *_ctx, const char *path, + const char *value_name, + uint32_t value_type, DATA_BLOB value) +{ + struct registry_context *ctx = (struct registry_context *)_ctx; + struct registry_key *tmp; + WERROR error; + + /* Open key */ + error = reg_open_key_abs(ctx, ctx, path, &tmp); + + if (W_ERROR_EQUAL(error, WERR_BADFILE)) { + DEBUG(0, ("Error opening key '%s'\n", path)); + return error; + } + + /* Set value */ + error = reg_val_set(tmp, value_name, + value_type, value); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error setting value '%s'\n", value_name)); + return error; + } + + return WERR_OK; +} + +static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name, + const char *value_name) +{ + struct registry_context *ctx = (struct registry_context *)_ctx; + struct registry_key *tmp; + WERROR error; + + /* Open key */ + error = reg_open_key_abs(ctx, ctx, key_name, &tmp); + + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error opening key '%s'\n", key_name)); + return error; + } + + error = reg_del_value(tmp, value_name); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error deleting value '%s'\n", value_name)); + return error; + } + + + return WERR_OK; +} + +static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name) +{ + struct registry_context *ctx = (struct registry_context *)_ctx; + struct registry_key *key; + WERROR error; + int i; + uint32_t num_values; + + error = reg_open_key_abs(ctx, ctx, key_name, &key); + + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error opening key '%s'\n", key_name)); + return error; + } + + W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL, + NULL, &num_values, NULL, NULL, NULL, NULL)); + + for (i = 0; i < num_values; i++) { + const char *name; + W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i, + &name, + NULL, NULL)); + W_ERROR_NOT_OK_RETURN(reg_del_value(key, name)); + } + + return WERR_OK; +} + +/** + * Apply diff to a registry context + */ +_PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, const char *filename) +{ + struct reg_diff_callbacks callbacks; + + callbacks.add_key = reg_diff_apply_add_key; + callbacks.del_key = reg_diff_apply_del_key; + callbacks.set_value = reg_diff_apply_set_value; + callbacks.del_value = reg_diff_apply_del_value; + callbacks.del_all_values = reg_diff_apply_del_all_values; + callbacks.done = NULL; + + return reg_diff_load(filename, lp_iconv_convenience(global_loadparm), + &callbacks, ctx); +} diff --git a/source4/lib/registry/patchfile_dotreg.c b/source4/lib/registry/patchfile_dotreg.c new file mode 100644 index 0000000000..1bc9c60753 --- /dev/null +++ b/source4/lib/registry/patchfile_dotreg.c @@ -0,0 +1,266 @@ +/* + Unix SMB/CIFS implementation. + Reading .REG files + + Copyright (C) Jelmer Vernooij 2004-2007 + Copyright (C) Wilco Baan Hofman 2006-2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* FIXME Newer .REG files, created by Windows XP and above use unicode UCS-2 */ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "system/filesys.h" +#include "param/param.h" + +/** + * @file + * @brief Registry patch files + */ + +#define HEADER_STRING "REGEDIT4" + +struct dotreg_data { + int fd; + struct smb_iconv_convenience *iconv_convenience; +}; + +static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\n[%s]\n", key_name); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\n[-%s]\n", key_name); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_set_value(void *_data, const char *path, + const char *value_name, + uint32_t value_type, DATA_BLOB value) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\"%s\"=%s:%s\n", + value_name, str_regtype(value_type), + reg_val_data_string(NULL, data->iconv_convenience, value_type, value)); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_del_value(void *_data, const char *path, + const char *value_name) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\"%s\"=-\n", value_name); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_done(void *_data) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + close(data->fd); + talloc_free(data); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_del_all_values(void *callback_data, + const char *key_name) +{ + return WERR_NOT_SUPPORTED; +} + +/** + * Save registry diff + */ +_PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename, + struct smb_iconv_convenience *iconv_convenience, + struct reg_diff_callbacks **callbacks, + void **callback_data) +{ + struct dotreg_data *data; + + data = talloc_zero(ctx, struct dotreg_data); + *callback_data = data; + + data->iconv_convenience = iconv_convenience; + + if (filename) { + data->fd = open(filename, O_CREAT|O_WRONLY, 0755); + if (data->fd < 0) { + DEBUG(0, ("Unable to open %s\n", filename)); + return WERR_BADFILE; + } + } else { + data->fd = STDOUT_FILENO; + } + + fdprintf(data->fd, "%s\n\n", HEADER_STRING); + + *callbacks = talloc(ctx, struct reg_diff_callbacks); + + (*callbacks)->add_key = reg_dotreg_diff_add_key; + (*callbacks)->del_key = reg_dotreg_diff_del_key; + (*callbacks)->set_value = reg_dotreg_diff_set_value; + (*callbacks)->del_value = reg_dotreg_diff_del_value; + (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values; + (*callbacks)->done = reg_dotreg_diff_done; + + return WERR_OK; +} + +/** + * Load diff file + */ +_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, + struct smb_iconv_convenience *iconv_convenience, + const struct reg_diff_callbacks *callbacks, + void *callback_data) +{ + char *line, *p, *q; + char *curkey = NULL; + TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load"); + WERROR error; + uint32_t value_type; + DATA_BLOB value; + + line = afdgets(fd, mem_ctx, 0); + if (!line) { + DEBUG(0, ("Can't read from file.\n")); + talloc_free(mem_ctx); + close(fd); + return WERR_GENERAL_FAILURE; + } + + while ((line = afdgets(fd, mem_ctx, 0))) { + /* Ignore comments and empty lines */ + if (strlen(line) == 0 || line[0] == ';') { + talloc_free(line); + + if (curkey) { + talloc_free(curkey); + } + curkey = NULL; + continue; + } + + /* Start of key */ + if (line[0] == '[') { + p = strchr_m(line, ']'); + if (p[strlen(p)-1] != ']') { + DEBUG(0, ("Missing ']'\n")); + return WERR_GENERAL_FAILURE; + } + /* Deleting key */ + if (line[1] == '-') { + curkey = talloc_strndup(line, line+2, strlen(line)-3); + + error = callbacks->del_key(callback_data, + curkey); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0,("Error deleting key %s\n", + curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + curkey = NULL; + continue; + } + curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2); + + error = callbacks->add_key(callback_data, curkey); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0,("Error adding key %s\n", curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + continue; + } + + /* Deleting/Changing value */ + p = strchr_m(line, '='); + if (p == NULL) { + DEBUG(0, ("Malformed line\n")); + talloc_free(line); + continue; + } + + *p = '\0'; p++; + + if (curkey == NULL) { + DEBUG(0, ("Value change without key\n")); + talloc_free(line); + continue; + } + + /* Delete value */ + if (strcmp(p, "-") == 0) { + error = callbacks->del_value(callback_data, + curkey, line); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error deleting value %s in key %s\n", + line, curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + continue; + } + + q = strchr_m(p, ':'); + if (q) { + *q = '\0'; + q++; + } + + reg_string_to_val(line, iconv_convenience, + q?p:"REG_SZ", q?q:p, + &value_type, &value); + + error = callbacks->set_value(callback_data, curkey, line, + value_type, value); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error setting value for %s in %s\n", + line, curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + } + + close(fd); + + return WERR_OK; +} diff --git a/source4/lib/registry/patchfile_preg.c b/source4/lib/registry/patchfile_preg.c new file mode 100644 index 0000000000..bb46495c19 --- /dev/null +++ b/source4/lib/registry/patchfile_preg.c @@ -0,0 +1,359 @@ +/* + Unix SMB/CIFS implementation. + Reading Registry.pol PReg registry files + + Copyright (C) Wilco Baan Hofman 2006-2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "system/filesys.h" +#include "param/param.h" +#include "librpc/gen_ndr/winreg.h" + +struct preg_data { + int fd; + TALLOC_CTX *ctx; + struct smb_iconv_convenience *ic; +}; + +static WERROR preg_read_utf16(struct smb_iconv_convenience *ic, int fd, char *c) +{ + uint16_t v; + + if (read(fd, &v, 2) < 2) { + return WERR_GENERAL_FAILURE; + } + push_codepoint(ic, c, v); + return WERR_OK; +} +static WERROR preg_write_utf16(struct smb_iconv_convenience *ic, int fd, const char *string) +{ + codepoint_t v; + uint16_t i; + size_t size; + + for (i = 0; i < strlen(string); i+=size) { + v = next_codepoint(ic, &string[i], &size); + if (write(fd, &v, 2) < 2) { + return WERR_GENERAL_FAILURE; + } + } + return WERR_OK; +} +/* PReg does not support adding keys. */ +static WERROR reg_preg_diff_add_key(void *_data, const char *key_name) +{ + return WERR_OK; +} + +static WERROR reg_preg_diff_set_value(void *_data, const char *key_name, + const char *value_name, + uint32_t value_type, DATA_BLOB value_data) +{ + struct preg_data *data = _data; + uint32_t buf; + + preg_write_utf16(data->ic, data->fd, "["); + preg_write_utf16(data->ic, data->fd, key_name); + preg_write_utf16(data->ic, data->fd, ";"); + preg_write_utf16(data->ic, data->fd, value_name); + preg_write_utf16(data->ic, data->fd, ";"); + SIVAL(&buf, 0, value_type); + write(data->fd, &buf, sizeof(uint32_t)); + preg_write_utf16(data->ic, data->fd, ";"); + SIVAL(&buf, 0, value_data.length); + write(data->fd, &buf, sizeof(uint32_t)); + preg_write_utf16(data->ic, data->fd, ";"); + write(data->fd, value_data.data, value_data.length); + preg_write_utf16(data->ic, data->fd, "]"); + + return WERR_OK; +} + +static WERROR reg_preg_diff_del_key(void *_data, const char *key_name) +{ + struct preg_data *data = _data; + char *parent_name; + DATA_BLOB blob; + + parent_name = talloc_strndup(data->ctx, key_name, strrchr(key_name, '\\')-key_name); + blob.data = (void *)talloc_strndup(data->ctx, key_name+(strrchr(key_name, '\\')-key_name)+1, + strlen(key_name)-(strrchr(key_name, '\\')-key_name)); + blob.length = strlen((char *)blob.data)+1; + + + /* FIXME: These values should be accumulated to be written at done(). */ + return reg_preg_diff_set_value(data, parent_name, "**DeleteKeys", REG_SZ, blob); +} + +static WERROR reg_preg_diff_del_value(void *_data, const char *key_name, + const char *value_name) +{ + struct preg_data *data = _data; + char *val; + DATA_BLOB blob; + + val = talloc_asprintf(data->ctx, "**Del.%s", value_name); + + blob.data = (void *)talloc(data->ctx, uint32_t); + *(uint32_t *)blob.data = 0; + blob.length = 4; + return reg_preg_diff_set_value(data, key_name, val, REG_DWORD, blob); +} + +static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name) +{ + struct preg_data *data = _data; + DATA_BLOB blob; + + blob.data = (void *)talloc(data->ctx, uint32_t); + *(uint32_t *)blob.data = 0; + blob.length = 4; + + return reg_preg_diff_set_value(data, key_name, "**DelVals.", REG_DWORD, blob); +} + +static WERROR reg_preg_diff_done(void *_data) +{ + struct preg_data *data = (struct preg_data *)_data; + + close(data->fd); + talloc_free(data); + return WERR_OK; +} + +/** + * Save registry diff + */ +_PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename, + struct smb_iconv_convenience *ic, + struct reg_diff_callbacks **callbacks, + void **callback_data) +{ + struct preg_data *data; + struct { + char hdr[4]; + uint32_t version; + } preg_header; + + + data = talloc_zero(ctx, struct preg_data); + *callback_data = data; + + if (filename) { + data->fd = open(filename, O_CREAT|O_WRONLY, 0755); + if (data->fd < 0) { + DEBUG(0, ("Unable to open %s\n", filename)); + return WERR_BADFILE; + } + } else { + data->fd = STDOUT_FILENO; + } + + strncpy(preg_header.hdr, "PReg", 4); + SIVAL(&preg_header, 4, 1); + write(data->fd, (uint8_t *)&preg_header,8); + + data->ctx = ctx; + data->ic = ic; + + *callbacks = talloc(ctx, struct reg_diff_callbacks); + + (*callbacks)->add_key = reg_preg_diff_add_key; + (*callbacks)->del_key = reg_preg_diff_del_key; + (*callbacks)->set_value = reg_preg_diff_set_value; + (*callbacks)->del_value = reg_preg_diff_del_value; + (*callbacks)->del_all_values = reg_preg_diff_del_all_values; + (*callbacks)->done = reg_preg_diff_done; + + return WERR_OK; +} +/** + * Load diff file + */ +_PUBLIC_ WERROR reg_preg_diff_load(int fd, + struct smb_iconv_convenience *iconv_convenience, + const struct reg_diff_callbacks *callbacks, + void *callback_data) +{ + struct { + char hdr[4]; + uint32_t version; + } preg_header; + char *buf; + size_t buf_size = 1024; + char *buf_ptr; + TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load"); + WERROR ret = WERR_OK; + DATA_BLOB data = {NULL, 0}; + char *key = NULL; + char *value_name = NULL; + + buf = talloc_array(mem_ctx, char, buf_size); + buf_ptr = buf; + + /* Read first 8 bytes (the header) */ + if (read(fd, &preg_header, 8) != 8) { + DEBUG(0, ("Could not read PReg file: %s\n", + strerror(errno))); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + preg_header.version = IVAL(&preg_header.version, 0); + + if (strncmp(preg_header.hdr, "PReg", 4) != 0) { + DEBUG(0, ("This file is not a valid preg registry file\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + if (preg_header.version > 1) { + DEBUG(0, ("Warning: file format version is higher than expected.\n")); + } + + /* Read the entries */ + while(1) { + uint32_t value_type, length; + + if (!W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr))) { + break; + } + if (*buf_ptr != '[') { + DEBUG(0, ("Error in PReg file.\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + + /* Get the path */ + buf_ptr = buf; + while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) && + *buf_ptr != ';' && buf_ptr-buf < buf_size) { + buf_ptr++; + } + buf[buf_ptr-buf] = '\0'; + key = talloc_strdup(mem_ctx, buf); + + /* Get the name */ + buf_ptr = buf; + while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) && + *buf_ptr != ';' && buf_ptr-buf < buf_size) { + buf_ptr++; + } + buf[buf_ptr-buf] = '\0'; + value_name = talloc_strdup(mem_ctx, buf); + + /* Get the type */ + if (read(fd, &value_type, 4) < 4) { + DEBUG(0, ("Error while reading PReg\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + value_type = IVAL(&value_type, 0); + + /* Read past delimiter */ + buf_ptr = buf; + if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) && + *buf_ptr == ';') && buf_ptr-buf < buf_size) { + DEBUG(0, ("Error in PReg file.\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + /* Get data length */ + if (read(fd, &length, 4) < 4) { + DEBUG(0, ("Error while reading PReg\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + /* Read past delimiter */ + buf_ptr = buf; + if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) && + *buf_ptr == ';') && buf_ptr-buf < buf_size) { + DEBUG(0, ("Error in PReg file.\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + /* Get the data */ + buf_ptr = buf; + if (length < buf_size && + read(fd, buf_ptr, length) != length) { + DEBUG(0, ("Error while reading PReg\n")); + ret = WERR_GENERAL_FAILURE; + goto cleanup; + } + data = data_blob_talloc(mem_ctx, buf, length); + + /* Check if delimiter is in place (whine if it isn't) */ + buf_ptr = buf; + if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) && + *buf_ptr == ']') && buf_ptr-buf < buf_size) { + DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n", + *buf_ptr, *buf_ptr)); + } + + if (strcasecmp(value_name, "**DelVals") == 0) { + callbacks->del_all_values(callback_data, key); + } else if (strncasecmp(value_name, "**Del.",6) == 0) { + char *p = value_name+6; + + callbacks->del_value(callback_data, key, p); + } else if (strcasecmp(value_name, "**DeleteValues") == 0) { + char *p, *q; + + p = (char *) data.data; + + while ((q = strchr_m(p, ';'))) { + *q = '\0'; + q++; + + callbacks->del_value(callback_data, key, p); + + p = q; + } + callbacks->del_value(callback_data, key, p); + } else if (strcasecmp(value_name, "**DeleteKeys") == 0) { + char *p, *q, *full_key; + + p = (char *) data.data; + + while ((q = strchr_m(p, ';'))) { + *q = '\0'; + q++; + + full_key = talloc_asprintf(mem_ctx, "%s\\%s", + key, p); + callbacks->del_key(callback_data, full_key); + talloc_free(full_key); + + p = q; + } + full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p); + callbacks->del_key(callback_data, full_key); + talloc_free(full_key); + } else { + callbacks->add_key(callback_data, key); + callbacks->set_value(callback_data, key, value_name, + value_type, data); + } + } +cleanup: + close(fd); + talloc_free(data.data); + talloc_free(key); + talloc_free(value_name); + talloc_free(buf); + return ret; +} diff --git a/source4/lib/registry/regf.c b/source4/lib/registry/regf.c new file mode 100644 index 0000000000..57a895aa00 --- /dev/null +++ b/source4/lib/registry/regf.c @@ -0,0 +1,2165 @@ +/* + Samba CIFS implementation + Registry backend for REGF files + Copyright (C) 2005-2007 Jelmer Vernooij, jelmer@samba.org + Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "includes.h" +#include "system/filesys.h" +#include "system/time.h" +#include "lib/registry/tdr_regf.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "librpc/gen_ndr/winreg.h" +#include "param/param.h" +#include "lib/registry/registry.h" +#include "libcli/security/security.h" + + +static struct hive_operations reg_backend_regf; + +/** + * There are several places on the web where the REGF format is explained; + * + * TODO: Links + */ + +/* TODO: + * - Return error codes that make more sense + * - Locking + * - do more things in-memory + */ + +/* + * Read HBIN blocks into memory + */ + +struct regf_data { + int fd; + struct hbin_block **hbins; + struct regf_hdr *header; + struct smb_iconv_convenience *iconv_convenience; +}; + +static WERROR regf_save_hbin(struct regf_data *data); + +struct regf_key_data { + struct hive_key key; + struct regf_data *hive; + uint32_t offset; + struct nk_block *nk; +}; + +static struct hbin_block *hbin_by_offset(const struct regf_data *data, + uint32_t offset, uint32_t *rel_offset) +{ + int i; + + for (i = 0; data->hbins[i]; i++) { + if (offset >= data->hbins[i]->offset_from_first && + offset < data->hbins[i]->offset_from_first+ + data->hbins[i]->offset_to_next) { + if (rel_offset != NULL) + *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20; + return data->hbins[i]; + } + } + + return NULL; +} + +/** + * Validate a regf header + * For now, do nothing, but we should check the checksum + */ +static uint32_t regf_hdr_checksum(const uint8_t *buffer) +{ + uint32_t checksum = 0, x; + int i; + + for (i = 0; i < 0x01FB; i+= 4) { + x = IVAL(buffer, i); + checksum ^= x; + } + + return checksum; +} + +/** + * Obtain the contents of a HBIN block + */ +static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset) +{ + DATA_BLOB ret; + struct hbin_block *hbin; + uint32_t rel_offset; + + ret.data = NULL; + ret.length = 0; + + hbin = hbin_by_offset(data, offset, &rel_offset); + + if (hbin == NULL) { + DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset)); + return ret; + } + + ret.length = IVAL(hbin->data, rel_offset); + if (!(ret.length & 0x80000000)) { + DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset)); + return ret; + } + + /* remove high bit */ + ret.length = (ret.length ^ 0xffffffff) + 1; + + ret.length -= 4; /* 4 bytes for the length... */ + ret.data = hbin->data + + (offset - hbin->offset_from_first - 0x20) + 4; + + return ret; +} + +static bool hbin_get_tdr(struct regf_data *regf, uint32_t offset, + TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p) +{ + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + + pull->data = hbin_get(regf, offset); + if (!pull->data.data) { + DEBUG(1, ("Unable to get data at 0x%04x\n", offset)); + talloc_free(pull); + return false; + } + + if (NT_STATUS_IS_ERR(pull_fn(pull, ctx, p))) { + DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", + offset)); + talloc_free(pull); + return false; + } + talloc_free(pull); + + return true; +} + +/* Allocate some new data */ +static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size, + uint32_t *offset) +{ + DATA_BLOB ret; + uint32_t rel_offset = -1; /* Relative offset ! */ + struct hbin_block *hbin = NULL; + int i; + + *offset = 0; + + if (size == 0) + return data_blob(NULL, 0); + + size += 4; /* Need to include int32 for the length */ + + /* Allocate as a multiple of 8 */ + size = (size + 7) & ~7; + + ret.data = NULL; + ret.length = 0; + + for (i = 0; (hbin = data->hbins[i]); i++) { + int j; + int32_t my_size; + for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) { + my_size = IVALS(hbin->data, j); + + if (my_size == 0x0) { + DEBUG(0, ("Invalid zero-length block! File is corrupt.\n")); + return ret; + } + + if (my_size % 8 != 0) { + DEBUG(0, ("Encountered non-aligned block!\n")); + } + + if (my_size < 0) { /* Used... */ + my_size = -my_size; + } else if (my_size == size) { /* exact match */ + rel_offset = j; + DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", + size)); + break; + } else if (my_size > size) { /* data will remain */ + rel_offset = j; + /* Split this block and mark the next block as free */ + SIVAL(hbin->data, rel_offset+size, my_size-size); + DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", + my_size, size)); + break; + } + } + + if (rel_offset != -1) + break; + } + + /* No space available in previous hbins, + * allocate new one */ + if (data->hbins[i] == NULL) { + DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", + size)); + data->hbins = talloc_realloc(data, data->hbins, + struct hbin_block *, i+2); + hbin = talloc(data->hbins, struct hbin_block); + SMB_ASSERT(hbin != NULL); + + data->hbins[i] = hbin; + data->hbins[i+1] = NULL; + + hbin->HBIN_ID = talloc_strdup(hbin, "hbin"); + hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next); + hbin->offset_to_next = 0x1000; + hbin->unknown[0] = 0; + hbin->unknown[0] = 0; + unix_to_nt_time(&hbin->last_change, time(NULL)); + hbin->block_size = hbin->offset_to_next; + hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20); + + rel_offset = 0x0; + SIVAL(hbin->data, size, hbin->block_size - size - 0x20); + } + + /* Set size and mark as used */ + SIVAL(hbin->data, rel_offset, -size); + + ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */ + ret.length = size - 0x4; + if (offset) { + uint32_t new_rel_offset; + *offset = hbin->offset_from_first + rel_offset + 0x20; + SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin); + SMB_ASSERT(new_rel_offset == rel_offset); + } + + return ret; +} + +/* Store a data blob. Return the offset at which it was stored */ +static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob) +{ + uint32_t ret; + DATA_BLOB dest = hbin_alloc(data, blob.length, &ret); + + memcpy(dest.data, blob.data, blob.length); + + return ret; +} + +static uint32_t hbin_store_tdr(struct regf_data *data, + tdr_push_fn_t push_fn, void *p) +{ + struct tdr_push *push = tdr_push_init(data, data->iconv_convenience); + uint32_t ret; + + if (NT_STATUS_IS_ERR(push_fn(push, p))) { + DEBUG(0, ("Error during push\n")); + return -1; + } + + ret = hbin_store(data, push->data); + + talloc_free(push); + + return ret; +} + + +/* Free existing data */ +static void hbin_free (struct regf_data *data, uint32_t offset) +{ + int32_t size; + uint32_t rel_offset; + int32_t next_size; + struct hbin_block *hbin; + + SMB_ASSERT (offset > 0); + + hbin = hbin_by_offset(data, offset, &rel_offset); + + if (hbin == NULL) + return; + + /* Get original size */ + size = IVALS(hbin->data, rel_offset); + + if (size > 0) { + DEBUG(1, ("Trying to free already freed block at 0x%04x\n", + offset)); + return; + } + /* Mark as unused */ + size = -size; + + /* If the next block is free, merge into big free block */ + if (rel_offset + size < hbin->offset_to_next) { + next_size = IVALS(hbin->data, rel_offset+size); + if (next_size > 0) { + size += next_size; + } + } + + /* Write block size */ + SIVALS(hbin->data, rel_offset, size); +} + +/** + * Store a data blob data was already stored, but has changed in size + * Will try to save it at the current location if possible, otherwise + * does a free + store */ +static uint32_t hbin_store_resize(struct regf_data *data, + uint32_t orig_offset, DATA_BLOB blob) +{ + uint32_t rel_offset; + struct hbin_block *hbin = hbin_by_offset(data, orig_offset, + &rel_offset); + int32_t my_size; + int32_t orig_size; + int32_t needed_size; + int32_t possible_size; + int i; + + SMB_ASSERT(orig_offset > 0); + + if (!hbin) + return hbin_store(data, blob); + + /* Get original size */ + orig_size = -IVALS(hbin->data, rel_offset); + + needed_size = blob.length + 4; /* Add int32 containing length */ + needed_size = (needed_size + 7) & ~7; /* Align */ + + /* Fits into current allocated block */ + if (orig_size >= needed_size) { + memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length); + /* If the difference in size is greater than 0x4, split the block + * and free/merge it */ + if (orig_size - needed_size > 0x4) { + SIVALS(hbin->data, rel_offset, -needed_size); + SIVALS(hbin->data, rel_offset + needed_size, + needed_size-orig_size); + hbin_free(data, orig_offset + needed_size); + } + return orig_offset; + } + + possible_size = orig_size; + + /* Check if it can be combined with the next few free records */ + for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) { + if (IVALS(hbin->data, i) < 0) /* Used */ + break; + + my_size = IVALS(hbin->data, i); + + if (my_size == 0x0) { + DEBUG(0, ("Invalid zero-length block! File is corrupt.\n")); + break; + } else { + possible_size += my_size; + } + + if (possible_size >= blob.length) { + SIVAL(hbin->data, rel_offset, -possible_size); + memcpy(hbin->data + rel_offset + 0x4, + blob.data, blob.length); + return orig_offset; + } + } + + hbin_free(data, orig_offset); + return hbin_store(data, blob); +} + +static uint32_t hbin_store_tdr_resize(struct regf_data *regf, + tdr_push_fn_t push_fn, + uint32_t orig_offset, void *p) +{ + struct tdr_push *push = tdr_push_init(regf, regf->iconv_convenience); + uint32_t ret; + + if (NT_STATUS_IS_ERR(push_fn(push, p))) { + DEBUG(0, ("Error during push\n")); + return -1; + } + + ret = hbin_store_resize(regf, orig_offset, push->data); + + talloc_free(push); + + return ret; +} + +static uint32_t regf_create_lh_hash(const char *name) +{ + char *hash_name; + uint32_t ret = 0; + uint16_t i; + + hash_name = strupper_talloc(NULL, name); + for (i = 0; *(hash_name + i) != 0; i++) { + ret *= 37; + ret += *(hash_name + i); + } + talloc_free(hash_name); + return ret; +} + +static WERROR regf_get_info(TALLOC_CTX *mem_ctx, + const struct hive_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_mod_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + const struct regf_key_data *private_data = + (const struct regf_key_data *)key; + + if (num_subkeys != NULL) + *num_subkeys = private_data->nk->num_subkeys; + + if (num_values != NULL) + *num_values = private_data->nk->num_values; + + if (classname != NULL) { + if (private_data->nk->clsname_offset != -1) { + DATA_BLOB data = hbin_get(private_data->hive, + private_data->nk->clsname_offset); + *classname = talloc_strndup(mem_ctx, + (char*)data.data, + private_data->nk->clsname_length); + } else + *classname = NULL; + } + + /* TODO: Last mod time */ + + /* TODO: max valnamelen */ + + /* TODO: max valbufsize */ + + /* TODO: max subkeynamelen */ + + return WERR_OK; +} + +static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx, + struct regf_data *regf, + uint32_t offset) +{ + struct nk_block *nk; + struct regf_key_data *ret; + + ret = talloc_zero(ctx, struct regf_key_data); + ret->key.ops = ®_backend_regf; + ret->hive = talloc_reference(ret, regf); + ret->offset = offset; + nk = talloc(ret, struct nk_block); + if (nk == NULL) + return NULL; + + ret->nk = nk; + + if (!hbin_get_tdr(regf, offset, nk, + (tdr_pull_fn_t)tdr_pull_nk_block, nk)) { + DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset)); + return NULL; + } + + if (strcmp(nk->header, "nk") != 0) { + DEBUG(0, ("Expected nk record, got %s\n", nk->header)); + talloc_free(ret); + return NULL; + } + + return ret; +} + + +static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key, + int idx, const char **name, + uint32_t *data_type, DATA_BLOB *data) +{ + const struct regf_key_data *private_data = + (const struct regf_key_data *)key; + struct vk_block *vk; + struct regf_data *regf = private_data->hive; + uint32_t vk_offset; + DATA_BLOB tmp; + + if (idx >= private_data->nk->num_values) + return WERR_NO_MORE_ITEMS; + + tmp = hbin_get(regf, private_data->nk->values_offset); + if (!tmp.data) { + DEBUG(0, ("Unable to find value list\n")); + return WERR_GENERAL_FAILURE; + } + + if (tmp.length < private_data->nk->num_values * 4) { + DEBUG(1, ("Value counts mismatch\n")); + } + + vk_offset = IVAL(tmp.data, idx * 4); + + vk = talloc(NULL, struct vk_block); + W_ERROR_HAVE_NO_MEMORY(vk); + + if (!hbin_get_tdr(regf, vk_offset, vk, + (tdr_pull_fn_t)tdr_pull_vk_block, vk)) { + DEBUG(0, ("Unable to get VK block at %d\n", vk_offset)); + talloc_free(vk); + return WERR_GENERAL_FAILURE; + } + + /* FIXME: name character set ?*/ + if (name != NULL) + *name = talloc_strndup(ctx, vk->data_name, vk->name_length); + + if (data_type != NULL) + *data_type = vk->data_type; + + if (vk->data_length & 0x80000000) { + vk->data_length &=~0x80000000; + data->data = (uint8_t *)&vk->data_offset; + data->length = vk->data_length; + } else { + *data = hbin_get(regf, vk->data_offset); + } + + if (data->length < vk->data_length) { + DEBUG(1, ("Read data less than indicated data length!\n")); + } + + talloc_free(vk); + + return WERR_OK; +} + +static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx, + struct hive_key *key, const char *name, + uint32_t *type, DATA_BLOB *data) +{ + int i; + const char *vname; + WERROR error; + + /* FIXME: Do binary search? Is this list sorted at all? */ + + for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i, + &vname, type, data)); + i++) { + if (!strcmp(vname, name)) + return WERR_OK; + } + + if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) + return WERR_BADFILE; + + return error; +} + + +static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx, + const struct hive_key *key, + uint32_t idx, const char **name, + const char **classname, + NTTIME *last_mod_time) +{ + DATA_BLOB data; + struct regf_key_data *ret; + const struct regf_key_data *private_data = (const struct regf_key_data *)key; + struct nk_block *nk = private_data->nk; + uint32_t key_off=0; + + if (idx >= nk->num_subkeys) + return WERR_NO_MORE_ITEMS; + + data = hbin_get(private_data->hive, nk->subkeys_offset); + if (!data.data) { + DEBUG(0, ("Unable to find subkey list\n")); + return WERR_GENERAL_FAILURE; + } + + if (!strncmp((char *)data.data, "li", 2)) { + struct li_block li; + struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience); + + DEBUG(10, ("Subkeys in LI list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) { + DEBUG(0, ("Error parsing LI list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(li.header, "li", 2)); + + if (li.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } + key_off = li.nk_offset[idx]; + + } else if (!strncmp((char *)data.data, "lf", 2)) { + struct lf_block lf; + struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience); + + DEBUG(10, ("Subkeys in LF list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) { + DEBUG(0, ("Error parsing LF list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(lf.header, "lf", 2)); + + if (lf.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } + + key_off = lf.hr[idx].nk_offset; + } else if (!strncmp((char *)data.data, "lh", 2)) { + struct lh_block lh; + struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience); + + DEBUG(10, ("Subkeys in LH list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) { + DEBUG(0, ("Error parsing LH list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(lh.header, "lh", 2)); + + if (lh.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } + key_off = lh.hr[idx].nk_offset; + } else if (!strncmp((char *)data.data, "ri", 2)) { + struct ri_block ri; + struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience); + uint16_t i; + uint16_t sublist_count = 0; + + DEBUG(10, ("Subkeys in RI list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) { + DEBUG(0, ("Error parsing RI list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + SMB_ASSERT(!strncmp(ri.header, "ri", 2)); + + for (i = 0; i < ri.key_count; i++) { + DATA_BLOB list_data; + + /* Get sublist data blob */ + list_data = hbin_get(private_data->hive, ri.offset[i]); + if (!list_data.data) { + DEBUG(0, ("Error getting RI list.")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + + pull->data = list_data; + + if (!strncmp((char *)list_data.data, "li", 2)) { + struct li_block li; + + DEBUG(10, ("Subkeys in RI->LI list\n")); + + if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, + nk, + &li))) { + DEBUG(0, ("Error parsing LI list from RI\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + SMB_ASSERT(!strncmp(li.header, "li", 2)); + + /* Advance to next sublist if necessary */ + if (idx >= sublist_count + li.key_count) { + sublist_count += li.key_count; + continue; + } + key_off = li.nk_offset[idx - sublist_count]; + sublist_count += li.key_count; + break; + } else if (!strncmp((char *)list_data.data, "lh", 2)) { + struct lh_block lh; + + DEBUG(10, ("Subkeys in RI->LH list\n")); + + if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, + nk, + &lh))) { + DEBUG(0, ("Error parsing LH list from RI\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + SMB_ASSERT(!strncmp(lh.header, "lh", 2)); + + /* Advance to next sublist if necessary */ + if (idx >= sublist_count + lh.key_count) { + sublist_count += lh.key_count; + continue; + } + key_off = lh.hr[idx - sublist_count].nk_offset; + sublist_count += lh.key_count; + break; + } else { + DEBUG(0,("Unknown sublist in ri block\n")); + talloc_free(pull); + + return WERR_GENERAL_FAILURE; + } + + } + talloc_free(pull); + + + if (idx > sublist_count) { + return WERR_NO_MORE_ITEMS; + } + + } else { + DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", + nk->subkeys_offset, data.data[0], data.data[1])); + return WERR_GENERAL_FAILURE; + } + + ret = regf_get_key (ctx, private_data->hive, key_off); + + if (classname != NULL) { + if (ret->nk->clsname_offset != -1) { + DATA_BLOB db = hbin_get(ret->hive, + ret->nk->clsname_offset); + *classname = talloc_strndup(ctx, + (char*)db.data, + ret->nk->clsname_length); + } else + *classname = NULL; + } + + if (last_mod_time != NULL) + *last_mod_time = ret->nk->last_change; + + if (name != NULL) + *name = talloc_steal(ctx, ret->nk->key_name); + + talloc_free(ret); + + return WERR_OK; +} + +static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx, + const struct hive_key *key, + uint32_t offset, + const char *name, uint32_t *ret) +{ + DATA_BLOB subkey_data; + struct nk_block subkey; + struct tdr_pull *pull; + const struct regf_key_data *private_data = + (const struct regf_key_data *)key; + + subkey_data = hbin_get(private_data->hive, offset); + if (!subkey_data.data) { + DEBUG(0, ("Unable to retrieve subkey HBIN\n")); + return WERR_GENERAL_FAILURE; + } + + pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience); + + pull->data = subkey_data; + + if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, ctx, &subkey))) { + DEBUG(0, ("Error parsing NK structure.\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + + if (strncmp(subkey.header, "nk", 2)) { + DEBUG(0, ("Not an NK structure.\n")); + return WERR_GENERAL_FAILURE; + } + + if (!strcasecmp(subkey.key_name, name)) { + *ret = offset; + } else { + *ret = 0; + } + return WERR_OK; +} + +static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx, + const struct hive_key *key, + const char *name, + struct hive_key **ret) +{ + DATA_BLOB data; + const struct regf_key_data *private_data = + (const struct regf_key_data *)key; + struct nk_block *nk = private_data->nk; + uint32_t key_off = 0; + + data = hbin_get(private_data->hive, nk->subkeys_offset); + if (!data.data) { + DEBUG(0, ("Unable to find subkey list\n")); + return WERR_GENERAL_FAILURE; + } + + if (!strncmp((char *)data.data, "li", 2)) { + struct li_block li; + struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience); + uint16_t i; + + DEBUG(10, ("Subkeys in LI list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) { + DEBUG(0, ("Error parsing LI list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(li.header, "li", 2)); + + if (li.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } + + for (i = 0; i < li.key_count; i++) { + W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, + li.nk_offset[i], + name, + &key_off)); + if (key_off != 0) + break; + } + if (key_off == 0) + return WERR_BADFILE; + } else if (!strncmp((char *)data.data, "lf", 2)) { + struct lf_block lf; + struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience); + uint16_t i; + + DEBUG(10, ("Subkeys in LF list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) { + DEBUG(0, ("Error parsing LF list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(lf.header, "lf", 2)); + + if (lf.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } + + for (i = 0; i < lf.key_count; i++) { + if (strncmp(lf.hr[i].hash, name, 4)) { + continue; + } + W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, + key, + lf.hr[i].nk_offset, + name, + &key_off)); + if (key_off != 0) + break; + } + if (key_off == 0) + return WERR_BADFILE; + } else if (!strncmp((char *)data.data, "lh", 2)) { + struct lh_block lh; + struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience); + uint16_t i; + uint32_t hash; + + DEBUG(10, ("Subkeys in LH list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) { + DEBUG(0, ("Error parsing LH list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(lh.header, "lh", 2)); + + if (lh.key_count != nk->num_subkeys) { + DEBUG(0, ("Subkey counts don't match\n")); + return WERR_GENERAL_FAILURE; + } + + hash = regf_create_lh_hash(name); + for (i = 0; i < lh.key_count; i++) { + if (lh.hr[i].base37 != hash) { + continue; + } + W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, + key, + lh.hr[i].nk_offset, + name, + &key_off)); + if (key_off != 0) + break; + } + if (key_off == 0) + return WERR_BADFILE; + } else if (!strncmp((char *)data.data, "ri", 2)) { + struct ri_block ri; + struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience); + uint16_t i, j; + + DEBUG(10, ("Subkeys in RI list\n")); + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) { + DEBUG(0, ("Error parsing RI list\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + SMB_ASSERT(!strncmp(ri.header, "ri", 2)); + + for (i = 0; i < ri.key_count; i++) { + DATA_BLOB list_data; + + /* Get sublist data blob */ + list_data = hbin_get(private_data->hive, ri.offset[i]); + if (list_data.data == NULL) { + DEBUG(0, ("Error getting RI list.")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + + pull->data = list_data; + + if (!strncmp((char *)list_data.data, "li", 2)) { + struct li_block li; + + if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, + nk, + &li))) { + DEBUG(0, ("Error parsing LI list from RI\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + SMB_ASSERT(!strncmp(li.header, "li", 2)); + + for (j = 0; j < li.key_count; j++) { + W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, + li.nk_offset[j], + name, + &key_off)); + if (key_off) + break; + } + } else if (!strncmp((char *)list_data.data, "lh", 2)) { + struct lh_block lh; + uint32_t hash; + + if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, + nk, + &lh))) { + DEBUG(0, ("Error parsing LH list from RI\n")); + talloc_free(pull); + return WERR_GENERAL_FAILURE; + } + SMB_ASSERT(!strncmp(lh.header, "lh", 2)); + + hash = regf_create_lh_hash(name); + for (j = 0; j < lh.key_count; j++) { + if (lh.hr[j].base37 != hash) { + continue; + } + W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, + lh.hr[j].nk_offset, + name, + &key_off)); + if (key_off) + break; + } + } + if (key_off) + break; + } + talloc_free(pull); + if (!key_off) + return WERR_BADFILE; + } else { + DEBUG(0, ("Unknown subkey list type.\n")); + return WERR_GENERAL_FAILURE; + } + + *ret = (struct hive_key *)regf_get_key(ctx, private_data->hive, + key_off); + return WERR_OK; +} + +static WERROR regf_set_sec_desc(struct hive_key *key, + const struct security_descriptor *sec_desc) +{ + const struct regf_key_data *private_data = + (const struct regf_key_data *)key; + struct sk_block cur_sk, sk, new_sk; + struct regf_data *regf = private_data->hive; + struct nk_block root; + DATA_BLOB data; + uint32_t sk_offset, cur_sk_offset; + bool update_cur_sk = false; + + /* Get the root nk */ + hbin_get_tdr(regf, regf->header->data_offset, regf, + (tdr_pull_fn_t) tdr_pull_nk_block, &root); + + /* Push the security descriptor to a blob */ + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf, NULL, + sec_desc, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) { + DEBUG(0, ("Unable to push security descriptor\n")); + return WERR_GENERAL_FAILURE; + } + + /* Get the current security descriptor for the key */ + if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf, + (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) { + DEBUG(0, ("Unable to find security descriptor for current key\n")); + return WERR_BADFILE; + } + /* If there's no change, change nothing. */ + if (memcmp(data.data, cur_sk.sec_desc, + MIN(data.length, cur_sk.rec_size)) == 0) { + return WERR_OK; + } + + /* Delete the current sk if only this key is using it */ + if (cur_sk.ref_cnt == 1) { + /* Get the previous security descriptor for the key */ + if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf, + (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) { + DEBUG(0, ("Unable to find prev security descriptor for current key\n")); + return WERR_BADFILE; + } + /* Change and store the previous security descriptor */ + sk.next_offset = cur_sk.next_offset; + hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, + cur_sk.prev_offset, &sk); + + /* Get the next security descriptor for the key */ + if (!hbin_get_tdr(regf, cur_sk.next_offset, regf, + (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) { + DEBUG(0, ("Unable to find next security descriptor for current key\n")); + return WERR_BADFILE; + } + /* Change and store the next security descriptor */ + sk.prev_offset = cur_sk.prev_offset; + hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, + cur_sk.next_offset, &sk); + + hbin_free(regf, private_data->nk->sk_offset); + } else { + /* This key will no longer be referring to this sk */ + cur_sk.ref_cnt--; + update_cur_sk = true; + } + + sk_offset = root.sk_offset; + + do { + cur_sk_offset = sk_offset; + if (!hbin_get_tdr(regf, sk_offset, regf, + (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) { + DEBUG(0, ("Unable to find security descriptor\n")); + return WERR_BADFILE; + } + if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) { + private_data->nk->sk_offset = sk_offset; + sk.ref_cnt++; + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_sk_block, + sk_offset, &sk); + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_nk_block, + private_data->offset, + private_data->nk); + return WERR_OK; + } + sk_offset = sk.next_offset; + } while (sk_offset != root.sk_offset); + + ZERO_STRUCT(new_sk); + new_sk.header = "sk"; + new_sk.prev_offset = cur_sk_offset; + new_sk.next_offset = root.sk_offset; + new_sk.ref_cnt = 1; + new_sk.rec_size = data.length; + new_sk.sec_desc = data.data; + + sk_offset = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_sk_block, + &new_sk); + if (sk_offset == -1) { + DEBUG(0, ("Error storing sk block\n")); + return WERR_GENERAL_FAILURE; + } + private_data->nk->sk_offset = sk_offset; + + if (update_cur_sk) { + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_sk_block, + private_data->nk->sk_offset, &cur_sk); + } + + /* Get the previous security descriptor for the key */ + if (!hbin_get_tdr(regf, new_sk.prev_offset, regf, + (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) { + DEBUG(0, ("Unable to find security descriptor for previous key\n")); + return WERR_BADFILE; + } + /* Change and store the previous security descriptor */ + sk.next_offset = sk_offset; + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_sk_block, + cur_sk.prev_offset, &sk); + + /* Get the next security descriptor for the key (always root, as we append) */ + if (!hbin_get_tdr(regf, new_sk.next_offset, regf, + (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) { + DEBUG(0, ("Unable to find security descriptor for current key\n")); + return WERR_BADFILE; + } + /* Change and store the next security descriptor (always root, as we append) */ + sk.prev_offset = sk_offset; + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_sk_block, + root.sk_offset, &sk); + + + /* Store the nk. */ + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_sk_block, + private_data->offset, private_data->nk); + return WERR_OK; +} + +static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key, + struct security_descriptor **sd) +{ + const struct regf_key_data *private_data = + (const struct regf_key_data *)key; + struct sk_block sk; + struct regf_data *regf = private_data->hive; + DATA_BLOB data; + + if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx, + (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) { + DEBUG(0, ("Unable to find security descriptor\n")); + return WERR_GENERAL_FAILURE; + } + + if (strcmp(sk.header, "sk") != 0) { + DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header)); + return WERR_GENERAL_FAILURE; + } + + *sd = talloc(ctx, struct security_descriptor); + W_ERROR_HAVE_NO_MEMORY(*sd); + + data.data = sk.sec_desc; + data.length = sk.rec_size; + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&data, ctx, NULL, *sd, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) { + DEBUG(0, ("Error parsing security descriptor\n")); + return WERR_GENERAL_FAILURE; + } + + return WERR_OK; +} + +static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset, + const char *name, + uint32_t key_offset, uint32_t *ret) +{ + DATA_BLOB data; + + /* Create a new key if necessary */ + if (list_offset == -1) { + if (regf->header->version.major != 1) { + DEBUG(0, ("Can't store keys in unknown registry format\n")); + return WERR_NOT_SUPPORTED; + } + if (regf->header->version.minor < 3) { + /* Store LI */ + struct li_block li; + ZERO_STRUCT(li); + li.header = "li"; + li.key_count = 1; + + li.nk_offset = talloc_array(regf, uint32_t, 1); + W_ERROR_HAVE_NO_MEMORY(li.nk_offset); + li.nk_offset[0] = key_offset; + + *ret = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_li_block, + &li); + + talloc_free(li.nk_offset); + } else if (regf->header->version.minor == 3 || + regf->header->version.minor == 4) { + /* Store LF */ + struct lf_block lf; + ZERO_STRUCT(lf); + lf.header = "lf"; + lf.key_count = 1; + + lf.hr = talloc_array(regf, struct hash_record, 1); + W_ERROR_HAVE_NO_MEMORY(lf.hr); + lf.hr[0].nk_offset = key_offset; + lf.hr[0].hash = talloc_strndup(lf.hr, name, 4); + W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash); + + *ret = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_lf_block, + &lf); + + talloc_free(lf.hr); + } else if (regf->header->version.minor == 5) { + /* Store LH */ + struct lh_block lh; + ZERO_STRUCT(lh); + lh.header = "lh"; + lh.key_count = 1; + + lh.hr = talloc_array(regf, struct lh_hash, 1); + W_ERROR_HAVE_NO_MEMORY(lh.hr); + lh.hr[0].nk_offset = key_offset; + lh.hr[0].base37 = regf_create_lh_hash(name); + + *ret = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_lh_block, + &lh); + + talloc_free(lh.hr); + } + return WERR_OK; + } + + data = hbin_get(regf, list_offset); + if (!data.data) { + DEBUG(0, ("Unable to find subkey list\n")); + return WERR_BADFILE; + } + + if (!strncmp((char *)data.data, "li", 2)) { + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + struct li_block li; + + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) { + DEBUG(0, ("Error parsing LI list\n")); + talloc_free(pull); + return WERR_BADFILE; + } + talloc_free(pull); + + if (strncmp(li.header, "li", 2) != 0) { + abort(); + DEBUG(0, ("LI header corrupt\n")); + return WERR_BADFILE; + } + + li.nk_offset = talloc_realloc(regf, li.nk_offset, + uint32_t, li.key_count+1); + W_ERROR_HAVE_NO_MEMORY(li.nk_offset); + li.nk_offset[li.key_count] = key_offset; + li.key_count++; + *ret = hbin_store_tdr_resize(regf, + (tdr_push_fn_t)tdr_push_li_block, + list_offset, &li); + + talloc_free(li.nk_offset); + } else if (!strncmp((char *)data.data, "lf", 2)) { + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + struct lf_block lf; + + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) { + DEBUG(0, ("Error parsing LF list\n")); + talloc_free(pull); + return WERR_BADFILE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(lf.header, "lf", 2)); + + lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, + lf.key_count+1); + W_ERROR_HAVE_NO_MEMORY(lf.hr); + lf.hr[lf.key_count].nk_offset = key_offset; + lf.hr[lf.key_count].hash = talloc_strndup(lf.hr, name, 4); + W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash); + lf.key_count++; + *ret = hbin_store_tdr_resize(regf, + (tdr_push_fn_t)tdr_push_lf_block, + list_offset, &lf); + + talloc_free(lf.hr); + } else if (!strncmp((char *)data.data, "lh", 2)) { + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + struct lh_block lh; + + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) { + DEBUG(0, ("Error parsing LH list\n")); + talloc_free(pull); + return WERR_BADFILE; + } + talloc_free(pull); + SMB_ASSERT(!strncmp(lh.header, "lh", 2)); + + lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash, + lh.key_count+1); + W_ERROR_HAVE_NO_MEMORY(lh.hr); + lh.hr[lh.key_count].nk_offset = key_offset; + lh.hr[lh.key_count].base37 = regf_create_lh_hash(name); + lh.key_count++; + *ret = hbin_store_tdr_resize(regf, + (tdr_push_fn_t)tdr_push_lh_block, + list_offset, &lh); + + talloc_free(lh.hr); + } else if (!strncmp((char *)data.data, "ri", 2)) { + /* FIXME */ + DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n")); + return WERR_NOT_SUPPORTED; + } else { + DEBUG(0, ("Cannot add to unknown subkey list\n")); + return WERR_BADFILE; + } + + return WERR_OK; +} + +static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset, + uint32_t key_offset, uint32_t *ret) +{ + DATA_BLOB data; + + data = hbin_get(regf, list_offset); + if (!data.data) { + DEBUG(0, ("Unable to find subkey list\n")); + return WERR_BADFILE; + } + + if (strncmp((char *)data.data, "li", 2) == 0) { + struct li_block li; + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + uint16_t i; + bool found_offset = false; + + DEBUG(10, ("Subkeys in LI list\n")); + + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) { + DEBUG(0, ("Error parsing LI list\n")); + talloc_free(pull); + return WERR_BADFILE; + } + talloc_free(pull); + + SMB_ASSERT(!strncmp(li.header, "li", 2)); + + for (i = 0; i < li.key_count; i++) { + if (found_offset) { + li.nk_offset[i-1] = li.nk_offset[i]; + } + if (li.nk_offset[i] == key_offset) { + found_offset = true; + continue; + } + } + if (!found_offset) { + DEBUG(2, ("Subkey not found\n")); + return WERR_BADFILE; + } + li.key_count--; + + /* If the there are no entries left, free the subkey list */ + if (li.key_count == 0) { + hbin_free(regf, list_offset); + *ret = -1; + } + + /* Store li block */ + *ret = hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_li_block, + list_offset, &li); + } else if (strncmp((char *)data.data, "lf", 2) == 0) { + struct lf_block lf; + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + uint16_t i; + bool found_offset = false; + + DEBUG(10, ("Subkeys in LF list\n")); + + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) { + DEBUG(0, ("Error parsing LF list\n")); + talloc_free(pull); + return WERR_BADFILE; + } + talloc_free(pull); + + SMB_ASSERT(!strncmp(lf.header, "lf", 2)); + + for (i = 0; i < lf.key_count; i++) { + if (found_offset) { + lf.hr[i-1] = lf.hr[i]; + continue; + } + if (lf.hr[i].nk_offset == key_offset) { + found_offset = 1; + continue; + } + } + if (!found_offset) { + DEBUG(2, ("Subkey not found\n")); + return WERR_BADFILE; + } + lf.key_count--; + + /* If the there are no entries left, free the subkey list */ + if (lf.key_count == 0) { + hbin_free(regf, list_offset); + *ret = -1; + return WERR_OK; + } + + /* Store lf block */ + *ret = hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_lf_block, + list_offset, &lf); + } else if (strncmp((char *)data.data, "lh", 2) == 0) { + struct lh_block lh; + struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience); + uint16_t i; + bool found_offset = false; + + DEBUG(10, ("Subkeys in LH list\n")); + + pull->data = data; + + if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) { + DEBUG(0, ("Error parsing LF list\n")); + talloc_free(pull); + return WERR_BADFILE; + } + talloc_free(pull); + + SMB_ASSERT(!strncmp(lh.header, "lh", 2)); + + for (i = 0; i < lh.key_count; i++) { + if (found_offset) { + lh.hr[i-1] = lh.hr[i]; + continue; + } + if (lh.hr[i].nk_offset == key_offset) { + found_offset = 1; + continue; + } + } + if (!found_offset) { + DEBUG(0, ("Subkey not found\n")); + return WERR_BADFILE; + } + lh.key_count--; + + /* If the there are no entries left, free the subkey list */ + if (lh.key_count == 0) { + hbin_free(regf, list_offset); + *ret = -1; + return WERR_OK; + } + + /* Store lh block */ + *ret = hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_lh_block, + list_offset, &lh); + } else if (strncmp((char *)data.data, "ri", 2) == 0) { + /* FIXME */ + DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n")); + return WERR_NOT_SUPPORTED; + } else { + DEBUG (0, ("Unknown header found in subkey list.\n")); + return WERR_BADFILE; + } + return WERR_OK; +} + +static WERROR regf_del_value (struct hive_key *key, const char *name) +{ + struct regf_key_data *private_data = (struct regf_key_data *)key; + struct regf_data *regf = private_data->hive; + struct nk_block *nk = private_data->nk; + struct vk_block vk; + uint32_t vk_offset; + bool found_offset = false; + DATA_BLOB values; + uint32_t i; + + if (nk->values_offset == -1) { + return WERR_BADFILE; + } + + values = hbin_get(regf, nk->values_offset); + + for (i = 0; i < nk->num_values; i++) { + if (found_offset) { + ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i]; + } else { + vk_offset = IVAL(values.data, i * 4); + if (!hbin_get_tdr(regf, vk_offset, private_data, + (tdr_pull_fn_t)tdr_pull_vk_block, + &vk)) { + DEBUG(0, ("Unable to get VK block at %d\n", + vk_offset)); + return WERR_BADFILE; + } + if (strcmp(vk.data_name, name) == 0) { + hbin_free(regf, vk_offset); + found_offset = true; + } + } + } + if (!found_offset) { + return WERR_BADFILE; + } else { + nk->num_values--; + values.length = (nk->num_values)*4; + } + + /* Store values list and nk */ + if (nk->num_values == 0) { + hbin_free(regf, nk->values_offset); + nk->values_offset = -1; + } else { + nk->values_offset = hbin_store_resize(regf, + nk->values_offset, + values); + } + hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, + private_data->offset, nk); + + return regf_save_hbin(private_data->hive); +} + + +static WERROR regf_del_key(const struct hive_key *parent, const char *name) +{ + const struct regf_key_data *private_data = + (const struct regf_key_data *)parent; + struct regf_key_data *key; + struct nk_block *parent_nk; + WERROR error; + + SMB_ASSERT(private_data); + + parent_nk = private_data->nk; + + if (parent_nk->subkeys_offset == -1) { + DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n")); + return WERR_BADFILE; + } + + /* Find the key */ + if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name, + (struct hive_key **)&key))) { + DEBUG(2, ("Key '%s' not found\n", name)); + return WERR_BADFILE; + } + + if (key->nk->subkeys_offset != -1) { + char *sk_name; + struct hive_key *sk = (struct hive_key *)key; + int i = key->nk->num_subkeys; + while (i--) { + /* Get subkey information. */ + error = regf_get_subkey_by_index(parent_nk, sk, 0, + (const char **)&sk_name, + NULL, NULL); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't retrieve subkey by index.\n")); + return error; + } + + /* Delete subkey. */ + error = regf_del_key(sk, sk_name); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't delete key '%s'.\n", sk_name)); + return error; + } + + talloc_free(sk_name); + } + } + + if (key->nk->values_offset != -1) { + char *val_name; + struct hive_key *sk = (struct hive_key *)key; + DATA_BLOB data; + int i = key->nk->num_values; + while (i--) { + /* Get value information. */ + error = regf_get_value(parent_nk, sk, 0, + (const char **)&val_name, + NULL, &data); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't retrieve value by index.\n")); + return error; + } + + /* Delete value. */ + error = regf_del_value(sk, val_name); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't delete value '%s'.\n", val_name)); + return error; + } + + talloc_free(val_name); + } + } + + /* Delete it from the subkey list. */ + error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset, + key->offset, &parent_nk->subkeys_offset); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n")); + return error; + } + + /* Re-store parent key */ + parent_nk->num_subkeys--; + hbin_store_tdr_resize(private_data->hive, + (tdr_push_fn_t) tdr_push_nk_block, + private_data->offset, parent_nk); + + if (key->nk->clsname_offset != -1) { + hbin_free(private_data->hive, key->nk->clsname_offset); + } + hbin_free(private_data->hive, key->offset); + + return regf_save_hbin(private_data->hive); +} + +static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent, + const char *name, const char *classname, + struct security_descriptor *sec_desc, + struct hive_key **ret) +{ + const struct regf_key_data *private_data = + (const struct regf_key_data *)parent; + struct nk_block *parent_nk = private_data->nk, nk; + struct nk_block *root; + struct regf_data *regf = private_data->hive; + uint32_t offset; + WERROR error; + + nk.header = "nk"; + nk.type = REG_SUB_KEY; + unix_to_nt_time(&nk.last_change, time(NULL)); + nk.uk1 = 0; + nk.parent_offset = private_data->offset; + nk.num_subkeys = 0; + nk.uk2 = 0; + nk.subkeys_offset = -1; + nk.unknown_offset = -1; + nk.num_values = 0; + nk.values_offset = -1; + memset(nk.unk3, 0, 5); + nk.clsname_offset = -1; /* FIXME: fill in */ + nk.clsname_length = 0; + nk.key_name = name; + + /* Get the security descriptor of the root key */ + root = talloc_zero(ctx, struct nk_block); + W_ERROR_HAVE_NO_MEMORY(root); + + if (!hbin_get_tdr(regf, regf->header->data_offset, root, + (tdr_pull_fn_t)tdr_pull_nk_block, root)) { + DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset)); + return WERR_GENERAL_FAILURE; + } + nk.sk_offset = root->sk_offset; + talloc_free(root); + + /* Store the new nk key */ + offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk); + + error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset, + &parent_nk->subkeys_offset); + if (!W_ERROR_IS_OK(error)) { + hbin_free(regf, offset); + return error; + } + + parent_nk->num_subkeys++; + + /* Since the subkey offset of the parent can change, store it again */ + hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, + nk.parent_offset, parent_nk); + + *ret = (struct hive_key *)regf_get_key(ctx, regf, offset); + + return regf_save_hbin(private_data->hive); +} + +static WERROR regf_set_value(struct hive_key *key, const char *name, + uint32_t type, const DATA_BLOB data) +{ + struct regf_key_data *private_data = (struct regf_key_data *)key; + struct regf_data *regf = private_data->hive; + struct nk_block *nk = private_data->nk; + struct vk_block vk; + uint32_t i; + uint32_t tmp_vk_offset, vk_offset, old_vk_offset = -1; + DATA_BLOB values; + + ZERO_STRUCT(vk); + + /* find the value offset, if it exists */ + if (nk->values_offset != -1) { + values = hbin_get(regf, nk->values_offset); + + for (i = 0; i < nk->num_values; i++) { + tmp_vk_offset = IVAL(values.data, i * 4); + if (!hbin_get_tdr(regf, tmp_vk_offset, private_data, + (tdr_pull_fn_t)tdr_pull_vk_block, + &vk)) { + DEBUG(0, ("Unable to get VK block at %d\n", + tmp_vk_offset)); + return WERR_GENERAL_FAILURE; + } + if (strcmp(vk.data_name, name) == 0) { + old_vk_offset = tmp_vk_offset; + break; + } + } + /* Free data, if any */ + if (!(vk.data_length & 0x80000000)) { + hbin_free(regf, vk.data_offset); + } + } + if (old_vk_offset == -1) { + vk.header = "vk"; + vk.name_length = strlen(name); + if (name != NULL && name[0] != 0) { + vk.flag = 1; + vk.data_name = name; + } else { + vk.data_name = NULL; + vk.flag = 0; + } + } + /* Set the type and data */ + vk.data_length = data.length; + vk.data_type = type; + if (type == REG_DWORD) { + vk.data_length |= 0x80000000; + vk.data_offset = *(uint32_t *)data.data; + } else { + /* Store data somewhere */ + vk.data_offset = hbin_store(regf, data); + } + if (old_vk_offset == -1) { + /* Store new vk */ + vk_offset = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_vk_block, + &vk); + } else { + /* Store vk at offset */ + vk_offset = hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_vk_block, + old_vk_offset ,&vk); + } + + /* Re-allocate the value list */ + if (nk->values_offset == -1) { + nk->values_offset = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_uint32, + &vk_offset); + nk->num_values = 1; + } else { + + /* Change if we're changing, otherwise we're adding the value */ + if (old_vk_offset != -1) { + /* Find and overwrite the offset. */ + for (i = 0; i < nk->num_values; i++) { + if (IVAL(values.data, i * 4) == old_vk_offset) { + SIVAL(values.data, i * 4, vk_offset); + break; + } + } + } else { + /* Create a new value list */ + DATA_BLOB value_list; + + value_list.length = (nk->num_values+1)*4; + value_list.data = (uint8_t *)talloc_array(private_data, + uint32_t, + nk->num_values+1); + W_ERROR_HAVE_NO_MEMORY(value_list.data); + memcpy(value_list.data, values.data, nk->num_values * 4); + + SIVAL(value_list.data, nk->num_values * 4, vk_offset); + nk->num_values++; + nk->values_offset = hbin_store_resize(regf, + nk->values_offset, + value_list); + } + + } + hbin_store_tdr_resize(regf, + (tdr_push_fn_t) tdr_push_nk_block, + private_data->offset, nk); + return regf_save_hbin(private_data->hive); +} + +static WERROR regf_save_hbin(struct regf_data *regf) +{ + struct tdr_push *push = tdr_push_init(regf, regf->iconv_convenience); + int i; + + W_ERROR_HAVE_NO_MEMORY(push); + + if (lseek(regf->fd, 0, SEEK_SET) == -1) { + DEBUG(0, ("Error lseeking in regf file\n")); + return WERR_GENERAL_FAILURE; + } + + /* Recompute checksum */ + if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) { + DEBUG(0, ("Failed to push regf header\n")); + return WERR_GENERAL_FAILURE; + } + regf->header->chksum = regf_hdr_checksum(push->data.data); + talloc_free(push); + + if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, regf->iconv_convenience, + (tdr_push_fn_t)tdr_push_regf_hdr, + regf->header))) { + DEBUG(0, ("Error writing registry file header\n")); + return WERR_GENERAL_FAILURE; + } + + if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) { + DEBUG(0, ("Error lseeking to 0x1000 in regf file\n")); + return WERR_GENERAL_FAILURE; + } + + for (i = 0; regf->hbins[i]; i++) { + if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, regf->iconv_convenience, + (tdr_push_fn_t)tdr_push_hbin_block, + regf->hbins[i]))) { + DEBUG(0, ("Error writing HBIN block\n")); + return WERR_GENERAL_FAILURE; + } + } + + return WERR_OK; +} + +WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, + struct smb_iconv_convenience *iconv_convenience, + const char *location, + int minor_version, struct hive_key **key) +{ + struct regf_data *regf; + struct regf_hdr *regf_hdr; + struct nk_block nk; + struct sk_block sk; + WERROR error; + DATA_BLOB data; + struct security_descriptor *sd; + uint32_t sk_offset; + + regf = (struct regf_data *)talloc_zero(NULL, struct regf_data); + + regf->iconv_convenience = iconv_convenience; + + W_ERROR_HAVE_NO_MEMORY(regf); + + DEBUG(5, ("Attempting to create registry file\n")); + + /* Get the header */ + regf->fd = creat(location, 0644); + + if (regf->fd == -1) { + DEBUG(0,("Could not create file: %s, %s\n", location, + strerror(errno))); + talloc_free(regf); + return WERR_GENERAL_FAILURE; + } + + regf_hdr = talloc_zero(regf, struct regf_hdr); + W_ERROR_HAVE_NO_MEMORY(regf_hdr); + regf_hdr->REGF_ID = "regf"; + unix_to_nt_time(®f_hdr->modtime, time(NULL)); + regf_hdr->version.major = 1; + regf_hdr->version.minor = minor_version; + regf_hdr->last_block = 0x1000; /* Block size */ + regf_hdr->description = talloc_strdup(regf_hdr, + "Registry created by Samba 4"); + W_ERROR_HAVE_NO_MEMORY(regf_hdr->description); + regf_hdr->chksum = 0; + + regf->header = regf_hdr; + + /* Create all hbin blocks */ + regf->hbins = talloc_array(regf, struct hbin_block *, 1); + W_ERROR_HAVE_NO_MEMORY(regf->hbins); + regf->hbins[0] = NULL; + + nk.header = "nk"; + nk.type = REG_SUB_KEY; + unix_to_nt_time(&nk.last_change, time(NULL)); + nk.uk1 = 0; + nk.parent_offset = -1; + nk.num_subkeys = 0; + nk.uk2 = 0; + nk.subkeys_offset = -1; + nk.unknown_offset = -1; + nk.num_values = 0; + nk.values_offset = -1; + memset(nk.unk3, 0, 5); + nk.clsname_offset = -1; + nk.clsname_length = 0; + nk.sk_offset = 0x80; + nk.key_name = "SambaRootKey"; + + /* + * It should be noted that changing the key_name to something shorter + * creates a shorter nk block, which makes the position of the sk block + * change. All Windows registries I've seen have the sk at 0x80. + * I therefore recommend that our regf files share that offset -- Wilco + */ + + /* Create a security descriptor. */ + sd = security_descriptor_dacl_create(regf, + 0, + NULL, NULL, + SID_NT_AUTHENTICATED_USERS, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_GENERIC_ALL, + SEC_ACE_FLAG_OBJECT_INHERIT, + NULL); + + /* Push the security descriptor to a blob */ + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf, NULL, + sd, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) { + DEBUG(0, ("Unable to push security descriptor\n")); + return WERR_GENERAL_FAILURE; + } + + ZERO_STRUCT(sk); + sk.header = "sk"; + sk.prev_offset = 0x80; + sk.next_offset = 0x80; + sk.ref_cnt = 1; + sk.rec_size = data.length; + sk.sec_desc = data.data; + + /* Store the new nk key */ + regf->header->data_offset = hbin_store_tdr(regf, + (tdr_push_fn_t)tdr_push_nk_block, + &nk); + /* Store the sk block */ + sk_offset = hbin_store_tdr(regf, + (tdr_push_fn_t) tdr_push_sk_block, + &sk); + if (sk_offset != 0x80) { + DEBUG(0, ("Error storing sk block, should be at 0x80, stored at 0x%x\n", nk.sk_offset)); + return WERR_GENERAL_FAILURE; + } + + + *key = (struct hive_key *)regf_get_key(parent_ctx, regf, + regf->header->data_offset); + + error = regf_save_hbin(regf); + if (!W_ERROR_IS_OK(error)) { + return error; + } + + /* We can drop our own reference now that *key will have created one */ + talloc_free(regf); + + return WERR_OK; +} + +WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, const char *location, + struct smb_iconv_convenience *iconv_convenience, struct hive_key **key) +{ + struct regf_data *regf; + struct regf_hdr *regf_hdr; + struct tdr_pull *pull; + int i; + + regf = (struct regf_data *)talloc_zero(NULL, struct regf_data); + + regf->iconv_convenience = iconv_convenience; + + W_ERROR_HAVE_NO_MEMORY(regf); + + DEBUG(5, ("Attempting to load registry file\n")); + + /* Get the header */ + regf->fd = open(location, O_RDWR); + + if (regf->fd == -1) { + DEBUG(0,("Could not load file: %s, %s\n", location, + strerror(errno))); + talloc_free(regf); + return WERR_GENERAL_FAILURE; + } + + pull = tdr_pull_init(regf, regf->iconv_convenience); + + pull->data.data = (uint8_t*)fd_load(regf->fd, &pull->data.length, regf); + + if (pull->data.data == NULL) { + DEBUG(0, ("Error reading data\n")); + talloc_free(regf); + return WERR_GENERAL_FAILURE; + } + + regf_hdr = talloc(regf, struct regf_hdr); + W_ERROR_HAVE_NO_MEMORY(regf_hdr); + + if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr, regf_hdr))) { + talloc_free(regf); + return WERR_GENERAL_FAILURE; + } + + regf->header = regf_hdr; + + if (strcmp(regf_hdr->REGF_ID, "regf") != 0) { + DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n", + regf_hdr->REGF_ID, location)); + talloc_free(regf); + return WERR_GENERAL_FAILURE; + } + + /* Validate the header ... */ + if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) { + DEBUG(0, ("Registry file checksum error: %s: %d,%d\n", + location, regf_hdr->chksum, + regf_hdr_checksum(pull->data.data))); + talloc_free(regf); + return WERR_GENERAL_FAILURE; + } + + pull->offset = 0x1000; + + i = 0; + /* Read in all hbin blocks */ + regf->hbins = talloc_array(regf, struct hbin_block *, 1); + W_ERROR_HAVE_NO_MEMORY(regf->hbins); + + regf->hbins[0] = NULL; + + while (pull->offset < pull->data.length && + pull->offset <= regf->header->last_block) { + struct hbin_block *hbin = talloc(regf->hbins, + struct hbin_block); + + W_ERROR_HAVE_NO_MEMORY(hbin); + + if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin, hbin))) { + DEBUG(0, ("[%d] Error parsing HBIN block\n", i)); + talloc_free(regf); + return WERR_FOOBAR; + } + + if (strcmp(hbin->HBIN_ID, "hbin") != 0) { + DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", + i, hbin->HBIN_ID)); + talloc_free(regf); + return WERR_FOOBAR; + } + + regf->hbins[i] = hbin; + i++; + regf->hbins = talloc_realloc(regf, regf->hbins, + struct hbin_block *, i+2); + regf->hbins[i] = NULL; + } + + talloc_free(pull); + + DEBUG(1, ("%d HBIN blocks read\n", i)); + + *key = (struct hive_key *)regf_get_key(parent_ctx, regf, + regf->header->data_offset); + + /* We can drop our own reference now that *key will have created one */ + talloc_free(regf); + + return WERR_OK; +} + +static struct hive_operations reg_backend_regf = { + .name = "regf", + .get_key_info = regf_get_info, + .enum_key = regf_get_subkey_by_index, + .get_key_by_name = regf_get_subkey_by_name, + .get_value_by_name = regf_get_value_by_name, + .enum_value = regf_get_value, + .get_sec_desc = regf_get_sec_desc, + .set_sec_desc = regf_set_sec_desc, + .add_key = regf_add_key, + .set_value = regf_set_value, + .del_key = regf_del_key, + .delete_value = regf_del_value, +}; diff --git a/source4/lib/registry/regf.idl b/source4/lib/registry/regf.idl new file mode 100644 index 0000000000..ffd7072b7a --- /dev/null +++ b/source4/lib/registry/regf.idl @@ -0,0 +1,167 @@ +/* + Definitions for the REGF registry file format as used by + Windows NT4 and above. + + Copyright (C) 2005 Jelmer Vernooij, jelmer@samba.org + Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl + + Based on two files from Samba 3: + regedit.c by Richard Sharpe + regfio.c by Jerry Carter + +*/ + +interface regf +{ + const int REGF_OFFSET_NONE = 0xffffffff; + + /* + * Registry version number + * 1.2.0.1 for WinNT 3.51 + * 1.3.0.1 for WinNT 4 + * 1.5.0.1 for WinXP + */ + + [noprint] struct regf_version { + [value(1)] uint32 major; + [value(3)] uint32 minor; + [value(0)] uint32 release; + [value(1)] uint32 build; + }; + + /* + "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! + */ + + [public,noprint] struct regf_hdr { + [charset(DOS)] uint8 REGF_ID[4]; /* 'regf' */ + uint32 update_counter1; + uint32 update_counter2; + NTTIME modtime; + regf_version version; + uint32 data_offset; + uint32 last_block; + [value(1)] uint32 uk7; /* 1 */ + [charset(UTF16)] uint16 description[0x20]; + uint32 padding[99]; /* Padding */ + /* Checksum of first 0x200 bytes XOR-ed */ + uint32 chksum; + }; + + /* + hbin probably means hive-bin (i.e. hive-container) + This block is always a multiple + of 4kb in size. + */ + [public,noprint] struct hbin_block { + [charset(DOS)] uint8 HBIN_ID[4]; /* hbin */ + uint32 offset_from_first; /* Offset from 1st hbin-Block */ + uint32 offset_to_next; /* Offset to the next hbin-Block */ + uint32 unknown[2]; + NTTIME last_change; + uint32 block_size; /* Block size (including the header!) */ + uint8 data[offset_to_next-0x20]; + /* data is filled with: + uint32 length; + Negative if in use, positive otherwise + Always a multiple of 8 + uint8_t data[length]; + Free space marker if 0xffffffff + */ + }; + + [noprint] enum reg_key_type { + REG_ROOT_KEY = 0x20, + REG_SUB_KEY = 0x2C, + REG_SYM_LINK = 0x10 + }; + + /* + The nk-record can be treated as a combination of tree-record and + key-record of the win 95 registry. + */ + [public,noprint] struct nk_block { + [charset(DOS)] uint8 header[2]; + reg_key_type type; + NTTIME last_change; + uint32 uk1; + uint32 parent_offset; + uint32 num_subkeys; + uint32 uk2; + uint32 subkeys_offset; + uint32 unknown_offset; + uint32 num_values; + uint32 values_offset; /* Points to a list of offsets of vk-records */ + uint32 sk_offset; + uint32 clsname_offset; + uint32 unk3[5]; + [value(strlen(key_name))] uint16 name_length; + uint16 clsname_length; + [charset(DOS)] uint8 key_name[name_length]; + }; + + /* sk (? Security Key ?) is the ACL of the registry. */ + [noprint,public] struct sk_block { + [charset(DOS)] uint8 header[2]; + uint16 tag; + uint32 prev_offset; + uint32 next_offset; + uint32 ref_cnt; + uint32 rec_size; + uint8 sec_desc[rec_size]; + }; + + [noprint] struct lh_hash { + uint32 nk_offset; + uint32 base37; /* base37 of key name */ + }; + + /* Subkey listing with hash of first 4 characters */ + [public,noprint] struct lh_block { + [charset(DOS)] uint8 header[2]; + uint16 key_count; + lh_hash hr[key_count]; + }; + + [public,noprint] struct li_block { + [charset(DOS)] uint8 header[2]; + uint16 key_count; + uint32 nk_offset[key_count]; + }; + + [public,noprint] struct ri_block { + [charset(DOS)] uint8 header[2]; + uint16 key_count; + uint32 offset[key_count]; /* li/lh offset */ + }; + + /* The vk-record consists information to a single value (value key). */ + [public,noprint] struct vk_block { + [charset(DOS)] uint8 header[2]; + [value(strlen(data_name))] uint16 name_length; + uint32 data_length; /* If top-bit set, offset contains the data */ + uint32 data_offset; + uint32 data_type; + uint16 flag; /* =1, has name, else no name (=Default). */ + uint16 unk1; + [charset(DOS)] uint8 data_name[name_length]; + }; + + [noprint] struct hash_record { + uint32 nk_offset; + [charset(DOS)] uint8 hash[4]; + }; + + /* + The lf-record is the counterpart to the RGKN-record (the + hash-function) + */ + [public,noprint] struct lf_block { + [charset(DOS)] uint8 header[2]; + uint16 key_count; + hash_record hr[key_count]; /* Array of hash records, depending on key_count */ + }; +} diff --git a/source4/lib/registry/registry.h b/source4/lib/registry/registry.h new file mode 100644 index 0000000000..e134e3e532 --- /dev/null +++ b/source4/lib/registry/registry.h @@ -0,0 +1,513 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Gerald Carter 2002. + Copyright (C) Jelmer Vernooij 2003-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _REGISTRY_H /* _REGISTRY_H */ +#define _REGISTRY_H + +struct registry_context; +struct loadparm_context; +struct smb_iconv_convenience; + +#include <talloc.h> +#include "libcli/util/werror.h" +#include "librpc/gen_ndr/security.h" +#include "libcli/util/ntstatus.h" +#include "util/time.h" +#include "util/data_blob.h" + +/** + * The hive API. This API is generally used for + * reading a specific file that contains just one hive. + * + * Good examples are .DAT (NTUSER.DAT) files. + * + * This API does not have any notification support (that + * should be provided by the registry implementation), nor + * does it understand what predefined keys are. + */ + +struct hive_key { + const struct hive_operations *ops; +}; + +struct hive_operations { + const char *name; + + /** + * Open a specific subkey + */ + WERROR (*enum_key) (TALLOC_CTX *mem_ctx, + const struct hive_key *key, uint32_t idx, + const char **name, + const char **classname, + NTTIME *last_mod_time); + + /** + * Open a subkey by name + */ + WERROR (*get_key_by_name) (TALLOC_CTX *mem_ctx, + const struct hive_key *key, const char *name, + struct hive_key **subkey); + + /** + * Add a new key. + */ + WERROR (*add_key) (TALLOC_CTX *ctx, + const struct hive_key *parent_key, const char *name, + const char *classname, + struct security_descriptor *desc, + struct hive_key **key); + /** + * Remove an existing key. + */ + WERROR (*del_key) (const struct hive_key *key, const char *name); + + /** + * Force write of a key to disk. + */ + WERROR (*flush_key) (struct hive_key *key); + + /** + * Retrieve a registry value with a specific index. + */ + WERROR (*enum_value) (TALLOC_CTX *mem_ctx, + struct hive_key *key, int idx, + const char **name, uint32_t *type, + DATA_BLOB *data); + + /** + * Retrieve a registry value with the specified name + */ + WERROR (*get_value_by_name) (TALLOC_CTX *mem_ctx, + struct hive_key *key, const char *name, + uint32_t *type, DATA_BLOB *data); + + /** + * Set a value on the specified registry key. + */ + WERROR (*set_value) (struct hive_key *key, const char *name, + uint32_t type, const DATA_BLOB data); + + /** + * Remove a value. + */ + WERROR (*delete_value) (struct hive_key *key, const char *name); + + /* Security Descriptors */ + + /** + * Change the security descriptor on a registry key. + * + * This should return WERR_NOT_SUPPORTED if the underlying + * format does not have a mechanism for storing + * security descriptors. + */ + WERROR (*set_sec_desc) (struct hive_key *key, + const struct security_descriptor *desc); + + /** + * Retrieve the security descriptor on a registry key. + * + * This should return WERR_NOT_SUPPORTED if the underlying + * format does not have a mechanism for storing + * security descriptors. + */ + WERROR (*get_sec_desc) (TALLOC_CTX *ctx, + const struct hive_key *key, + struct security_descriptor **desc); + + /** + * Retrieve general information about a key. + */ + WERROR (*get_key_info) (TALLOC_CTX *mem_ctx, + const struct hive_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize); +}; + +struct cli_credentials; +struct auth_session_info; +struct event_context; + +WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct hive_key **root); +WERROR hive_key_get_info(TALLOC_CTX *mem_ctx, const struct hive_key *key, + const char **classname, uint32_t *num_subkeys, + uint32_t *num_values, NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, uint32_t *max_valbufsize); +WERROR hive_key_add_name(TALLOC_CTX *ctx, const struct hive_key *parent_key, + const char *name, const char *classname, + struct security_descriptor *desc, + struct hive_key **key); +WERROR hive_key_del(const struct hive_key *key, const char *name); +WERROR hive_get_key_by_name(TALLOC_CTX *mem_ctx, + const struct hive_key *key, const char *name, + struct hive_key **subkey); +WERROR hive_enum_key(TALLOC_CTX *mem_ctx, + const struct hive_key *key, uint32_t idx, + const char **name, + const char **classname, + NTTIME *last_mod_time); + +WERROR hive_key_set_value(struct hive_key *key, const char *name, + uint32_t type, const DATA_BLOB data); + +WERROR hive_get_value(TALLOC_CTX *mem_ctx, + struct hive_key *key, const char *name, + uint32_t *type, DATA_BLOB *data); +WERROR hive_get_value_by_index(TALLOC_CTX *mem_ctx, + struct hive_key *key, uint32_t idx, + const char **name, + uint32_t *type, DATA_BLOB *data); +WERROR hive_get_sec_desc(TALLOC_CTX *mem_ctx, + struct hive_key *key, + struct security_descriptor **security); + +WERROR hive_set_sec_desc(struct hive_key *key, + const struct security_descriptor *security); + +WERROR hive_key_del_value(struct hive_key *key, const char *name); + +WERROR hive_key_flush(struct hive_key *key); + + +/* Individual backends */ +WERROR reg_open_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key); +WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, + const char *location, struct smb_iconv_convenience *iconv_convenience, + struct hive_key **key); +WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct hive_key **k); + + +WERROR reg_create_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key); +WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, + struct smb_iconv_convenience *iconv_convenience, + const char *location, + int major_version, + struct hive_key **key); + + + +/* Handles for the predefined keys */ +#define HKEY_CLASSES_ROOT 0x80000000 +#define HKEY_CURRENT_USER 0x80000001 +#define HKEY_LOCAL_MACHINE 0x80000002 +#define HKEY_USERS 0x80000003 +#define HKEY_PERFORMANCE_DATA 0x80000004 +#define HKEY_CURRENT_CONFIG 0x80000005 +#define HKEY_DYN_DATA 0x80000006 +#define HKEY_PERFORMANCE_TEXT 0x80000050 +#define HKEY_PERFORMANCE_NLSTEXT 0x80000060 + +#define HKEY_FIRST HKEY_CLASSES_ROOT +#define HKEY_LAST HKEY_PERFORMANCE_NLSTEXT + +struct reg_predefined_key { + uint32_t handle; + const char *name; +}; + +extern const struct reg_predefined_key reg_predefined_keys[]; + +#define REG_DELETE -1 + +/* + * The general idea here is that every backend provides a 'hive'. Combining + * various hives gives you a complete registry like windows has + */ + +#define REGISTRY_INTERFACE_VERSION 1 + +struct reg_key_operations; + +/* structure to store the registry handles */ +struct registry_key +{ + struct registry_context *context; +}; + +struct registry_value +{ + const char *name; + unsigned int data_type; + DATA_BLOB data; +}; + +/* FIXME */ +typedef void (*reg_key_notification_function) (void); +typedef void (*reg_value_notification_function) (void); + +struct cli_credentials; + +struct registry_operations { + const char *name; + + WERROR (*get_key_info) (TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char **classname, + uint32_t *numsubkeys, + uint32_t *numvalues, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize); + + WERROR (*flush_key) (struct registry_key *key); + + WERROR (*get_predefined_key) (struct registry_context *ctx, + uint32_t key_id, + struct registry_key **key); + + WERROR (*open_key) (TALLOC_CTX *mem_ctx, + struct registry_key *parent, + const char *path, + struct registry_key **key); + + WERROR (*create_key) (TALLOC_CTX *mem_ctx, + struct registry_key *parent, + const char *name, + const char *key_class, + struct security_descriptor *security, + struct registry_key **key); + + WERROR (*delete_key) (struct registry_key *key, const char *name); + + WERROR (*delete_value) (struct registry_key *key, const char *name); + + WERROR (*enum_key) (TALLOC_CTX *mem_ctx, + const struct registry_key *key, uint32_t idx, + const char **name, + const char **keyclass, + NTTIME *last_changed_time); + + WERROR (*enum_value) (TALLOC_CTX *mem_ctx, + const struct registry_key *key, uint32_t idx, + const char **name, + uint32_t *type, + DATA_BLOB *data); + + WERROR (*get_sec_desc) (TALLOC_CTX *mem_ctx, + const struct registry_key *key, + struct security_descriptor **security); + + WERROR (*set_sec_desc) (struct registry_key *key, + const struct security_descriptor *security); + + WERROR (*load_key) (struct registry_key *key, + const char *key_name, + const char *path); + + WERROR (*unload_key) (struct registry_key *key, const char *name); + + WERROR (*notify_value_change) (struct registry_key *key, + reg_value_notification_function fn); + + WERROR (*get_value) (TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char *name, + uint32_t *type, + DATA_BLOB *data); + + WERROR (*set_value) (struct registry_key *key, + const char *name, + uint32_t type, + const DATA_BLOB data); +}; + +/** + * Handle to a full registry + * contains zero or more hives + */ +struct registry_context { + const struct registry_operations *ops; +}; + +struct auth_session_info; +struct event_context; +struct loadparm_context; + +/** + * Open the locally defined registry. + */ +WERROR reg_open_local(TALLOC_CTX *mem_ctx, + struct registry_context **ctx); + +WERROR reg_open_samba(TALLOC_CTX *mem_ctx, + struct registry_context **ctx, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *session_info, + struct cli_credentials *credentials); + +/** + * Open the registry on a remote machine. + */ +WERROR reg_open_remote(struct registry_context **ctx, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct loadparm_context *lp_ctx, + const char *location, struct event_context *ev); + +WERROR reg_open_wine(struct registry_context **ctx, const char *path); + +const char *reg_get_predef_name(uint32_t hkey); +WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, + const char *name, + struct registry_key **key); +WERROR reg_get_predefined_key(struct registry_context *ctx, + uint32_t hkey, + struct registry_key **key); + +WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, + const char *name, struct registry_key **result); + +WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, + const struct registry_key *key, uint32_t idx, + const char **name, + uint32_t *type, + DATA_BLOB *data); +WERROR reg_key_get_info(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char **class_name, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *last_change_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize); +WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + int idx, + const char **name, + const char **classname, + NTTIME *last_mod_time); +WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char *name, + struct registry_key **subkey); +WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, + const struct registry_key *key, + const char *name, + uint32_t *type, + DATA_BLOB *data); +WERROR reg_key_del(struct registry_key *parent, const char *name); +WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, + struct registry_key *parent, const char *name, + const char *classname, + struct security_descriptor *desc, + struct registry_key **newkey); +WERROR reg_val_set(struct registry_key *key, const char *value, + uint32_t type, DATA_BLOB data); +WERROR reg_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, + struct security_descriptor **secdesc); +WERROR reg_del_value(struct registry_key *key, const char *valname); +WERROR reg_key_flush(struct registry_key *key); +WERROR reg_create_key(TALLOC_CTX *mem_ctx, + struct registry_key *parent, + const char *name, + const char *key_class, + struct security_descriptor *security, + struct registry_key **key); + +/* Utility functions */ +const char *str_regtype(int type); +char *reg_val_data_string(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, uint32_t type, const DATA_BLOB data); +char *reg_val_description(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, const char *name, + uint32_t type, const DATA_BLOB data); +bool reg_string_to_val(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, const char *type_str, + const char *data_str, uint32_t *type, DATA_BLOB *data); +WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, + const char *name, struct registry_key **result); +WERROR reg_key_del_abs(struct registry_context *ctx, const char *path); +WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, + const char *path, uint32_t access_mask, + struct security_descriptor *sec_desc, + struct registry_key **result); +WERROR reg_load_key(struct registry_context *ctx, struct registry_key *key, + const char *name, const char *filename); + +WERROR reg_mount_hive(struct registry_context *rctx, + struct hive_key *hive_key, + uint32_t key_id, + const char **elements); + +struct registry_key *reg_import_hive_key(struct registry_context *ctx, + struct hive_key *hive, + uint32_t predef_key, + const char **elements); +WERROR reg_set_sec_desc(struct registry_key *key, + const struct security_descriptor *security); + +struct reg_diff_callbacks { + WERROR (*add_key) (void *callback_data, const char *key_name); + WERROR (*set_value) (void *callback_data, const char *key_name, + const char *value_name, uint32_t value_type, + DATA_BLOB value); + WERROR (*del_value) (void *callback_data, const char *key_name, + const char *value_name); + WERROR (*del_key) (void *callback_data, const char *key_name); + WERROR (*del_all_values) (void *callback_data, const char *key_name); + WERROR (*done) (void *callback_data); +}; + +WERROR reg_diff_apply(struct registry_context *ctx, const char *filename); + +WERROR reg_generate_diff(struct registry_context *ctx1, + struct registry_context *ctx2, + const struct reg_diff_callbacks *callbacks, + void *callback_data); +WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename, + struct smb_iconv_convenience *iconv_convenience, + struct reg_diff_callbacks **callbacks, + void **callback_data); +WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename, + struct smb_iconv_convenience *ic, + struct reg_diff_callbacks **callbacks, + void **callback_data); +WERROR reg_generate_diff_key(struct registry_key *oldkey, + struct registry_key *newkey, + const char *path, + const struct reg_diff_callbacks *callbacks, + void *callback_data); +WERROR reg_diff_load(const char *filename, + struct smb_iconv_convenience *iconv_convenience, + const struct reg_diff_callbacks *callbacks, + void *callback_data); + + + +#endif /* _REGISTRY_H */ diff --git a/source4/lib/registry/registry.i b/source4/lib/registry/registry.i new file mode 100644 index 0000000000..c55197c3d0 --- /dev/null +++ b/source4/lib/registry/registry.i @@ -0,0 +1,214 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +%define DOCSTRING +"Access to various registry formats and the Samba registry." +%enddef + +%module(docstring=DOCSTRING) registry + +%{ +/* Include headers */ +#include <stdint.h> +#include <stdbool.h> + +#include "includes.h" +#include "registry.h" +#include "param/param.h" +#include "events/events.h" + +typedef struct registry_context reg; +typedef struct hive_key hive_key; +%} +%include "../../libcli/util/errors.i" + +/* FIXME: This should be in another file */ +%typemap(default,noblock=1) struct auth_session_info * { + $1 = NULL; +} + +%import "stdint.i" +%import "../../lib/talloc/talloc.i" +%import "../../auth/credentials/credentials.i" +%import "../../param/param.i" +%import "../events/events.i" + +/* Utility functions */ + +const char *reg_get_predef_name(uint32_t hkey); +const char *str_regtype(int type); + +/* Registry contexts */ +%typemap(in,noblock=1,numinputs=0) struct registry_context ** (struct registry_context *tmp) { + $1 = &tmp; +} + +%typemap(argout,noblock=1) struct registry_context ** { + $result = SWIG_NewPointerObj(*$1, SWIGTYPE_p_registry_context, 0); +} + +%rename(Registry) reg_open_local; +WERROR reg_open_local(TALLOC_CTX *parent_ctx, struct registry_context **ctx); + +%typemap(in,noblock=1) const char ** { + /* Check if is a list */ + if (PyList_Check($input)) { + int size = PyList_Size($input); + int i = 0; + $1 = (char **) malloc((size+1)*sizeof(const char *)); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input,i); + if (PyString_Check(o)) + $1[i] = PyString_AsString(PyList_GetItem($input,i)); + else { + PyErr_SetString(PyExc_TypeError,"list must contain strings"); + free($1); + return NULL; + } + } + $1[i] = 0; + } else { + PyErr_SetString(PyExc_TypeError,"not a list"); + return NULL; + } +} + +%typemap(freearg,noblock=1) const char ** { + free((char **) $1); +} + +%talloctype(reg); + +typedef struct registry_context { + %extend { + + %feature("docstring") get_predefined_key_by_name "S.get_predefined_key_by_name(name) -> key\n" + "Find a predefined key by name"; + WERROR get_predefined_key_by_name(const char *name, + struct registry_key **key); + + %feature("docstring") key_del_abs "S.key_del_abs(name) -> None\n" + "Delete a key by absolute path."; + WERROR key_del_abs(const char *path); + %feature("docstring") get_predefined_key "S.get_predefined_key(hkey_id) -> key\n" + "Find a predefined key by id"; + WERROR get_predefined_key(uint32_t hkey_id, struct registry_key **key); + %feature("docstring") diff_apply "S.diff_apply(filename) -> None\n" + "Apply the diff from the specified file"; + + WERROR diff_apply(const char *filename); + WERROR generate_diff(struct registry_context *ctx2, const struct reg_diff_callbacks *callbacks, + void *callback_data); + + WERROR mount_hive(struct hive_key *key, uint32_t hkey_id, + const char **elements=NULL); + + struct registry_key *import_hive_key(struct hive_key *hive, uint32_t predef_key, const char **elements); + %feature("docstring") mount_hive "S.mount_hive(key, predef_name) -> None\n" + "Mount the specified key at the specified path."; + WERROR mount_hive(struct hive_key *key, const char *predef_name) + { + int i; + for (i = 0; reg_predefined_keys[i].name; i++) { + if (!strcasecmp(reg_predefined_keys[i].name, predef_name)) + return reg_mount_hive($self, key, + reg_predefined_keys[i].handle, NULL); + } + return WERR_INVALID_NAME; + } + + } +} reg; + +/* Hives */ +%typemap(in,noblock=1,numinputs=0) struct hive_key ** (struct hive_key *tmp) { + $1 = &tmp; +} + +%typemap(argout,noblock=1) struct hive_key ** { + Py_XDECREF($result); + $result = SWIG_NewPointerObj(*$1, SWIGTYPE_p_hive_key, 0); +} + +%feature("docstring") reg_open_hive "S.__init__(location, session_info=None, credentials=None, loadparm_context=None)"; +%rename(hive_key) reg_open_hive; +WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct hive_key **root); + +%feature("docstring") reg_open_ldb_file "open_ldb(location, session_info=None, credentials=None, loadparm_context=None) -> key"; +%rename(open_ldb) reg_open_ldb_file; +WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct hive_key **k); + +%feature("docstring") reg_create_directory "create_dir(location) -> key"; +%rename(create_dir) reg_create_directory; +WERROR reg_create_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key); + +%feature("docstring") reg_open_directory "open_dir(location) -> key"; +%rename(open_dir) reg_open_directory; +WERROR reg_open_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key); + +%talloctype(hive_key); + +typedef struct hive_key { + %extend { + %feature("docstring") del "S.del(name) -> None\n" + "Delete a subkey"; + WERROR del(const char *name); + %feature("docstring") flush "S.flush() -> None\n" + "Flush this key to disk"; + WERROR flush(void); + %feature("docstring") del_value "S.del_value(name) -> None\n" + "Delete a value"; + WERROR del_value(const char *name); + %feature("docstring") set_value "S.set_value(name, type, data) -> None\n" + "Set a value"; + WERROR set_value(const char *name, uint32_t type, const DATA_BLOB data); + } +} hive_key; + +%rename(open_samba) reg_open_samba; + +%feature("docstring") reg_open_samba "open_samba() -> reg"; +WERROR reg_open_samba(TALLOC_CTX *mem_ctx, + struct registry_context **ctx, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *session_info, + struct cli_credentials *credentials); + +/* Constants */ +%constant uint32_t HKEY_CLASSES_ROOT = HKEY_CLASSES_ROOT; +%constant uint32_t HKEY_CURRENT_USER = HKEY_CURRENT_USER; +%constant uint32_t HKEY_LOCAL_MACHINE = HKEY_LOCAL_MACHINE; +%constant uint32_t HKEY_USERS = HKEY_USERS; +%constant uint32_t HKEY_PERFORMANCE_DATA = HKEY_PERFORMANCE_DATA; +%constant uint32_t HKEY_CURRENT_CONFIG = HKEY_CURRENT_CONFIG; +%constant uint32_t HKEY_DYN_DATA = HKEY_DYN_DATA; +%constant uint32_t HKEY_PERFORMANCE_TEXT = HKEY_PERFORMANCE_TEXT; +%constant uint32_t HKEY_PERFORMANCE_NLSTEXT = HKEY_PERFORMANCE_NLSTEXT; diff --git a/source4/lib/registry/registry.pc.in b/source4/lib/registry/registry.pc.in new file mode 100644 index 0000000000..d981a45b2c --- /dev/null +++ b/source4/lib/registry/registry.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: registry +Description: Windows-style registry library +Requires: talloc +Requires.private: ldb +Version: 0.0.1 +Libs: -L${libdir} -lregistry +Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 diff --git a/source4/lib/registry/registry.py b/source4/lib/registry/registry.py new file mode 100644 index 0000000000..e086a6ad37 --- /dev/null +++ b/source4/lib/registry/registry.py @@ -0,0 +1,151 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 1.3.36 +# +# Don't modify this file, modify the SWIG interface instead. + +""" +Access to various registry formats and the Samba registry. +""" + +import _registry +import new +new_instancemethod = new.instancemethod +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'PySwigObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static) or hasattr(self,name): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError,name + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +import types +try: + _object = types.ObjectType + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 +del types + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +import credentials +import param +import events +reg_get_predef_name = _registry.reg_get_predef_name +str_regtype = _registry.str_regtype +Registry = _registry.Registry +class reg(object): + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + __repr__ = _swig_repr + def get_predefined_key_by_name(*args, **kwargs): + """ + S.get_predefined_key_by_name(name) -> key + Find a predefined key by name + """ + return _registry.reg_get_predefined_key_by_name(*args, **kwargs) + + def key_del_abs(*args, **kwargs): + """ + S.key_del_abs(name) -> None + Delete a key by absolute path. + """ + return _registry.reg_key_del_abs(*args, **kwargs) + + def get_predefined_key(*args, **kwargs): + """ + S.get_predefined_key(hkey_id) -> key + Find a predefined key by id + """ + return _registry.reg_get_predefined_key(*args, **kwargs) + + def diff_apply(*args, **kwargs): + """ + S.diff_apply(filename) -> None + Apply the diff from the specified file + """ + return _registry.reg_diff_apply(*args, **kwargs) + + def mount_hive(*args): + """ + S.mount_hive(key, predef_name) -> None + Mount the specified key at the specified path. + """ + return _registry.reg_mount_hive(*args) + + def __init__(self, *args, **kwargs): + _registry.reg_swiginit(self,_registry.new_reg(*args, **kwargs)) + __swig_destroy__ = _registry.delete_reg +reg.get_predefined_key_by_name = new_instancemethod(_registry.reg_get_predefined_key_by_name,None,reg) +reg.key_del_abs = new_instancemethod(_registry.reg_key_del_abs,None,reg) +reg.get_predefined_key = new_instancemethod(_registry.reg_get_predefined_key,None,reg) +reg.diff_apply = new_instancemethod(_registry.reg_diff_apply,None,reg) +reg.generate_diff = new_instancemethod(_registry.reg_generate_diff,None,reg) +reg.import_hive_key = new_instancemethod(_registry.reg_import_hive_key,None,reg) +reg.mount_hive = new_instancemethod(_registry.reg_mount_hive,None,reg) +reg_swigregister = _registry.reg_swigregister +reg_swigregister(reg) + + +def hive_key(*args, **kwargs): + """S.__init__(location, session_info=None, credentials=None, loadparm_context=None)""" + return _registry.hive_key(*args, **kwargs) + +def open_ldb(*args, **kwargs): + """open_ldb(location, session_info=None, credentials=None, loadparm_context=None) -> key""" + return _registry.open_ldb(*args, **kwargs) + +def create_dir(*args, **kwargs): + """create_dir(location) -> key""" + return _registry.create_dir(*args, **kwargs) + +def open_dir(*args, **kwargs): + """open_dir(location) -> key""" + return _registry.open_dir(*args, **kwargs) + +def open_samba(*args, **kwargs): + """open_samba() -> reg""" + return _registry.open_samba(*args, **kwargs) +HKEY_CLASSES_ROOT = _registry.HKEY_CLASSES_ROOT +HKEY_CURRENT_USER = _registry.HKEY_CURRENT_USER +HKEY_LOCAL_MACHINE = _registry.HKEY_LOCAL_MACHINE +HKEY_USERS = _registry.HKEY_USERS +HKEY_PERFORMANCE_DATA = _registry.HKEY_PERFORMANCE_DATA +HKEY_CURRENT_CONFIG = _registry.HKEY_CURRENT_CONFIG +HKEY_DYN_DATA = _registry.HKEY_DYN_DATA +HKEY_PERFORMANCE_TEXT = _registry.HKEY_PERFORMANCE_TEXT +HKEY_PERFORMANCE_NLSTEXT = _registry.HKEY_PERFORMANCE_NLSTEXT + + diff --git a/source4/lib/registry/registry_wrap.c b/source4/lib/registry/registry_wrap.c new file mode 100644 index 0000000000..809610fd1d --- /dev/null +++ b/source4/lib/registry/registry_wrap.c @@ -0,0 +1,4479 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.36 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPYTHON +#define SWIG_PYTHON_NO_BUILD_NONE +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIG_MSC_UNSUPPRESS_4505 +# if defined(_MSC_VER) +# pragma warning(disable : 4505) /* unreferenced local function has been removed */ +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + + +/* Python.h has to appear first */ +#include <Python.h> + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if (<obj is ok>) { + if (<need new object>) { + *ptr = <ptr to new allocated object>; + return SWIG_NEWOBJ; + } else { + *ptr = <ptr to old object>; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class<int>" == "Class<int >", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like <name1>|<name2>|... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like <name1>|<name2>|... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + + +/* Add PyOS_snprintf for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# define PyOS_snprintf _snprintf +# else +# define PyOS_snprintf snprintf +# endif +#endif + +/* A crude PyString_FromFormat implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 + +#ifndef SWIG_PYBUFFER_SIZE +# define SWIG_PYBUFFER_SIZE 1024 +#endif + +static PyObject * +PyString_FromFormat(const char *fmt, ...) { + va_list ap; + char buf[SWIG_PYBUFFER_SIZE * 2]; + int res; + va_start(ap, fmt); + res = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); +} +#endif + +/* Add PyObject_Del for old Pythons */ +#if PY_VERSION_HEX < 0x01060000 +# define PyObject_Del(op) PyMem_DEL((op)) +#endif +#ifndef PyObject_DEL +# define PyObject_DEL PyObject_Del +#endif + +/* A crude PyExc_StopIteration exception for old Pythons */ +#if PY_VERSION_HEX < 0x02020000 +# ifndef PyExc_StopIteration +# define PyExc_StopIteration PyExc_RuntimeError +# endif +# ifndef PyObject_GenericGetAttr +# define PyObject_GenericGetAttr 0 +# endif +#endif +/* Py_NotImplemented is defined in 2.1 and up. */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef Py_NotImplemented +# define Py_NotImplemented PyExc_RuntimeError +# endif +#endif + + +/* A crude PyString_AsStringAndSize implementation for old Pythons */ +#if PY_VERSION_HEX < 0x02010000 +# ifndef PyString_AsStringAndSize +# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} +# endif +#endif + +/* PySequence_Size for old Pythons */ +#if PY_VERSION_HEX < 0x02000000 +# ifndef PySequence_Size +# define PySequence_Size PySequence_Length +# endif +#endif + + +/* PyBool_FromLong for old Pythons */ +#if PY_VERSION_HEX < 0x02030000 +static +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result = ok ? Py_True : Py_False; + Py_INCREF(result); + return result; +} +#endif + +/* Py_ssize_t for old Pythons */ +/* This code is as recommended by: */ +/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +# define PY_SSIZE_T_MAX INT_MAX +# define PY_SSIZE_T_MIN INT_MIN +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIME PyObject* +SWIG_Python_ErrorType(int code) { + PyObject* type = 0; + switch(code) { + case SWIG_MemoryError: + type = PyExc_MemoryError; + break; + case SWIG_IOError: + type = PyExc_IOError; + break; + case SWIG_RuntimeError: + type = PyExc_RuntimeError; + break; + case SWIG_IndexError: + type = PyExc_IndexError; + break; + case SWIG_TypeError: + type = PyExc_TypeError; + break; + case SWIG_DivisionByZero: + type = PyExc_ZeroDivisionError; + break; + case SWIG_OverflowError: + type = PyExc_OverflowError; + break; + case SWIG_SyntaxError: + type = PyExc_SyntaxError; + break; + case SWIG_ValueError: + type = PyExc_ValueError; + break; + case SWIG_SystemError: + type = PyExc_SystemError; + break; + case SWIG_AttributeError: + type = PyExc_AttributeError; + break; + default: + type = PyExc_RuntimeError; + } + return type; +} + + +SWIGRUNTIME void +SWIG_Python_AddErrorMsg(const char* mesg) +{ + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + + if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + PyErr_Clear(); + Py_XINCREF(type); + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + Py_DECREF(old_str); + Py_DECREF(value); + } else { + PyErr_SetString(PyExc_RuntimeError, mesg); + } +} + + + +#if defined(SWIG_PYTHON_NO_THREADS) +# if defined(SWIG_PYTHON_THREADS) +# undef SWIG_PYTHON_THREADS +# endif +#endif +#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ +# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) +# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ +# define SWIG_PYTHON_USE_GIL +# endif +# endif +# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ +# ifndef SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() +# endif +# ifdef __cplusplus /* C++ code */ + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + public: + void end() { if (status) { PyEval_RestoreThread(save); status = false; }} + SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} + ~SWIG_Python_Thread_Allow() { end(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow +# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() +# else /* C code */ +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() +# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() +# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) +# define SWIG_PYTHON_INITIALIZE_THREADS +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADS +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif + +/* ----------------------------------------------------------------------------- + * Python API portion that goes into the runtime + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_PY_POINTER 4 +#define SWIG_PY_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * pyrun.swg + * + * This file contains the runtime support for Python modules + * and includes code for managing global variables and pointer + * type checking. + * + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) +#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) +#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(ptr, type, flags) +#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) +#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) +#define swig_owntype int + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Python_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) +#define SWIG_NewClientData(obj) PySwigClientData_New(obj) + +#define SWIG_SetErrorObj SWIG_Python_SetErrorObj +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Runtime API implementation */ + +/* Error manipulation */ + +SWIGINTERN void +SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetObject(errtype, obj); + Py_DECREF(obj); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +SWIGINTERN void +SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(errtype, (char *) msg); + SWIG_PYTHON_THREAD_END_BLOCK; +} + +#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) + +/* Set a constant value */ + +SWIGINTERN void +SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { + PyDict_SetItemString(d, (char*) name, obj); + Py_DECREF(obj); +} + +/* Append a value to the result obj */ + +SWIGINTERN PyObject* +SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { +#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyList_Check(result)) { + PyObject *o2 = result; + result = PyList_New(1); + PyList_SetItem(result, 0, o2); + } + PyList_Append(result,obj); + Py_DECREF(obj); + } + return result; +#else + PyObject* o2; + PyObject* o3; + if (!result) { + result = obj; + } else if (result == Py_None) { + Py_DECREF(result); + result = obj; + } else { + if (!PyTuple_Check(result)) { + o2 = result; + result = PyTuple_New(1); + PyTuple_SET_ITEM(result, 0, o2); + } + o3 = PyTuple_New(1); + PyTuple_SET_ITEM(o3, 0, obj); + o2 = result; + result = PySequence_Concat(o2, o3); + Py_DECREF(o2); + Py_DECREF(o3); + } + return result; +#endif +} + +/* Unpack the argument tuple */ + +SWIGINTERN int +SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) +{ + if (!args) { + if (!min && !max) { + return 1; + } else { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", + name, (min == max ? "" : "at least "), (int)min); + return 0; + } + } + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); + return 0; + } else { + register Py_ssize_t l = PyTuple_GET_SIZE(args); + if (l < min) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at least "), (int)min, (int)l); + return 0; + } else if (l > max) { + PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", + name, (min == max ? "" : "at most "), (int)max, (int)l); + return 0; + } else { + register int i; + for (i = 0; i < l; ++i) { + objs[i] = PyTuple_GET_ITEM(args, i); + } + for (; l < max; ++l) { + objs[l] = 0; + } + return i + 1; + } + } +} + +/* A functor is a function object with one single object argument */ +#if PY_VERSION_HEX >= 0x02020000 +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#else +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); +#endif + +/* + Helper for static pointer initialization for both C and C++ code, for example + static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); +*/ +#ifdef __cplusplus +#define SWIG_STATIC_POINTER(var) var +#else +#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var +#endif + +/* ----------------------------------------------------------------------------- + * Pointer declarations + * ----------------------------------------------------------------------------- */ + +/* Flags for new pointer objects */ +#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) +#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) + +#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* How to access Py_None */ +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# ifndef SWIG_PYTHON_NO_BUILD_NONE +# ifndef SWIG_PYTHON_BUILD_NONE +# define SWIG_PYTHON_BUILD_NONE +# endif +# endif +#endif + +#ifdef SWIG_PYTHON_BUILD_NONE +# ifdef Py_None +# undef Py_None +# define Py_None SWIG_Py_None() +# endif +SWIGRUNTIMEINLINE PyObject * +_SWIG_Py_None(void) +{ + PyObject *none = Py_BuildValue((char*)""); + Py_DECREF(none); + return none; +} +SWIGRUNTIME PyObject * +SWIG_Py_None(void) +{ + static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); + return none; +} +#endif + +/* The python void return value */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Py_Void(void) +{ + PyObject *none = Py_None; + Py_INCREF(none); + return none; +} + +/* PySwigClientData */ + +typedef struct { + PyObject *klass; + PyObject *newraw; + PyObject *newargs; + PyObject *destroy; + int delargs; + int implicitconv; +} PySwigClientData; + +SWIGRUNTIMEINLINE int +SWIG_Python_CheckImplicit(swig_type_info *ty) +{ + PySwigClientData *data = (PySwigClientData *)ty->clientdata; + return data ? data->implicitconv : 0; +} + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_ExceptionType(swig_type_info *desc) { + PySwigClientData *data = desc ? (PySwigClientData *) desc->clientdata : 0; + PyObject *klass = data ? data->klass : 0; + return (klass ? klass : PyExc_RuntimeError); +} + + +SWIGRUNTIME PySwigClientData * +PySwigClientData_New(PyObject* obj) +{ + if (!obj) { + return 0; + } else { + PySwigClientData *data = (PySwigClientData *)malloc(sizeof(PySwigClientData)); + /* the klass element */ + data->klass = obj; + Py_INCREF(data->klass); + /* the newraw method and newargs arguments used to create a new raw instance */ + if (PyClass_Check(obj)) { + data->newraw = 0; + data->newargs = obj; + Py_INCREF(obj); + } else { +#if (PY_VERSION_HEX < 0x02020000) + data->newraw = 0; +#else + data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); +#endif + if (data->newraw) { + Py_INCREF(data->newraw); + data->newargs = PyTuple_New(1); + PyTuple_SetItem(data->newargs, 0, obj); + } else { + data->newargs = obj; + } + Py_INCREF(data->newargs); + } + /* the destroy method, aka as the C++ delete method */ + data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); + if (PyErr_Occurred()) { + PyErr_Clear(); + data->destroy = 0; + } + if (data->destroy) { + int flags; + Py_INCREF(data->destroy); + flags = PyCFunction_GET_FLAGS(data->destroy); +#ifdef METH_O + data->delargs = !(flags & (METH_O)); +#else + data->delargs = 0; +#endif + } else { + data->delargs = 0; + } + data->implicitconv = 0; + return data; + } +} + +SWIGRUNTIME void +PySwigClientData_Del(PySwigClientData* data) +{ + Py_XDECREF(data->newraw); + Py_XDECREF(data->newargs); + Py_XDECREF(data->destroy); +} + +/* =============== PySwigObject =====================*/ + +typedef struct { + PyObject_HEAD + void *ptr; + swig_type_info *ty; + int own; + PyObject *next; +} PySwigObject; + +SWIGRUNTIME PyObject * +PySwigObject_long(PySwigObject *v) +{ + return PyLong_FromVoidPtr(v->ptr); +} + +SWIGRUNTIME PyObject * +PySwigObject_format(const char* fmt, PySwigObject *v) +{ + PyObject *res = NULL; + PyObject *args = PyTuple_New(1); + if (args) { + if (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0) { + PyObject *ofmt = PyString_FromString(fmt); + if (ofmt) { + res = PyString_Format(ofmt,args); + Py_DECREF(ofmt); + } + Py_DECREF(args); + } + } + return res; +} + +SWIGRUNTIME PyObject * +PySwigObject_oct(PySwigObject *v) +{ + return PySwigObject_format("%o",v); +} + +SWIGRUNTIME PyObject * +PySwigObject_hex(PySwigObject *v) +{ + return PySwigObject_format("%x",v); +} + +SWIGRUNTIME PyObject * +#ifdef METH_NOARGS +PySwigObject_repr(PySwigObject *v) +#else +PySwigObject_repr(PySwigObject *v, PyObject *args) +#endif +{ + const char *name = SWIG_TypePrettyName(v->ty); + PyObject *hex = PySwigObject_hex(v); + PyObject *repr = PyString_FromFormat("<Swig Object of type '%s' at 0x%s>", name, PyString_AsString(hex)); + Py_DECREF(hex); + if (v->next) { +#ifdef METH_NOARGS + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next); +#else + PyObject *nrep = PySwigObject_repr((PySwigObject *)v->next, args); +#endif + PyString_ConcatAndDel(&repr,nrep); + } + return repr; +} + +SWIGRUNTIME int +PySwigObject_print(PySwigObject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ +#ifdef METH_NOARGS + PyObject *repr = PySwigObject_repr(v); +#else + PyObject *repr = PySwigObject_repr(v, NULL); +#endif + if (repr) { + fputs(PyString_AsString(repr), fp); + Py_DECREF(repr); + return 0; + } else { + return 1; + } +} + +SWIGRUNTIME PyObject * +PySwigObject_str(PySwigObject *v) +{ + char result[SWIG_BUFFER_SIZE]; + return SWIG_PackVoidPtr(result, v->ptr, v->ty->name, sizeof(result)) ? + PyString_FromString(result) : 0; +} + +SWIGRUNTIME int +PySwigObject_compare(PySwigObject *v, PySwigObject *w) +{ + void *i = v->ptr; + void *j = w->ptr; + return (i < j) ? -1 : ((i > j) ? 1 : 0); +} + +SWIGRUNTIME PyTypeObject* _PySwigObject_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigObject_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigObject_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigObject_Check(PyObject *op) { + return ((op)->ob_type == PySwigObject_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0); +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own); + +SWIGRUNTIME void +PySwigObject_dealloc(PyObject *v) +{ + PySwigObject *sobj = (PySwigObject *) v; + PyObject *next = sobj->next; + if (sobj->own == SWIG_POINTER_OWN) { + swig_type_info *ty = sobj->ty; + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + PyObject *destroy = data ? data->destroy : 0; + if (destroy) { + /* destroy is always a VARARGS method */ + PyObject *res; + if (data->delargs) { + /* we need to create a temporal object to carry the destroy operation */ + PyObject *tmp = PySwigObject_New(sobj->ptr, ty, 0); + res = SWIG_Python_CallFunctor(destroy, tmp); + Py_DECREF(tmp); + } else { + PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); + PyObject *mself = PyCFunction_GET_SELF(destroy); + res = ((*meth)(mself, v)); + } + Py_XDECREF(res); + } +#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) + else { + const char *name = SWIG_TypePrettyName(ty); + printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); + } +#endif + } + Py_XDECREF(next); + PyObject_DEL(v); +} + +SWIGRUNTIME PyObject* +PySwigObject_append(PyObject* v, PyObject* next) +{ + PySwigObject *sobj = (PySwigObject *) v; +#ifndef METH_O + PyObject *tmp = 0; + if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; + next = tmp; +#endif + if (!PySwigObject_Check(next)) { + return NULL; + } + sobj->next = next; + Py_INCREF(next); + return SWIG_Py_Void(); +} + +SWIGRUNTIME PyObject* +#ifdef METH_NOARGS +PySwigObject_next(PyObject* v) +#else +PySwigObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *) v; + if (sobj->next) { + Py_INCREF(sobj->next); + return sobj->next; + } else { + return SWIG_Py_Void(); + } +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_disown(PyObject *v) +#else +PySwigObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = 0; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +#ifdef METH_NOARGS +PySwigObject_acquire(PyObject *v) +#else +PySwigObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) +#endif +{ + PySwigObject *sobj = (PySwigObject *)v; + sobj->own = SWIG_POINTER_OWN; + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject* +PySwigObject_own(PyObject *v, PyObject *args) +{ + PyObject *val = 0; +#if (PY_VERSION_HEX < 0x02020000) + if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) +#else + if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) +#endif + { + return NULL; + } + else + { + PySwigObject *sobj = (PySwigObject *)v; + PyObject *obj = PyBool_FromLong(sobj->own); + if (val) { +#ifdef METH_NOARGS + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v); + } else { + PySwigObject_disown(v); + } +#else + if (PyObject_IsTrue(val)) { + PySwigObject_acquire(v,args); + } else { + PySwigObject_disown(v,args); + } +#endif + } + return obj; + } +} + +#ifdef METH_O +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_NOARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_NOARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_O, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_NOARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#else +static PyMethodDef +swigobject_methods[] = { + {(char *)"disown", (PyCFunction)PySwigObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, + {(char *)"acquire", (PyCFunction)PySwigObject_acquire, METH_VARARGS, (char *)"aquires ownership of the pointer"}, + {(char *)"own", (PyCFunction)PySwigObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, + {(char *)"append", (PyCFunction)PySwigObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, + {(char *)"next", (PyCFunction)PySwigObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, + {(char *)"__repr__",(PyCFunction)PySwigObject_repr, METH_VARARGS, (char *)"returns object representation"}, + {0, 0, 0, 0} +}; +#endif + +#if PY_VERSION_HEX < 0x02020000 +SWIGINTERN PyObject * +PySwigObject_getattr(PySwigObject *sobj,char *name) +{ + return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); +} +#endif + +SWIGRUNTIME PyTypeObject* +_PySwigObject_type(void) { + static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; + + static PyNumberMethods PySwigObject_as_number = { + (binaryfunc)0, /*nb_add*/ + (binaryfunc)0, /*nb_subtract*/ + (binaryfunc)0, /*nb_multiply*/ + (binaryfunc)0, /*nb_divide*/ + (binaryfunc)0, /*nb_remainder*/ + (binaryfunc)0, /*nb_divmod*/ + (ternaryfunc)0,/*nb_power*/ + (unaryfunc)0, /*nb_negative*/ + (unaryfunc)0, /*nb_positive*/ + (unaryfunc)0, /*nb_absolute*/ + (inquiry)0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + (coercion)0, /*nb_coerce*/ + (unaryfunc)PySwigObject_long, /*nb_int*/ + (unaryfunc)PySwigObject_long, /*nb_long*/ + (unaryfunc)0, /*nb_float*/ + (unaryfunc)PySwigObject_oct, /*nb_oct*/ + (unaryfunc)PySwigObject_hex, /*nb_hex*/ +#if PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ +#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ +#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ + 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ +#endif + }; + + static PyTypeObject pyswigobject_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigObject", /* tp_name */ + sizeof(PySwigObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigObject_dealloc, /* tp_dealloc */ + (printfunc)PySwigObject_print, /* tp_print */ +#if PY_VERSION_HEX < 0x02020000 + (getattrfunc)PySwigObject_getattr, /* tp_getattr */ +#else + (getattrfunc)0, /* tp_getattr */ +#endif + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigObject_compare, /* tp_compare */ + (reprfunc)PySwigObject_repr, /* tp_repr */ + &PySwigObject_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigObject_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigobject_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + swigobject_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigobject_type = tmp; + pyswigobject_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigobject_type; +} + +SWIGRUNTIME PyObject * +PySwigObject_New(void *ptr, swig_type_info *ty, int own) +{ + PySwigObject *sobj = PyObject_NEW(PySwigObject, PySwigObject_type()); + if (sobj) { + sobj->ptr = ptr; + sobj->ty = ty; + sobj->own = own; + sobj->next = 0; + } + return (PyObject *)sobj; +} + +/* ----------------------------------------------------------------------------- + * Implements a simple Swig Packed type, and use it instead of string + * ----------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + void *pack; + swig_type_info *ty; + size_t size; +} PySwigPacked; + +SWIGRUNTIME int +PySwigPacked_print(PySwigPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) +{ + char result[SWIG_BUFFER_SIZE]; + fputs("<Swig Packed ", fp); + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + fputs("at ", fp); + fputs(result, fp); + } + fputs(v->ty->name,fp); + fputs(">", fp); + return 0; +} + +SWIGRUNTIME PyObject * +PySwigPacked_repr(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { + return PyString_FromFormat("<Swig Packed at %s%s>", result, v->ty->name); + } else { + return PyString_FromFormat("<Swig Packed %s>", v->ty->name); + } +} + +SWIGRUNTIME PyObject * +PySwigPacked_str(PySwigPacked *v) +{ + char result[SWIG_BUFFER_SIZE]; + if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ + return PyString_FromFormat("%s%s", result, v->ty->name); + } else { + return PyString_FromString(v->ty->name); + } +} + +SWIGRUNTIME int +PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w) +{ + size_t i = v->size; + size_t j = w->size; + int s = (i < j) ? -1 : ((i > j) ? 1 : 0); + return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); +} + +SWIGRUNTIME PyTypeObject* _PySwigPacked_type(void); + +SWIGRUNTIME PyTypeObject* +PySwigPacked_type(void) { + static PyTypeObject *SWIG_STATIC_POINTER(type) = _PySwigPacked_type(); + return type; +} + +SWIGRUNTIMEINLINE int +PySwigPacked_Check(PyObject *op) { + return ((op)->ob_type == _PySwigPacked_type()) + || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0); +} + +SWIGRUNTIME void +PySwigPacked_dealloc(PyObject *v) +{ + if (PySwigPacked_Check(v)) { + PySwigPacked *sobj = (PySwigPacked *) v; + free(sobj->pack); + } + PyObject_DEL(v); +} + +SWIGRUNTIME PyTypeObject* +_PySwigPacked_type(void) { + static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; + static PyTypeObject pyswigpacked_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + (char *)"PySwigPacked", /* tp_name */ + sizeof(PySwigPacked), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PySwigPacked_dealloc, /* tp_dealloc */ + (printfunc)PySwigPacked_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)PySwigPacked_compare, /* tp_compare */ + (reprfunc)PySwigPacked_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)PySwigPacked_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + swigpacked_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + pyswigpacked_type = tmp; + pyswigpacked_type.ob_type = &PyType_Type; + type_init = 1; + } + return &pyswigpacked_type; +} + +SWIGRUNTIME PyObject * +PySwigPacked_New(void *ptr, size_t size, swig_type_info *ty) +{ + PySwigPacked *sobj = PyObject_NEW(PySwigPacked, PySwigPacked_type()); + if (sobj) { + void *pack = malloc(size); + if (pack) { + memcpy(pack, ptr, size); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = size; + } else { + PyObject_DEL((PyObject *) sobj); + sobj = 0; + } + } + return (PyObject *) sobj; +} + +SWIGRUNTIME swig_type_info * +PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size) +{ + if (PySwigPacked_Check(obj)) { + PySwigPacked *sobj = (PySwigPacked *)obj; + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +SWIGRUNTIMEINLINE PyObject * +_SWIG_This(void) +{ + return PyString_FromString("this"); +} + +SWIGRUNTIME PyObject * +SWIG_This(void) +{ + static PyObject *SWIG_STATIC_POINTER(swig_this) = _SWIG_This(); + return swig_this; +} + +/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ + +SWIGRUNTIME PySwigObject * +SWIG_Python_GetSwigThis(PyObject *pyobj) +{ + if (PySwigObject_Check(pyobj)) { + return (PySwigObject *) pyobj; + } else { + PyObject *obj = 0; +#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) + if (PyInstance_Check(pyobj)) { + obj = _PyInstance_Lookup(pyobj, SWIG_This()); + } else { + PyObject **dictptr = _PyObject_GetDictPtr(pyobj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; + } else { +#ifdef PyWeakref_CheckProxy + if (PyWeakref_CheckProxy(pyobj)) { + PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); + return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; + } +#endif + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } + } + } +#else + obj = PyObject_GetAttr(pyobj,SWIG_This()); + if (obj) { + Py_DECREF(obj); + } else { + if (PyErr_Occurred()) PyErr_Clear(); + return 0; + } +#endif + if (obj && !PySwigObject_Check(obj)) { + /* a PyObject is called 'this', try to get the 'real this' + PySwigObject from it */ + return SWIG_Python_GetSwigThis(obj); + } + return (PySwigObject *)obj; + } +} + +/* Acquire a pointer value */ + +SWIGRUNTIME int +SWIG_Python_AcquirePtr(PyObject *obj, int own) { + if (own == SWIG_POINTER_OWN) { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (sobj) { + int oldown = sobj->own; + sobj->own = own; + return oldown; + } + } + return 0; +} + +/* Convert a pointer value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { + if (!obj) return SWIG_ERROR; + if (obj == Py_None) { + if (ptr) *ptr = 0; + return SWIG_OK; + } else { + PySwigObject *sobj = SWIG_Python_GetSwigThis(obj); + if (own) + *own = 0; + while (sobj) { + void *vptr = sobj->ptr; + if (ty) { + swig_type_info *to = sobj->ty; + if (to == ty) { + /* no type cast needed */ + if (ptr) *ptr = vptr; + break; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) { + sobj = (PySwigObject *)sobj->next; + } else { + if (ptr) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + if (newmemory == SWIG_CAST_NEW_MEMORY) { + assert(own); + if (own) + *own = *own | SWIG_CAST_NEW_MEMORY; + } + } + break; + } + } + } else { + if (ptr) *ptr = vptr; + break; + } + } + if (sobj) { + if (own) + *own = *own | sobj->own; + if (flags & SWIG_POINTER_DISOWN) { + sobj->own = 0; + } + return SWIG_OK; + } else { + int res = SWIG_ERROR; + if (flags & SWIG_POINTER_IMPLICIT_CONV) { + PySwigClientData *data = ty ? (PySwigClientData *) ty->clientdata : 0; + if (data && !data->implicitconv) { + PyObject *klass = data->klass; + if (klass) { + PyObject *impconv; + data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ + impconv = SWIG_Python_CallFunctor(klass, obj); + data->implicitconv = 0; + if (PyErr_Occurred()) { + PyErr_Clear(); + impconv = 0; + } + if (impconv) { + PySwigObject *iobj = SWIG_Python_GetSwigThis(impconv); + if (iobj) { + void *vptr; + res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); + if (SWIG_IsOK(res)) { + if (ptr) { + *ptr = vptr; + /* transfer the ownership to 'ptr' */ + iobj->own = 0; + res = SWIG_AddCast(res); + res = SWIG_AddNewMask(res); + } else { + res = SWIG_AddCast(res); + } + } + } + Py_DECREF(impconv); + } + } + } + } + return res; + } + } +} + +/* Convert a function ptr value */ + +SWIGRUNTIME int +SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { + if (!PyCFunction_Check(obj)) { + return SWIG_ConvertPtr(obj, ptr, ty, 0); + } else { + void *vptr = 0; + + /* here we get the method pointer for callbacks */ + const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); + const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; + if (desc) { + desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; + if (!desc) return SWIG_ERROR; + } + if (ty) { + swig_cast_info *tc = SWIG_TypeCheck(desc,ty); + if (tc) { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,vptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } else { + return SWIG_ERROR; + } + } else { + *ptr = vptr; + } + return SWIG_OK; + } +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = PySwigPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Create a new pointer object + * ----------------------------------------------------------------------------- */ + +/* + Create a new instance object, whitout calling __init__, and set the + 'this' attribute. +*/ + +SWIGRUNTIME PyObject* +SWIG_Python_NewShadowInstance(PySwigClientData *data, PyObject *swig_this) +{ +#if (PY_VERSION_HEX >= 0x02020000) + PyObject *inst = 0; + PyObject *newraw = data->newraw; + if (newraw) { + inst = PyObject_Call(newraw, data->newargs, NULL); + if (inst) { +#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + PyDict_SetItem(dict, SWIG_This(), swig_this); + } + } +#else + PyObject *key = SWIG_This(); + PyObject_SetAttr(inst, key, swig_this); +#endif + } + } else { + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + } + return inst; +#else +#if (PY_VERSION_HEX >= 0x02010000) + PyObject *inst; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, SWIG_This(), swig_this); + inst = PyInstance_NewRaw(data->newargs, dict); + Py_DECREF(dict); + return (PyObject *) inst; +#else + PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + return NULL; + } + inst->in_class = (PyClassObject *)data->newargs; + Py_INCREF(inst->in_class); + inst->in_dict = PyDict_New(); + if (inst->in_dict == NULL) { + Py_DECREF(inst); + return NULL; + } +#ifdef Py_TPFLAGS_HAVE_WEAKREFS + inst->in_weakreflist = NULL; +#endif +#ifdef Py_TPFLAGS_GC + PyObject_GC_Init(inst); +#endif + PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); + return (PyObject *) inst; +#endif +#endif +} + +SWIGRUNTIME void +SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) +{ + PyObject *dict; +#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) + PyObject **dictptr = _PyObject_GetDictPtr(inst); + if (dictptr != NULL) { + dict = *dictptr; + if (dict == NULL) { + dict = PyDict_New(); + *dictptr = dict; + } + PyDict_SetItem(dict, SWIG_This(), swig_this); + return; + } +#endif + dict = PyObject_GetAttrString(inst, (char*)"__dict__"); + PyDict_SetItem(dict, SWIG_This(), swig_this); + Py_DECREF(dict); +} + + +SWIGINTERN PyObject * +SWIG_Python_InitShadowInstance(PyObject *args) { + PyObject *obj[2]; + if (!SWIG_Python_UnpackTuple(args,(char*)"swiginit", 2, 2, obj)) { + return NULL; + } else { + PySwigObject *sthis = SWIG_Python_GetSwigThis(obj[0]); + if (sthis) { + PySwigObject_append((PyObject*) sthis, obj[1]); + } else { + SWIG_Python_SetSwigThis(obj[0], obj[1]); + } + return SWIG_Py_Void(); + } +} + +/* Create a new pointer object */ + +SWIGRUNTIME PyObject * +SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + if (!ptr) { + return SWIG_Py_Void(); + } else { + int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; + PyObject *robj = PySwigObject_New(ptr, type, own); + PySwigClientData *clientdata = type ? (PySwigClientData *)(type->clientdata) : 0; + if (clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { + PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); + if (inst) { + Py_DECREF(robj); + robj = inst; + } + } + return robj; + } +} + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE PyObject * +SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? PySwigPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +#ifdef SWIG_LINK_RUNTIME +void *SWIG_ReturnGlobalTypeList(void *); +#endif + +SWIGRUNTIME swig_module_info * +SWIG_Python_GetModule(void) { + static void *type_pointer = (void *)0; + /* first check if module already created */ + if (!type_pointer) { +#ifdef SWIG_LINK_RUNTIME + type_pointer = SWIG_ReturnGlobalTypeList((void *)0); +#else + type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); + if (PyErr_Occurred()) { + PyErr_Clear(); + type_pointer = (void *)0; + } +#endif + } + return (swig_module_info *) type_pointer; +} + +#if PY_MAJOR_VERSION < 2 +/* PyModule_AddObject function was introduced in Python 2.0. The following function + is copied out of Python/modsupport.c in python version 2.3.4 */ +SWIGINTERN int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return SWIG_ERROR; + } + if (!o) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return SWIG_ERROR; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return SWIG_ERROR; + } + if (PyDict_SetItemString(dict, name, o)) + return SWIG_ERROR; + Py_DECREF(o); + return SWIG_OK; +} +#endif + +SWIGRUNTIME void +SWIG_Python_DestroyModule(void *vptr) +{ + swig_module_info *swig_module = (swig_module_info *) vptr; + swig_type_info **types = swig_module->types; + size_t i; + for (i =0; i < swig_module->size; ++i) { + swig_type_info *ty = types[i]; + if (ty->owndata) { + PySwigClientData *data = (PySwigClientData *) ty->clientdata; + if (data) PySwigClientData_Del(data); + } + } + Py_DECREF(SWIG_This()); +} + +SWIGRUNTIME void +SWIG_Python_SetModule(swig_module_info *swig_module) { + static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */ + + PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, + swig_empty_runtime_method_table); + PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); + if (pointer && module) { + PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); + } else { + Py_XDECREF(pointer); + } +} + +/* The python cached type query */ +SWIGRUNTIME PyObject * +SWIG_Python_TypeCache(void) { + static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); + return cache; +} + +SWIGRUNTIME swig_type_info * +SWIG_Python_TypeQuery(const char *type) +{ + PyObject *cache = SWIG_Python_TypeCache(); + PyObject *key = PyString_FromString(type); + PyObject *obj = PyDict_GetItem(cache, key); + swig_type_info *descriptor; + if (obj) { + descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); + } else { + swig_module_info *swig_module = SWIG_Python_GetModule(); + descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); + if (descriptor) { + obj = PyCObject_FromVoidPtr(descriptor, NULL); + PyDict_SetItem(cache, key, obj); + Py_DECREF(obj); + } + } + Py_DECREF(key); + return descriptor; +} + +/* + For backward compatibility only +*/ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) +#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) + +SWIGRUNTIME int +SWIG_Python_AddErrMesg(const char* mesg, int infront) +{ + if (PyErr_Occurred()) { + PyObject *type = 0; + PyObject *value = 0; + PyObject *traceback = 0; + PyErr_Fetch(&type, &value, &traceback); + if (value) { + PyObject *old_str = PyObject_Str(value); + Py_XINCREF(type); + PyErr_Clear(); + if (infront) { + PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str)); + } else { + PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg); + } + Py_DECREF(old_str); + } + return 1; + } else { + return 0; + } +} + +SWIGRUNTIME int +SWIG_Python_ArgFail(int argnum) +{ + if (PyErr_Occurred()) { + /* add information about failing argument */ + char mesg[256]; + PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); + return SWIG_Python_AddErrMesg(mesg, 1); + } else { + return 0; + } +} + +SWIGRUNTIMEINLINE const char * +PySwigObject_GetDesc(PyObject *self) +{ + PySwigObject *v = (PySwigObject *)self; + swig_type_info *ty = v ? v->ty : 0; + return ty ? ty->str : (char*)""; +} + +SWIGRUNTIME void +SWIG_Python_TypeError(const char *type, PyObject *obj) +{ + if (type) { +#if defined(SWIG_COBJECT_TYPES) + if (obj && PySwigObject_Check(obj)) { + const char *otype = (const char *) PySwigObject_GetDesc(obj); + if (otype) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received", + type, otype); + return; + } + } else +#endif + { + const char *otype = (obj ? obj->ob_type->tp_name : 0); + if (otype) { + PyObject *str = PyObject_Str(obj); + const char *cstr = str ? PyString_AsString(str) : 0; + if (cstr) { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", + type, otype, cstr); + } else { + PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", + type, otype); + } + Py_XDECREF(str); + return; + } + } + PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); + } else { + PyErr_Format(PyExc_TypeError, "unexpected type is received"); + } +} + + +/* Convert a pointer value, signal an exception on a type mismatch */ +SWIGRUNTIME void * +SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) { + void *result; + if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { + PyErr_Clear(); + if (flags & SWIG_POINTER_EXCEPTION) { + SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); + SWIG_Python_ArgFail(argnum); + } + } + return result; +} + + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_TALLOC_CTX swig_types[0] +#define SWIGTYPE_p_auth_session_info swig_types[1] +#define SWIGTYPE_p_char swig_types[2] +#define SWIGTYPE_p_cli_credentials swig_types[3] +#define SWIGTYPE_p_event_context swig_types[4] +#define SWIGTYPE_p_hive_key swig_types[5] +#define SWIGTYPE_p_int swig_types[6] +#define SWIGTYPE_p_loadparm_context swig_types[7] +#define SWIGTYPE_p_loadparm_service swig_types[8] +#define SWIGTYPE_p_long_long swig_types[9] +#define SWIGTYPE_p_p_char swig_types[10] +#define SWIGTYPE_p_p_hive_key swig_types[11] +#define SWIGTYPE_p_p_registry_context swig_types[12] +#define SWIGTYPE_p_p_registry_key swig_types[13] +#define SWIGTYPE_p_param_context swig_types[14] +#define SWIGTYPE_p_param_opt swig_types[15] +#define SWIGTYPE_p_param_section swig_types[16] +#define SWIGTYPE_p_reg_diff_callbacks swig_types[17] +#define SWIGTYPE_p_registry_context swig_types[18] +#define SWIGTYPE_p_registry_key swig_types[19] +#define SWIGTYPE_p_short swig_types[20] +#define SWIGTYPE_p_signed_char swig_types[21] +#define SWIGTYPE_p_unsigned_char swig_types[22] +#define SWIGTYPE_p_unsigned_int swig_types[23] +#define SWIGTYPE_p_unsigned_long_long swig_types[24] +#define SWIGTYPE_p_unsigned_short swig_types[25] +static swig_type_info *swig_types[27]; +static swig_module_info swig_module = {swig_types, 26, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#if (PY_VERSION_HEX <= 0x02000000) +# if !defined(SWIG_PYTHON_CLASSIC) +# error "This python version requires swig to be run with the '-classic' option" +# endif +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif +#ifndef METH_O +# error "This python version requires swig to be run with the '-nofastunpack' option" +#endif +#ifdef SWIG_TypeQuery +# undef SWIG_TypeQuery +#endif +#define SWIG_TypeQuery SWIG_Python_TypeQuery + +/*----------------------------------------------- + @(target):= _registry.so + ------------------------------------------------*/ +#define SWIG_init init_registry + +#define SWIG_name "_registry" + +#define SWIGVERSION 0x010336 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + +/* Include headers */ +#include <stdint.h> +#include <stdbool.h> + +#include "includes.h" +#include "registry.h" +#include "param/param.h" +#include "events/events.h" + +typedef struct registry_context reg; +typedef struct hive_key hive_key; + + +#include "libcli/util/pyerrors.h" + + +#include <limits.h> +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +SWIGINTERN int +SWIG_AsVal_double (PyObject *obj, double *val) +{ + int res = SWIG_TypeError; + if (PyFloat_Check(obj)) { + if (val) *val = PyFloat_AsDouble(obj); + return SWIG_OK; + } else if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + double v = PyLong_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + double d = PyFloat_AsDouble(obj); + if (!PyErr_Occurred()) { + if (val) *val = d; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); + } else { + PyErr_Clear(); + } + } + } +#endif + return res; +} + + +#include <float.h> + + +#include <math.h> + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) +{ + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v >= 0) { + if (val) *val = v; + return SWIG_OK; + } else { + return SWIG_OverflowError; + } + } else if (PyLong_Check(obj)) { + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + unsigned long v = PyLong_AsUnsignedLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { + if (val) *val = (unsigned long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_unsigned_SS_int (PyObject * obj, unsigned int *val) +{ + unsigned long v; + int res = SWIG_AsVal_unsigned_SS_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v > UINT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (unsigned int)(v); + } + } + return res; +} + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + if (carray) { + if (size > INT_MAX) { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + return pchar_descriptor ? + SWIG_NewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); + } else { + return PyString_FromStringAndSize(carray, (int)(size)); + } + } else { + return SWIG_Py_Void(); + } +} + + +SWIGINTERNINLINE PyObject * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + + +SWIGINTERN int +SWIG_AsVal_long (PyObject *obj, long* val) +{ + if (PyInt_Check(obj)) { + if (val) *val = PyInt_AsLong(obj); + return SWIG_OK; + } else if (PyLong_Check(obj)) { + long v = PyLong_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_OK; + } else { + PyErr_Clear(); + } + } +#ifdef SWIG_PYTHON_CAST_MODE + { + int dispatch = 0; + long v = PyInt_AsLong(obj); + if (!PyErr_Occurred()) { + if (val) *val = v; + return SWIG_AddCast(SWIG_OK); + } else { + PyErr_Clear(); + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } +#endif + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int (PyObject * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long (obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (int)(v); + } + } + return res; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ + if (PyString_Check(obj)) { + char *cstr; Py_ssize_t len; + PyString_AsStringAndSize(obj, &cstr, &len); + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = PyString_AsString(obj); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + +SWIGINTERN WERROR reg_mount_hive__SWIG_1(reg *self,struct hive_key *key,char const *predef_name){ + int i; + for (i = 0; reg_predefined_keys[i].name; i++) { + if (!strcasecmp(reg_predefined_keys[i].name, predef_name)) + return reg_mount_hive(self, key, + reg_predefined_keys[i].handle, NULL); + } + return WERR_INVALID_NAME; + } + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject* +SWIG_From_unsigned_SS_long (unsigned long value) +{ + return (value > LONG_MAX) ? + PyLong_FromUnsignedLong(value) : PyInt_FromLong((long)(value)); +} + + +SWIGINTERNINLINE PyObject * +SWIG_From_unsigned_SS_int (unsigned int value) +{ + return SWIG_From_unsigned_SS_long (value); +} + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN PyObject *_wrap_reg_get_predef_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + uint32_t arg1 ; + unsigned int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "hkey", NULL + }; + char *result = 0 ; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:reg_get_predef_name",kwnames,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_unsigned_SS_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "reg_get_predef_name" "', argument " "1"" of type '" "uint32_t""'"); + } + arg1 = (uint32_t)(val1); + result = (char *)reg_get_predef_name(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_str_regtype(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + int arg1 ; + int val1 ; + int ecode1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "type", NULL + }; + char *result = 0 ; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:str_regtype",kwnames,&obj0)) SWIG_fail; + ecode1 = SWIG_AsVal_int(obj0, &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "str_regtype" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + result = (char *)str_regtype(arg1); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_Registry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + struct registry_context **arg2 = (struct registry_context **) 0 ; + struct registry_context *tmp2 ; + WERROR result; + + arg1 = NULL; + arg2 = &tmp2; + if (!SWIG_Python_UnpackTuple(args,"Registry",0,0,0)) SWIG_fail; + result = reg_open_local(arg1,arg2); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + resultobj = SWIG_NewPointerObj(*arg2, SWIGTYPE_p_registry_context, 0); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_get_predefined_key_by_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + char *arg2 = (char *) 0 ; + struct registry_key **arg3 = (struct registry_key **) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "name",(char *) "key", NULL + }; + WERROR result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:reg_get_predefined_key_by_name",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_get_predefined_key_by_name" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_get_predefined_key_by_name" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_p_registry_key, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "reg_get_predefined_key_by_name" "', argument " "3"" of type '" "struct registry_key **""'"); + } + arg3 = (struct registry_key **)(argp3); + result = reg_get_predefined_key_by_name(arg1,(char const *)arg2,arg3); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_key_del_abs(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "path", NULL + }; + WERROR result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:reg_key_del_abs",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_key_del_abs" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_key_del_abs" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = reg_key_del_abs(arg1,(char const *)arg2); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_get_predefined_key(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + uint32_t arg2 ; + struct registry_key **arg3 = (struct registry_key **) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + unsigned int val2 ; + int ecode2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "hkey_id",(char *) "key", NULL + }; + WERROR result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:reg_get_predefined_key",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_get_predefined_key" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "reg_get_predefined_key" "', argument " "2"" of type '" "uint32_t""'"); + } + arg2 = (uint32_t)(val2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_p_registry_key, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "reg_get_predefined_key" "', argument " "3"" of type '" "struct registry_key **""'"); + } + arg3 = (struct registry_key **)(argp3); + result = reg_get_predefined_key(arg1,arg2,arg3); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_diff_apply(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + char *arg2 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "filename", NULL + }; + WERROR result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:reg_diff_apply",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_diff_apply" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_diff_apply" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = reg_diff_apply(arg1,(char const *)arg2); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_generate_diff(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + struct registry_context *arg2 = (struct registry_context *) 0 ; + struct reg_diff_callbacks *arg3 = (struct reg_diff_callbacks *) 0 ; + void *arg4 = (void *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + int res4 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "ctx2",(char *) "callbacks",(char *) "callback_data", NULL + }; + WERROR result; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO:reg_generate_diff",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_generate_diff" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_generate_diff" "', argument " "2"" of type '" "struct registry_context *""'"); + } + arg2 = (struct registry_context *)(argp2); + res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_reg_diff_callbacks, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "reg_generate_diff" "', argument " "3"" of type '" "struct reg_diff_callbacks const *""'"); + } + arg3 = (struct reg_diff_callbacks *)(argp3); + res4 = SWIG_ConvertPtr(obj3,SWIG_as_voidptrptr(&arg4), 0, 0); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "reg_generate_diff" "', argument " "4"" of type '" "void *""'"); + } + result = reg_generate_diff(arg1,arg2,(struct reg_diff_callbacks const *)arg3,arg4); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_mount_hive__SWIG_0(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + struct hive_key *arg2 = (struct hive_key *) 0 ; + uint32_t arg3 ; + char **arg4 = (char **) NULL ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + unsigned int val3 ; + int ecode3 = 0 ; + WERROR result; + + if ((nobjs < 3) || (nobjs > 4)) SWIG_fail; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_mount_hive" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_hive_key, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_mount_hive" "', argument " "2"" of type '" "struct hive_key *""'"); + } + arg2 = (struct hive_key *)(argp2); + ecode3 = SWIG_AsVal_unsigned_SS_int(swig_obj[2], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "reg_mount_hive" "', argument " "3"" of type '" "uint32_t""'"); + } + arg3 = (uint32_t)(val3); + if (swig_obj[3]) { + /* Check if is a list */ + if (PyList_Check(swig_obj[3])) { + int size = PyList_Size(swig_obj[3]); + int i = 0; + arg4 = (char **) malloc((size+1)*sizeof(const char *)); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem(swig_obj[3],i); + if (PyString_Check(o)) + arg4[i] = PyString_AsString(PyList_GetItem(swig_obj[3],i)); + else { + PyErr_SetString(PyExc_TypeError,"list must contain strings"); + free(arg4); + return NULL; + } + } + arg4[i] = 0; + } else { + PyErr_SetString(PyExc_TypeError,"not a list"); + return NULL; + } + } + result = reg_mount_hive(arg1,arg2,arg3,(char const **)arg4); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + free((char **) arg4); + return resultobj; +fail: + free((char **) arg4); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_import_hive_key(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + struct hive_key *arg2 = (struct hive_key *) 0 ; + uint32_t arg3 ; + char **arg4 = (char **) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + unsigned int val3 ; + int ecode3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + char * kwnames[] = { + (char *) "self",(char *) "hive",(char *) "predef_key",(char *) "elements", NULL + }; + struct registry_key *result = 0 ; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO:reg_import_hive_key",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_import_hive_key" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_hive_key, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_import_hive_key" "', argument " "2"" of type '" "struct hive_key *""'"); + } + arg2 = (struct hive_key *)(argp2); + ecode3 = SWIG_AsVal_unsigned_SS_int(obj2, &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "reg_import_hive_key" "', argument " "3"" of type '" "uint32_t""'"); + } + arg3 = (uint32_t)(val3); + /* Check if is a list */ + if (PyList_Check(obj3)) { + int size = PyList_Size(obj3); + int i = 0; + arg4 = (char **) malloc((size+1)*sizeof(const char *)); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem(obj3,i); + if (PyString_Check(o)) + arg4[i] = PyString_AsString(PyList_GetItem(obj3,i)); + else { + PyErr_SetString(PyExc_TypeError,"list must contain strings"); + free(arg4); + return NULL; + } + } + arg4[i] = 0; + } else { + PyErr_SetString(PyExc_TypeError,"not a list"); + return NULL; + } + result = (struct registry_key *)reg_import_hive_key(arg1,arg2,arg3,(char const **)arg4); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_registry_key, 0 | 0 ); + free((char **) arg4); + return resultobj; +fail: + free((char **) arg4); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_mount_hive__SWIG_1(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + struct hive_key *arg2 = (struct hive_key *) 0 ; + char *arg3 = (char *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + WERROR result; + + if ((nobjs < 3) || (nobjs > 3)) SWIG_fail; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_registry_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "reg_mount_hive" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + res2 = SWIG_ConvertPtr(swig_obj[1], &argp2,SWIGTYPE_p_hive_key, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "reg_mount_hive" "', argument " "2"" of type '" "struct hive_key *""'"); + } + arg2 = (struct hive_key *)(argp2); + res3 = SWIG_AsCharPtrAndSize(swig_obj[2], &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "reg_mount_hive" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + result = reg_mount_hive__SWIG_1(arg1,arg2,(char const *)arg3); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_reg_mount_hive(PyObject *self, PyObject *args) { + int argc; + PyObject *argv[5]; + + if (!(argc = SWIG_Python_UnpackTuple(args,"reg_mount_hive",0,4,argv))) SWIG_fail; + --argc; + if ((argc >= 3) && (argc <= 4)) { + int _v = 0; + { + { + int res = SWIG_AsVal_unsigned_SS_int(argv[2], NULL); + _v = SWIG_CheckState(res); + } + } + if (!_v) goto check_1; + return _wrap_reg_mount_hive__SWIG_0(self, argc, argv); + } +check_1: + + if (argc == 3) { + return _wrap_reg_mount_hive__SWIG_1(self, argc, argv); + } + +fail: + SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'reg_mount_hive'.\n" + " Possible C/C++ prototypes are:\n" + " mount_hive(reg *,struct hive_key *,uint32_t,char const **)\n" + " mount_hive(reg *,struct hive_key *,char const *)\n"); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_new_reg(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + reg *result = 0 ; + + if (!SWIG_Python_UnpackTuple(args,"new_reg",0,0,0)) SWIG_fail; + result = (reg *)calloc(1, sizeof(reg)); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_registry_context, SWIG_POINTER_NEW | 0 ); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_delete_reg(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + reg *arg1 = (reg *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_registry_context, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_reg" "', argument " "1"" of type '" "reg *""'"); + } + arg1 = (reg *)(argp1); + free((char *) arg1); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *reg_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_registry_context, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); +} + +SWIGINTERN PyObject *reg_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); +} + +SWIGINTERN PyObject *_wrap_hive_key(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char *arg2 = (char *) 0 ; + struct auth_session_info *arg3 = (struct auth_session_info *) 0 ; + struct cli_credentials *arg4 = (struct cli_credentials *) 0 ; + struct event_context *arg5 = (struct event_context *) 0 ; + struct loadparm_context *arg6 = (struct loadparm_context *) 0 ; + struct hive_key **arg7 = (struct hive_key **) 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + void *argp5 = 0 ; + int res5 = 0 ; + void *argp6 = 0 ; + int res6 = 0 ; + struct hive_key *tmp7 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + char * kwnames[] = { + (char *) "location",(char *) "session_info",(char *) "credentials",(char *) "ev_ctx",(char *) "lp_ctx", NULL + }; + WERROR result; + + arg3 = NULL; + arg4 = NULL; + arg5 = event_context_init(NULL); + arg6 = loadparm_init(NULL); + arg1 = NULL; + arg7 = &tmp7; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:hive_key",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res2 = SWIG_AsCharPtrAndSize(obj0, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "hive_key" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (obj1) { + res3 = SWIG_ConvertPtr(obj1, &argp3,SWIGTYPE_p_auth_session_info, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "hive_key" "', argument " "3"" of type '" "struct auth_session_info *""'"); + } + arg3 = (struct auth_session_info *)(argp3); + } + if (obj2) { + res4 = SWIG_ConvertPtr(obj2, &argp4,SWIGTYPE_p_cli_credentials, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "hive_key" "', argument " "4"" of type '" "struct cli_credentials *""'"); + } + arg4 = (struct cli_credentials *)(argp4); + } + if (obj3) { + res5 = SWIG_ConvertPtr(obj3, &argp5,SWIGTYPE_p_event_context, 0 | 0 ); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "hive_key" "', argument " "5"" of type '" "struct event_context *""'"); + } + arg5 = (struct event_context *)(argp5); + } + if (obj4) { + res6 = SWIG_ConvertPtr(obj4, &argp6,SWIGTYPE_p_loadparm_context, 0 | 0 ); + if (!SWIG_IsOK(res6)) { + SWIG_exception_fail(SWIG_ArgError(res6), "in method '" "hive_key" "', argument " "6"" of type '" "struct loadparm_context *""'"); + } + arg6 = (struct loadparm_context *)(argp6); + } + result = reg_open_hive(arg1,(char const *)arg2,arg3,arg4,arg5,arg6,arg7); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + Py_XDECREF(resultobj); + resultobj = SWIG_NewPointerObj(*arg7, SWIGTYPE_p_hive_key, 0); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_open_ldb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char *arg2 = (char *) 0 ; + struct auth_session_info *arg3 = (struct auth_session_info *) 0 ; + struct cli_credentials *arg4 = (struct cli_credentials *) 0 ; + struct event_context *arg5 = (struct event_context *) 0 ; + struct loadparm_context *arg6 = (struct loadparm_context *) 0 ; + struct hive_key **arg7 = (struct hive_key **) 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + void *argp3 = 0 ; + int res3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + void *argp5 = 0 ; + int res5 = 0 ; + void *argp6 = 0 ; + int res6 = 0 ; + struct hive_key *tmp7 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + PyObject * obj4 = 0 ; + char * kwnames[] = { + (char *) "location",(char *) "session_info",(char *) "credentials",(char *) "ev_ctx",(char *) "lp_ctx", NULL + }; + WERROR result; + + arg3 = NULL; + arg4 = NULL; + arg5 = event_context_init(NULL); + arg6 = loadparm_init(NULL); + arg1 = NULL; + arg7 = &tmp7; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:open_ldb",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; + res2 = SWIG_AsCharPtrAndSize(obj0, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "open_ldb" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + if (obj1) { + res3 = SWIG_ConvertPtr(obj1, &argp3,SWIGTYPE_p_auth_session_info, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "open_ldb" "', argument " "3"" of type '" "struct auth_session_info *""'"); + } + arg3 = (struct auth_session_info *)(argp3); + } + if (obj2) { + res4 = SWIG_ConvertPtr(obj2, &argp4,SWIGTYPE_p_cli_credentials, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "open_ldb" "', argument " "4"" of type '" "struct cli_credentials *""'"); + } + arg4 = (struct cli_credentials *)(argp4); + } + if (obj3) { + res5 = SWIG_ConvertPtr(obj3, &argp5,SWIGTYPE_p_event_context, 0 | 0 ); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "open_ldb" "', argument " "5"" of type '" "struct event_context *""'"); + } + arg5 = (struct event_context *)(argp5); + } + if (obj4) { + res6 = SWIG_ConvertPtr(obj4, &argp6,SWIGTYPE_p_loadparm_context, 0 | 0 ); + if (!SWIG_IsOK(res6)) { + SWIG_exception_fail(SWIG_ArgError(res6), "in method '" "open_ldb" "', argument " "6"" of type '" "struct loadparm_context *""'"); + } + arg6 = (struct loadparm_context *)(argp6); + } + result = reg_open_ldb_file(arg1,(char const *)arg2,arg3,arg4,arg5,arg6,arg7); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + Py_XDECREF(resultobj); + resultobj = SWIG_NewPointerObj(*arg7, SWIGTYPE_p_hive_key, 0); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_create_dir(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char *arg2 = (char *) 0 ; + struct hive_key **arg3 = (struct hive_key **) 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + struct hive_key *tmp3 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "location", NULL + }; + WERROR result; + + arg1 = NULL; + arg3 = &tmp3; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:create_dir",kwnames,&obj0)) SWIG_fail; + res2 = SWIG_AsCharPtrAndSize(obj0, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "create_dir" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = reg_create_directory(arg1,(char const *)arg2,arg3); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + Py_XDECREF(resultobj); + resultobj = SWIG_NewPointerObj(*arg3, SWIGTYPE_p_hive_key, 0); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_open_dir(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char *arg2 = (char *) 0 ; + struct hive_key **arg3 = (struct hive_key **) 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + struct hive_key *tmp3 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "location", NULL + }; + WERROR result; + + arg1 = NULL; + arg3 = &tmp3; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:open_dir",kwnames,&obj0)) SWIG_fail; + res2 = SWIG_AsCharPtrAndSize(obj0, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "open_dir" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = reg_open_directory(arg1,(char const *)arg2,arg3); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + Py_XDECREF(resultobj); + resultobj = SWIG_NewPointerObj(*arg3, SWIGTYPE_p_hive_key, 0); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_open_samba(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + struct registry_context **arg2 = (struct registry_context **) 0 ; + struct event_context *arg3 = (struct event_context *) 0 ; + struct loadparm_context *arg4 = (struct loadparm_context *) 0 ; + struct auth_session_info *arg5 = (struct auth_session_info *) 0 ; + struct cli_credentials *arg6 = (struct cli_credentials *) 0 ; + struct registry_context *tmp2 ; + void *argp3 = 0 ; + int res3 = 0 ; + void *argp4 = 0 ; + int res4 = 0 ; + void *argp5 = 0 ; + int res5 = 0 ; + void *argp6 = 0 ; + int res6 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + PyObject * obj3 = 0 ; + char * kwnames[] = { + (char *) "ev_ctx",(char *) "lp_ctx",(char *) "session_info",(char *) "credentials", NULL + }; + WERROR result; + + arg3 = event_context_init(NULL); + arg4 = loadparm_init(NULL); + arg5 = NULL; + arg6 = NULL; + arg1 = NULL; + arg2 = &tmp2; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OOOO:open_samba",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; + if (obj0) { + res3 = SWIG_ConvertPtr(obj0, &argp3,SWIGTYPE_p_event_context, 0 | 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "open_samba" "', argument " "3"" of type '" "struct event_context *""'"); + } + arg3 = (struct event_context *)(argp3); + } + if (obj1) { + res4 = SWIG_ConvertPtr(obj1, &argp4,SWIGTYPE_p_loadparm_context, 0 | 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "open_samba" "', argument " "4"" of type '" "struct loadparm_context *""'"); + } + arg4 = (struct loadparm_context *)(argp4); + } + if (obj2) { + res5 = SWIG_ConvertPtr(obj2, &argp5,SWIGTYPE_p_auth_session_info, 0 | 0 ); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "open_samba" "', argument " "5"" of type '" "struct auth_session_info *""'"); + } + arg5 = (struct auth_session_info *)(argp5); + } + if (obj3) { + res6 = SWIG_ConvertPtr(obj3, &argp6,SWIGTYPE_p_cli_credentials, 0 | 0 ); + if (!SWIG_IsOK(res6)) { + SWIG_exception_fail(SWIG_ArgError(res6), "in method '" "open_samba" "', argument " "6"" of type '" "struct cli_credentials *""'"); + } + arg6 = (struct cli_credentials *)(argp6); + } + result = reg_open_samba(arg1,arg2,arg3,arg4,arg5,arg6); + if (!W_ERROR_IS_OK(result)) { + PyErr_SetWERROR(result); + SWIG_fail; + } else if (resultobj == NULL) { + resultobj = Py_None; + } + resultobj = SWIG_NewPointerObj(*arg2, SWIGTYPE_p_registry_context, 0); + return resultobj; +fail: + return NULL; +} + + +static PyMethodDef SwigMethods[] = { + { (char *)"reg_get_predef_name", (PyCFunction) _wrap_reg_get_predef_name, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"str_regtype", (PyCFunction) _wrap_str_regtype, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"Registry", (PyCFunction)_wrap_Registry, METH_NOARGS, NULL}, + { (char *)"reg_get_predefined_key_by_name", (PyCFunction) _wrap_reg_get_predefined_key_by_name, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.get_predefined_key_by_name(name) -> key\n" + "Find a predefined key by name\n" + ""}, + { (char *)"reg_key_del_abs", (PyCFunction) _wrap_reg_key_del_abs, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.key_del_abs(name) -> None\n" + "Delete a key by absolute path.\n" + ""}, + { (char *)"reg_get_predefined_key", (PyCFunction) _wrap_reg_get_predefined_key, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.get_predefined_key(hkey_id) -> key\n" + "Find a predefined key by id\n" + ""}, + { (char *)"reg_diff_apply", (PyCFunction) _wrap_reg_diff_apply, METH_VARARGS | METH_KEYWORDS, (char *)"\n" + "S.diff_apply(filename) -> None\n" + "Apply the diff from the specified file\n" + ""}, + { (char *)"reg_generate_diff", (PyCFunction) _wrap_reg_generate_diff, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"reg_import_hive_key", (PyCFunction) _wrap_reg_import_hive_key, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"reg_mount_hive", _wrap_reg_mount_hive, METH_VARARGS, NULL}, + { (char *)"new_reg", (PyCFunction)_wrap_new_reg, METH_NOARGS, NULL}, + { (char *)"delete_reg", (PyCFunction)_wrap_delete_reg, METH_O, NULL}, + { (char *)"reg_swigregister", reg_swigregister, METH_VARARGS, NULL}, + { (char *)"reg_swiginit", reg_swiginit, METH_VARARGS, NULL}, + { (char *)"hive_key", (PyCFunction) _wrap_hive_key, METH_VARARGS | METH_KEYWORDS, (char *)"S.__init__(location, session_info=None, credentials=None, loadparm_context=None)"}, + { (char *)"open_ldb", (PyCFunction) _wrap_open_ldb, METH_VARARGS | METH_KEYWORDS, (char *)"open_ldb(location, session_info=None, credentials=None, loadparm_context=None) -> key"}, + { (char *)"create_dir", (PyCFunction) _wrap_create_dir, METH_VARARGS | METH_KEYWORDS, (char *)"create_dir(location) -> key"}, + { (char *)"open_dir", (PyCFunction) _wrap_open_dir, METH_VARARGS | METH_KEYWORDS, (char *)"open_dir(location) -> key"}, + { (char *)"open_samba", (PyCFunction) _wrap_open_samba, METH_VARARGS | METH_KEYWORDS, (char *)"open_samba() -> reg"}, + { NULL, NULL, 0, NULL } +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_auth_session_info = {"_p_auth_session_info", "struct auth_session_info *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_cli_credentials = {"_p_cli_credentials", "struct cli_credentials *|cli_credentials *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_event_context = {"_p_event_context", "struct event_context *|event *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_hive_key = {"_p_hive_key", "struct hive_key *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_loadparm_context = {"_p_loadparm_context", "struct loadparm_context *|loadparm_context *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_loadparm_service = {"_p_loadparm_service", "struct loadparm_service *|loadparm_service *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_hive_key = {"_p_p_hive_key", "struct hive_key **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_registry_context = {"_p_p_registry_context", "struct registry_context **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_registry_key = {"_p_p_registry_key", "struct registry_key **", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_context = {"_p_param_context", "struct param_context *|param *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_opt = {"_p_param_opt", "struct param_opt *|param_opt *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_section = {"_p_param_section", "struct param_section *|param_section *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_reg_diff_callbacks = {"_p_reg_diff_callbacks", "struct reg_diff_callbacks *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_registry_context = {"_p_registry_context", "struct registry_context *|reg *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_registry_key = {"_p_registry_key", "struct registry_key *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_TALLOC_CTX, + &_swigt__p_auth_session_info, + &_swigt__p_char, + &_swigt__p_cli_credentials, + &_swigt__p_event_context, + &_swigt__p_hive_key, + &_swigt__p_int, + &_swigt__p_loadparm_context, + &_swigt__p_loadparm_service, + &_swigt__p_long_long, + &_swigt__p_p_char, + &_swigt__p_p_hive_key, + &_swigt__p_p_registry_context, + &_swigt__p_p_registry_key, + &_swigt__p_param_context, + &_swigt__p_param_opt, + &_swigt__p_param_section, + &_swigt__p_reg_diff_callbacks, + &_swigt__p_registry_context, + &_swigt__p_registry_key, + &_swigt__p_short, + &_swigt__p_signed_char, + &_swigt__p_unsigned_char, + &_swigt__p_unsigned_int, + &_swigt__p_unsigned_long_long, + &_swigt__p_unsigned_short, +}; + +static swig_cast_info _swigc__p_TALLOC_CTX[] = { {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_auth_session_info[] = { {&_swigt__p_auth_session_info, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_cli_credentials[] = { {&_swigt__p_cli_credentials, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_event_context[] = { {&_swigt__p_event_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_hive_key[] = { {&_swigt__p_hive_key, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_loadparm_context[] = { {&_swigt__p_loadparm_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_loadparm_service[] = { {&_swigt__p_loadparm_service, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_char[] = { {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_hive_key[] = { {&_swigt__p_p_hive_key, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_registry_context[] = { {&_swigt__p_p_registry_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_registry_key[] = { {&_swigt__p_p_registry_key, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_context[] = { {&_swigt__p_param_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_opt[] = { {&_swigt__p_param_opt, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_section[] = { {&_swigt__p_param_section, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_reg_diff_callbacks[] = { {&_swigt__p_reg_diff_callbacks, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_registry_context[] = { {&_swigt__p_registry_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_registry_key[] = { {&_swigt__p_registry_key, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_TALLOC_CTX, + _swigc__p_auth_session_info, + _swigc__p_char, + _swigc__p_cli_credentials, + _swigc__p_event_context, + _swigc__p_hive_key, + _swigc__p_int, + _swigc__p_loadparm_context, + _swigc__p_loadparm_service, + _swigc__p_long_long, + _swigc__p_p_char, + _swigc__p_p_hive_key, + _swigc__p_p_registry_context, + _swigc__p_p_registry_key, + _swigc__p_param_context, + _swigc__p_param_opt, + _swigc__p_param_section, + _swigc__p_reg_diff_callbacks, + _swigc__p_registry_context, + _swigc__p_registry_key, + _swigc__p_short, + _swigc__p_signed_char, + _swigc__p_unsigned_char, + _swigc__p_unsigned_int, + _swigc__p_unsigned_long_long, + _swigc__p_unsigned_short, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_const_info swig_const_table[] = { +{0, 0, 0, 0.0, 0, 0}}; + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + /* Python-specific SWIG API */ +#define SWIG_newvarlink() SWIG_Python_newvarlink() +#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) +#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) + + /* ----------------------------------------------------------------------------- + * global variable support code. + * ----------------------------------------------------------------------------- */ + + typedef struct swig_globalvar { + char *name; /* Name of global variable */ + PyObject *(*get_attr)(void); /* Return the current value */ + int (*set_attr)(PyObject *); /* Set the value */ + struct swig_globalvar *next; + } swig_globalvar; + + typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar *vars; + } swig_varlinkobject; + + SWIGINTERN PyObject * + swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { + return PyString_FromString("<Swig global variables>"); + } + + SWIGINTERN PyObject * + swig_varlink_str(swig_varlinkobject *v) { + PyObject *str = PyString_FromString("("); + swig_globalvar *var; + for (var = v->vars; var; var=var->next) { + PyString_ConcatAndDel(&str,PyString_FromString(var->name)); + if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); + } + PyString_ConcatAndDel(&str,PyString_FromString(")")); + return str; + } + + SWIGINTERN int + swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { + PyObject *str = swig_varlink_str(v); + fprintf(fp,"Swig global variables "); + fprintf(fp,"%s\n", PyString_AsString(str)); + Py_DECREF(str); + return 0; + } + + SWIGINTERN void + swig_varlink_dealloc(swig_varlinkobject *v) { + swig_globalvar *var = v->vars; + while (var) { + swig_globalvar *n = var->next; + free(var->name); + free(var); + var = n; + } + } + + SWIGINTERN PyObject * + swig_varlink_getattr(swig_varlinkobject *v, char *n) { + PyObject *res = NULL; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->get_attr)(); + break; + } + var = var->next; + } + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN int + swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + int res = 1; + swig_globalvar *var = v->vars; + while (var) { + if (strcmp(var->name,n) == 0) { + res = (*var->set_attr)(p); + break; + } + var = var->next; + } + if (res == 1 && !PyErr_Occurred()) { + PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + } + return res; + } + + SWIGINTERN PyTypeObject* + swig_varlink_type(void) { + static char varlink__doc__[] = "Swig var link object"; + static PyTypeObject varlink_type; + static int type_init = 0; + if (!type_init) { + const PyTypeObject tmp + = { + PyObject_HEAD_INIT(NULL) + 0, /* Number of items in variable part (ob_size) */ + (char *)"swigvarlink", /* Type name (tp_name) */ + sizeof(swig_varlinkobject), /* Basic size (tp_basicsize) */ + 0, /* Itemsize (tp_itemsize) */ + (destructor) swig_varlink_dealloc, /* Deallocator (tp_dealloc) */ + (printfunc) swig_varlink_print, /* Print (tp_print) */ + (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */ + (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)swig_varlink_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + varlink__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +#if PY_VERSION_HEX >= 0x02020000 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ +#endif +#if PY_VERSION_HEX >= 0x02030000 + 0, /* tp_del */ +#endif +#ifdef COUNT_ALLOCS + 0,0,0,0 /* tp_alloc -> tp_next */ +#endif + }; + varlink_type = tmp; + varlink_type.ob_type = &PyType_Type; + type_init = 1; + } + return &varlink_type; + } + + /* Create a variable linking object for use later */ + SWIGINTERN PyObject * + SWIG_Python_newvarlink(void) { + swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); + if (result) { + result->vars = 0; + } + return ((PyObject*) result); + } + + SWIGINTERN void + SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { + swig_varlinkobject *v = (swig_varlinkobject *) p; + swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + if (gv) { + size_t size = strlen(name)+1; + gv->name = (char *)malloc(size); + if (gv->name) { + strncpy(gv->name,name,size); + gv->get_attr = get_attr; + gv->set_attr = set_attr; + gv->next = v->vars; + } + } + v->vars = gv; + } + + SWIGINTERN PyObject * + SWIG_globals(void) { + static PyObject *_SWIG_globals = 0; + if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); + return _SWIG_globals; + } + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + SWIGINTERN void + SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { + PyObject *obj = 0; + size_t i; + for (i = 0; constants[i].type; ++i) { + switch(constants[i].type) { + case SWIG_PY_POINTER: + obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_PY_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + PyDict_SetItemString(d, constants[i].name, obj); + Py_DECREF(obj); + } + } + } + + /* -----------------------------------------------------------------------------*/ + /* Fix SwigMethods to carry the callback ptrs when needed */ + /* -----------------------------------------------------------------------------*/ + + SWIGINTERN void + SWIG_Python_FixMethods(PyMethodDef *methods, + swig_const_info *const_table, + swig_type_info **types, + swig_type_info **types_initial) { + size_t i; + for (i = 0; methods[i].ml_name; ++i) { + const char *c = methods[i].ml_doc; + if (c && (c = strstr(c, "swig_ptr: "))) { + int j; + swig_const_info *ci = 0; + const char *name = c + 10; + for (j = 0; const_table[j].type; ++j) { + if (strncmp(const_table[j].name, name, + strlen(const_table[j].name)) == 0) { + ci = &(const_table[j]); + break; + } + } + if (ci) { + size_t shift = (ci->ptype) - types; + swig_type_info *ty = types_initial[shift]; + size_t ldoc = (c - methods[i].ml_doc); + size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; + char *ndoc = (char*)malloc(ldoc + lptr + 10); + if (ndoc) { + char *buff = ndoc; + void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; + if (ptr) { + strncpy(buff, methods[i].ml_doc, ldoc); + buff += ldoc; + strncpy(buff, "swig_ptr: ", 10); + buff += 10; + SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); + methods[i].ml_doc = ndoc; + } + } + } + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT void SWIG_init(void) { + PyObject *m, *d; + + /* Fix SwigMethods to carry the callback ptrs when needed */ + SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); + + m = Py_InitModule((char *) SWIG_name, SwigMethods); + d = PyModule_GetDict(m); + + SWIG_InitializeModule(0); + SWIG_InstallConstants(d,swig_const_table); + + + SWIG_Python_SetConstant(d, "HKEY_CLASSES_ROOT",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_CLASSES_ROOT))); + SWIG_Python_SetConstant(d, "HKEY_CURRENT_USER",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_CURRENT_USER))); + SWIG_Python_SetConstant(d, "HKEY_LOCAL_MACHINE",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_LOCAL_MACHINE))); + SWIG_Python_SetConstant(d, "HKEY_USERS",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_USERS))); + SWIG_Python_SetConstant(d, "HKEY_PERFORMANCE_DATA",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_PERFORMANCE_DATA))); + SWIG_Python_SetConstant(d, "HKEY_CURRENT_CONFIG",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_CURRENT_CONFIG))); + SWIG_Python_SetConstant(d, "HKEY_DYN_DATA",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_DYN_DATA))); + SWIG_Python_SetConstant(d, "HKEY_PERFORMANCE_TEXT",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_PERFORMANCE_TEXT))); + SWIG_Python_SetConstant(d, "HKEY_PERFORMANCE_NLSTEXT",SWIG_From_unsigned_SS_int((unsigned int)(HKEY_PERFORMANCE_NLSTEXT))); +} + diff --git a/source4/lib/registry/rpc.c b/source4/lib/registry/rpc.c new file mode 100644 index 0000000000..18b7607713 --- /dev/null +++ b/source4/lib/registry/rpc.c @@ -0,0 +1,454 @@ +/* + Samba Unix/Linux SMB implementation + RPC backend for the registry library + Copyright (C) 2003-2007 Jelmer Vernooij, jelmer@samba.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "includes.h" +#include "registry.h" +#include "librpc/gen_ndr/ndr_winreg_c.h" + +struct rpc_key { + struct registry_key key; + struct policy_handle pol; + struct dcerpc_pipe *pipe; + + uint32_t num_values; + uint32_t num_subkeys; + uint32_t max_valnamelen; + uint32_t max_valdatalen; + uint32_t max_subkeynamelen; +}; + +struct rpc_registry_context { + struct registry_context context; + struct dcerpc_pipe *pipe; +}; + +static struct registry_operations reg_backend_rpc; + +/** + * This is the RPC backend for the registry library. + */ + +static void init_winreg_String(struct winreg_String *name, const char *s) +{ + name->name = s; +} + + +#define openhive(u) static WERROR open_ ## u(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *hnd) \ +{ \ + struct winreg_Open ## u r; \ + NTSTATUS status; \ + \ + r.in.system_name = NULL; \ + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; \ + r.out.handle = hnd;\ + \ + status = dcerpc_winreg_Open ## u(p, mem_ctx, &r); \ + if (NT_STATUS_IS_ERR(status)) {\ + DEBUG(0,("Error executing open\n"));\ + return ntstatus_to_werror(status);\ + }\ +\ + return r.out.result;\ +} + +openhive(HKLM) +openhive(HKCU) +openhive(HKPD) +openhive(HKU) +openhive(HKCR) +openhive(HKDD) +openhive(HKCC) + +static struct { + uint32_t hkey; + WERROR (*open) (struct dcerpc_pipe *p, TALLOC_CTX *, + struct policy_handle *h); +} known_hives[] = { + { HKEY_LOCAL_MACHINE, open_HKLM }, + { HKEY_CURRENT_USER, open_HKCU }, + { HKEY_CLASSES_ROOT, open_HKCR }, + { HKEY_PERFORMANCE_DATA, open_HKPD }, + { HKEY_USERS, open_HKU }, + { HKEY_DYN_DATA, open_HKDD }, + { HKEY_CURRENT_CONFIG, open_HKCC }, + { 0, NULL } +}; + +static WERROR rpc_query_key(const struct registry_key *k); + +static WERROR rpc_get_predefined_key(struct registry_context *ctx, + uint32_t hkey_type, + struct registry_key **k) +{ + int n; + struct rpc_key *mykeydata; + struct rpc_registry_context *rctx = talloc_get_type(ctx, struct rpc_registry_context); + + *k = NULL; + + for(n = 0; known_hives[n].hkey; n++) { + if(known_hives[n].hkey == hkey_type) + break; + } + + if (known_hives[n].open == NULL) { + DEBUG(1, ("No such hive %d\n", hkey_type)); + return WERR_NO_MORE_ITEMS; + } + + mykeydata = talloc_zero(ctx, struct rpc_key); + mykeydata->key.context = ctx; + mykeydata->pipe = talloc_reference(mykeydata, rctx->pipe); + mykeydata->num_values = -1; + mykeydata->num_subkeys = -1; + *k = (struct registry_key *)mykeydata; + return known_hives[n].open(mykeydata->pipe, mykeydata, &(mykeydata->pol)); +} + +#if 0 +static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k) +{ + struct winreg_OpenKey r; + struct rpc_key_data *mykeydata; + + k->backend_data = mykeydata = talloc(mem_ctx, struct rpc_key_data); + mykeydata->num_values = -1; + mykeydata->num_subkeys = -1; + + /* Then, open the handle using the hive */ + + memset(&r, 0, sizeof(struct winreg_OpenKey)); + r.in.handle = &(((struct rpc_key_data *)k->hive->root->backend_data)->pol); + init_winreg_String(&r.in.keyname, k->path); + r.in.unknown = 0x00000000; + r.in.access_mask = 0x02000000; + r.out.handle = &mykeydata->pol; + + dcerpc_winreg_OpenKey((struct dcerpc_pipe *)k->hive->backend_data, + mem_ctx, &r); + + return r.out.result; +} +#endif + +static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, struct registry_key *h, + const char *name, struct registry_key **key) +{ + struct rpc_key *parentkeydata = talloc_get_type(h, struct rpc_key), + *mykeydata; + struct winreg_OpenKey r; + NTSTATUS status; + + mykeydata = talloc(mem_ctx, struct rpc_key); + + mykeydata->key.context = parentkeydata->key.context; + mykeydata->pipe = talloc_reference(mykeydata, parentkeydata->pipe); + mykeydata->num_values = -1; + mykeydata->num_subkeys = -1; + *key = (struct registry_key *)mykeydata; + + /* Then, open the handle using the hive */ + ZERO_STRUCT(r); + r.in.parent_handle = &parentkeydata->pol; + init_winreg_String(&r.in.keyname, name); + r.in.unknown = 0x00000000; + r.in.access_mask = 0x02000000; + r.out.handle = &mykeydata->pol; + + status = dcerpc_winreg_OpenKey(mykeydata->pipe, mem_ctx, &r); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(0,("Error executing openkey: %s\n", nt_errstr(status))); + return ntstatus_to_werror(status); + } + + return r.out.result; +} + +static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, + const struct registry_key *parent, + uint32_t n, + const char **value_name, + uint32_t *type, + DATA_BLOB *data) +{ + struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key); + WERROR error; + struct winreg_EnumValue r; + uint32_t in_type = 0; + NTSTATUS status; + struct winreg_StringBuf name; + uint32_t zero = 0; + + ZERO_STRUCT(r); + + if (mykeydata->num_values == -1) { + error = rpc_query_key(parent); + if(!W_ERROR_IS_OK(error)) return error; + } + + name.length = 0; + name.size = mykeydata->max_valnamelen * 2; + name.name = NULL; + + r.in.handle = &mykeydata->pol; + r.in.enum_index = n; + r.in.name = &name; + r.in.type = &in_type; + r.in.value = talloc_zero_array(mem_ctx, uint8_t, 0); + r.in.length = &zero; + r.in.size = &mykeydata->max_valdatalen; + r.out.name = &name; + r.out.type = type; + + status = dcerpc_winreg_EnumValue(mykeydata->pipe, mem_ctx, &r); + if(NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status))); + return WERR_GENERAL_FAILURE; + } + + if(NT_STATUS_IS_OK(status) && + W_ERROR_IS_OK(r.out.result) && r.out.length) { + *value_name = talloc_strdup(mem_ctx, r.out.name->name); + *data = data_blob_talloc(mem_ctx, r.out.value, *r.out.length); + return WERR_OK; + } + + return r.out.result; +} + +static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, + const struct registry_key *parent, + uint32_t n, + const char **name, + const char **keyclass, + NTTIME *last_changed_time) +{ + struct winreg_EnumKey r; + struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key); + NTSTATUS status; + struct winreg_StringBuf namebuf, classbuf; + NTTIME change_time = 0; + + ZERO_STRUCT(r); + + namebuf.length = 0; + namebuf.size = 1024; + namebuf.name = NULL; + classbuf.length = 0; + classbuf.size = 0; + classbuf.name = NULL; + + r.in.handle = &mykeydata->pol; + r.in.enum_index = n; + r.in.name = &namebuf; + r.in.keyclass = &classbuf; + r.in.last_changed_time = &change_time; + + r.out.name = &namebuf; + + status = dcerpc_winreg_EnumKey(mykeydata->pipe, mem_ctx, &r); + if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) { + *name = talloc_strdup(mem_ctx, r.out.name->name); + if (keyclass != NULL) + *keyclass = talloc_strdup(mem_ctx, r.out.keyclass->name); + } + + return r.out.result; +} + +static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, + struct registry_key *parent, const char *name, + const char *key_class, + struct security_descriptor *sec, + struct registry_key **key) +{ + NTSTATUS status; + struct winreg_CreateKey r; + struct rpc_key *parentkd = talloc_get_type(parent, struct rpc_key); + struct rpc_key *rpck = talloc(mem_ctx, struct rpc_key); + + init_winreg_String(&r.in.name, name); + init_winreg_String(&r.in.keyclass, NULL); + + r.in.handle = &parentkd->pol; + r.out.new_handle = &rpck->pol; + r.in.options = 0; + r.in.access_mask = SEC_STD_ALL; + r.in.secdesc = NULL; + + status = dcerpc_winreg_CreateKey(parentkd->pipe, mem_ctx, &r); + + if (!NT_STATUS_IS_OK(status)) { + talloc_free(rpck); + DEBUG(1, ("CreateKey failed - %s\n", nt_errstr(status))); + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(r.out.result)) { + rpck->pipe = talloc_reference(rpck, parentkd->pipe); + *key = (struct registry_key *)rpck; + } + + return r.out.result; +} + +static WERROR rpc_query_key(const struct registry_key *k) +{ + NTSTATUS status; + struct winreg_QueryInfoKey r; + struct rpc_key *mykeydata = talloc_get_type(k, struct rpc_key); + TALLOC_CTX *mem_ctx = talloc_init("query_key"); + uint32_t max_subkeysize; + uint32_t secdescsize; + NTTIME last_changed_time; + + ZERO_STRUCT(r.out); + + r.out.num_subkeys = &mykeydata->num_subkeys; + r.out.max_subkeylen = &mykeydata->max_subkeynamelen; + r.out.max_valnamelen = &mykeydata->max_valnamelen; + r.out.max_valbufsize = &mykeydata->max_valdatalen; + r.out.max_subkeysize = &max_subkeysize; + r.out.num_values = &mykeydata->num_values; + r.out.secdescsize = &secdescsize; + r.out.last_changed_time = &last_changed_time; + + r.out.classname = r.in.classname = talloc_zero(mem_ctx, struct winreg_String); + init_winreg_String(r.in.classname, NULL); + r.in.handle = &mykeydata->pol; + + status = dcerpc_winreg_QueryInfoKey(mykeydata->pipe, mem_ctx, &r); + talloc_free(mem_ctx); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("QueryInfoKey failed - %s\n", nt_errstr(status))); + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(r.out.result)) { + } + + return r.out.result; +} + +static WERROR rpc_del_key(struct registry_key *parent, const char *name) +{ + NTSTATUS status; + struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key); + struct winreg_DeleteKey r; + TALLOC_CTX *mem_ctx = talloc_init("del_key"); + + r.in.handle = &mykeydata->pol; + init_winreg_String(&r.in.key, name); + + status = dcerpc_winreg_DeleteKey(mykeydata->pipe, mem_ctx, &r); + + talloc_free(mem_ctx); + + return r.out.result; +} + +static WERROR rpc_get_info(TALLOC_CTX *mem_ctx, const struct registry_key *key, + const char **classname, + uint32_t *numsubkeys, + uint32_t *numvalue, + NTTIME *last_changed_time, + uint32_t *max_subkeynamelen, + uint32_t *max_valnamelen, + uint32_t *max_valbufsize) +{ + struct rpc_key *mykeydata = talloc_get_type(key, struct rpc_key); + WERROR error; + + if (mykeydata->num_values == -1) { + error = rpc_query_key(key); + if(!W_ERROR_IS_OK(error)) return error; + } + + /* FIXME: *classname = talloc_strdup(mem_ctx, mykeydata->classname); */ + /* FIXME: *last_changed_time = mykeydata->last_changed_time */ + + if (numvalue != NULL) + *numvalue = mykeydata->num_values; + + if (numsubkeys != NULL) + *numsubkeys = mykeydata->num_subkeys; + + if (max_valnamelen != NULL) + *max_valnamelen = mykeydata->max_valnamelen; + + if (max_valbufsize != NULL) + *max_valbufsize = mykeydata->max_valdatalen; + + if (max_subkeynamelen != NULL) + *max_subkeynamelen = mykeydata->max_subkeynamelen; + + return WERR_OK; +} + +static struct registry_operations reg_backend_rpc = { + .name = "rpc", + .open_key = rpc_open_key, + .get_predefined_key = rpc_get_predefined_key, + .enum_key = rpc_get_subkey_by_index, + .enum_value = rpc_get_value_by_index, + .create_key = rpc_add_key, + .delete_key = rpc_del_key, + .get_key_info = rpc_get_info, + .get_predefined_key = rpc_get_predefined_key, +}; + +_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + struct loadparm_context *lp_ctx, + const char *location, struct event_context *ev) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + struct rpc_registry_context *rctx; + + dcerpc_init(); + + rctx = talloc(NULL, struct rpc_registry_context); + + /* Default to local smbd if no connection is specified */ + if (!location) { + location = talloc_strdup(rctx, "ncalrpc:"); + } + + status = dcerpc_pipe_connect(rctx /* TALLOC_CTX */, + &p, location, + &ndr_table_winreg, + credentials, ev, lp_ctx); + rctx->pipe = p; + + if(NT_STATUS_IS_ERR(status)) { + DEBUG(1, ("Unable to open '%s': %s\n", location, + nt_errstr(status))); + talloc_free(rctx); + *ctx = NULL; + return ntstatus_to_werror(status); + } + + *ctx = (struct registry_context *)rctx; + (*ctx)->ops = ®_backend_rpc; + + return WERR_OK; +} diff --git a/source4/lib/registry/samba.c b/source4/lib/registry/samba.c new file mode 100644 index 0000000000..84a8112f17 --- /dev/null +++ b/source4/lib/registry/samba.c @@ -0,0 +1,97 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij 2004-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "registry.h" +#include "param/param.h" + +/** + * @file + * @brief Samba-specific registry functions + */ + +static WERROR mount_samba_hive(struct registry_context *ctx, + struct event_context *event_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *auth_info, + struct cli_credentials *creds, + const char *name, + uint32_t hive_id) +{ + WERROR error; + struct hive_key *hive; + const char *location; + + location = talloc_asprintf(ctx, "%s/%s.ldb", + lp_private_dir(lp_ctx), + name); + + error = reg_open_hive(ctx, location, auth_info, creds, event_ctx, lp_ctx, &hive); + + if (W_ERROR_EQUAL(error, WERR_BADFILE)) + error = reg_open_ldb_file(ctx, location, auth_info, + creds, event_ctx, lp_ctx, &hive); + + if (!W_ERROR_IS_OK(error)) + return error; + + return reg_mount_hive(ctx, hive, hive_id, NULL); +} + + +_PUBLIC_ WERROR reg_open_samba(TALLOC_CTX *mem_ctx, + struct registry_context **ctx, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *session_info, + struct cli_credentials *credentials) +{ + WERROR result; + + result = reg_open_local(mem_ctx, ctx); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + mount_samba_hive(*ctx, ev_ctx, lp_ctx, session_info, credentials, + "hklm", HKEY_LOCAL_MACHINE); + + mount_samba_hive(*ctx, ev_ctx, lp_ctx, session_info, credentials, + "hkcr", HKEY_CLASSES_ROOT); + + /* FIXME: Should be mounted from NTUSER.DAT in the home directory of the + * current user */ + mount_samba_hive(*ctx, ev_ctx, lp_ctx, session_info, credentials, + "hkcu", HKEY_CURRENT_USER); + + mount_samba_hive(*ctx, ev_ctx, lp_ctx, session_info, credentials, + "hku", HKEY_USERS); + + /* FIXME: Different hive backend for HKEY_CLASSES_ROOT: merged view of HKEY_LOCAL_MACHINE\Software\Classes + * and HKEY_CURRENT_USER\Software\Classes */ + + /* FIXME: HKEY_CURRENT_CONFIG is an alias for HKEY_LOCAL_MACHINE\System\CurrentControlSet\Hardware Profiles\Current */ + + /* FIXME: HKEY_PERFORMANCE_DATA is dynamically generated */ + + /* FIXME: HKEY_LOCAL_MACHINE\Hardware is autogenerated */ + + /* FIXME: HKEY_LOCAL_MACHINE\Security\SAM is an alias for HKEY_LOCAL_MACHINE\SAM */ + + return WERR_OK; +} diff --git a/source4/lib/registry/tests/bindings.py b/source4/lib/registry/tests/bindings.py new file mode 100644 index 0000000000..1fb5c70b70 --- /dev/null +++ b/source4/lib/registry/tests/bindings.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import unittest +from samba import registry +import samba.tests + +class HelperTests(unittest.TestCase): + def test_predef_to_name(self): + self.assertEquals("HKEY_LOCAL_MACHINE", + registry.reg_get_predef_name(0x80000002)) + + def test_str_regtype(self): + self.assertEquals("REG_DWORD", registry.str_regtype(4)) + + + +class HiveTests(samba.tests.TestCaseInTempDir): + def setUp(self): + super(HiveTests, self).setUp() + self.hive_path = os.path.join(self.tempdir, "ldb_new.ldb") + self.hive = registry.open_ldb(self.hive_path) + + def tearDown(self): + del self.hive + os.unlink(self.hive_path) + + def test_ldb_new(self): + self.assertTrue(self.hive is not None) + + #def test_flush(self): + # self.hive.flush() + + #def test_del_value(self): + # self.hive.del_value("FOO") + + +class RegistryTests(unittest.TestCase): + def test_new(self): + self.registry = registry.Registry() diff --git a/source4/lib/registry/tests/diff.c b/source4/lib/registry/tests/diff.c new file mode 100644 index 0000000000..44ea090527 --- /dev/null +++ b/source4/lib/registry/tests/diff.c @@ -0,0 +1,296 @@ +/* + Unix SMB/CIFS implementation. + + local testing of registry diff functionality + + Copyright (C) Jelmer Vernooij 2007 + Copyright (C) Wilco Baan Hofman 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "torture/torture.h" +#include "librpc/gen_ndr/winreg.h" +#include "param/param.h" + +struct diff_tcase_data { + struct registry_context *r1_ctx; + struct registry_context *r2_ctx; + struct reg_diff_callbacks *callbacks; + void *callback_data; + char *tempdir; + char *filename; +}; + +static bool test_generate_diff(struct torture_context *tctx, void *tcase_data) +{ + WERROR error; + struct diff_tcase_data *td = tcase_data; + + error = reg_generate_diff(td->r1_ctx, td->r2_ctx, + td->callbacks, + td->callback_data); + torture_assert_werr_ok(tctx, error, "reg_generate_diff"); + + return true; +} + +#if 0 +static bool test_diff_load(struct torture_context *tctx, void *tcase_data) +{ + struct diff_tcase_data *td = tcase_data; + struct smb_iconv_convenience *ic; + struct reg_diff_callbacks *callbacks; + void *data; + WERROR error; + + ic = lp_iconv_convenience(tctx->lp_ctx); + + error = reg_diff_load(td->filename, iconv_convenience, callbacks, data); + torture_assert_werr_ok(tctx, error, "reg_diff_load"); + + return true; +} +#endif +static bool test_diff_apply(struct torture_context *tctx, void *tcase_data) +{ + struct diff_tcase_data *td = tcase_data; + struct registry_key *key; + WERROR error; + + error = reg_diff_apply(td->r1_ctx, td->filename); + torture_assert_werr_ok(tctx, error, "reg_diff_apply"); + + error = td->r1_ctx->ops->get_predefined_key(td->r1_ctx, HKEY_LOCAL_MACHINE, &key); + torture_assert_werr_ok(tctx, error, "Opening HKEY_LOCAL_MACHINE failed"); + + /* If this generates an error it could be that the apply doesn't work, + * but also that the reg_generate_diff didn't work. */ + error = td->r1_ctx->ops->open_key(td->r1_ctx, key, "Software", &key); + torture_assert_werr_ok(tctx, error, "Opening HKLM\\Software failed"); + error = td->r1_ctx->ops->open_key(td->r1_ctx, key, "Microsoft", &key); + torture_assert_werr_ok(tctx, error, "Opening HKLM\\Software\\Microsoft failed"); + error = td->r1_ctx->ops->open_key(td->r1_ctx, key, "Windows", &key); + torture_assert_werr_ok(tctx, error, "Opening HKLM\\..\\Microsoft\\Windows failed"); + error = td->r1_ctx->ops->open_key(td->r1_ctx, key, "CurrentVersion", &key); + torture_assert_werr_ok(tctx, error, "Opening HKLM\\..\\Windows\\CurrentVersion failed"); + error = td->r1_ctx->ops->open_key(td->r1_ctx, key, "Policies", &key); + torture_assert_werr_ok(tctx, error, "Opening HKLM\\..\\CurrentVersion\\Policies failed"); + error = td->r1_ctx->ops->open_key(td->r1_ctx, key, "Explorer", &key); + torture_assert_werr_ok(tctx, error, "Opening HKLM\\..\\Policies\\Explorer failed"); + + return true; +} + +static const char *added_key = NULL; + +static WERROR test_add_key(void *callback_data, const char *key_name) +{ + added_key = talloc_strdup(callback_data, key_name); + + return WERR_OK; +} + +static bool test_generate_diff_key_add(struct torture_context *tctx, void *tcase_data) +{ + struct reg_diff_callbacks cb; + struct registry_key rk; + + return true; + + ZERO_STRUCT(cb); + + cb.add_key = test_add_key; + + if (W_ERROR_IS_OK(reg_generate_diff_key(&rk, NULL, "bla", &cb, tctx))) + return false; + + torture_assert_str_equal(tctx, added_key, "bla", "key added"); + + return true; +} + +static bool test_generate_diff_key_null(struct torture_context *tctx, void *tcase_data) +{ + struct reg_diff_callbacks cb; + + ZERO_STRUCT(cb); + + if (!W_ERROR_IS_OK(reg_generate_diff_key(NULL, NULL, "", &cb, NULL))) + return false; + + return true; +} + +static void tcase_add_tests (struct torture_tcase *tcase) +{ + torture_tcase_add_simple_test(tcase, "test_generate_diff_key_add", + test_generate_diff_key_add); + torture_tcase_add_simple_test(tcase, "test_generate_diff_key_null", + test_generate_diff_key_null); + torture_tcase_add_simple_test(tcase, "test_generate_diff", + test_generate_diff); + torture_tcase_add_simple_test(tcase, "test_diff_apply", + test_diff_apply); +/* torture_tcase_add_simple_test(tcase, "test_diff_load", + test_diff_load); +*/ +} + +static bool diff_setup_tcase(struct torture_context *tctx, void **data) +{ + struct registry_context *r1_ctx, *r2_ctx; + WERROR error; + NTSTATUS status; + struct hive_key *r1_hklm, *r1_hkcu; + struct hive_key *r2_hklm, *r2_hkcu; + const char *filename; + struct diff_tcase_data *td; + struct registry_key *key, *newkey; + DATA_BLOB blob; + + td = talloc(tctx, struct diff_tcase_data); + + /* Create two registry contexts */ + error = reg_open_local(tctx, &r1_ctx); + torture_assert_werr_ok(tctx, error, "Opening registry 1 for patch tests failed"); + + error = reg_open_local(tctx, &r2_ctx); + torture_assert_werr_ok(tctx, error, "Opening registry 2 for patch tests failed"); + + /* Create temp directory */ + status = torture_temp_dir(tctx, "patchfile", &td->tempdir); + torture_assert_ntstatus_ok(tctx, status, "Creating temp dir failed"); + + /* Create and mount HKLM and HKCU hives for registry 1 */ + filename = talloc_asprintf(tctx, "%s/r1_local_machine.ldb", td->tempdir); + error = reg_open_ldb_file(tctx, filename, NULL, NULL, tctx->ev, tctx->lp_ctx, &r1_hklm); + torture_assert_werr_ok(tctx, error, "Opening local machine file failed"); + + error = reg_mount_hive(r1_ctx, r1_hklm, HKEY_LOCAL_MACHINE, NULL); + torture_assert_werr_ok(tctx, error, "Mounting hive failed"); + + filename = talloc_asprintf(tctx, "%s/r1_current_user.ldb", td->tempdir); + error = reg_open_ldb_file(tctx, filename, NULL, NULL, tctx->ev, tctx->lp_ctx, &r1_hkcu); + torture_assert_werr_ok(tctx, error, "Opening current user file failed"); + + error = reg_mount_hive(r1_ctx, r1_hkcu, HKEY_CURRENT_USER, NULL); + torture_assert_werr_ok(tctx, error, "Mounting hive failed"); + + /* Create and mount HKLM and HKCU hives for registry 2 */ + filename = talloc_asprintf(tctx, "%s/r2_local_machine.ldb", td->tempdir); + error = reg_open_ldb_file(tctx, filename, NULL, NULL, tctx->ev, tctx->lp_ctx, &r2_hklm); + torture_assert_werr_ok(tctx, error, "Opening local machine file failed"); + + error = reg_mount_hive(r2_ctx, r2_hklm, HKEY_LOCAL_MACHINE, NULL); + torture_assert_werr_ok(tctx, error, "Mounting hive failed"); + + filename = talloc_asprintf(tctx, "%s/r2_current_user.ldb", td->tempdir); + error = reg_open_ldb_file(tctx, filename, NULL, NULL, tctx->ev, tctx->lp_ctx, &r2_hkcu); + torture_assert_werr_ok(tctx, error, "Opening current user file failed"); + + error = reg_mount_hive(r2_ctx, r2_hkcu, HKEY_CURRENT_USER, NULL); + torture_assert_werr_ok(tctx, error, "Mounting hive failed"); + + error = r1_ctx->ops->get_predefined_key(r1_ctx, HKEY_CURRENT_USER, &key); + torture_assert_werr_ok(tctx, error, "Opening HKEY_CURRENT_USER failed"); + error = r1_ctx->ops->create_key(r1_ctx, key, "Network", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Opening HKCU\\Network failed"); + error = r1_ctx->ops->create_key(r1_ctx, newkey, "L", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Opening HKCU\\Network\\L failed"); + + error = r2_ctx->ops->get_predefined_key(r2_ctx, HKEY_LOCAL_MACHINE, &key); + torture_assert_werr_ok(tctx, error, "Opening HKEY_LOCAL_MACHINE failed"); + error = r2_ctx->ops->create_key(r2_ctx, key, "Software", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Creating HKLM\\Sofware failed"); + error = r2_ctx->ops->create_key(r2_ctx, newkey, "Microsoft", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Creating HKLM\\Software\\Microsoft failed"); + error = r2_ctx->ops->create_key(r2_ctx, newkey, "Windows", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Creating HKLM\\Software\\Microsoft\\Windows failed"); + error = r2_ctx->ops->create_key(r2_ctx, newkey, "CurrentVersion", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Creating HKLM\\..\\Windows\\CurrentVersion failed"); + error = r2_ctx->ops->create_key(r2_ctx, newkey, "Policies", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Creating HKLM\\..\\CurrentVersion\\Policies failed"); + error = r2_ctx->ops->create_key(r2_ctx, newkey, "Explorer", NULL, NULL, &newkey); + torture_assert_werr_ok(tctx, error, "Creating HKLM\\..\\Policies\\Explorer failed"); + + + blob.data = (void *)talloc(r2_ctx, uint32_t); + SIVAL(blob.data, 0, 0x03ffffff); + blob.length = sizeof(uint32_t); + + r1_ctx->ops->set_value(newkey, "NoDrives", REG_DWORD, blob); + + /* Set test case data */ + td->r1_ctx = r1_ctx; + td->r2_ctx = r2_ctx; + + *data = td; + + return true; +} + +static bool diff_setup_preg_tcase (struct torture_context *tctx, void **data) +{ + struct diff_tcase_data *td; + struct smb_iconv_convenience *ic; + WERROR error; + + diff_setup_tcase(tctx, data); + td = *data; + + ic = lp_iconv_convenience(tctx->lp_ctx); + + td->filename = talloc_asprintf(tctx, "%s/test.pol", td->tempdir); + error = reg_preg_diff_save(tctx, td->filename, ic, &td->callbacks, &td->callback_data); + torture_assert_werr_ok(tctx, error, "reg_preg_diff_save"); + + return true; +} + +static bool diff_setup_dotreg_tcase (struct torture_context *tctx, void **data) +{ + struct diff_tcase_data *td; + struct smb_iconv_convenience *ic; + WERROR error; + + diff_setup_tcase(tctx, data); + td = *data; + + ic = lp_iconv_convenience(tctx->lp_ctx); + + td->filename = talloc_asprintf(tctx, "%s/test.reg", td->tempdir); + error = reg_dotreg_diff_save(tctx, td->filename, ic, &td->callbacks, &td->callback_data); + torture_assert_werr_ok(tctx, error, "reg_dotreg_diff_save"); + + return true; +} + +struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx) +{ + struct torture_tcase *tcase; + struct torture_suite *suite = torture_suite_create(mem_ctx, "DIFF"); + + tcase = torture_suite_add_tcase(suite, "PReg"); + torture_tcase_set_fixture(tcase, diff_setup_preg_tcase, NULL); + tcase_add_tests(tcase); + + tcase = torture_suite_add_tcase(suite, "dotreg"); + torture_tcase_set_fixture(tcase, diff_setup_dotreg_tcase, NULL); + tcase_add_tests(tcase); + + return suite; +} diff --git a/source4/lib/registry/tests/generic.c b/source4/lib/registry/tests/generic.c new file mode 100644 index 0000000000..6eae26bc46 --- /dev/null +++ b/source4/lib/registry/tests/generic.c @@ -0,0 +1,138 @@ +/* + Unix SMB/CIFS implementation. + + local testing of registry library + + Copyright (C) Jelmer Vernooij 2005-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "torture/torture.h" +#include "librpc/gen_ndr/winreg.h" +#include "param/param.h" + +struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx); +struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx); +struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx); + +static bool test_str_regtype(struct torture_context *ctx) +{ + torture_assert_str_equal(ctx, str_regtype(1), + "REG_SZ", "REG_SZ failed"); + torture_assert_str_equal(ctx, str_regtype(4), + "REG_DWORD", "REG_DWORD failed"); + + return true; +} + + +static bool test_reg_val_data_string_dword(struct torture_context *ctx) +{ + uint32_t d = 0x20; + DATA_BLOB db = { (uint8_t *)&d, sizeof(d) }; + torture_assert_str_equal(ctx, "0x20", + reg_val_data_string(ctx, lp_iconv_convenience(ctx->lp_ctx), REG_DWORD, db), + "dword failed"); + return true; +} + +static bool test_reg_val_data_string_sz(struct torture_context *ctx) +{ + DATA_BLOB db; + db.length = convert_string_talloc(ctx, lp_iconv_convenience(ctx->lp_ctx), CH_UNIX, CH_UTF16, + "bla", 3, (void **)&db.data); + torture_assert_str_equal(ctx, "bla", + reg_val_data_string(ctx, lp_iconv_convenience(ctx->lp_ctx), REG_SZ, db), + "sz failed"); + db.length = 4; + torture_assert_str_equal(ctx, "bl", + reg_val_data_string(ctx, lp_iconv_convenience(ctx->lp_ctx), REG_SZ, db), + "sz failed"); + return true; +} + +static bool test_reg_val_data_string_binary(struct torture_context *ctx) +{ + uint8_t x[] = { 0x1, 0x2, 0x3, 0x4 }; + DATA_BLOB db = { x, 4 }; + torture_assert_str_equal(ctx, "01020304", + reg_val_data_string(ctx, lp_iconv_convenience(ctx->lp_ctx), REG_BINARY, db), + "binary failed"); + return true; +} + + +static bool test_reg_val_data_string_empty(struct torture_context *ctx) +{ + DATA_BLOB db = { NULL, 0 }; + torture_assert_str_equal(ctx, "", + reg_val_data_string(ctx, lp_iconv_convenience(ctx->lp_ctx), REG_BINARY, db), + "empty failed"); + return true; +} + +static bool test_reg_val_description(struct torture_context *ctx) +{ + DATA_BLOB data; + data.length = convert_string_talloc(ctx, lp_iconv_convenience(ctx->lp_ctx), CH_UNIX, CH_UTF16, + "stationary traveller", + strlen("stationary traveller"), + (void **)&data.data); + torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller", + reg_val_description(ctx, lp_iconv_convenience(ctx->lp_ctx), "camel", REG_SZ, data), + "reg_val_description failed"); + return true; +} + + +static bool test_reg_val_description_nullname(struct torture_context *ctx) +{ + DATA_BLOB data; + data.length = convert_string_talloc(ctx, lp_iconv_convenience(ctx->lp_ctx), CH_UNIX, CH_UTF16, + "west berlin", + strlen("west berlin"), + (void **)&data.data); + torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin", + reg_val_description(ctx, lp_iconv_convenience(ctx->lp_ctx), NULL, REG_SZ, data), + "description with null name failed"); + return true; +} + +struct torture_suite *torture_registry(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "REGISTRY"); + torture_suite_add_simple_test(suite, "str_regtype", + test_str_regtype); + torture_suite_add_simple_test(suite, "reg_val_data_string dword", + test_reg_val_data_string_dword); + torture_suite_add_simple_test(suite, "reg_val_data_string sz", + test_reg_val_data_string_sz); + torture_suite_add_simple_test(suite, "reg_val_data_string binary", + test_reg_val_data_string_binary); + torture_suite_add_simple_test(suite, "reg_val_data_string empty", + test_reg_val_data_string_empty); + torture_suite_add_simple_test(suite, "reg_val_description", + test_reg_val_description); + torture_suite_add_simple_test(suite, "reg_val_description null", + test_reg_val_description_nullname); + + torture_suite_add_suite(suite, torture_registry_hive(suite)); + torture_suite_add_suite(suite, torture_registry_registry(suite)); + torture_suite_add_suite(suite, torture_registry_diff(suite)); + + return suite; +} diff --git a/source4/lib/registry/tests/hive.c b/source4/lib/registry/tests/hive.c new file mode 100644 index 0000000000..edc97c2468 --- /dev/null +++ b/source4/lib/registry/tests/hive.c @@ -0,0 +1,493 @@ +/* + Unix SMB/CIFS implementation. + + local testing of registry library - hives + + Copyright (C) Jelmer Vernooij 2005-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "torture/torture.h" +#include "librpc/gen_ndr/winreg.h" +#include "system/filesys.h" +#include "param/param.h" +#include "libcli/security/security.h" + +static bool test_del_nonexistant_key(struct torture_context *tctx, + const void *test_data) +{ + const struct hive_key *root = (const struct hive_key *)test_data; + WERROR error = hive_key_del(root, "bla"); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "invalid return code"); + + return true; +} + +static bool test_keyinfo_root(struct torture_context *tctx, + const void *test_data) +{ + uint32_t num_subkeys, num_values; + const struct hive_key *root = (const struct hive_key *)test_data; + WERROR error; + + /* This is a new backend. There should be no subkeys and no + * values */ + error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values, + NULL, NULL, NULL, NULL); + torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()"); + + torture_assert_int_equal(tctx, num_subkeys, 0, + "New key has non-zero subkey count"); + + torture_assert_werr_ok(tctx, error, "reg_key_num_values"); + + torture_assert_int_equal(tctx, num_values, 0, + "New key has non-zero value count"); + + return true; +} + +static bool test_keyinfo_nums(struct torture_context *tctx, void *test_data) +{ + uint32_t num_subkeys, num_values; + struct hive_key *root = (struct hive_key *)test_data; + WERROR error; + struct hive_key *subkey; + char data[4]; + SIVAL(data, 0, 42); + + error = hive_key_add_name(tctx, root, "Nested Keyll", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_key_set_value(root, "Answer", REG_DWORD, + data_blob_talloc(tctx, data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + /* This is a new backend. There should be no subkeys and no + * values */ + error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values, + NULL, NULL, NULL, NULL); + torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()"); + + torture_assert_int_equal(tctx, num_subkeys, 1, "subkey count"); + + torture_assert_werr_ok(tctx, error, "reg_key_num_values"); + + torture_assert_int_equal(tctx, num_values, 1, "value count"); + + return true; +} + +static bool test_add_subkey(struct torture_context *tctx, + const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + + error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_key_del(root, "Nested Key"); + torture_assert_werr_ok(tctx, error, "reg_key_del"); + + return true; +} + +static bool test_del_recursive(struct torture_context *tctx, + const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + struct hive_key *subkey2; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + char data[4]; + SIVAL(data, 0, 42); + + /* Create a new key under the root */ + error = hive_key_add_name(mem_ctx, root, "Parent Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + /* Create a new key under "Parent Key" */ + error = hive_key_add_name(mem_ctx, subkey, "Child Key", NULL, + NULL, &subkey2); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + /* Create a new value under "Child Key" */ + error = hive_key_set_value(subkey2, "Answer Recursive", REG_DWORD, + data_blob_talloc(mem_ctx, data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + /* Deleting "Parent Key" will also delete "Child Key" and the value. */ + error = hive_key_del(root, "Parent Key"); + torture_assert_werr_ok(tctx, error, "hive_key_del"); + + return true; +} + +static bool test_flush_key(struct torture_context *tctx, void *test_data) +{ + struct hive_key *root = (struct hive_key *)test_data; + + torture_assert_werr_ok(tctx, hive_key_flush(root), "flush key"); + + return true; +} + +static bool test_del_key(struct torture_context *tctx, const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + + error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_key_del(root, "Nested Key"); + torture_assert_werr_ok(tctx, error, "reg_key_del"); + + error = hive_key_del(root, "Nested Key"); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, "reg_key_del"); + + return true; +} + +static bool test_set_value(struct torture_context *tctx, + const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + char data[4]; + SIVAL(data, 0, 42); + + error = hive_key_add_name(mem_ctx, root, "YA Nested Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_key_set_value(subkey, "Answer", REG_DWORD, + data_blob_talloc(mem_ctx, data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + return true; +} + +static bool test_get_value(struct torture_context *tctx, const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + char data[4]; + uint32_t type; + DATA_BLOB value; + + SIVAL(data, 0, 42); + + error = hive_key_add_name(mem_ctx, root, "EYA Nested Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "getting missing value"); + + error = hive_key_set_value(subkey, "Answer", REG_DWORD, + data_blob_talloc(mem_ctx, data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value); + torture_assert_werr_ok(tctx, error, "getting value"); + + torture_assert_int_equal(tctx, value.length, 4, "value length"); + torture_assert_int_equal(tctx, type, REG_DWORD, "value type"); + + torture_assert_mem_equal(tctx, &data, value.data, sizeof(uint32_t), + "value data"); + + return true; +} + +static bool test_del_value(struct torture_context *tctx, const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + char data[4]; + uint32_t type; + DATA_BLOB value; + + SIVAL(data, 0, 42); + + error = hive_key_add_name(mem_ctx, root, "EEYA Nested Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_key_set_value(subkey, "Answer", REG_DWORD, + data_blob_talloc(mem_ctx, data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + error = hive_key_del_value(subkey, "Answer"); + torture_assert_werr_ok(tctx, error, "deleting value"); + + error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, "getting value"); + + error = hive_key_del_value(subkey, "Answer"); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "deleting value"); + + return true; +} + +static bool test_list_values(struct torture_context *tctx, + const void *test_data) +{ + WERROR error; + struct hive_key *subkey; + const struct hive_key *root = (const struct hive_key *)test_data; + TALLOC_CTX *mem_ctx = tctx; + char data[4]; + uint32_t type; + DATA_BLOB value; + const char *name; + int data_val = 42; + SIVAL(data, 0, data_val); + + error = hive_key_add_name(mem_ctx, root, "AYAYA Nested Key", NULL, + NULL, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_key_set_value(subkey, "Answer", REG_DWORD, + data_blob_talloc(mem_ctx, data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "hive_key_set_value"); + + error = hive_get_value_by_index(mem_ctx, subkey, 0, &name, + &type, &value); + torture_assert_werr_ok(tctx, error, "getting value"); + + torture_assert_str_equal(tctx, name, "Answer", "value name"); + + torture_assert_int_equal(tctx, value.length, 4, "value length"); + torture_assert_int_equal(tctx, type, REG_DWORD, "value type"); + + + torture_assert_int_equal(tctx, data_val, IVAL(value.data, 0), "value data"); + + error = hive_get_value_by_index(mem_ctx, subkey, 1, &name, + &type, &value); + torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, + "getting missing value"); + + return true; +} + +static bool test_hive_security(struct torture_context *tctx, const void *_data) +{ + struct hive_key *subkey = NULL; + const struct hive_key *root = _data; + WERROR error; + struct security_descriptor *osd, *nsd; + + osd = security_descriptor_dacl_create(tctx, + 0, + NULL, NULL, + SID_NT_AUTHENTICATED_USERS, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_GENERIC_ALL, + SEC_ACE_FLAG_OBJECT_INHERIT, + NULL); + + + error = hive_key_add_name(tctx, root, "SecurityKey", NULL, + osd, &subkey); + torture_assert_werr_ok(tctx, error, "hive_key_add_name"); + + error = hive_get_sec_desc(tctx, subkey, &nsd); + torture_assert_werr_ok (tctx, error, "getting security descriptor"); + + torture_assert(tctx, security_descriptor_equal(osd, nsd), + "security descriptor changed!"); + + /* Create a fresh security descriptor */ + talloc_free(osd); + osd = security_descriptor_dacl_create(tctx, + 0, + NULL, NULL, + SID_NT_AUTHENTICATED_USERS, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_GENERIC_ALL, + SEC_ACE_FLAG_OBJECT_INHERIT, + NULL); + + error = hive_set_sec_desc(subkey, osd); + torture_assert_werr_ok(tctx, error, "setting security descriptor"); + + error = hive_get_sec_desc(tctx, subkey, &nsd); + torture_assert_werr_ok (tctx, error, "getting security descriptor"); + + torture_assert(tctx, security_descriptor_equal(osd, nsd), + "security descriptor changed!"); + + return true; +} + +static void tcase_add_tests(struct torture_tcase *tcase) +{ + torture_tcase_add_simple_test_const(tcase, "del_nonexistant_key", + test_del_nonexistant_key); + torture_tcase_add_simple_test_const(tcase, "add_subkey", + test_add_subkey); + torture_tcase_add_simple_test(tcase, "flush_key", + test_flush_key); + /* test_del_recursive() test must run before test_keyinfo_root(). + test_keyinfo_root() checks the number of subkeys, which verifies + the recursive delete worked properly. */ + torture_tcase_add_simple_test_const(tcase, "del_recursive", + test_del_recursive); + torture_tcase_add_simple_test_const(tcase, "get_info", + test_keyinfo_root); + torture_tcase_add_simple_test(tcase, "get_info_nums", + test_keyinfo_nums); + torture_tcase_add_simple_test_const(tcase, "set_value", + test_set_value); + torture_tcase_add_simple_test_const(tcase, "get_value", + test_get_value); + torture_tcase_add_simple_test_const(tcase, "list_values", + test_list_values); + torture_tcase_add_simple_test_const(tcase, "del_key", + test_del_key); + torture_tcase_add_simple_test_const(tcase, "del_value", + test_del_value); + torture_tcase_add_simple_test_const(tcase, "check hive security", + test_hive_security); +} + +static bool hive_setup_dir(struct torture_context *tctx, void **data) +{ + struct hive_key *key; + WERROR error; + char *dirname; + NTSTATUS status; + + status = torture_temp_dir(tctx, "hive-dir", &dirname); + if (!NT_STATUS_IS_OK(status)) + return false; + + rmdir(dirname); + + error = reg_create_directory(tctx, dirname, &key); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to initialize dir hive\n"); + return false; + } + + *data = key; + + return true; +} + +static bool hive_setup_ldb(struct torture_context *tctx, void **data) +{ + struct hive_key *key; + WERROR error; + char *dirname; + NTSTATUS status; + + status = torture_temp_dir(tctx, "hive-ldb", &dirname); + if (!NT_STATUS_IS_OK(status)) + return false; + + rmdir(dirname); + + error = reg_open_ldb_file(tctx, dirname, NULL, NULL, tctx->ev, tctx->lp_ctx, &key); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to initialize ldb hive\n"); + return false; + } + + *data = key; + + return true; +} + +static bool hive_setup_regf(struct torture_context *tctx, void **data) +{ + struct hive_key *key; + WERROR error; + char *dirname; + NTSTATUS status; + + status = torture_temp_dir(tctx, "hive-regf", &dirname); + if (!NT_STATUS_IS_OK(status)) + return false; + + rmdir(dirname); + + error = reg_create_regf_file(tctx, lp_iconv_convenience(tctx->lp_ctx), + dirname, 5, &key); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to create new regf file\n"); + return false; + } + + *data = key; + + return true; +} + +static bool test_dir_refuses_null_location(struct torture_context *tctx) +{ + torture_assert_werr_equal(tctx, WERR_INVALID_PARAM, + reg_open_directory(NULL, NULL, NULL), + "reg_open_directory accepts NULL location"); + return true; +} + +struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx) +{ + struct torture_tcase *tcase; + struct torture_suite *suite = torture_suite_create(mem_ctx, "HIVE"); + + torture_suite_add_simple_test(suite, "dir-refuses-null-location", + test_dir_refuses_null_location); + + tcase = torture_suite_add_tcase(suite, "dir"); + torture_tcase_set_fixture(tcase, hive_setup_dir, NULL); + tcase_add_tests(tcase); + + tcase = torture_suite_add_tcase(suite, "ldb"); + torture_tcase_set_fixture(tcase, hive_setup_ldb, NULL); + tcase_add_tests(tcase); + + tcase = torture_suite_add_tcase(suite, "regf"); + torture_tcase_set_fixture(tcase, hive_setup_regf, NULL); + tcase_add_tests(tcase); + + return suite; +} diff --git a/source4/lib/registry/tests/registry.c b/source4/lib/registry/tests/registry.c new file mode 100644 index 0000000000..7274bf009d --- /dev/null +++ b/source4/lib/registry/tests/registry.c @@ -0,0 +1,594 @@ +/* + Unix SMB/CIFS implementation. + + local testing of registry library - registry backend + + Copyright (C) Jelmer Vernooij 2005-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "torture/torture.h" +#include "librpc/gen_ndr/winreg.h" +#include "libcli/security/security.h" +#include "system/filesys.h" + +/** + * Test obtaining a predefined key. + */ +static bool test_get_predefined(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root; + WERROR error; + + error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + return true; +} + +/** + * Test obtaining a predefined key. + */ +static bool test_get_predefined_unknown(struct torture_context *tctx, + void *_data) +{ + struct registry_context *rctx = _data; + struct registry_key *root; + WERROR error; + + error = reg_get_predefined_key(rctx, 1337, &root); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "getting predefined key failed"); + return true; +} + +static bool test_predef_key_by_name(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root; + WERROR error; + + error = reg_get_predefined_key_by_name(rctx, "HKEY_CLASSES_ROOT", + &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + + error = reg_get_predefined_key_by_name(rctx, "HKEY_classes_ROOT", + &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key case insensitively failed"); + + return true; +} + +static bool test_predef_key_by_name_invalid(struct torture_context *tctx, + void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root; + WERROR error; + + error = reg_get_predefined_key_by_name(rctx, "BLA", &root); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "getting predefined key failed"); + return true; +} + +/** + * Test creating a new subkey + */ +static bool test_create_subkey(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *newkey; + WERROR error; + + error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + + error = reg_key_add_name(rctx, root, "Bad Bentheim", NULL, NULL, + &newkey); + torture_assert_werr_ok(tctx, error, "Creating key return code"); + torture_assert(tctx, newkey != NULL, "Creating new key"); + + return true; +} + +/** + * Test creating a new nested subkey + */ +static bool test_create_nested_subkey(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *newkey1, *newkey2; + WERROR error; + + error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + + error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL, + &newkey1); + torture_assert_werr_ok(tctx, error, "Creating key return code"); + torture_assert(tctx, newkey1 != NULL, "Creating new key"); + + error = reg_key_add_name(rctx, root, "Hamburg\\Hamburg", NULL, NULL, + &newkey2); + torture_assert_werr_ok(tctx, error, "Creating key return code"); + torture_assert(tctx, newkey2 != NULL, "Creating new key"); + + return true; +} + +/** + * Test creating a new subkey + */ +static bool test_key_add_abs_top(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root; + WERROR error; + + error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT", 0, NULL, + &root); + torture_assert_werr_equal(tctx, error, WERR_ALREADY_EXISTS, + "create top level"); + + return true; +} + +/** + * Test creating a new subkey + */ +static bool test_key_add_abs(struct torture_context *tctx, void *_data) +{ + WERROR error; + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *result1, *result2; + + error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT\\bloe", 0, NULL, + &result1); + torture_assert_werr_ok(tctx, error, "create lowest"); + + error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT\\bloe\\bla", 0, + NULL, &result1); + torture_assert_werr_ok(tctx, error, "create nested"); + + error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + + error = reg_open_key(tctx, root, "bloe", &result2); + torture_assert_werr_ok(tctx, error, "opening key"); + + error = reg_open_key(tctx, root, "bloe\\bla", &result2); + torture_assert_werr_ok(tctx, error, "opening key"); + + return true; +} + + +static bool test_del_key(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *newkey; + WERROR error; + + error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + + error = reg_key_add_name(rctx, root, "Polen", NULL, NULL, &newkey); + + torture_assert_werr_ok(tctx, error, "Creating key return code"); + torture_assert(tctx, newkey != NULL, "Creating new key"); + + error = reg_key_del(root, "Polen"); + torture_assert_werr_ok(tctx, error, "Delete key"); + + error = reg_key_del(root, "Polen"); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "Delete missing key"); + + return true; +} + +/** + * Convenience function for opening the HKEY_CLASSES_ROOT hive and + * creating a single key for testing purposes. + */ +static bool create_test_key(struct torture_context *tctx, + struct registry_context *rctx, + const char *name, + struct registry_key **root, + struct registry_key **subkey) +{ + WERROR error; + + error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, root); + torture_assert_werr_ok(tctx, error, + "getting predefined key failed"); + + error = reg_key_add_name(rctx, *root, name, NULL, NULL, subkey); + torture_assert_werr_ok(tctx, error, "Creating key return code"); + + return true; +} + + +static bool test_flush_key(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *subkey; + WERROR error; + + if (!create_test_key(tctx, rctx, "Bremen", &root, &subkey)) + return false; + + error = reg_key_flush(subkey); + torture_assert_werr_ok(tctx, error, "flush key"); + + torture_assert_werr_equal(tctx, reg_key_flush(NULL), + WERR_INVALID_PARAM, "flush key"); + + return true; +} + +static bool test_query_key(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *subkey; + WERROR error; + NTTIME last_changed_time; + uint32_t num_subkeys, num_values; + const char *classname; + + if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey)) + return false; + + error = reg_key_get_info(tctx, subkey, &classname, + &num_subkeys, &num_values, + &last_changed_time, NULL, NULL, NULL); + + torture_assert_werr_ok(tctx, error, "get info key"); + torture_assert(tctx, classname == NULL, "classname"); + torture_assert_int_equal(tctx, num_subkeys, 0, "num subkeys"); + torture_assert_int_equal(tctx, num_values, 0, "num values"); + + return true; +} + +static bool test_query_key_nums(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *root, *subkey1, *subkey2; + WERROR error; + uint32_t num_subkeys, num_values; + char data[4]; + SIVAL(data, 0, 42); + + if (!create_test_key(tctx, rctx, "Berlin", &root, &subkey1)) + return false; + + error = reg_key_add_name(rctx, subkey1, "Bentheim", NULL, NULL, + &subkey2); + torture_assert_werr_ok(tctx, error, "Creating key return code"); + + error = reg_val_set(subkey1, "Answer", REG_DWORD, + data_blob_talloc(tctx, &data, sizeof(data))); + torture_assert_werr_ok(tctx, error, "set value"); + + error = reg_key_get_info(tctx, subkey1, NULL, &num_subkeys, + &num_values, NULL, NULL, NULL, NULL); + + torture_assert_werr_ok(tctx, error, "get info key"); + torture_assert_int_equal(tctx, num_subkeys, 1, "num subkeys"); + torture_assert_int_equal(tctx, num_values, 1, "num values"); + + return true; +} + +/** + * Test that the subkeys of a key can be enumerated, that + * the returned parameters for get_subkey_by_index are optional and + * that enumerating the parents of a non-top-level node works. + */ +static bool test_list_subkeys(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *subkey = NULL, *root; + WERROR error; + NTTIME last_mod_time; + const char *classname, *name; + + if (!create_test_key(tctx, rctx, "Goettingen", &root, &subkey)) + return false; + + error = reg_key_get_subkey_by_index(tctx, root, 0, &name, &classname, + &last_mod_time); + + torture_assert_werr_ok(tctx, error, "Enum keys return code"); + torture_assert_str_equal(tctx, name, "Goettingen", "Enum keys data"); + + + error = reg_key_get_subkey_by_index(tctx, root, 0, NULL, NULL, NULL); + + torture_assert_werr_ok(tctx, error, + "Enum keys with NULL arguments return code"); + + error = reg_key_get_subkey_by_index(tctx, root, 1, NULL, NULL, NULL); + + torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, + "Invalid error for no more items"); + + error = reg_key_get_subkey_by_index(tctx, subkey, 0, NULL, NULL, NULL); + + torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, + "Invalid error for no more items"); + + return true; +} + +/** + * Test setting a value + */ +static bool test_set_value(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *subkey = NULL, *root; + WERROR error; + char data[4]; + + SIVAL(data, 0, 42); + + if (!create_test_key(tctx, rctx, "Dusseldorf", &root, &subkey)) + return false; + + error = reg_val_set(subkey, "Answer", REG_DWORD, + data_blob_talloc(tctx, data, sizeof(data))); + torture_assert_werr_ok (tctx, error, "setting value"); + + return true; +} + +/** + * Test getting/setting security descriptors + */ +static bool test_security(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *subkey = NULL, *root; + WERROR error; + struct security_descriptor *osd, *nsd; + + if (!create_test_key(tctx, rctx, "Düsseldorf", &root, &subkey)) + return false; + + osd = security_descriptor_dacl_create(tctx, + 0, + NULL, NULL, + SID_NT_AUTHENTICATED_USERS, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_GENERIC_ALL, + SEC_ACE_FLAG_OBJECT_INHERIT, + NULL); + + error = reg_set_sec_desc(subkey, osd); + torture_assert_werr_ok(tctx, error, "setting security descriptor"); + + error = reg_get_sec_desc(tctx, subkey, &nsd); + torture_assert_werr_ok (tctx, error, "getting security descriptor"); + + torture_assert(tctx, security_descriptor_equal(osd, nsd), + "security descriptor changed!"); + + return true; +} + +/** + * Test getting a value + */ +static bool test_get_value(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *subkey = NULL, *root; + WERROR error; + DATA_BLOB data; + char value[4]; + uint32_t type; + SIVAL(value, 0, 42); + + if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey)) + return false; + + error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, + &data); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "getting missing value"); + + error = reg_val_set(subkey, __FUNCTION__, REG_DWORD, + data_blob_talloc(tctx, value, sizeof(value))); + torture_assert_werr_ok(tctx, error, "setting value"); + + error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, + &data); + torture_assert_werr_ok(tctx, error, "getting value"); + + torture_assert_int_equal(tctx, sizeof(value), data.length, "value length ok"); + torture_assert_mem_equal(tctx, data.data, value, sizeof(value), + "value content ok"); + torture_assert_int_equal(tctx, REG_DWORD, type, "value type"); + + return true; +} + +/** + * Test unsetting a value + */ +static bool test_del_value(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx =(struct registry_context *)_data; + struct registry_key *subkey = NULL, *root; + WERROR error; + DATA_BLOB data; + uint32_t type; + char value[4]; + SIVAL(value, 0, 42); + + if (!create_test_key(tctx, rctx, "Warschau", &root, &subkey)) + return false; + + error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, + &data); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "getting missing value"); + + error = reg_val_set(subkey, __FUNCTION__, REG_DWORD, + data_blob_talloc(tctx, value, sizeof(value))); + torture_assert_werr_ok (tctx, error, "setting value"); + + error = reg_del_value(subkey, __FUNCTION__); + torture_assert_werr_ok (tctx, error, "unsetting value"); + + error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, + &type, &data); + torture_assert_werr_equal(tctx, error, WERR_BADFILE, + "getting missing value"); + + return true; +} + +/** + * Test listing values + */ +static bool test_list_values(struct torture_context *tctx, void *_data) +{ + struct registry_context *rctx = (struct registry_context *)_data; + struct registry_key *subkey = NULL, *root; + WERROR error; + DATA_BLOB data; + uint32_t type; + const char *name; + char value[4]; + SIVAL(value, 0, 42); + + if (!create_test_key(tctx, rctx, "Bonn", &root, &subkey)) + return false; + + error = reg_val_set(subkey, "bar", REG_DWORD, + data_blob_talloc(tctx, value, sizeof(value))); + torture_assert_werr_ok (tctx, error, "setting value"); + + error = reg_key_get_value_by_index(tctx, subkey, 0, &name, + &type, &data); + torture_assert_werr_ok(tctx, error, "getting value"); + + torture_assert_str_equal(tctx, name, "bar", "value name"); + torture_assert_int_equal(tctx, sizeof(value), data.length, "value length"); + torture_assert_mem_equal(tctx, data.data, value, sizeof(value), + "value content"); + torture_assert_int_equal(tctx, REG_DWORD, type, "value type"); + + error = reg_key_get_value_by_index(tctx, subkey, 1, &name, + &type, &data); + torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, + "getting missing value"); + + return true; +} + +static bool setup_local_registry(struct torture_context *tctx, void **data) +{ + struct registry_context *rctx; + WERROR error; + char *tempdir; + NTSTATUS status; + struct hive_key *hive_key; + const char *filename; + + error = reg_open_local(tctx, &rctx); + torture_assert_werr_ok(tctx, error, "Opening local registry failed"); + + status = torture_temp_dir(tctx, "registry-local", &tempdir); + torture_assert_ntstatus_ok(tctx, status, "Creating temp dir failed"); + + filename = talloc_asprintf(tctx, "%s/classes_root.ldb", tempdir); + error = reg_open_ldb_file(tctx, filename, NULL, NULL, tctx->ev, tctx->lp_ctx, &hive_key); + torture_assert_werr_ok(tctx, error, "Opening classes_root file failed"); + + error = reg_mount_hive(rctx, hive_key, HKEY_CLASSES_ROOT, NULL); + torture_assert_werr_ok(tctx, error, "Mounting hive failed"); + + *data = rctx; + + return true; +} + +static void tcase_add_tests(struct torture_tcase *tcase) +{ + torture_tcase_add_simple_test(tcase, "list_subkeys", + test_list_subkeys); + torture_tcase_add_simple_test(tcase, "get_predefined_key", + test_get_predefined); + torture_tcase_add_simple_test(tcase, "get_predefined_key", + test_get_predefined_unknown); + torture_tcase_add_simple_test(tcase, "create_key", + test_create_subkey); + torture_tcase_add_simple_test(tcase, "create_key", + test_create_nested_subkey); + torture_tcase_add_simple_test(tcase, "key_add_abs", + test_key_add_abs); + torture_tcase_add_simple_test(tcase, "key_add_abs_top", + test_key_add_abs_top); + torture_tcase_add_simple_test(tcase, "set_value", + test_set_value); + torture_tcase_add_simple_test(tcase, "get_value", + test_get_value); + torture_tcase_add_simple_test(tcase, "list_values", + test_list_values); + torture_tcase_add_simple_test(tcase, "del_key", + test_del_key); + torture_tcase_add_simple_test(tcase, "del_value", + test_del_value); + torture_tcase_add_simple_test(tcase, "flush_key", + test_flush_key); + torture_tcase_add_simple_test(tcase, "query_key", + test_query_key); + torture_tcase_add_simple_test(tcase, "query_key_nums", + test_query_key_nums); + torture_tcase_add_simple_test(tcase, "test_predef_key_by_name", + test_predef_key_by_name); + torture_tcase_add_simple_test(tcase, "security", + test_security); + torture_tcase_add_simple_test(tcase,"test_predef_key_by_name_invalid", + test_predef_key_by_name_invalid); +} + +struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx) +{ + struct torture_tcase *tcase; + struct torture_suite *suite = torture_suite_create(mem_ctx, "REGISTRY"); + + tcase = torture_suite_add_tcase(suite, "local"); + torture_tcase_set_fixture(tcase, setup_local_registry, NULL); + tcase_add_tests(tcase); + + return suite; +} diff --git a/source4/lib/registry/tools/common.c b/source4/lib/registry/tools/common.c new file mode 100644 index 0000000000..f770f6a3ca --- /dev/null +++ b/source4/lib/registry/tools/common.c @@ -0,0 +1,88 @@ +/* + Unix SMB/CIFS implementation. + Popt routines specifically for registry + + Copyright (C) Jelmer Vernooij 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "auth/credentials/credentials.h" +#include "lib/registry/registry.h" +#include "lib/registry/tools/common.h" + +struct registry_context *reg_common_open_remote(const char *remote, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct cli_credentials *creds) +{ + struct registry_context *h = NULL; + WERROR error; + + error = reg_open_remote(&h, NULL, creds, lp_ctx, remote, ev_ctx); + + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to open remote registry at %s:%s \n", + remote, win_errstr(error)); + return NULL; + } + + return h; +} + +struct registry_key *reg_common_open_file(const char *path, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct cli_credentials *creds) +{ + struct hive_key *hive_root; + struct registry_context *h = NULL; + WERROR error; + + error = reg_open_hive(NULL, path, NULL, creds, ev_ctx, lp_ctx, &hive_root); + + if(!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to open '%s': %s \n", + path, win_errstr(error)); + return NULL; + } + + error = reg_open_local(NULL, &h); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to initialize local registry: %s\n", + win_errstr(error)); + return NULL; + } + + return reg_import_hive_key(h, hive_root, -1, NULL); +} + +struct registry_context *reg_common_open_local(struct cli_credentials *creds, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx) +{ + WERROR error; + struct registry_context *h = NULL; + + error = reg_open_samba(NULL, &h, ev_ctx, lp_ctx, NULL, creds); + + if(!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to open local registry:%s \n", + win_errstr(error)); + return NULL; + } + + return h; +} diff --git a/source4/lib/registry/tools/regdiff.c b/source4/lib/registry/tools/regdiff.c new file mode 100644 index 0000000000..240c582340 --- /dev/null +++ b/source4/lib/registry/tools/regdiff.c @@ -0,0 +1,149 @@ +/* + Unix SMB/CIFS implementation. + simple registry frontend + + Copyright (C) Jelmer Vernooij 2004-2007 + Copyright (C) Wilco Baan Hofman 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "lib/events/events.h" +#include "lib/cmdline/popt_common.h" +#include "lib/registry/tools/common.h" +#include "param/param.h" + +enum reg_backend { REG_UNKNOWN, REG_LOCAL, REG_REMOTE, REG_NULL }; + +static struct registry_context *open_backend(poptContext pc, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + enum reg_backend backend, + const char *remote_host) +{ + WERROR error; + struct registry_context *ctx; + + switch (backend) { + case REG_UNKNOWN: + poptPrintUsage(pc, stderr, 0); + return NULL; + case REG_LOCAL: + error = reg_open_samba(NULL, &ctx, ev_ctx, lp_ctx, NULL, cmdline_credentials); + break; + case REG_REMOTE: + error = reg_open_remote(&ctx, NULL, cmdline_credentials, lp_ctx, + remote_host, NULL); + break; + case REG_NULL: + error = reg_open_local(NULL, &ctx); + break; + } + + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error: %s\n", win_errstr(error)); + return NULL; + } + + return ctx; +} + +int main(int argc, const char **argv) +{ + int opt; + poptContext pc; + char *outputfile = NULL; + enum reg_backend backend1 = REG_UNKNOWN, backend2 = REG_UNKNOWN; + const char *remote1 = NULL, *remote2 = NULL; + struct registry_context *h1 = NULL, *h2 = NULL; + WERROR error; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"output", 'o', POPT_ARG_STRING, &outputfile, 0, "output file to use", NULL }, + {"null", 'n', POPT_ARG_NONE, NULL, 'n', "Diff from NULL", NULL }, + {"remote", 'R', POPT_ARG_STRING, NULL, 'R', "Connect to remote server" , NULL }, + {"local", 'L', POPT_ARG_NONE, NULL, 'L', "Open local registry", NULL }, + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + { NULL } + }; + TALLOC_CTX *ctx; + void *callback_data; + struct event_context *ev_ctx; + struct reg_diff_callbacks *callbacks; + + ctx = talloc_init("regdiff"); + + pc = poptGetContext(argv[0], argc, argv, long_options,0); + + while((opt = poptGetNextOpt(pc)) != -1) { + error = WERR_OK; + switch(opt) { + case 'L': + if (backend1 == REG_UNKNOWN) + backend1 = REG_LOCAL; + else if (backend2 == REG_UNKNOWN) + backend2 = REG_LOCAL; + break; + case 'n': + if (backend1 == REG_UNKNOWN) + backend1 = REG_NULL; + else if (backend2 == REG_UNKNOWN) + backend2 = REG_NULL; + break; + case 'R': + if (backend1 == REG_UNKNOWN) { + backend1 = REG_REMOTE; + remote1 = poptGetOptArg(pc); + } else if (backend2 == REG_UNKNOWN) { + backend2 = REG_REMOTE; + remote2 = poptGetOptArg(pc); + } + break; + } + + } + + ev_ctx = s4_event_context_init(NULL); + + h1 = open_backend(pc, ev_ctx, cmdline_lp_ctx, backend1, remote1); + if (h1 == NULL) + return 1; + + h2 = open_backend(pc, ev_ctx, cmdline_lp_ctx, backend2, remote2); + if (h2 == NULL) + return 1; + + poptFreeContext(pc); + + error = reg_dotreg_diff_save(ctx, outputfile, lp_iconv_convenience(cmdline_lp_ctx), &callbacks, + &callback_data); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Problem saving registry diff to '%s': %s\n", + outputfile, win_errstr(error)); + return -1; + } + + error = reg_generate_diff(h1, h2, callbacks, callback_data); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Unable to generate diff between keys: %s\n", + win_errstr(error)); + return -1; + } + + return 0; +} diff --git a/source4/lib/registry/tools/regpatch.c b/source4/lib/registry/tools/regpatch.c new file mode 100644 index 0000000000..add59a5e64 --- /dev/null +++ b/source4/lib/registry/tools/regpatch.c @@ -0,0 +1,74 @@ +/* + Unix SMB/CIFS implementation. + simple registry frontend + + Copyright (C) 2004-2007 Jelmer Vernooij, jelmer@samba.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "lib/registry/registry.h" +#include "lib/cmdline/popt_common.h" +#include "lib/registry/tools/common.h" +#include "param/param.h" +#include "events/events.h" + +int main(int argc, char **argv) +{ + int opt; + poptContext pc; + const char *patch; + struct registry_context *h; + const char *file = NULL; + const char *remote = NULL; + struct event_context *ev_ctx; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL}, + {"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL }, + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + { NULL } + }; + + pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0); + + while((opt = poptGetNextOpt(pc)) != -1) { + } + + ev_ctx = s4_event_context_init(NULL); + + if (remote) { + h = reg_common_open_remote (remote, ev_ctx, cmdline_lp_ctx, cmdline_credentials); + } else { + h = reg_common_open_local (cmdline_credentials, ev_ctx, cmdline_lp_ctx); + } + + if (h == NULL) + return 1; + + patch = poptGetArg(pc); + if (patch == NULL) { + poptPrintUsage(pc, stderr, 0); + return 1; + } + + poptFreeContext(pc); + + reg_diff_apply(h, patch); + + return 0; +} diff --git a/source4/lib/registry/tools/regshell.c b/source4/lib/registry/tools/regshell.c new file mode 100644 index 0000000000..98f7f02c38 --- /dev/null +++ b/source4/lib/registry/tools/regshell.c @@ -0,0 +1,584 @@ +/* + Unix SMB/CIFS implementation. + simple registry frontend + + Copyright (C) Jelmer Vernooij 2004-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "lib/cmdline/popt_common.h" +#include "lib/events/events.h" +#include "system/time.h" +#include "lib/smbreadline/smbreadline.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "lib/registry/tools/common.h" +#include "param/param.h" + +struct regshell_context { + struct registry_context *registry; + const char *path; + struct registry_key *current; +}; + +/* * + * ck/cd - change key + * ls - list values/keys + * rmval/rm - remove value + * rmkey/rmdir - remove key + * mkkey/mkdir - make key + * ch - change hive + * info - show key info + * save - save hive + * print - print value + * help + * exit + */ + +static WERROR cmd_info(struct regshell_context *ctx, int argc, char **argv) +{ + struct security_descriptor *sec_desc = NULL; + time_t last_mod; + WERROR error; + const char *classname = NULL; + NTTIME last_change; + uint32_t max_subkeynamelen; + uint32_t max_valnamelen; + uint32_t max_valbufsize; + uint32_t num_subkeys; + uint32_t num_values; + + error = reg_key_get_info(ctx, ctx->current, &classname, &num_subkeys, &num_values, + &last_change, &max_subkeynamelen, &max_valnamelen, &max_valbufsize); + if (!W_ERROR_IS_OK(error)) { + printf("Error getting key info: %s\n", win_errstr(error)); + return error; + } + + + printf("Name: %s\n", strchr(ctx->path, '\\')?strrchr(ctx->path, '\\')+1: + ctx->path); + printf("Full path: %s\n", ctx->path); + if (classname != NULL) + printf("Key Class: %s\n", classname); + last_mod = nt_time_to_unix(last_change); + printf("Time Last Modified: %s\n", ctime(&last_mod)); + printf("Number of subkeys: %d\n", num_subkeys); + printf("Number of values: %d\n", num_values); + + if (max_valnamelen > 0) + printf("Maximum value name length: %d\n", max_valnamelen); + + if (max_valbufsize > 0) + printf("Maximum value data length: %d\n", max_valbufsize); + + if (max_subkeynamelen > 0) + printf("Maximum sub key name length: %d\n", max_subkeynamelen); + + error = reg_get_sec_desc(ctx, ctx->current, &sec_desc); + if (!W_ERROR_IS_OK(error)) { + printf("Error getting security descriptor\n"); + return error; + } + ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, + "Security", sec_desc); + talloc_free(sec_desc); + + return WERR_OK; +} + +static WERROR cmd_predef(struct regshell_context *ctx, int argc, char **argv) +{ + struct registry_key *ret = NULL; + if (argc < 2) { + fprintf(stderr, "Usage: predef predefined-key-name\n"); + } else if (!ctx) { + fprintf(stderr, "No full registry loaded, no predefined keys defined\n"); + } else { + WERROR error = reg_get_predefined_key_by_name(ctx->registry, + argv[1], &ret); + + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error opening predefined key %s: %s\n", + argv[1], win_errstr(error)); + return error; + } + + ctx->path = strupper_talloc(ctx, argv[1]); + ctx->current = ret; + } + + return WERR_OK; +} + +static WERROR cmd_pwd(struct regshell_context *ctx, + int argc, char **argv) +{ + printf("%s\n", ctx->path); + return WERR_OK; +} + +static WERROR cmd_set(struct regshell_context *ctx, int argc, char **argv) +{ + struct registry_value val; + WERROR error; + + if (argc < 4) { + fprintf(stderr, "Usage: set value-name type value\n"); + return WERR_INVALID_PARAM; + } + + if (!reg_string_to_val(ctx, lp_iconv_convenience(cmdline_lp_ctx), + argv[2], argv[3], &val.data_type, + &val.data)) { + fprintf(stderr, "Unable to interpret data\n"); + return WERR_INVALID_PARAM; + } + + error = reg_val_set(ctx->current, argv[1], val.data_type, val.data); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error setting value: %s\n", win_errstr(error)); + return error; + } + + return WERR_OK; +} + +static WERROR cmd_ck(struct regshell_context *ctx, int argc, char **argv) +{ + struct registry_key *new = NULL; + WERROR error; + + if(argc == 2) { + error = reg_open_key(ctx->registry, ctx->current, argv[1], + &new); + if(!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error opening specified key: %s\n", + win_errstr(error))); + return error; + } + + ctx->path = talloc_asprintf(ctx, "%s\\%s", ctx->path, argv[1]); + ctx->current = new; + } + printf("New path is: %s\n", ctx->path); + + return WERR_OK; +} + +static WERROR cmd_print(struct regshell_context *ctx, int argc, char **argv) +{ + uint32_t value_type; + DATA_BLOB value_data; + WERROR error; + + if (argc != 2) { + fprintf(stderr, "Usage: print <valuename>\n"); + return WERR_INVALID_PARAM; + } + + error = reg_key_get_value_by_name(ctx, ctx->current, argv[1], + &value_type, &value_data); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "No such value '%s'\n", argv[1]); + return error; + } + + printf("%s\n%s\n", str_regtype(value_type), + reg_val_data_string(ctx, lp_iconv_convenience(cmdline_lp_ctx), value_type, value_data)); + + return WERR_OK; +} + +static WERROR cmd_ls(struct regshell_context *ctx, int argc, char **argv) +{ + int i; + WERROR error; + uint32_t data_type; + DATA_BLOB data; + const char *name = NULL; + + for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(ctx, + ctx->current, + i, + &name, + NULL, + NULL)); i++) { + printf("K %s\n", name); + } + + if (!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) { + DEBUG(0, ("Error occured while browsing thru keys: %s\n", + win_errstr(error))); + } + + for (i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(ctx, + ctx->current, + i, + &name, + &data_type, + &data)); i++) { + printf("V \"%s\" %s %s\n", name, str_regtype(data_type), + reg_val_data_string(ctx, lp_iconv_convenience(cmdline_lp_ctx), data_type, data)); + } + + return WERR_OK; +} +static WERROR cmd_mkkey(struct regshell_context *ctx, int argc, char **argv) +{ + struct registry_key *tmp; + WERROR error; + + if(argc < 2) { + fprintf(stderr, "Usage: mkkey <keyname>\n"); + return WERR_INVALID_PARAM; + } + + error = reg_key_add_name(ctx, ctx->current, argv[1], 0, NULL, &tmp); + + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]); + return error; + } + + return WERR_OK; +} + +static WERROR cmd_rmkey(struct regshell_context *ctx, + int argc, char **argv) +{ + WERROR error; + + if(argc < 2) { + fprintf(stderr, "Usage: rmkey <name>\n"); + return WERR_INVALID_PARAM; + } + + error = reg_key_del(ctx->current, argv[1]); + if(!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error deleting '%s'\n", argv[1]); + return error; + } else { + fprintf(stderr, "Successfully deleted '%s'\n", argv[1]); + } + + return WERR_OK; +} + +static WERROR cmd_rmval(struct regshell_context *ctx, int argc, char **argv) +{ + WERROR error; + + if(argc < 2) { + fprintf(stderr, "Usage: rmval <valuename>\n"); + return WERR_INVALID_PARAM; + } + + error = reg_del_value(ctx->current, argv[1]); + if(!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Error deleting value '%s'\n", argv[1]); + return error; + } else { + fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]); + } + + return WERR_OK; +} + +_NORETURN_ static WERROR cmd_exit(struct regshell_context *ctx, + int argc, char **argv) +{ + exit(0); + return WERR_OK; +} + +static WERROR cmd_help(struct regshell_context *ctx, int, char **); + +static struct { + const char *name; + const char *alias; + const char *help; + WERROR (*handle)(struct regshell_context *ctx, int argc, char **argv); +} regshell_cmds[] = { + {"ck", "cd", "Change current key", cmd_ck }, + {"info", "i", "Show detailed information of a key", cmd_info }, + {"list", "ls", "List values/keys in current key", cmd_ls }, + {"print", "p", "Print value", cmd_print }, + {"mkkey", "mkdir", "Make new key", cmd_mkkey }, + {"rmval", "rm", "Remove value", cmd_rmval }, + {"rmkey", "rmdir", "Remove key", cmd_rmkey }, + {"pwd", "pwk", "Printing current key", cmd_pwd }, + {"set", "update", "Update value", cmd_set }, + {"help", "?", "Help", cmd_help }, + {"exit", "quit", "Exit", cmd_exit }, + {"predef", "predefined", "Go to predefined key", cmd_predef }, + {NULL } +}; + +static WERROR cmd_help(struct regshell_context *ctx, + int argc, char **argv) +{ + int i; + printf("Available commands:\n"); + for(i = 0; regshell_cmds[i].name; i++) { + printf("%s - %s\n", regshell_cmds[i].name, + regshell_cmds[i].help); + } + return WERR_OK; +} + +static WERROR process_cmd(struct regshell_context *ctx, + char *line) +{ + int argc; + char **argv = NULL; + int ret, i; + + if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) { + fprintf(stderr, "regshell: %s\n", poptStrerror(ret)); + return WERR_INVALID_PARAM; + } + + for(i = 0; regshell_cmds[i].name; i++) { + if(!strcmp(regshell_cmds[i].name, argv[0]) || + (regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) { + return regshell_cmds[i].handle(ctx, argc, argv); + } + } + + fprintf(stderr, "No such command '%s'\n", argv[0]); + + return WERR_INVALID_PARAM; +} + +#define MAX_COMPLETIONS 100 + +static struct registry_key *current_key = NULL; + +static char **reg_complete_command(const char *text, int start, int end) +{ + /* Complete command */ + char **matches; + int i, len, samelen=0, count=1; + + matches = malloc_array_p(char *, MAX_COMPLETIONS); + if (!matches) return NULL; + matches[0] = NULL; + + len = strlen(text); + for (i=0;regshell_cmds[i].handle && count < MAX_COMPLETIONS-1;i++) { + if (strncmp(text, regshell_cmds[i].name, len) == 0) { + matches[count] = strdup(regshell_cmds[i].name); + if (!matches[count]) + goto cleanup; + if (count == 1) + samelen = strlen(matches[count]); + else + while (strncmp(matches[count], matches[count-1], samelen) != 0) + samelen--; + count++; + } + } + + switch (count) { + case 0: /* should never happen */ + case 1: + goto cleanup; + case 2: + matches[0] = strdup(matches[1]); + break; + default: + matches[0] = strndup(matches[1], samelen); + } + matches[count] = NULL; + return matches; + +cleanup: + count--; + while (count >= 0) { + free(matches[count]); + count--; + } + free(matches); + return NULL; +} + +static char **reg_complete_key(const char *text, int start, int end) +{ + struct registry_key *base; + const char *subkeyname; + int i, j = 1; + int samelen = 0; + int len; + char **matches; + const char *base_n = ""; + TALLOC_CTX *mem_ctx; + WERROR status; + + matches = malloc_array_p(char *, MAX_COMPLETIONS); + if (!matches) return NULL; + matches[0] = NULL; + mem_ctx = talloc_init("completion"); + + base = current_key; + + len = strlen(text); + for(i = 0; j < MAX_COMPLETIONS-1; i++) { + status = reg_key_get_subkey_by_index(mem_ctx, base, i, + &subkeyname, NULL, NULL); + if(W_ERROR_IS_OK(status)) { + if(!strncmp(text, subkeyname, len)) { + matches[j] = strdup(subkeyname); + j++; + + if (j == 1) + samelen = strlen(matches[j]); + else + while (strncmp(matches[j], matches[j-1], samelen) != 0) + samelen--; + } + } else if(W_ERROR_EQUAL(status, WERR_NO_MORE_ITEMS)) { + break; + } else { + printf("Error creating completion list: %s\n", + win_errstr(status)); + talloc_free(mem_ctx); + return NULL; + } + } + + if (j == 1) { /* No matches at all */ + SAFE_FREE(matches); + talloc_free(mem_ctx); + return NULL; + } + + if (j == 2) { /* Exact match */ + asprintf(&matches[0], "%s%s", base_n, matches[1]); + } else { + asprintf(&matches[0], "%s%s", base_n, + talloc_strndup(mem_ctx, matches[1], samelen)); + } + talloc_free(mem_ctx); + + matches[j] = NULL; + return matches; +} + +static char **reg_completion(const char *text, int start, int end) +{ + smb_readline_ca_char(' '); + + if (start == 0) { + return reg_complete_command(text, start, end); + } else { + return reg_complete_key(text, start, end); + } +} + +int main(int argc, char **argv) +{ + int opt; + const char *file = NULL; + poptContext pc; + const char *remote = NULL; + struct regshell_context *ctx; + struct event_context *ev_ctx; + bool ret = true; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"file", 'F', POPT_ARG_STRING, &file, 0, "open hive file", NULL }, + {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL}, + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + { NULL } + }; + + pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0); + + while((opt = poptGetNextOpt(pc)) != -1) { + } + + ctx = talloc_zero(NULL, struct regshell_context); + + ev_ctx = s4_event_context_init(ctx); + + if (remote != NULL) { + ctx->registry = reg_common_open_remote(remote, ev_ctx, + cmdline_lp_ctx, cmdline_credentials); + } else if (file != NULL) { + ctx->current = reg_common_open_file(file, ev_ctx, cmdline_lp_ctx, cmdline_credentials); + if (ctx->current == NULL) + return 1; + ctx->registry = ctx->current->context; + ctx->path = talloc_strdup(ctx, ""); + } else { + ctx->registry = reg_common_open_local(cmdline_credentials, ev_ctx, cmdline_lp_ctx); + } + + if (ctx->registry == NULL) + return 1; + + if (ctx->current == NULL) { + int i; + + for (i = 0; reg_predefined_keys[i].handle; i++) { + WERROR err; + err = reg_get_predefined_key(ctx->registry, + reg_predefined_keys[i].handle, + &ctx->current); + if (W_ERROR_IS_OK(err)) { + ctx->path = talloc_strdup(ctx, + reg_predefined_keys[i].name); + break; + } else { + ctx->current = NULL; + } + } + } + + if (ctx->current == NULL) { + fprintf(stderr, "Unable to access any of the predefined keys\n"); + return -1; + } + + poptFreeContext(pc); + + while (true) { + char *line, *prompt; + + asprintf(&prompt, "%s> ", ctx->path); + + current_key = ctx->current; /* No way to pass a void * pointer + via readline :-( */ + line = smb_readline(prompt, NULL, reg_completion); + + if (line == NULL) { + free(prompt); + break; + } + + if (line[0] != '\n') { + ret = W_ERROR_IS_OK(process_cmd(ctx, line)); + } + free(line); + free(prompt); + } + talloc_free(ctx); + + return (ret?0:1); +} diff --git a/source4/lib/registry/tools/regtree.c b/source4/lib/registry/tools/regtree.c new file mode 100644 index 0000000000..19e4a010b4 --- /dev/null +++ b/source4/lib/registry/tools/regtree.c @@ -0,0 +1,169 @@ +/* + Unix SMB/CIFS implementation. + simple registry frontend + + Copyright (C) Jelmer Vernooij 2004-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "lib/registry/tools/common.h" +#include "lib/events/events.h" +#include "lib/cmdline/popt_common.h" +#include "param/param.h" + +/** + * Print a registry key recursively + * + * @param level Level at which to print + * @param p Key to print + * @param fullpath Whether the full pat hshould be printed or just the last bit + * @param novals Whether values should not be printed + */ +static void print_tree(int level, struct registry_key *p, + const char *name, + bool fullpath, bool novals) +{ + struct registry_key *subkey; + const char *valuename; + const char *keyname; + uint32_t value_type; + DATA_BLOB value_data; + struct security_descriptor *sec_desc; + WERROR error; + int i; + TALLOC_CTX *mem_ctx; + + for(i = 0; i < level; i++) putchar(' '); puts(name); + + mem_ctx = talloc_init("print_tree"); + for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, + p, + i, + &keyname, + NULL, + NULL)); i++) { + SMB_ASSERT(strlen(keyname) > 0); + if (!W_ERROR_IS_OK(reg_open_key(mem_ctx, p, keyname, &subkey))) + continue; + print_tree(level+1, subkey, (fullpath && strlen(name))? + talloc_asprintf(mem_ctx, "%s\\%s", + name, keyname): + keyname, fullpath, novals); + } + talloc_free(mem_ctx); + + if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) { + DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n", + name, win_errstr(error))); + } + + if (!novals) { + mem_ctx = talloc_init("print_tree"); + for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, + p, + i, + &valuename, + &value_type, + &value_data)); i++) { + int j; + char *desc; + for(j = 0; j < level+1; j++) putchar(' '); + desc = reg_val_description(mem_ctx, lp_iconv_convenience(cmdline_lp_ctx), valuename, + value_type, value_data); + printf("%s\n", desc); + } + talloc_free(mem_ctx); + + if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) { + DEBUG(0, ("Error occured while fetching values for '%s': %s\n", + name, win_errstr(error))); + } + } + + mem_ctx = talloc_init("sec_desc"); + if (NT_STATUS_IS_ERR(reg_get_sec_desc(mem_ctx, p, &sec_desc))) { + DEBUG(0, ("Error getting security descriptor\n")); + } + talloc_free(mem_ctx); +} + +int main(int argc, char **argv) +{ + int opt, i; + const char *file = NULL; + const char *remote = NULL; + poptContext pc; + struct registry_context *h = NULL; + struct registry_key *start_key = NULL; + struct event_context *ev_ctx; + WERROR error; + bool fullpath = false, no_values = false; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL }, + {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL }, + {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL}, + {"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL}, + POPT_COMMON_SAMBA + POPT_COMMON_CREDENTIALS + POPT_COMMON_VERSION + { NULL } + }; + + pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0); + + while((opt = poptGetNextOpt(pc)) != -1) { + } + + ev_ctx = s4_event_context_init(NULL); + + if (remote != NULL) { + h = reg_common_open_remote(remote, ev_ctx, cmdline_lp_ctx, cmdline_credentials); + } else if (file != NULL) { + start_key = reg_common_open_file(file, ev_ctx, cmdline_lp_ctx, cmdline_credentials); + } else { + h = reg_common_open_local(cmdline_credentials, ev_ctx, cmdline_lp_ctx); + } + + if (h == NULL && start_key == NULL) + return 1; + + poptFreeContext(pc); + + error = WERR_OK; + + if (start_key != NULL) { + print_tree(0, start_key, "", fullpath, no_values); + } else { + for(i = 0; reg_predefined_keys[i].handle; i++) { + error = reg_get_predefined_key(h, + reg_predefined_keys[i].handle, + &start_key); + if (!W_ERROR_IS_OK(error)) { + fprintf(stderr, "Skipping %s: %s\n", + reg_predefined_keys[i].name, + win_errstr(error)); + continue; + } + SMB_ASSERT(start_key != NULL); + print_tree(0, start_key, reg_predefined_keys[i].name, + fullpath, no_values); + } + } + + return 0; +} diff --git a/source4/lib/registry/util.c b/source4/lib/registry/util.c new file mode 100644 index 0000000000..68efd56a86 --- /dev/null +++ b/source4/lib/registry/util.c @@ -0,0 +1,252 @@ +/* + Unix SMB/CIFS implementation. + Transparent registry backend handling + Copyright (C) Jelmer Vernooij 2003-2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "librpc/gen_ndr/winreg.h" +#include "param/param.h" + +/** + * @file + * @brief Registry utility functions + */ + +static const struct { + uint32_t id; + const char *name; +} reg_value_types[] = { + { REG_SZ, "REG_SZ" }, + { REG_DWORD, "REG_DWORD" }, + { REG_BINARY, "REG_BINARY" }, + { REG_EXPAND_SZ, "REG_EXPAND_SZ" }, + { REG_NONE, "REG_NONE" }, + { 0, NULL } +}; + +/** Return string description of registry value type */ +_PUBLIC_ const char *str_regtype(int type) +{ + int i; + for (i = 0; reg_value_types[i].name; i++) { + if (reg_value_types[i].id == type) + return reg_value_types[i].name; + } + + return "Unknown"; +} + +_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + uint32_t type, + const DATA_BLOB data) +{ + char *ret = NULL; + + if (data.length == 0) + return talloc_strdup(mem_ctx, ""); + + switch (type) { + case REG_EXPAND_SZ: + case REG_SZ: + convert_string_talloc(mem_ctx, iconv_convenience, CH_UTF16, CH_UNIX, + data.data, data.length, + (void **)&ret); + return ret; + case REG_BINARY: + ret = data_blob_hex_string(mem_ctx, &data); + return ret; + case REG_DWORD: + if (*(int *)data.data == 0) + return talloc_strdup(mem_ctx, "0"); + return talloc_asprintf(mem_ctx, "0x%x", + *(int *)data.data); + case REG_MULTI_SZ: + /* FIXME */ + break; + default: + break; + } + + return ret; +} + +/** Generate a string that describes a registry value */ +_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + const char *name, + uint32_t data_type, + const DATA_BLOB data) +{ + return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>", + str_regtype(data_type), + reg_val_data_string(mem_ctx, iconv_convenience, data_type, data)); +} + +_PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + const char *type_str, + const char *data_str, uint32_t *type, + DATA_BLOB *data) +{ + int i; + *type = -1; + + /* Find the correct type */ + for (i = 0; reg_value_types[i].name; i++) { + if (!strcmp(reg_value_types[i].name, type_str)) { + *type = reg_value_types[i].id; + break; + } + } + + if (*type == -1) + return false; + + /* Convert data appropriately */ + + switch (*type) + { + case REG_SZ: + case REG_EXPAND_SZ: + data->length = convert_string_talloc(mem_ctx, iconv_convenience, CH_UNIX, CH_UTF16, + data_str, strlen(data_str), + (void **)&data->data); + break; + + case REG_DWORD: { + uint32_t tmp = strtol(data_str, NULL, 0); + *data = data_blob_talloc(mem_ctx, &tmp, 4); + } + break; + + case REG_NONE: + ZERO_STRUCTP(data); + break; + + case REG_BINARY: + *data = strhex_to_data_blob(data_str); + talloc_steal(mem_ctx, data->data); + break; + + default: + /* FIXME */ + return false; + } + return true; +} + +/** Open a key by name (including the predefined key name!) */ +WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, + const char *name, struct registry_key **result) +{ + struct registry_key *predef; + WERROR error; + int predeflength; + char *predefname; + + if (strchr(name, '\\') != NULL) + predeflength = strchr(name, '\\')-name; + else + predeflength = strlen(name); + + predefname = talloc_strndup(mem_ctx, name, predeflength); + error = reg_get_predefined_key_by_name(handle, predefname, &predef); + talloc_free(predefname); + + if (!W_ERROR_IS_OK(error)) { + return error; + } + + if (strchr(name, '\\')) { + return reg_open_key(mem_ctx, predef, strchr(name, '\\')+1, + result); + } else { + *result = predef; + return WERR_OK; + } +} + +static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, + const char *path, struct registry_key **parent, + const char **name) +{ + char *parent_name; + WERROR error; + + if (strchr(path, '\\') == NULL) { + return WERR_FOOBAR; + } + + parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path); + + error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent); + if (!W_ERROR_IS_OK(error)) { + return error; + } + + *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1); + + return WERR_OK; +} + +WERROR reg_key_del_abs(struct registry_context *ctx, const char *path) +{ + struct registry_key *parent; + const char *n; + TALLOC_CTX *mem_ctx = talloc_init("reg_key_del_abs"); + WERROR error; + + if (!strchr(path, '\\')) { + return WERR_FOOBAR; + } + + error = get_abs_parent(mem_ctx, ctx, path, &parent, &n); + if (W_ERROR_IS_OK(error)) { + error = reg_key_del(parent, n); + } + + talloc_free(mem_ctx); + + return error; +} + +WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, + const char *path, uint32_t access_mask, + struct security_descriptor *sec_desc, + struct registry_key **result) +{ + struct registry_key *parent; + const char *n; + WERROR error; + + if (!strchr(path, '\\')) { + return WERR_ALREADY_EXISTS; + } + + error = get_abs_parent(mem_ctx, ctx, path, &parent, &n); + if (!W_ERROR_IS_OK(error)) { + DEBUG(2, ("Opening parent of %s failed with %s\n", path, + win_errstr(error))); + return error; + } + + error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result); + + return error; +} diff --git a/source4/lib/registry/wine.c b/source4/lib/registry/wine.c new file mode 100644 index 0000000000..77d2ce66e9 --- /dev/null +++ b/source4/lib/registry/wine.c @@ -0,0 +1,45 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2007. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/registry/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; +} |