From aebfb3b9f415d3c1f6b2a39aee27b072d48893cb Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 8 Apr 2004 22:39:47 +0000 Subject: r128: Another registry update. Changes: - Start with the LDB backend - The API is now more windows-like, which should make it easier to use in rpc_server - Added a GTK+ front-end - Added some more IDL More updates will follow, especially in the RPC field.. (This used to be commit 3adffa021779b26047a20f16a3c0b53d74751560) --- source4/Makefile.in | 6 + source4/include/doserr.h | 3 + source4/lib/ldb/include/proto.h | 126 ---- source4/lib/registry/TODO | 18 +- source4/lib/registry/common/reg_interface.c | 368 +++++----- source4/lib/registry/common/reg_util.c | 22 +- source4/lib/registry/common/registry.h | 55 +- source4/lib/registry/config.m4 | 3 + .../lib/registry/reg_backend_dir/reg_backend_dir.c | 46 +- .../registry/reg_backend_gconf/reg_backend_gconf.c | 54 +- .../lib/registry/reg_backend_ldb/reg_backend_ldb.c | 75 +- .../lib/registry/reg_backend_nt4/reg_backend_nt4.c | 106 +-- .../lib/registry/reg_backend_rpc/reg_backend_rpc.c | 85 ++- .../registry/reg_backend_wine/reg_backend_wine.c | 1 + source4/lib/registry/tools/gregedit.c | 758 +++++++++++++++++++++ source4/lib/registry/tools/regshell.c | 1 + source4/librpc/idl/winreg.idl | 35 +- source4/rpc_server/winreg/rpc_winreg.c | 214 +++--- source4/torture/rpc/winreg.c | 97 ++- 19 files changed, 1486 insertions(+), 587 deletions(-) create mode 100644 source4/lib/registry/tools/gregedit.c diff --git a/source4/Makefile.in b/source4/Makefile.in index 8f9bad0da5..d089bcbde9 100644 --- a/source4/Makefile.in +++ b/source4/Makefile.in @@ -140,6 +140,7 @@ DCERPC_LIBS = @DCERPC_LIBS@ REG_OBJS = @REG_OBJS@ REG_LIBS = @REG_LIBS@ +GTK_LIBS = @GTK_LIBS@ TORTURE_RAW_OBJS = @TORTURE_RAW_OBJS@ @@ -191,6 +192,7 @@ NDRDUMP_OBJS = utils/ndrdump.o utils/rewrite.o \ NDRDUMP_LIBS = $(LIBSMB_LIBS) $(CONFIG_LIBS) $(LIBBASIC_LIBS) REGTREE_OBJ = $(REG_OBJS) lib/registry/tools/regtree.o $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBSMB_OBJS) +GREGEDIT_OBJ = $(REG_OBJS) lib/registry/tools/gregedit.o $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBSMB_OBJS) REGSHELL_OBJ = $(REG_OBJS) lib/registry/tools/regshell.o $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBCMDLINE_OBJS) $(LIBSMB_OBJS) REGPATCH_OBJ = $(REG_OBJS) lib/registry/tools/regpatch.o $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBSMB_OBJS) REGDIFF_OBJ = $(REG_OBJS) lib/registry/tools/regdiff.o $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBSMB_OBJS) @@ -350,6 +352,10 @@ bin/regtree@EXEEXT@: $(REGTREE_OBJ) bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(REGTREE_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS) +bin/gregedit@EXEEXT@: $(GREGEDIT_OBJ) bin/.dummy + @echo Linking $@ + @$(CC) $(FLGS) -o $@ $(GREGEDIT_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS) $(GTK_LIBS) + bin/regpatch@EXEEXT@: $(REGPATCH_OBJ) bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(REGPATCH_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS) diff --git a/source4/include/doserr.h b/source4/include/doserr.h index 114366ff6e..e3582889d8 100644 --- a/source4/include/doserr.h +++ b/source4/include/doserr.h @@ -231,4 +231,7 @@ #define WERR_DFS_INTERNAL_ERROR W_ERROR(NERR_BASE+590) #define WERR_DFS_CANT_CREATE_JUNCT W_ERROR(NERR_BASE+569) + +#define WERR_FOOBAR WERR_GENERAL_FAILURE + #endif /* _DOSERR_H */ diff --git a/source4/lib/ldb/include/proto.h b/source4/lib/ldb/include/proto.h index 8690d96fee..e69de29bb2 100644 --- a/source4/lib/ldb/include/proto.h +++ b/source4/lib/ldb/include/proto.h @@ -1,126 +0,0 @@ -#ifndef _PROTO_H_ -#define _PROTO_H_ - -/* This file is automatically generated with "make proto". DO NOT EDIT */ - - -/* The following definitions come from common/ldb.c */ - -struct ldb_context *ldb_connect(const char *url, unsigned int flags, - const char *options[]); -int ldb_close(struct ldb_context *ldb); -int ldb_search(struct ldb_context *ldb, - const char *base, - enum ldb_scope scope, - const char *expression, - const char *attrs[], struct ldb_message ***res); -int ldb_search_free(struct ldb_context *ldb, struct ldb_message **msgs); -int ldb_add(struct ldb_context *ldb, - const struct ldb_message *message); -int ldb_modify(struct ldb_context *ldb, - const struct ldb_message *message); -int ldb_delete(struct ldb_context *ldb, const char *dn); -const char *ldb_errstring(struct ldb_context *ldb); - -/* The following definitions come from common/ldb_ldif.c */ - -char *ldb_base64_encode(const char *buf, int len); -int ldb_should_b64_encode(const struct ldb_val *val); -int ldif_write(int (*fprintf_fn)(void *, const char *, ...), - void *private, - const struct ldb_message *msg); -void ldif_read_free(struct ldb_message *msg); -struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private); -struct ldb_message *ldif_read_file(FILE *f); -struct ldb_message *ldif_read_string(const char *s); -int ldif_write_file(FILE *f, const struct ldb_message *msg); - -/* The following definitions come from common/ldb_parse.c */ - -struct ldb_parse_tree *ldb_parse_tree(const char *s); -void ldb_parse_tree_free(struct ldb_parse_tree *tree); - -/* The following definitions come from common/util.c */ - -void *realloc_array(void *ptr, size_t el_size, unsigned count); -int list_find(const void *needle, - const void *base, size_t nmemb, size_t size, comparison_fn_t comp_fn); - -/* The following definitions come from ldb_ldap/ldb_ldap.c */ - -struct ldb_context *lldb_connect(const char *url, - unsigned int flags, - const char *options[]); - -/* The following definitions come from ldb_tdb/ldb_index.c */ - -int ltdb_search_indexed(struct ldb_context *ldb, - const char *base, - enum ldb_scope scope, - struct ldb_parse_tree *tree, - const char *attrs[], struct ldb_message ***res); -int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg); -int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg); - -/* The following definitions come from ldb_tdb/ldb_match.c */ - -int ldb_message_match(struct ldb_context *ldb, - struct ldb_message *msg, - struct ldb_parse_tree *tree, - const char *base, - enum ldb_scope scope); - -/* The following definitions come from ldb_tdb/ldb_pack.c */ - -int ltdb_pack_data(struct ldb_context *ctx, - const struct ldb_message *message, - struct TDB_DATA *data); -int ltdb_unpack_data(struct ldb_context *ctx, - const struct TDB_DATA *data, - struct ldb_message *message); - -/* The following definitions come from ldb_tdb/ldb_search.c */ - -int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr); -int ltdb_has_wildcard(const struct ldb_val *val); -void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg); -int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg); -int ltdb_search_dn(struct ldb_context *ldb, char *dn, - const char *attrs[], struct ldb_message ***res); -int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg, - const char *attrs[], - unsigned int *count, - struct ldb_message ***res); -int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs); -int ltdb_search(struct ldb_context *ldb, const char *base, - enum ldb_scope scope, const char *expression, - const char *attrs[], struct ldb_message ***res); - -/* The following definitions come from ldb_tdb/ldb_tdb.c */ - -struct TDB_DATA ltdb_key(const char *dn); -int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs); -int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn); -struct ldb_context *ltdb_connect(const char *url, - unsigned int flags, - const char *options[]); - -/* The following definitions come from ldb_tdb/ldbadd.c */ - - -/* The following definitions come from ldb_tdb/ldbdel.c */ - - -/* The following definitions come from ldb_tdb/ldbsearch.c */ - - -/* The following definitions come from tools/ldbadd.c */ - - -/* The following definitions come from tools/ldbdel.c */ - - -/* The following definitions come from tools/ldbsearch.c */ - - -#endif /* _PROTO_H_ */ diff --git a/source4/lib/registry/TODO b/source4/lib/registry/TODO index ac467d0078..fc741cea40 100644 --- a/source4/lib/registry/TODO +++ b/source4/lib/registry/TODO @@ -1,10 +1,6 @@ - support subtrees -- ../../, /bla/blie support in regshell -- use memory pools? -- get rid of all the nasty memory leaks.. -- security stuff -- clean up code -- rpc_server +- ..\..\, \bla\blie support in regshell +- finish rpc_server reg_backend_dir: - value support @@ -15,9 +11,15 @@ reg_backend_nt4: reg_backend_rpc: - value enum support - write support + - rewrite reg_backend_ldb: - - implement + - finish reg_backend_wine.c: - - implement + - finish + +gregedit.c: + - support for editing values / adding values / deleting values + - support for adding/deleting keys + - support for security descriptors diff --git a/source4/lib/registry/common/reg_interface.c b/source4/lib/registry/common/reg_interface.c index b6b38e9b62..9c78ae55fb 100644 --- a/source4/lib/registry/common/reg_interface.c +++ b/source4/lib/registry/common/reg_interface.c @@ -32,7 +32,7 @@ static struct reg_init_function_entry *reg_find_backend_entry(const char *name); /* Register new backend */ NTSTATUS registry_register(void *_function) { - REG_OPS *functions = _function; + struct registry_ops *functions = _function; struct reg_init_function_entry *entry = backends; if (!functions || !functions->name) { @@ -69,17 +69,19 @@ static struct reg_init_function_entry *reg_find_backend_entry(const char *name) } /* Open a registry file/host/etc */ -REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_load) +WERROR reg_open(const char *backend, const char *location, const char *credentials, REG_HANDLE **h) { struct reg_init_function_entry *entry; static BOOL reg_first_init = True; TALLOC_CTX *mem_ctx; REG_HANDLE *ret; + NTSTATUS status; + WERROR werr; if(reg_first_init) { - if (!NT_STATUS_IS_OK(register_subsystem("registry", registry_register))) { - return False; - } + status = register_subsystem("registry", registry_register); + if (!NT_STATUS_IS_OK(status)) + return WERR_GENERAL_FAILURE; static_init_reg; reg_first_init = False; @@ -89,7 +91,7 @@ REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_lo if (!entry) { DEBUG(0, ("No such registry backend '%s' loaded!\n", backend)); - return NULL; + return WERR_GENERAL_FAILURE; } mem_ctx = talloc_init(backend); @@ -99,31 +101,35 @@ REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_lo ret->functions = entry->functions; ret->backend_data = NULL; ret->mem_ctx = mem_ctx; + *h = ret; if(!entry->functions->open_registry) { - return ret; + return WERR_OK; } - if(entry->functions->open_registry(ret, location, try_full_load)) - return ret; + werr = entry->functions->open_registry(ret, location, credentials); + + if(W_ERROR_IS_OK(werr)) + return WERR_OK; talloc_destroy(mem_ctx); - return NULL; + return werr; } /* 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 */ -REG_KEY *reg_open_key(REG_KEY *parent, const char *name) +WERROR reg_open_key(REG_KEY *parent, const char *name, REG_KEY **result) { char *fullname; + WERROR status; REG_KEY *ret = NULL; TALLOC_CTX *mem_ctx; if(!parent) { DEBUG(0, ("Invalid parent key specified")); - return NULL; + return WERR_INVALID_PARAM; } if(!parent->handle->functions->open_key && @@ -136,10 +142,10 @@ REG_KEY *reg_open_key(REG_KEY *parent, const char *name) while(curbegin && *curbegin) { if(curend)*curend = '\0'; - curkey = reg_key_get_subkey_by_name(curkey, curbegin); - if(!curkey) { + status = reg_key_get_subkey_by_name(curkey, curbegin, result); + if(!NT_STATUS_IS_OK(status)) { SAFE_FREE(orig); - return NULL; + return status; } if(!curend) break; curbegin = curend + 1; @@ -147,255 +153,287 @@ REG_KEY *reg_open_key(REG_KEY *parent, const char *name) } SAFE_FREE(orig); - return curkey; + *result = curkey; + return WERR_OK; } mem_ctx = talloc_init("mem_ctx"); fullname = talloc_asprintf(mem_ctx, "%s%s%s", parent->path, parent->path[strlen(parent->path)-1] == '\\'?"":"\\", name); - +\ if(!parent->handle->functions->open_key) { DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n")); - return NULL; + return WERR_NOT_SUPPORTED; } - ret = parent->handle->functions->open_key(parent->handle, fullname); + status = parent->handle->functions->open_key(parent->handle, fullname, result); - if(ret) { - ret->handle = parent->handle; - ret->path = fullname; - talloc_steal(mem_ctx, ret->mem_ctx, fullname); + if(!NT_STATUS_IS_OK(status)) { + talloc_destroy(mem_ctx); + return status; } + + ret->handle = parent->handle; + ret->path = fullname; + talloc_steal(mem_ctx, ret->mem_ctx, fullname); talloc_destroy(mem_ctx); - return ret; + *result = ret; + + return WERR_OK; } -REG_VAL *reg_key_get_value_by_index(REG_KEY *key, int idx) +WERROR reg_key_get_value_by_index(REG_KEY *key, int idx, REG_VAL **val) { - REG_VAL *ret; - - if(!key) return NULL; + if(!key) return WERR_INVALID_PARAM; if(!key->handle->functions->get_value_by_index) { if(!key->cache_values) key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values); if(idx < key->cache_values_count && idx >= 0) { - ret = reg_val_dup(key->cache_values[idx]); + *val = reg_val_dup(key->cache_values[idx]); } else { - return NULL; + return WERR_NO_MORE_ITEMS; } } else { - ret = key->handle->functions->get_value_by_index(key, idx); + WERROR status = key->handle->functions->get_value_by_index(key, idx, val); + if(!W_ERROR_IS_OK(status)) + return status; } - if(ret) { - ret->parent = key; - ret->handle = key->handle; - } - - return ret; + (*val)->parent = key; + (*val)->handle = key->handle; + return WERR_OK; } -int reg_key_num_subkeys(REG_KEY *key) +WERROR reg_key_num_subkeys(REG_KEY *key, int *count) { - if(!key) return 0; + if(!key) return WERR_INVALID_PARAM; if(!key->handle->functions->num_subkeys) { if(!key->cache_subkeys) key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys); - return key->cache_subkeys_count; + *count = key->cache_subkeys_count; + return WERR_OK; } - return key->handle->functions->num_subkeys(key); + return key->handle->functions->num_subkeys(key, count); } -int reg_key_num_values(REG_KEY *key) +WERROR reg_key_num_values(REG_KEY *key, int *count) { - if(!key) return 0; + if(!key) return WERR_INVALID_PARAM; if(!key->handle->functions->num_values) { if(!key->handle->functions->fetch_values) { DEBUG(1, ("Backend '%s' doesn't support enumerating values\n", key->handle->functions->name)); - return 0; + return WERR_NOT_SUPPORTED; } if(!key->cache_values) key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values); - return key->cache_values_count; + *count = key->cache_values_count; + return WERR_OK; } - return key->handle->functions->num_values(key); + return key->handle->functions->num_values(key, count); } -REG_KEY *reg_key_get_subkey_by_index(REG_KEY *key, int idx) +WERROR reg_key_get_subkey_by_index(REG_KEY *key, int idx, REG_KEY **subkey) { - REG_KEY *ret = NULL; - - if(!key) return NULL; + if(!key) return WERR_INVALID_PARAM; if(!key->handle->functions->get_subkey_by_index) { if(!key->cache_subkeys) key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys); if(idx < key->cache_subkeys_count) { - ret = reg_key_dup(key->cache_subkeys[idx]); + *subkey = reg_key_dup(key->cache_subkeys[idx]); } else { - /* No such key ! */ - return NULL; + return WERR_NO_MORE_ITEMS; } } else { - ret = key->handle->functions->get_subkey_by_index(key, idx); + WERROR status = key->handle->functions->get_subkey_by_index(key, idx, subkey); + if(!NT_STATUS_IS_OK(status)) return status; } - if(ret && !ret->path) { - ret->path = talloc_asprintf(ret->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name); - ret->handle = key->handle; - } + (*subkey)->path = talloc_asprintf((*subkey)->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", (*subkey)->name); + (*subkey)->handle = key->handle; - return ret; + + return WERR_OK;; } -REG_KEY *reg_key_get_subkey_by_name(REG_KEY *key, const char *name) +WERROR reg_key_get_subkey_by_name(REG_KEY *key, const char *name, REG_KEY **subkey) { - int i, max; + int i; REG_KEY *ret = NULL; + WERROR error = WERR_OK; - if(!key) return NULL; + if(!key) return WERR_INVALID_PARAM; if(key->handle->functions->get_subkey_by_name) { - ret = key->handle->functions->get_subkey_by_name(key,name); + error = key->handle->functions->get_subkey_by_name(key,name,subkey); } else { - max = reg_key_num_subkeys(key); - for(i = 0; i < max; i++) { - REG_KEY *v = reg_key_get_subkey_by_index(key, i); - if(v && !strcmp(v->name, name)) { - ret = v; + for(i = 0; W_ERROR_IS_OK(error); i++) { + error = reg_key_get_subkey_by_index(key, i, subkey); + if(W_ERROR_IS_OK(error) && !strcmp((*subkey)->name, name)) { break; } - reg_key_free(v); + reg_key_free(*subkey); } - } - if(ret && !ret->path) { - ret->path = talloc_asprintf(ret->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name); - ret->handle = key->handle; } + + if(!W_ERROR_IS_OK(error) && W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) + return error; + + ret->path = talloc_asprintf(ret->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name); + ret->handle = key->handle; + + *subkey = ret; - return ret; + return WERR_OK; } -REG_VAL *reg_key_get_value_by_name(REG_KEY *key, const char *name) +WERROR reg_key_get_value_by_name(REG_KEY *key, const char *name, REG_VAL **val) { int i, max; REG_VAL *ret = NULL; + WERROR error = WERR_OK; - if(!key) return NULL; + if(!key) return WERR_INVALID_PARAM; if(key->handle->functions->get_value_by_name) { - ret = key->handle->functions->get_value_by_name(key,name); + error = key->handle->functions->get_value_by_name(key,name, val); } else { - max = reg_key_num_values(key); - for(i = 0; i < max; i++) { - REG_VAL *v = reg_key_get_value_by_index(key, i); - if(v && StrCaseCmp(v->name, name)) { - ret = v; + for(i = 0; W_ERROR_IS_OK(error); i++) { + error = reg_key_get_value_by_index(key, i, val); + if(W_ERROR_IS_OK(error) && StrCaseCmp((*val)->name, name)) { break; } - reg_val_free(v); + reg_val_free(*val); } } + + if(!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) + return error; - if(ret) { - ret->parent = key; - ret->handle = key->handle; - } + (*val)->parent = key; + (*val)->handle = key->handle; - return ret; + return WERR_OK; } -BOOL reg_key_del(REG_KEY *key) +WERROR reg_key_del(REG_KEY *key) { - if(key->handle->functions->del_key) { - if(key->handle->functions->del_key(key)) { - /* Invalidate cache */ - key->cache_subkeys = NULL; - key->cache_subkeys_count = 0; - return True; - } - } + WERROR error; + if(!key) return WERR_INVALID_PARAM; + + + if(!key->handle->functions->del_key) + return WERR_NOT_SUPPORTED; + + error = key->handle->functions->del_key(key); + if(!W_ERROR_IS_OK(error)) return error; - return False; + /* Invalidate cache */ + key->cache_subkeys = NULL; + key->cache_subkeys_count = 0; + return WERR_OK; } -BOOL reg_sync(REG_HANDLE *h, const char *location) +WERROR reg_sync(REG_KEY *h, const char *location) { - if(!h->functions->sync) - return True; + if(!h->handle->functions->sync_key) + return WERR_OK; - return h->functions->sync(h, location); + return h->handle->functions->sync_key(h, location); } -BOOL reg_key_del_recursive(REG_KEY *key) +WERROR reg_key_del_recursive(REG_KEY *key) { BOOL succeed = True; + WERROR error = WERR_OK; int i; /* Delete all values for specified key */ - for(i = 0; i < reg_key_num_values(key); i++) { - if(!reg_val_del(reg_key_get_value_by_index(key, i))) - succeed = False; + for(i = 0; W_ERROR_IS_OK(error); i++) { + REG_VAL *val; + error = reg_key_get_value_by_index(key, i, &val); + if(!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) + return error; + + if(W_ERROR_IS_OK(error)) { + error = reg_val_del(val); + if(!W_ERROR_IS_OK(error)) return error; + } } + error = WERR_OK; + /* Delete all keys below this one */ - for(i = 0; i < reg_key_num_subkeys(key); i++) { - if(!reg_key_del_recursive(reg_key_get_subkey_by_index(key, i))) - succeed = False; - } + for(i = 0; W_ERROR_IS_OK(error); i++) { + REG_KEY *subkey; + + error = reg_key_get_subkey_by_index(key, i, &subkey); + if(!W_ERROR_IS_OK(error)) return error; - if(succeed)reg_key_del(key); + error = reg_key_del_recursive(subkey); + if(!W_ERROR_IS_OK(error)) return error; + } - return succeed; + return reg_key_del(key); } -BOOL reg_val_del(REG_VAL *val) +WERROR reg_val_del(REG_VAL *val) { + WERROR error; + if (!val) return WERR_INVALID_PARAM; + if (!val->handle->functions->del_value) { DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name)); - return False; + return WERR_NOT_SUPPORTED; } - if(val->handle->functions->del_value(val)) { - val->parent->cache_values = NULL; - val->parent->cache_values_count = 0; - return True; - } - return False; + error = val->handle->functions->del_value(val); + + if(!W_ERROR_IS_OK(error)) return error; + + val->parent->cache_values = NULL; + val->parent->cache_values_count = 0; + + return WERR_OK; } -BOOL reg_key_add_name_recursive(REG_KEY *parent, const char *path) +WERROR reg_key_add_name_recursive(REG_KEY *parent, const char *path) { REG_KEY *cur, *prevcur = parent; + WERROR error; char *begin = (char *)path, *end; while(1) { end = strchr(begin, '\\'); if(end) *end = '\0'; - cur = reg_key_get_subkey_by_name(prevcur, begin); - if(!cur) { - if(!reg_key_add_name(prevcur, begin)) { printf("foo\n"); return False; } - cur = reg_key_get_subkey_by_name(prevcur, begin); - if(!cur) { - DEBUG(0, ("Can't find key after adding it : %s\n", begin)); - return False; - } + + error = reg_key_get_subkey_by_name(prevcur, begin, &cur); + + /* Key is not there, add it */ + if(W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) { + error = reg_key_add_name(prevcur, begin, 0, NULL, &cur); + if(!W_ERROR_IS_OK(error)) return error; + } + + if(!W_ERROR_IS_OK(error)) { + if(end) *end = '\\'; + return error; } if(!end) break; @@ -403,28 +441,36 @@ BOOL reg_key_add_name_recursive(REG_KEY *parent, const char *path) begin = end+1; prevcur = cur; } - return True; + return WERR_OK; } -BOOL reg_key_add_name(REG_KEY *parent, const char *name) +WERROR reg_key_add_name(REG_KEY *parent, const char *name, uint32 access_mask, SEC_DESC *desc, REG_KEY **newkey) { - if (!parent) return False; + WERROR error; + + if (!parent) return WERR_INVALID_PARAM; if (!parent->handle->functions->add_key) { DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name)); - return False; + return WERR_NOT_SUPPORTED; } - if(parent->handle->functions->add_key(parent, name)) { - parent->cache_subkeys = NULL; - parent->cache_subkeys_count = 0; - return True; - } - return False; + error = parent->handle->functions->add_key(parent, name, access_mask, desc, newkey); + + if(!W_ERROR_IS_OK(error)) return error; + + (*newkey)->handle = parent->handle; + (*newkey)->backend_data = talloc_asprintf((*newkey)->mem_ctx, "%s\\%s", reg_key_get_path(parent), name); + + parent->cache_subkeys = NULL; + parent->cache_subkeys_count = 0; + return WERR_OK; } -BOOL reg_val_update(REG_VAL *val, int type, void *data, int len) +WERROR reg_val_update(REG_VAL *val, int type, void *data, int len) { + WERROR error; + /* A 'real' update function has preference */ if (val->handle->functions->update_value) return val->handle->functions->update_value(val, type, data, len); @@ -433,18 +479,19 @@ BOOL reg_val_update(REG_VAL *val, int type, void *data, int len) if (val->handle->functions->add_value && val->handle->functions->del_value) { REG_VAL *new; - if(!val->handle->functions->del_value(val)) - return False; + if(!W_ERROR_IS_OK(error = val->handle->functions->del_value(val))) + return error; - new = val->handle->functions->add_value(val->parent, val->name, type, data, len); + error = val->handle->functions->add_value(val->parent, val->name, type, data, len); + if(!W_ERROR_IS_OK(error)) return error; memcpy(val, new, sizeof(REG_VAL)); val->parent->cache_values = NULL; val->parent->cache_values_count = 0; - return True; + return WERR_OK; } DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name)); - return False; + return WERR_NOT_SUPPORTED; } void reg_free(REG_HANDLE *h) @@ -454,37 +501,44 @@ void reg_free(REG_HANDLE *h) h->functions->close_registry(h); } -REG_KEY *reg_get_root(REG_HANDLE *h) +WERROR reg_get_root(REG_HANDLE *h, REG_KEY **key) { - REG_KEY *ret = NULL; + WERROR ret; if(h->functions->open_root_key) { - ret = h->functions->open_root_key(h); + ret = h->functions->open_root_key(h, key); } else if(h->functions->open_key) { - ret = h->functions->open_key(h, "\\"); + ret = h->functions->open_key(h, "\\", key); } else { DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name)); + ret = WERR_NOT_SUPPORTED; } - if(ret) { - ret->handle = h; - ret->path = talloc_strdup(ret->mem_ctx, "\\"); + if(W_ERROR_IS_OK(ret)) { + (*key)->handle = h; + (*key)->path = talloc_strdup((*key)->mem_ctx, "\\"); } return ret; } -REG_VAL *reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen) +WERROR reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen) { - REG_VAL *ret; + WERROR ret = WERR_OK; if(!key->handle->functions->add_value) - return NULL; + return WERR_NOT_SUPPORTED; ret = key->handle->functions->add_value(key, name, type, value, vallen); - ret->parent = key; - ret->handle = key->handle; + + if(!W_ERROR_IS_OK(ret)) return ret; /* Invalidate the cache */ key->cache_values = NULL; key->cache_values_count = 0; return ret; } + +WERROR reg_save(REG_HANDLE *h, const char *location) +{ + /* FIXME */ + return WERR_NOT_SUPPORTED; +} diff --git a/source4/lib/registry/common/reg_util.c b/source4/lib/registry/common/reg_util.c index 060d053fc2..5ca104fc2e 100644 --- a/source4/lib/registry/common/reg_util.c +++ b/source4/lib/registry/common/reg_util.c @@ -96,22 +96,26 @@ BOOL reg_val_set_string(REG_VAL *val, char *str) return False; } -REG_VAL *reg_key_get_subkey_val(REG_KEY *key, const char *subname, const char *valname) +WERROR reg_key_get_subkey_val(REG_KEY *key, const char *subname, const char *valname, REG_VAL **val) { - REG_KEY *k = reg_key_get_subkey_by_name(key, subname); - if(!k) return NULL; + REG_KEY *k; + WERROR error = reg_key_get_subkey_by_name(key, subname, &k); + if(!W_ERROR_IS_OK(error)) return error; - return reg_key_get_value_by_name(k, valname); + return reg_key_get_value_by_name(k, valname, val); } -BOOL reg_key_set_subkey_val(REG_KEY *key, const char *subname, const char *valname, uint32 type, uint8 *data, int real_len) +WERROR reg_key_set_subkey_val(REG_KEY *key, const char *subname, const char *valname, uint32 type, uint8 *data, int real_len) { - REG_KEY *k = reg_key_get_subkey_by_name(key, subname); + REG_KEY *k; REG_VAL *v; - if(!k) return False; + WERROR error; - v = reg_key_get_value_by_name(k, valname); - if(!v) return False; + error = reg_key_get_subkey_by_name(key, subname, &k); + if(!W_ERROR_IS_OK(error)) return error; + + error = reg_key_get_value_by_name(k, valname, &v); + if(!W_ERROR_IS_OK(error)) return error; return reg_val_update(v, type, data, real_len); } diff --git a/source4/lib/registry/common/registry.h b/source4/lib/registry/common/registry.h index 3565a7a585..6e12de258d 100644 --- a/source4/lib/registry/common/registry.h +++ b/source4/lib/registry/common/registry.h @@ -57,42 +57,55 @@ struct reg_val_s { int ref; }; +/* FIXME */ +typedef void (*key_notification_function) (); +typedef void (*value_notification_function) (); + + /* * Container for function pointers to enumeration routines * for virtual registry view */ -struct reg_ops_s { +struct registry_ops { const char *name; - BOOL (*open_registry) (REG_HANDLE *, const char *location, BOOL try_complete_load); - BOOL (*sync)(REG_HANDLE *, const char *location); - BOOL (*close_registry) (REG_HANDLE *); + WERROR (*open_registry) (REG_HANDLE *, const char *location, const char *credentials); + WERROR (*sync_key)(REG_KEY *, const char *location); + WERROR (*close_registry) (REG_HANDLE *); /* Either implement these */ - REG_KEY *(*open_root_key) (REG_HANDLE *); - int (*num_subkeys) (REG_KEY *); - int (*num_values) (REG_KEY *); - REG_KEY *(*get_subkey_by_index) (REG_KEY *, int idx); - REG_KEY *(*get_subkey_by_name) (REG_KEY *, const char *name); - REG_VAL *(*get_value_by_index) (REG_KEY *, int idx); - REG_VAL *(*get_value_by_name) (REG_KEY *, const char *name); + WERROR (*open_root_key) (REG_HANDLE *, REG_KEY **); + WERROR (*num_subkeys) (REG_KEY *, int *count); + WERROR (*num_values) (REG_KEY *, int *count); + WERROR (*get_subkey_by_index) (REG_KEY *, int idx, REG_KEY **); + WERROR (*get_subkey_by_name) (REG_KEY *, const char *name, REG_KEY **); + WERROR (*get_value_by_index) (REG_KEY *, int idx, REG_VAL **); + WERROR (*get_value_by_name) (REG_KEY *, const char *name, REG_VAL **); /* Or these */ - REG_KEY *(*open_key) (REG_HANDLE *, const char *name); - BOOL (*fetch_subkeys) (REG_KEY *, int *count, REG_KEY ***); - BOOL (*fetch_values) (REG_KEY *, int *count, REG_VAL ***); + WERROR (*open_key) (REG_HANDLE *, const char *name, REG_KEY **); + WERROR (*fetch_subkeys) (REG_KEY *, int *count, REG_KEY ***); + WERROR (*fetch_values) (REG_KEY *, int *count, REG_VAL ***); + + /* Security control */ + WERROR (*key_get_sec_desc) (REG_KEY *, SEC_DESC **); + WERROR (*key_set_sec_desc) (REG_KEY *, SEC_DESC *); + + /* Notification */ + WERROR (*request_key_change_notify) (REG_KEY *, key_notification_function); + WERROR (*request_value_change_notify) (REG_VAL *, value_notification_function); /* Key management */ - BOOL (*add_key)(REG_KEY *, const char *name); - BOOL (*del_key)(REG_KEY *); + WERROR (*add_key)(REG_KEY *, const char *name, uint32 access_mask, SEC_DESC *, REG_KEY **); + WERROR (*del_key)(REG_KEY *); /* Value management */ - REG_VAL *(*add_value)(REG_KEY *, const char *name, int type, void *data, int len); - BOOL (*del_value)(REG_VAL *); + WERROR (*add_value)(REG_KEY *, const char *name, int type, void *data, int len); + WERROR (*del_value)(REG_VAL *); /* If update is not available, value will first be deleted and then added * again */ - BOOL (*update_value)(REG_VAL *, int type, void *data, int len); + WERROR (*update_value)(REG_VAL *, int type, void *data, int len); void (*free_key_backend_data) (REG_KEY *); void (*free_val_backend_data) (REG_VAL *); @@ -105,7 +118,7 @@ typedef struct reg_sub_tree_s { } REG_SUBTREE; struct reg_handle_s { - REG_OPS *functions; + struct registry_ops *functions; REG_SUBTREE *subtrees; char *location; void *backend_data; @@ -114,7 +127,7 @@ struct reg_handle_s { struct reg_init_function_entry { /* Function to create a member of the pdb_methods list */ - REG_OPS *functions; + struct registry_ops *functions; struct reg_init_function_entry *prev, *next; }; diff --git a/source4/lib/registry/config.m4 b/source4/lib/registry/config.m4 index 146ef92b95..90dc50728b 100644 --- a/source4/lib/registry/config.m4 +++ b/source4/lib/registry/config.m4 @@ -8,9 +8,12 @@ LIBWINREG=libwinregistry PKG_CHECK_MODULES(GCONF, gconf-2.0, [ SMB_MODULE_DEFAULT(reg_gconf,STATIC) CFLAGS="$CFLAGS $GCONF_CFLAGS";], [AC_MSG_WARN([GConf not found, not building reg_gconf])]) +PKG_CHECK_MODULES(GTK, glib-2.0 gtk+-2.0, [ CFLAGS="$CFLAGS $GTK_CFLAGS"; ], [ AC_MSG_WARN([Will be unable to build gregedit])]) + SMB_MODULE(reg_nt4, REG, STATIC, lib/registry/reg_backend_nt4/reg_backend_nt4.o) SMB_MODULE(reg_dir, REG, STATIC, lib/registry/reg_backend_dir/reg_backend_dir.o) SMB_MODULE(reg_rpc, REG, STATIC, lib/registry/reg_backend_rpc/reg_backend_rpc.o) SMB_MODULE(reg_gconf, REG, NOT, lib/registry/reg_backend_gconf/reg_backend_gconf.o, [], [$GCONF_LIBS]) +SMB_MODULE(reg_ldb, REG, STATIC, lib/registry/reg_backend_ldb/reg_backend_ldb.o) SMB_SUBSYSTEM(REG,lib/registry/common/reg_interface.o,[lib/registry/common/reg_objects.o lib/registry/common/reg_util.o],lib/registry/common/winregistry_proto.h,[]) AC_CONFIG_FILES(lib/registry/winregistry.pc) diff --git a/source4/lib/registry/reg_backend_dir/reg_backend_dir.c b/source4/lib/registry/reg_backend_dir/reg_backend_dir.c index 9cb15cd285..4daaf3d628 100644 --- a/source4/lib/registry/reg_backend_dir/reg_backend_dir.c +++ b/source4/lib/registry/reg_backend_dir/reg_backend_dir.c @@ -21,7 +21,7 @@ #include "includes.h" #include "lib/registry/common/registry.h" -static BOOL reg_dir_add_key(REG_KEY *parent, const char *name) +static WERROR reg_dir_add_key(REG_KEY *parent, const char *name, uint32 access_mask, SEC_DESC *desc) { char *path; int ret; @@ -29,15 +29,16 @@ static BOOL reg_dir_add_key(REG_KEY *parent, const char *name) path = reg_path_win2unix(path); ret = mkdir(path, 0700); SAFE_FREE(path); - return (ret == 0); + if(ret == 0)return WERR_OK; + return WERR_INVALID_PARAM; } -static BOOL reg_dir_del_key(REG_KEY *k) +static WERROR reg_dir_del_key(REG_KEY *k) { - return (rmdir((char *)k->backend_data) == 0); + return (rmdir((char *)k->backend_data) == 0)?WERR_OK:WERR_GENERAL_FAILURE; } -static REG_KEY *reg_dir_open_key(REG_HANDLE *h, const char *name) +static WERROR reg_dir_open_key(REG_HANDLE *h, const char *name, REG_KEY **subkey) { DIR *d; char *fullpath; @@ -45,7 +46,7 @@ static REG_KEY *reg_dir_open_key(REG_HANDLE *h, const char *name) TALLOC_CTX *mem_ctx = talloc_init("tmp"); if(!name) { DEBUG(0, ("NULL pointer passed as directory name!")); - return NULL; + return WERR_INVALID_PARAM; } fullpath = talloc_asprintf(mem_ctx, "%s%s", h->location, name); fullpath = reg_path_win2unix(fullpath); @@ -54,16 +55,17 @@ static REG_KEY *reg_dir_open_key(REG_HANDLE *h, const char *name) if(!d) { DEBUG(3,("Unable to open '%s': %s\n", fullpath, strerror(errno))); talloc_destroy(mem_ctx); - return NULL; + return WERR_BADFILE; } closedir(d); ret = reg_key_new_abs(name, h, fullpath); talloc_steal(mem_ctx, ret->mem_ctx, fullpath); talloc_destroy(mem_ctx); - return ret; + *subkey = ret; + return WERR_OK; } -static BOOL reg_dir_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***r) +static WERROR reg_dir_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***r) { struct dirent *e; int max = 200; @@ -75,7 +77,7 @@ static BOOL reg_dir_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***r) d = opendir(fullpath); - if(!d) return False; + if(!d) return WERR_INVALID_PARAM; while((e = readdir(d))) { if(e->d_type == DT_DIR && @@ -96,35 +98,35 @@ static BOOL reg_dir_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***r) closedir(d); *r = ar; - return True; + return WERR_OK; } -static BOOL reg_dir_open(REG_HANDLE *h, const char *loc, BOOL try) { - if(!loc) return False; - return True; +static WERROR reg_dir_open(REG_HANDLE *h, const char *loc, const char *credentials) { + if(!loc) return WERR_INVALID_PARAM; + return WERR_OK; } -static REG_VAL *reg_dir_add_value(REG_KEY *p, const char *name, int type, void *data, int len) +static WERROR reg_dir_add_value(REG_KEY *p, const char *name, int type, void *data, int len, REG_VAL **value) { - REG_VAL *ret = reg_val_new(p, NULL); char *fullpath; FILE *fd; - ret->name = name?talloc_strdup(ret->mem_ctx, name):NULL; - fullpath = reg_path_win2unix(strdup(reg_val_get_path(ret))); + *value = reg_val_new(p, NULL); + (*value)->name = name?talloc_strdup((*value)->mem_ctx, name):NULL; + fullpath = reg_path_win2unix(strdup(reg_val_get_path(*value))); fd = fopen(fullpath, "w+"); /* FIXME */ - return NULL; + return WERR_NOT_SUPPORTED; } -static BOOL reg_dir_del_value(REG_VAL *v) +static WERROR reg_dir_del_value(REG_VAL *v) { /* FIXME*/ - return False; + return WERR_NOT_SUPPORTED; } -static REG_OPS reg_backend_dir = { +static struct registry_ops reg_backend_dir = { .name = "dir", .open_registry = reg_dir_open, .open_key = reg_dir_open_key, diff --git a/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c b/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c index 71d3361ce2..1acb3cbcec 100644 --- a/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c +++ b/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c @@ -22,18 +22,26 @@ #include "lib/registry/common/registry.h" #include -static BOOL reg_open_gconf(REG_HANDLE *h, const char *location, BOOL try_complete_load) +static WERROR gerror_to_werror(GError *error) +{ + if(error == NULL) return WERR_OK; + /* FIXME */ + return WERR_FOOBAR; +} + +static WERROR reg_open_gconf(REG_HANDLE *h, const char *location, const char *credentials) { h->backend_data = (void *)gconf_client_get_default(); - return True; + if(!h->backend_data) return WERR_FOOBAR; + return WERR_OK; } -static BOOL reg_close_gconf(REG_HANDLE *h) +static WERROR reg_close_gconf(REG_HANDLE *h) { - return True; + return WERR_OK; } -static REG_KEY *gconf_open_key (REG_HANDLE *h, const char *name) +static WERROR gconf_open_key (REG_HANDLE *h, const char *name, REG_KEY **key) { REG_KEY *ret; char *fullpath = reg_path_win2unix(strdup(name)); @@ -41,16 +49,17 @@ static REG_KEY *gconf_open_key (REG_HANDLE *h, const char *name) /* Check if key exists */ if(!gconf_client_dir_exists((GConfClient *)h->backend_data, fullpath, NULL)) { SAFE_FREE(fullpath); - return NULL; + return WERR_DEST_NOT_FOUND; } ret = reg_key_new_abs(name, h, NULL); ret->backend_data = talloc_strdup(ret->mem_ctx, fullpath); SAFE_FREE(fullpath); - return ret; + *key = ret; + return WERR_OK; } -static BOOL gconf_fetch_values(REG_KEY *p, int *count, REG_VAL ***vals) +static WERROR gconf_fetch_values(REG_KEY *p, int *count, REG_VAL ***vals) { GSList *entries; GSList *cur; @@ -113,22 +122,24 @@ static BOOL gconf_fetch_values(REG_KEY *p, int *count, REG_VAL ***vals) g_slist_free(entries); *vals = ar; - return True; + return WERR_OK; } -static BOOL gconf_fetch_subkeys(REG_KEY *p, int *count, REG_KEY ***subs) +static WERROR gconf_fetch_subkeys(REG_KEY *p, int *count, REG_KEY ***subs) { GSList *dirs; GSList *cur; - REG_KEY **ar = malloc(sizeof(REG_KEY *)); + REG_KEY **ar = talloc_array_p(p->mem_ctx, REG_KEY *, 1); char *fullpath = p->backend_data; cur = dirs = gconf_client_all_dirs((GConfClient*)p->handle->backend_data, fullpath,NULL); (*count) = 0; while(cur) { - ar[(*count)] = reg_key_new_abs(reg_path_unix2win((char *)cur->data), p->handle,NULL); - ar[(*count)]->backend_data = talloc_strdup(ar[*count]->mem_ctx, cur->data); - ar = realloc(ar, sizeof(REG_KEY *) * ((*count)+2)); + char *winpath = reg_path_unix2win(strdup((char *)cur->data)); + ar[(*count)] = reg_key_new_abs(winpath, p->handle,NULL); + free(winpath); + ar[(*count)]->backend_data = reg_path_win2unix(talloc_strdup(ar[*count]->mem_ctx, cur->data)); + ar = talloc_realloc_p(p->mem_ctx, ar, REG_KEY *, (*count)+2); (*count)++; g_free(cur->data); cur = cur->next; @@ -136,10 +147,10 @@ static BOOL gconf_fetch_subkeys(REG_KEY *p, int *count, REG_KEY ***subs) g_slist_free(dirs); *subs = ar; - return True; + return WERR_OK; } -static BOOL gconf_update_value(REG_VAL *val, int type, void *data, int len) +static WERROR gconf_update_value(REG_VAL *val, int type, void *data, int len) { GError *error = NULL; char *keypath = val->backend_data; @@ -152,22 +163,23 @@ static BOOL gconf_update_value(REG_VAL *val, int type, void *data, int len) case REG_EXPAND_SZ: gconf_client_set_string((GConfClient *)val->handle->backend_data, valpath, data, &error); free(valpath); - return (error == NULL); + return gerror_to_werror(error); case REG_DWORD: gconf_client_set_int((GConfClient *)val->handle->backend_data, valpath, *((int *)data), &error); free(valpath); - return (error == NULL); + return gerror_to_werror(error); default: DEBUG(0, ("Unsupported type: %d\n", type)); free(valpath); - return False; + return WERR_NOT_SUPPORTED; } - return False; + + return WERR_NOT_SUPPORTED; } -static REG_OPS reg_backend_gconf = { +static struct registry_ops reg_backend_gconf = { .name = "gconf", .open_registry = reg_open_gconf, .close_registry = reg_close_gconf, diff --git a/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c b/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c index afa60c5c4a..3cc1651519 100644 --- a/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c +++ b/source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c @@ -20,51 +20,96 @@ #include "includes.h" #include "lib/registry/common/registry.h" +#include "lib/ldb/include/ldb.h" + +char *reg_path_to_ldb(TALLOC_CTX *mem_ctx, const char *path) +{ + char *ret = talloc_strdup(mem_ctx, "(dn="); + char *begin = (char *)path; + char *end = NULL; + + while(begin) { + end = strchr(begin, '\\'); + if(end)end = '\0'; + if(end - begin != 0) ret = talloc_asprintf_append(mem_ctx, ret, "key=%s,", begin); + + if(end) { + *end = '\\'; + begin = end+1; + } else begin = NULL; + } + + ret[strlen(ret)-1] = ')'; + return ret; +} /* * Saves the dn as private_data for every key/val */ -static BOOL ldb_open_registry(REG_HANDLE *handle, const char *location, BOOL try_full_load) +static WERROR ldb_open_registry(REG_HANDLE *handle, const char *location, const char *credentials) { struct ldb_context *c; c = ldb_connect(location, 0, NULL); - if(!c) return False; + if(!c) return WERR_FOOBAR; handle->backend_data = c; - return True; + return WERR_OK; } -static BOOL ldb_close_registry(REG_HANDLE *h) +static WERROR ldb_close_registry(REG_HANDLE *h) { - ldb_close(h); - return True; + ldb_close((struct ldb_context *)h->backend_data); + return WERR_OK; } -static BOOL ldb_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***subkeys) +static WERROR ldb_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***subkeys) { - ldb_search(); + struct ldb_context *c = k->handle->backend_data; + char *path; + struct ldb_message **msg; + char *ldap_path; + TALLOC_CTX *mem_ctx = talloc_init("ldb_path"); + REG_KEY *key = NULL; + ldap_path = reg_path_to_ldb(mem_ctx, reg_key_get_path(k)); + + if(ldb_search(c, NULL, LDB_SCOPE_ONELEVEL, ldap_path, NULL,&msg) > 0) { + key = reg_key_new_abs(reg_key_get_path(k), k->handle, ldap_path); + talloc_steal(mem_ctx, key->mem_ctx, ldap_path); + /* FIXME */ + } + + ldap_search_free(c, msg); + talloc_destroy(mem_ctx); + return WERR_OK; } -static REG_KEY *ldb_open_key(REG_HANDLE *h, const char *name) + + +static WERROR ldb_open_key(REG_HANDLE *h, const char *name, REG_KEY **key) { struct ldb_context *c = h->backend_data; char *path; struct ldb_message **msg; - REG_KEY *key = NULL; - (dn=key=Systems, - if(ldb_search(c, NULL, LDP_SCOPE_BASE, "", NULL,&msg) > 0) { - key = reg_key_new_abs(name, h, base); + char *ldap_path; + TALLOC_CTX *mem_ctx = talloc_init("ldb_path"); + ldap_path = reg_path_to_ldb(mem_ctx, name); + + if(ldb_search(c, NULL, LDB_SCOPE_BASE, ldap_path, NULL,&msg) > 0) { + *key = reg_key_new_abs(name, h, ldap_path); + talloc_steal(mem_ctx, (*key)->mem_ctx, ldap_path); + /* FIXME */ } ldap_search_free(c, msg); + talloc_destroy(mem_ctx); - return key; + return WERR_OK;; } -static REG_OPS reg_backend_ldb = { +static struct registry_ops reg_backend_ldb = { .name = "ldb", .open_registry = ldb_open_registry, .close_registry = ldb_close_registry, diff --git a/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c b/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c index ef2565bda8..9d90523a75 100644 --- a/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c +++ b/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c @@ -881,7 +881,7 @@ static KEY_SEC_DESC *process_sk(REG_HANDLE *regf, SK_HDR *sk_hdr, int sk_off, in /* * Process a VK header and return a value */ -static REG_VAL *vk_to_val(REG_KEY *parent, VK_HDR *vk_hdr, int size) +static WERROR vk_to_val(REG_KEY *parent, VK_HDR *vk_hdr, int size, REG_VAL **value) { char val_name[1024]; REGF *regf = parent->handle->backend_data; @@ -889,12 +889,12 @@ static REG_VAL *vk_to_val(REG_KEY *parent, VK_HDR *vk_hdr, int size) const char *val_type; REG_VAL *tmp = NULL; - if (!vk_hdr) return NULL; + if (!vk_hdr) return WERR_INVALID_PARAM; if ((vk_id = SVAL(&vk_hdr->VK_ID,0)) != str_to_dword("vk")) { DEBUG(0, ("Unrecognized VK header ID: %0X, block: %0X, %s\n", vk_id, (int)vk_hdr, parent->handle->location)); - return NULL; + return WERR_GENERAL_FAILURE; } nam_len = SVAL(&vk_hdr->nam_len,0); @@ -943,7 +943,8 @@ static REG_VAL *vk_to_val(REG_KEY *parent, VK_HDR *vk_hdr, int size) tmp->data_len = dat_len; } - return tmp; + *value = tmp; + return WERR_OK; } static BOOL vl_verify(VL_TYPE vl, int count, int size) @@ -956,63 +957,67 @@ static BOOL vl_verify(VL_TYPE vl, int count, int size) return True; } -static BOOL lf_verify(REG_HANDLE *h, LF_HDR *lf_hdr, int size) +static WERROR lf_verify(REG_HANDLE *h, LF_HDR *lf_hdr, int size) { int lf_id; if ((lf_id = SVAL(&lf_hdr->LF_ID,0)) != str_to_dword("lf")) { DEBUG(0, ("Unrecognized LF Header format: %0X, Block: %0X, %s.\n", lf_id, (int)lf_hdr, h->location)); - return False; + return WERR_INVALID_PARAM; } - return True; + return WERR_OK; } -static int lf_num_entries(REG_HANDLE *h, LF_HDR *lf_hdr, int size) +static WERROR lf_num_entries(REG_HANDLE *h, LF_HDR *lf_hdr, int size, int *count) { - int count; + WERROR error; - if(!lf_verify(h, lf_hdr, size)) return 0; + error = lf_verify(h, lf_hdr, size); + if(!W_ERROR_IS_OK(error)) return error; SMB_REG_ASSERT(size < 0); - count = SVAL(&lf_hdr->key_count,0); - DEBUG(2, ("Key Count: %u\n", count)); - if (count <= 0) return 0; + *count = SVAL(&lf_hdr->key_count,0); + DEBUG(2, ("Key Count: %u\n", *count)); + if (*count <= 0) return WERR_INVALID_PARAM; - return count; + return WERR_OK; } -static REG_KEY *nk_to_key(REG_HANDLE *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent); +static WERROR nk_to_key(REG_HANDLE *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent, REG_KEY **); /* * Process an LF Header and return a list of sub-keys */ -static REG_KEY *lf_get_entry(REG_KEY *parent, LF_HDR *lf_hdr, int size, int n) +static WERROR lf_get_entry(REG_KEY *parent, LF_HDR *lf_hdr, int size, int n, REG_KEY **key) { REGF *regf = parent->handle->backend_data; int count, nk_off; NK_HDR *nk_hdr; + WERROR error; - if (!lf_hdr) return NULL; + if (!lf_hdr) return WERR_INVALID_PARAM; - if(!lf_verify(parent->handle, lf_hdr, size)) return NULL; + error = lf_verify(parent->handle, lf_hdr, size); + if(!W_ERROR_IS_OK(error)) return error; SMB_REG_ASSERT(size < 0); count = SVAL(&lf_hdr->key_count,0); DEBUG(2, ("Key Count: %u\n", count)); - if (count <= 0 || n > count) return NULL; + if (count <= 0) return WERR_GENERAL_FAILURE; + if (n >= count) return WERR_NO_MORE_ITEMS; nk_off = IVAL(&lf_hdr->hr[n].nk_off,0); DEBUG(2, ("NK Offset: %0X\n", nk_off)); nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off); - return nk_to_key(parent->handle, nk_hdr, BLK_SIZE(nk_hdr), parent); + return nk_to_key(parent->handle, nk_hdr, BLK_SIZE(nk_hdr), parent, key); } -static REG_KEY *nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *parent) +static WERROR nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *parent, REG_KEY **key) { REGF *regf = h->backend_data; REG_KEY *tmp = NULL, *own; @@ -1022,12 +1027,12 @@ static REG_KEY *nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *pare int type; char key_name[1024], cls_name[1024]; - if (!nk_hdr) return NULL; + if (!nk_hdr) return WERR_INVALID_PARAM; if ((nk_id = SVAL(&nk_hdr->NK_ID,0)) != str_to_dword("nk")) { DEBUG(0, ("Unrecognized NK Header format: %08X, Block: %0X. %s\n", nk_id, (int)nk_hdr, parent->handle->location)); - return NULL; + return WERR_INVALID_PARAM; } SMB_REG_ASSERT(size < 0); @@ -1047,7 +1052,7 @@ static REG_KEY *nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *pare DEBUG(0, ("Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr)); DEBUG(0, ("Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n", sizeof(NK_HDR), name_len, clsname_len)); - /*return NULL;*/ + return WERR_GENERAL_FAILURE; } DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", name_len, clsname_len)); @@ -1062,7 +1067,7 @@ static REG_KEY *nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *pare type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY); if(type == REG_ROOT_KEY && parent) { DEBUG(0,("Root key encountered below root level!\n")); - return NULL; + return WERR_GENERAL_FAILURE; } if(type == REG_ROOT_KEY) tmp = reg_key_new_abs(key_name, h, nk_hdr); @@ -1121,7 +1126,8 @@ static REG_KEY *nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *pare } - return tmp; + *key = tmp; + return WERR_OK; } /* @@ -1559,7 +1565,7 @@ error: return NULL; } -static BOOL nt_close_registry (REG_HANDLE *h) +static WERROR nt_close_registry (REG_HANDLE *h) { REGF *regf = h->backend_data; if (regf->base) munmap(regf->base, regf->sbuf.st_size); @@ -1570,10 +1576,10 @@ static BOOL nt_close_registry (REG_HANDLE *h) regf->sk_count = regf->sk_map_size = 0; free(regf); - return False; + return WERR_OK; } -static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load) +static WERROR nt_open_registry (REG_HANDLE *h, const char *location, const char *credentials) { REGF *regf = (REGF *)malloc(sizeof(REGF)); REGF_HDR *regf_hdr; @@ -1582,7 +1588,7 @@ static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load memset(regf, 0, sizeof(REGF)); regf->mem_ctx = talloc_init("regf"); - regf->owner_sid_str = def_owner_sid_str; + regf->owner_sid_str = credentials; h->backend_data = regf; DEBUG(5, ("Attempting to load registry file\n")); @@ -1591,7 +1597,7 @@ static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) { DEBUG(0, ("Unable to get header\n")); - return False; + return WERR_GENERAL_FAILURE; } /* Now process that header and start to read the rest in */ @@ -1599,7 +1605,7 @@ static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load if ((regf_id = IVAL(®f_hdr->REGF_ID,0)) != str_to_dword("regf")) { DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n", regf_id, h->location)); - return False; + return WERR_GENERAL_FAILURE; } /* @@ -1608,7 +1614,7 @@ static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load if (!valid_regf_hdr(regf_hdr)) { DEBUG(0, ("Registry file header does not validate: %s\n", h->location)); - return False; + return WERR_GENERAL_FAILURE; } /* Update the last mod date, and then go get the first NK record and on */ @@ -1625,7 +1631,7 @@ static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) { DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", hbin_id, h->location)); - return False; + return WERR_GENERAL_FAILURE; } /* @@ -1655,15 +1661,15 @@ static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load h->backend_data = regf; - return True; + return WERR_OK; } -static REG_KEY *nt_get_root_key(REG_HANDLE *h) +static WERROR nt_get_root_key(REG_HANDLE *h, REG_KEY **key) { - return nk_to_key(h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL); + return nk_to_key(h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL, key); } -static int nt_num_subkeys(REG_KEY *k) +static WERROR nt_num_subkeys(REG_KEY *k, int *num) { REGF *regf = k->handle->backend_data; LF_HDR *lf_hdr; @@ -1671,19 +1677,23 @@ static int nt_num_subkeys(REG_KEY *k) NK_HDR *nk_hdr = k->backend_data; lf_off = IVAL(&nk_hdr->lf_off,0); DEBUG(2, ("SubKey list offset: %0X\n", lf_off)); - if(lf_off == -1) return 0; + if(lf_off == -1) { + *num = 0; + return WERR_OK; + } lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); - return lf_num_entries(k->handle, lf_hdr, BLK_SIZE(lf_hdr)); + return lf_num_entries(k->handle, lf_hdr, BLK_SIZE(lf_hdr), num); } -static int nt_num_values(REG_KEY *k) +static WERROR nt_num_values(REG_KEY *k, int *count) { NK_HDR *nk_hdr = k->backend_data; - return IVAL(&nk_hdr->val_cnt,0); + *count = IVAL(&nk_hdr->val_cnt,0); + return WERR_OK; } -static REG_VAL *nt_value_by_index(REG_KEY *k, int n) +static WERROR nt_value_by_index(REG_KEY *k, int n, REG_VAL **value) { VL_TYPE *vl; int val_off, vk_off; @@ -1696,10 +1706,10 @@ static REG_VAL *nt_value_by_index(REG_KEY *k, int n) vk_off = IVAL(&vl[n],0); vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off); - return vk_to_val(k, vk_hdr, BLK_SIZE(vk_hdr)); + return vk_to_val(k, vk_hdr, BLK_SIZE(vk_hdr), value); } -static REG_KEY *nt_key_by_index(REG_KEY *k, int n) +static WERROR nt_key_by_index(REG_KEY *k, int n, REG_KEY **subkey) { REGF *regf = k->handle->backend_data; int lf_off; @@ -1714,13 +1724,13 @@ static REG_KEY *nt_key_by_index(REG_KEY *k, int n) if (lf_off != -1) { lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off); - return lf_get_entry(k, lf_hdr, BLK_SIZE(lf_hdr), n); + return lf_get_entry(k, lf_hdr, BLK_SIZE(lf_hdr), n, subkey); } - return NULL; + return WERR_NO_MORE_ITEMS; } -static REG_OPS reg_backend_nt4 = { +static struct registry_ops reg_backend_nt4 = { .name = "nt4", .open_registry = nt_open_registry, .close_registry = nt_close_registry, diff --git a/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c b/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c index ad4d537f9b..e61301d6f2 100644 --- a/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c +++ b/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c @@ -77,12 +77,18 @@ struct { { NULL, NULL } }; -static BOOL rpc_open_registry(REG_HANDLE *h, const char *location, BOOL try_full) +static WERROR rpc_open_registry(REG_HANDLE *h, const char *location, const char *credentials) { - BOOL res = True; struct rpc_data *mydata = talloc(h->mem_ctx, sizeof(struct rpc_data)); char *binding = strdup(location); NTSTATUS status; + char *user, *pass; + + if(!credentials || !location) return WERR_INVALID_PARAM; + + user = talloc_strdup(h->mem_ctx, credentials); + pass = strchr(user, '%'); + *pass = '\0'; pass++; ZERO_STRUCTP(mydata); @@ -90,26 +96,26 @@ static BOOL rpc_open_registry(REG_HANDLE *h, const char *location, BOOL try_full DCERPC_WINREG_UUID, DCERPC_WINREG_VERSION, lp_workgroup(), - "tridge", "samba"); + user, pass); - if(!NT_STATUS_IS_OK(status)) return False; h->backend_data = mydata; - return True; + return ntstatus_to_werror(status); } -static REG_KEY *rpc_open_root(REG_HANDLE *h) +static WERROR rpc_open_root(REG_HANDLE *h, REG_KEY **k) { /* There's not really a 'root' key here */ - return reg_key_new_abs("\\", h, h->backend_data); + *k = reg_key_new_abs("\\", h, h->backend_data); + return WERR_OK; } -static BOOL rpc_close_registry(REG_HANDLE *h) +static WERROR rpc_close_registry(REG_HANDLE *h) { dcerpc_pipe_close(((struct rpc_data *)h->backend_data)->pipe); free(h->backend_data); - return True; + return WERR_OK; } static struct policy_handle *rpc_get_key_handle(REG_HANDLE *h, const char *path) @@ -161,12 +167,15 @@ static struct policy_handle *rpc_get_key_handle(REG_HANDLE *h, const char *path) return key_handle; } -static REG_KEY *rpc_open_key(REG_HANDLE *h, const char *name) +static WERROR rpc_open_key(REG_HANDLE *h, const char *name, REG_KEY **key) { - return reg_key_new_abs(name, h, rpc_get_key_handle(h, name)); + struct policy_handle *pol = rpc_get_key_handle(h, name); + if(!pol) return WERR_DEST_NOT_FOUND; + *key = reg_key_new_abs(name, h, pol); + return WERR_OK; } -static BOOL rpc_fetch_subkeys(REG_KEY *parent, int *count, REG_KEY ***subkeys) +static WERROR rpc_fetch_subkeys(REG_KEY *parent, int *count, REG_KEY ***subkeys) { struct winreg_EnumKey r; struct winreg_EnumKeyNameRequest keyname; @@ -188,12 +197,12 @@ static BOOL rpc_fetch_subkeys(REG_KEY *parent, int *count, REG_KEY ***subkeys) *subkeys = ar; - return True; + return WERR_OK; } if(!parent->backend_data) parent->backend_data = rpc_get_key_handle(parent->handle, reg_key_get_path(parent)); - if(!parent->backend_data) return False; + if(!parent->backend_data) return WERR_GENERAL_FAILURE; (*count) = 0; r.in.handle = parent->backend_data; @@ -219,10 +228,10 @@ static BOOL rpc_fetch_subkeys(REG_KEY *parent, int *count, REG_KEY ***subkeys) } *subkeys = ar; - return True; + return r.out.result; } -static BOOL rpc_fetch_values(REG_KEY *parent, int *count, REG_VAL ***values) +static WERROR rpc_fetch_values(REG_KEY *parent, int *count, REG_VAL ***values) { struct winreg_EnumValue r; struct winreg_Uint8buf value; @@ -238,12 +247,12 @@ static BOOL rpc_fetch_values(REG_KEY *parent, int *count, REG_VAL ***values) /* Root */ if(parent->backend_data == parent->handle->backend_data) { *values = ar; - return True; + return WERR_OK; } if(!parent->backend_data) parent->backend_data = rpc_get_key_handle(parent->handle, reg_key_get_path(parent)); - if(!parent->backend_data) return False; + if(!parent->backend_data) return WERR_GENERAL_FAILURE; r.in.handle = parent->backend_data; r.in.enum_index = 0; @@ -283,22 +292,48 @@ static BOOL rpc_fetch_values(REG_KEY *parent, int *count, REG_VAL ***values) *values = ar; - return True; + return r.out.result; } -static BOOL rpc_add_key(REG_KEY *parent, const char *name) +static WERROR rpc_add_key(REG_KEY *parent, const char *name) { /* FIXME */ - return False; + return WERR_NOT_SUPPORTED; } -static BOOL rpc_del_key(REG_KEY *k) +static struct policy_handle*get_hive(REG_KEY *k) { - /* FIXME */ - return False; + int i; + struct rpc_data *mydata = k->handle->backend_data; + for(i = 0; known_hives[i].name; i++) { + if(!strncmp(known_hives[i].name, reg_key_get_path(k)+1, strlen(known_hives[i].name))) + return mydata->hives[i]; + } + return NULL; +} + +static WERROR rpc_del_key(REG_KEY *k) +{ + NTSTATUS status; + struct rpc_data *mydata = k->handle->backend_data; + struct winreg_DeleteKey r; + char *hivepath; + struct policy_handle *hive = get_hive(k); + + printf("first: %s\n", reg_key_get_path(k)); + hivepath = strchr(reg_key_get_path(k), '\\'); + hivepath = strchr(hivepath+1, '\\'); + printf("asfter: %s\n", hivepath+1); + + r.in.handle = hive; + init_winreg_String(&r.in.key, hivepath+1); + + status = dcerpc_winreg_DeleteKey(mydata->pipe, k->mem_ctx, &r); + + return r.out.result; } -static REG_OPS reg_backend_rpc = { +static struct registry_ops reg_backend_rpc = { .name = "rpc", .open_registry = rpc_open_registry, .close_registry = rpc_close_registry, diff --git a/source4/lib/registry/reg_backend_wine/reg_backend_wine.c b/source4/lib/registry/reg_backend_wine/reg_backend_wine.c index 6c8d7885cb..fd7d04bcf0 100644 --- a/source4/lib/registry/reg_backend_wine/reg_backend_wine.c +++ b/source4/lib/registry/reg_backend_wine/reg_backend_wine.c @@ -20,6 +20,7 @@ #include "includes.h" #include "lib/registry/common/registry.h" +#include "windows/registry.h" static REG_OPS reg_backend_wine = { .name = "wine", diff --git a/source4/lib/registry/tools/gregedit.c b/source4/lib/registry/tools/gregedit.c new file mode 100644 index 0000000000..b62fd7ec04 --- /dev/null +++ b/source4/lib/registry/tools/gregedit.c @@ -0,0 +1,758 @@ +/* + Unix SMB/CIFS implementation. + Gtk registry frontend + + Copyright (C) Jelmer Vernooij 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include "includes.h" + +GtkWidget *openfilewin; +GtkWidget *savefilewin; +GtkTreeStore *store_keys; +GtkListStore *store_vals; +GtkWidget *tree_keys; +GtkWidget *aboutwin; +GtkWidget *mainwin; + +GtkWidget *rpcwin; +GtkWidget *rpcwin_host; +GtkWidget *rpcwin_user; +GtkWidget *rpcwin_password; +GtkWidget *save; +GtkWidget *save_as; +GtkWidget* create_openfilewin (void); +GtkWidget* create_savefilewin (void); +static GtkWidget* create_aboutwin (void); +REG_HANDLE *registry = NULL; + +static void gtk_show_werror(WERROR err) +{ + GtkWidget *dialog = gtk_message_dialog_new( GTK_WINDOW(mainwin), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "Registry error: %s\n", win_errstr(err)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static void treeview_add_val(REG_VAL *val) +{ + GtkTreeIter iter; + gtk_list_store_append(store_vals, &iter); + gtk_list_store_set (store_vals, + &iter, + 0, + reg_val_name(val), + 1, + str_regtype(reg_val_type(val)), + 2, + reg_val_data_string(val), + 3, + val, + -1); +} + +static void expand_key(GtkTreeView *treeview, GtkTreeIter *parent, GtkTreePath *arg2) +{ + GtkTreeIter iter, tmpiter; + REG_KEY *k, *sub; + char *name; + GValue value; + WERROR error; + int i; + + /* See if this row has ever had a name gtk_tree_store_set()'ed to it. + If not, read the directory contents */ + gtk_tree_model_get(GTK_TREE_MODEL(store_keys), parent, + 0, &name, -1); + + if(!name) return; + + gtk_tree_model_get(GTK_TREE_MODEL(store_keys), parent, 1, &k, -1); + + g_assert(k); + + for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(k, i, &sub)); i++) { + /* Replace the blank child with the first directory entry + You may be tempted to remove the blank child node and then + append a new one. Don't. If you remove the blank child + node GTK gets confused and won't expand the parent row. */ + + if(i == 0) { + gtk_tree_model_iter_children(GTK_TREE_MODEL(store_keys), + &iter, parent); + } else { + gtk_tree_store_append(store_keys, &iter, parent); + } + gtk_tree_store_set (store_keys, + &iter, + 0, + reg_key_name(sub), + 1, + sub, + -1); + + gtk_tree_store_append(store_keys, &tmpiter, &iter); + } + + /* Remove placeholder child */ + if(i == 0) { + gtk_tree_model_iter_children(GTK_TREE_MODEL(store_keys), + &iter, parent); + gtk_tree_store_remove(store_keys, &iter); + } + + if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) gtk_show_werror(error); +} + +static void registry_load_root() +{ + REG_KEY *root; + GtkTreeIter iter, tmpiter; + WERROR error; + if(!registry) return; + + error = reg_get_root(registry, &root); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + return; + } + + gtk_tree_store_clear(store_keys); + + /* Add the root */ + gtk_tree_store_append(store_keys, &iter, NULL); + gtk_tree_store_set (store_keys, + &iter, + 0, + reg_key_name(root), + 1, + root, + -1); + + gtk_tree_store_append(store_keys, &tmpiter, &iter); + + gtk_widget_set_sensitive( save, True ); + gtk_widget_set_sensitive( save_as, True ); +} + +GtkWidget* create_rpcwin (void) +{ + GtkWidget *dialog_vbox1; + GtkWidget *table1; + GtkWidget *label1; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *dialog_action_area1; + GtkWidget *cancelbutton1; + GtkWidget *okbutton1; + + rpcwin = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (rpcwin), "Connect to remote server"); + + dialog_vbox1 = GTK_DIALOG (rpcwin)->vbox; + gtk_widget_show (dialog_vbox1); + + table1 = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 0); + + label1 = gtk_label_new ("Host:"); + gtk_widget_show (label1); + gtk_table_attach (GTK_TABLE (table1), label1, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5); + + label2 = gtk_label_new ("User:"); + gtk_widget_show (label2); + gtk_table_attach (GTK_TABLE (table1), label2, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5); + + label3 = gtk_label_new ("Password:"); + gtk_widget_show (label3); + gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5); + + rpcwin_host = gtk_entry_new (); + gtk_widget_show (rpcwin_host); + gtk_table_attach (GTK_TABLE (table1), rpcwin_host, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + rpcwin_user = gtk_entry_new (); + gtk_widget_show (rpcwin_user); + gtk_table_attach (GTK_TABLE (table1), rpcwin_user, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + rpcwin_password = gtk_entry_new (); + gtk_widget_show (rpcwin_password); + gtk_table_attach (GTK_TABLE (table1), rpcwin_password, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_visibility (GTK_ENTRY (rpcwin_password), FALSE); + + dialog_action_area1 = GTK_DIALOG (rpcwin)->action_area; + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + + cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (rpcwin), cancelbutton1, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton1, GTK_CAN_DEFAULT); + + okbutton1 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (rpcwin), okbutton1, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT); + + return rpcwin; +} + + +static void on_open_nt4_activate (GtkMenuItem *menuitem, gpointer user_data) +{ + gint result = gtk_dialog_run(GTK_DIALOG(create_openfilewin())); + char *filename; + WERROR error; + switch(result) { + case GTK_RESPONSE_OK: + filename = strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(openfilewin))); + error = reg_open("nt4", filename, NULL, ®istry); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + return; + } + registry_load_root(); + break; + default: + break; + } + + gtk_widget_destroy(openfilewin); +} + +void on_open_gconf_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + WERROR error = reg_open("gconf", NULL, NULL, ®istry); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + return; + } + + registry_load_root(); +} + +void +on_open_remote_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + char *location, *credentials; + gint result = gtk_dialog_run(GTK_DIALOG(create_rpcwin())); + WERROR error; + switch(result) { + case GTK_RESPONSE_OK: + asprintf(&location, "ncacn_np:%s", gtk_entry_get_text(GTK_ENTRY(rpcwin_host))); + asprintf(&credentials, "%s%%%s", gtk_entry_get_text(GTK_ENTRY(rpcwin_user)), gtk_entry_get_text(GTK_ENTRY(rpcwin_password))); + error = reg_open("rpc", location, credentials, ®istry); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + return; + } + free(location); free(credentials); + registry_load_root(); + break; + default: + break; + } + + gtk_widget_destroy(rpcwin); +} + + +void +on_save_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + WERROR error = reg_save(registry, NULL); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + } +} + + +void +on_save_as_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + gint result; + WERROR error; + create_savefilewin(); + result = gtk_dialog_run(GTK_DIALOG(savefilewin)); + switch(result) { + case GTK_RESPONSE_OK: + error = reg_save(registry, gtk_file_selection_get_filename(GTK_FILE_SELECTION(savefilewin))); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + } + break; + + default: + break; + + } + gtk_widget_destroy(savefilewin); +} + + +void +on_quit_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + gtk_main_quit(); +} + + +void +on_cut_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* FIXME */ +} + + +void +on_copy_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* FIXME */ +} + + +void +on_paste_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* FIXME */ +} + + +void +on_delete_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + /* FIXME */ +} + + +void +on_about_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + gtk_dialog_run(GTK_DIALOG(create_aboutwin())); + gtk_widget_destroy(aboutwin); +} + +void on_key_activate (GtkTreeView *treeview, + GtkTreePath *path, + gpointer user_data) +{ + int i; + REG_KEY *k; + REG_VAL *val; + WERROR error; + +//FIXME gtk_tree_model_get(GTK_TREE_MODEL(store_keys), iter, 1, &k, -1); + + gtk_list_store_clear(store_vals); + + for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(k, i, &val)); i++) { + treeview_add_val(val); + } + + if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) gtk_show_werror(error); + + return; +} + +GtkWidget* create_mainwin (void) +{ + GtkWidget *vbox1; + GtkWidget *menubar; + GtkWidget *menu_file; + GtkWidget *menu_file_menu; + GtkWidget *open_nt4; + GtkWidget *open_gconf; + GtkWidget *open_remote; + GtkWidget *separatormenuitem1; + GtkWidget *quit; + GtkWidget *men_edit; + GtkWidget *men_edit_menu; + GtkWidget *cut; + GtkWidget *copy; + GtkWidget *paste; + GtkWidget *delete; + GtkCellRenderer *renderer; + GtkTreeViewColumn *curcol; + GtkWidget *help; + GtkWidget *help_menu; + GtkWidget *about; + GtkWidget *hbox1; + GtkWidget *scrolledwindow1; + GtkWidget *scrolledwindow2; + GtkWidget *tree_vals; + GtkWidget *statusbar; + GtkAccelGroup *accel_group; + GtkTreeIter iter, child; + + accel_group = gtk_accel_group_new (); + + mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (mainwin), "Registry editor"); + gtk_window_set_default_size (GTK_WINDOW (mainwin), 642, 562); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (mainwin), vbox1); + + menubar = gtk_menu_bar_new (); + gtk_widget_show (menubar); + gtk_box_pack_start (GTK_BOX (vbox1), menubar, FALSE, FALSE, 0); + + menu_file = gtk_menu_item_new_with_mnemonic ("_File"); + gtk_widget_show (menu_file); + gtk_container_add (GTK_CONTAINER (menubar), menu_file); + + menu_file_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_file), menu_file_menu); + + open_nt4 = gtk_image_menu_item_new_with_mnemonic("_Open NT4 file"); + gtk_widget_show (open_nt4); + gtk_container_add (GTK_CONTAINER (menu_file_menu), open_nt4); + + open_gconf = gtk_image_menu_item_new_with_mnemonic ("_Open GConf"); + gtk_widget_show (open_gconf); + gtk_container_add (GTK_CONTAINER (menu_file_menu), open_gconf); + + open_remote = gtk_menu_item_new_with_mnemonic ("_Open Remote"); + gtk_widget_show (open_remote); + gtk_container_add (GTK_CONTAINER (menu_file_menu), open_remote); + + save = gtk_image_menu_item_new_from_stock ("gtk-save", accel_group); + gtk_widget_show (save); + gtk_widget_set_sensitive( save, False ); + gtk_container_add (GTK_CONTAINER (menu_file_menu), save); + + save_as = gtk_image_menu_item_new_from_stock ("gtk-save-as", accel_group); + gtk_widget_show (save_as); + gtk_widget_set_sensitive( save_as, False ); + gtk_container_add (GTK_CONTAINER (menu_file_menu), save_as); + + separatormenuitem1 = gtk_menu_item_new (); + gtk_widget_show (separatormenuitem1); + gtk_container_add (GTK_CONTAINER (menu_file_menu), separatormenuitem1); + gtk_widget_set_sensitive (separatormenuitem1, FALSE); + + quit = gtk_image_menu_item_new_from_stock ("gtk-quit", accel_group); + gtk_widget_show (quit); + gtk_container_add (GTK_CONTAINER (menu_file_menu), quit); + + men_edit = gtk_menu_item_new_with_mnemonic ("_Edit"); + gtk_widget_show (men_edit); + gtk_container_add (GTK_CONTAINER (menubar), men_edit); + + men_edit_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (men_edit), men_edit_menu); + + cut = gtk_image_menu_item_new_from_stock ("gtk-cut", accel_group); + gtk_widget_show (cut); + gtk_widget_set_sensitive(cut, False); + gtk_container_add (GTK_CONTAINER (men_edit_menu), cut); + + copy = gtk_image_menu_item_new_from_stock ("gtk-copy", accel_group); + gtk_widget_show (copy); + gtk_widget_set_sensitive(copy, False); + gtk_container_add (GTK_CONTAINER (men_edit_menu), copy); + + paste = gtk_image_menu_item_new_from_stock ("gtk-paste", accel_group); + gtk_widget_show (paste); + gtk_widget_set_sensitive(paste, False); + gtk_container_add (GTK_CONTAINER (men_edit_menu), paste); + + delete = gtk_image_menu_item_new_from_stock ("gtk-delete", accel_group); + gtk_widget_show (delete); + gtk_widget_set_sensitive(delete, False); + gtk_container_add (GTK_CONTAINER (men_edit_menu), delete); + + help = gtk_menu_item_new_with_mnemonic ("_Help"); + gtk_widget_show (help); + gtk_container_add (GTK_CONTAINER (menubar), help); + + help_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (help), help_menu); + + about = gtk_menu_item_new_with_mnemonic ("_About"); + gtk_widget_show (about); + gtk_container_add (GTK_CONTAINER (help_menu), about); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0); + + tree_keys = gtk_tree_view_new (); + + /* Column names */ + curcol = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title(curcol, "Name"); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(curcol, renderer, True); + + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_keys), curcol); + + gtk_tree_view_column_add_attribute(curcol, renderer, "text", 0); + gtk_widget_show (tree_keys); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), tree_keys); + store_keys = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_keys), GTK_TREE_MODEL(store_keys)); + g_object_unref(store_keys); + + g_signal_connect ((gpointer) tree_keys, "row-activated", + G_CALLBACK (on_key_activate), + NULL); + + g_signal_connect ((gpointer) tree_keys, "row-expanded", + G_CALLBACK (expand_key), + NULL); + + scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow2); + gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow2, TRUE, TRUE, 0); + + tree_vals = gtk_tree_view_new (); + /* Column names */ + curcol = gtk_tree_view_column_new_with_attributes ("Name", gtk_cell_renderer_text_new(), NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_vals), curcol); + + + curcol = gtk_tree_view_column_new_with_attributes ("Type", gtk_cell_renderer_text_new(), NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_vals), curcol); + + curcol = gtk_tree_view_column_new_with_attributes ("Value", gtk_cell_renderer_text_new(), NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_vals), curcol); + gtk_widget_show (tree_vals); + gtk_container_add (GTK_CONTAINER (scrolledwindow2), tree_vals); + + store_vals = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree_vals), GTK_TREE_MODEL(store_vals)); + g_object_unref(store_vals); + + statusbar = gtk_statusbar_new (); + gtk_widget_show (statusbar); + gtk_box_pack_start (GTK_BOX (vbox1), statusbar, FALSE, FALSE, 0); + gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbar), FALSE); + + g_signal_connect ((gpointer) open_nt4, "activate", + G_CALLBACK (on_open_nt4_activate), + NULL); + g_signal_connect ((gpointer) open_gconf, "activate", + G_CALLBACK (on_open_gconf_activate), + NULL); + g_signal_connect ((gpointer) open_remote, "activate", + G_CALLBACK (on_open_remote_activate), + NULL); + g_signal_connect ((gpointer) save, "activate", + G_CALLBACK (on_save_activate), + NULL); + g_signal_connect ((gpointer) save_as, "activate", + G_CALLBACK (on_save_as_activate), + NULL); + g_signal_connect ((gpointer) quit, "activate", + G_CALLBACK (on_quit_activate), + NULL); + g_signal_connect ((gpointer) cut, "activate", + G_CALLBACK (on_cut_activate), + NULL); + g_signal_connect ((gpointer) copy, "activate", + G_CALLBACK (on_copy_activate), + NULL); + g_signal_connect ((gpointer) paste, "activate", + G_CALLBACK (on_paste_activate), + NULL); + g_signal_connect ((gpointer) delete, "activate", + G_CALLBACK (on_delete_activate), + NULL); + g_signal_connect ((gpointer) about, "activate", + G_CALLBACK (on_about_activate), + NULL); + + gtk_window_add_accel_group (GTK_WINDOW (mainwin), accel_group); + + return mainwin; +} + +static GtkWidget* create_aboutwin (void) +{ + GtkWidget *dialog_vbox1; + GtkWidget *image1; + GtkWidget *label1; + GtkWidget *label2; + GtkWidget *dialog_action_area1; + GtkWidget *closebutton1; + + aboutwin = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (aboutwin), "About GRegEdit"); + gtk_window_set_resizable (GTK_WINDOW (aboutwin), FALSE); + + dialog_vbox1 = GTK_DIALOG (aboutwin)->vbox; + gtk_widget_show (dialog_vbox1); + + /* FIXME: Samba logo ? + image1 = create_pixmap (aboutwin, "samba.png"); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), image1, FALSE, TRUE, 0); */ + + label1 = gtk_label_new ("GRegEdit 0.1"); + gtk_widget_show (label1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), label1, FALSE, FALSE, 0); + gtk_label_set_use_markup (GTK_LABEL (label1), TRUE); + + label2 = gtk_label_new_with_mnemonic ("(C) 2004 Jelmer Vernooij \nPart of Samba\nhttp://www.samba.org/\n"); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), label2, TRUE, FALSE, 0); + gtk_label_set_use_markup (GTK_LABEL (label2), TRUE); + + dialog_action_area1 = GTK_DIALOG (aboutwin)->action_area; + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + + closebutton1 = gtk_button_new_from_stock ("gtk-close"); + gtk_widget_show (closebutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (aboutwin), closebutton1, GTK_RESPONSE_CLOSE); + GTK_WIDGET_SET_FLAGS (closebutton1, GTK_CAN_DEFAULT); + + return aboutwin; +} + + +GtkWidget* create_openfilewin (void) +{ + GtkWidget *ok_button; + GtkWidget *cancel_button; + + openfilewin = gtk_file_selection_new ("Select File"); + gtk_container_set_border_width (GTK_CONTAINER (openfilewin), 10); + + ok_button = GTK_FILE_SELECTION (openfilewin)->ok_button; + gtk_widget_show (ok_button); + GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT); + + cancel_button = GTK_FILE_SELECTION (openfilewin)->cancel_button; + gtk_widget_show (cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + return openfilewin; +} + +GtkWidget* create_savefilewin (void) +{ + GtkWidget *ok_button; + GtkWidget *cancel_button; + + savefilewin = gtk_file_selection_new ("Select File"); + gtk_container_set_border_width (GTK_CONTAINER (savefilewin), 10); + + ok_button = GTK_FILE_SELECTION (savefilewin)->ok_button; + gtk_widget_show (ok_button); + GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT); + + cancel_button = GTK_FILE_SELECTION (savefilewin)->cancel_button; + gtk_widget_show (cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + return savefilewin; +} + +int main (int argc, char *argv[]) +{ + poptContext pc; + const char *backend = NULL, *credentials = NULL, *location; + int opt; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL}, + {"credentials", 'c', POPT_ARG_STRING, &credentials, 0, "credentials (user%%password)", NULL}, + POPT_TABLEEND + }; + + gtk_init (&argc, &argv); + + pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0); + + while((opt = poptGetNextOpt(pc)) != -1) { + } + + location = poptGetArg(pc); + + if(location) { + WERROR error; + + if(!backend) { + if(credentials)backend = "rpc"; + else backend = "nt4"; + } + + error = reg_open(backend, location, credentials, ®istry); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(error); + return -1; + } + mainwin = create_mainwin (); + registry_load_root(); + } else + mainwin = create_mainwin (); + + gtk_widget_show (mainwin); + + gtk_main (); + + if(registry)reg_free(registry); + return 0; +} diff --git a/source4/lib/registry/tools/regshell.c b/source4/lib/registry/tools/regshell.c index 9074d1c716..e6b5fa51ee 100644 --- a/source4/lib/registry/tools/regshell.c +++ b/source4/lib/registry/tools/regshell.c @@ -201,6 +201,7 @@ int main (int argc, char **argv) REG_HANDLE *h; struct poptOption long_options[] = { POPT_AUTOHELP + POPT_COMMON_SAMBA {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL}, POPT_TABLEEND }; diff --git a/source4/librpc/idl/winreg.idl b/source4/librpc/idl/winreg.idl index 56c7ba6dde..39e46c0761 100644 --- a/source4/librpc/idl/winreg.idl +++ b/source4/librpc/idl/winreg.idl @@ -72,11 +72,11 @@ [in,out,ref] policy_handle *handle, [in] winreg_String key, [in] winreg_String class, - [in,out] uint32 reserved, + [in] uint32 reserved, + [out] uint32 *unknown, [in] uint32 access_mask, - [in] uint32 sec_info, - [in] sec_desc_buf *sec_desc, - [in] uint32 reserved2 + [in,ref] uint32 *sec_info, + [in] sec_desc_buf *sec_desc ); /******************/ @@ -150,6 +150,14 @@ /******************/ /* Function: 0x0c */ WERROR winreg_GetKeySecurity( + [in,ref] policy_handle *handle, + [in] uint32 sec_info, + [in] uint32 *len1, + [in] uint32 empty, + [in] uint32 len2, + [in] uint32 unknown1, + [in] uint32 unknown2, + [out] sec_desc_buf *data ); /******************/ @@ -211,11 +219,24 @@ /******************/ /* Function: 0x15 */ WERROR winreg_SetKeySecurity( + [in,ref] policy_handle *handle, + [in] uint32 sec_info, + [in] sec_desc_buf *sec_desc ); + typedef struct { + uint32 max_len; + [length_is(buf_max_len)] uint8 *buffer; + uint32 len; + } winreg_Value; + /******************/ /* Function: 0x16 */ WERROR winreg_SetValue( + [in,ref] policy_handle *handle, + [in] winreg_String name, + [in] uint32 type, + [in] winreg_Value value ); /******************/ @@ -226,11 +247,15 @@ /******************/ /* Function: 0x18 */ WERROR winreg_InitiateSystemShutdown( + [in] winreg_String message, + [in] uint32 timeout, + [in] uint16 flags ); /******************/ /* Function: 0x19 */ WERROR winreg_AbortSystemShutdown( + [in,ref] uint16 *server ); /******************/ @@ -264,7 +289,7 @@ /******************/ /* Function: 0x1e */ WERROR winreg_InitiateSystemShutdownEx( - ); + ); /******************/ /* Function: 0x1f */ diff --git a/source4/rpc_server/winreg/rpc_winreg.c b/source4/rpc_server/winreg/rpc_winreg.c index c1d6d6ad69..d9e8b49765 100644 --- a/source4/rpc_server/winreg/rpc_winreg.c +++ b/source4/rpc_server/winreg/rpc_winreg.c @@ -22,6 +22,18 @@ #include "includes.h" +/** + * General notes for the current implementation: + * + * - All hives are currently openened as subkeys of one single registry file + * (e.g. HKCR from \HKEY_CURRENT_USER, etc). This might be changed in + * the future and we might want to make it possible to configure + * what registries are behind which hives (e.g. + * \HKEY_CURRENT_USER -> gconf, + * \HKEY_LOCAL_MACHINE -> tdb, + * etc + */ + enum handle_types { HTYPE_REGKEY, HTYPE_REGVAL }; struct _privatedata { @@ -39,9 +51,10 @@ static void winreg_unbind(struct dcesrv_connection *dc, const struct dcesrv_inte static NTSTATUS winreg_bind(struct dcesrv_call_state *dc, const struct dcesrv_interface *di) { struct _privatedata *data; - data = talloc(dc->mem_ctx, sizeof(struct _privatedata)); - data->registry = reg_open(lp_parm_string(-1,"winreg","subsystem"),lp_parm_string(-1,"winreg", "file"), False); - if(!data->registry) return NT_STATUS_UNSUCCESSFUL; + WERROR error; + data = talloc(dc->conn->mem_ctx, sizeof(struct _privatedata)); + error = reg_open("dir", "/tmp/reg", "", &data->registry); + if(!W_ERROR_IS_OK(error)) return werror_to_ntstatus(error); dc->conn->private = data; return NT_STATUS_OK; } @@ -49,88 +62,78 @@ static NTSTATUS winreg_bind(struct dcesrv_call_state *dc, const struct dcesrv_in #define DCESRV_INTERFACE_WINREG_BIND winreg_bind #define DCESRV_INTERFACE_WINREG_UNBIND winreg_unbind -/* - winreg_OpenHKCR -*/ -static NTSTATUS winreg_OpenHKCR(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKCR *r) -{ - - return NT_STATUS_NOT_IMPLEMENTED; -} - +#define func_winreg_OpenHive(k,n) static NTSTATUS winreg_Open ## k (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_Open ## k *r) \ +{ \ + struct _privatedata *data = dce_call->conn->private; \ + REG_KEY *root/* = reg_get_root(data->registry)*/; \ + REG_KEY *k/* = reg_open_key(root, n)*/; \ +\ + if(!k) { \ + r->out.result = WERR_BADFILE; \ + } else { \ + struct dcesrv_handle *h = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY); \ + h->data = k; \ + r->out.handle = &h->wire_handle; \ + } \ +\ + r->out.result = WERR_OK; \ +\ + return NT_STATUS_OK; \ +} + +func_winreg_OpenHive(HKCR,"\\HKEY_CLASSES_ROOT") +func_winreg_OpenHive(HKCU,"\\HKEY_CURRENT_USER") +func_winreg_OpenHive(HKLM,"\\HKEY_LOCAL_MACHINE") +func_winreg_OpenHive(HKPD,"\\HKEY_PERFORMANCE_DATA") +func_winreg_OpenHive(HKU,"\\HKEY_USERS") +func_winreg_OpenHive(HKCC,"\\HKEY_CC") +func_winreg_OpenHive(HKDD,"\\HKEY_DD") +func_winreg_OpenHive(HKPT,"\\HKEY_PT") +func_winreg_OpenHive(HKPN,"\\HKEY_PN") /* - winreg_OpenHKCU + winreg_CloseKey */ -static NTSTATUS winreg_OpenHKCU(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKCU *r) +static NTSTATUS winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct winreg_CloseKey *r) { - struct _privatedata *data = dce_call->conn->private; - REG_KEY *root = reg_get_root(data->registry); - REG_KEY *k = reg_open_key(root, "\\HKEY_CURRENT_USER"); - - if(!k) { - r->out.result = WERR_BADFILE; - } else { - struct dcesrv_handle *h = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY); - h->data = k; - r->out.handle = &h->wire_handle; + struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY); + if(!h) { + return NT_STATUS_INVALID_HANDLE; } - r->out.result = WERR_OK; + reg_key_free((REG_KEY *)h->data); + dcesrv_handle_destroy(dce_call->conn, h); return NT_STATUS_OK; } -/* - winreg_OpenHKLM -*/ -static NTSTATUS winreg_OpenHKLM(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKLM *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - winreg_OpenHKPD -*/ -static NTSTATUS winreg_OpenHKPD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKPD *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - winreg_OpenHKU -*/ -static NTSTATUS winreg_OpenHKU(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKU *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - winreg_CloseKey -*/ -static NTSTATUS winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_CloseKey *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - /* winreg_CreateKey */ static NTSTATUS winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_CreateKey *r) { - return NT_STATUS_NOT_IMPLEMENTED; + struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY); + WERROR error; + REG_KEY *parent; + if(!h) { + return NT_STATUS_INVALID_HANDLE; + } + + parent = h->data; + error = reg_key_add_name_recursive(parent, r->in.key.name); + if(W_ERROR_IS_OK(error)) { + struct dcesrv_handle *newh = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY); + error = reg_open_key(parent, r->in.key.name, (REG_KEY **)&newh->data); + if(W_ERROR_IS_OK(error)) r->out.handle = &newh->wire_handle; + else dcesrv_handle_destroy(dce_call->conn, newh); + } + + r->out.result = error; + + return NT_STATUS_OK; } @@ -140,7 +143,19 @@ static NTSTATUS winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX static NTSTATUS winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_DeleteKey *r) { - return NT_STATUS_NOT_IMPLEMENTED; + struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY); + REG_KEY *parent, *key; + WERROR error; + if(!h) { + return NT_STATUS_INVALID_HANDLE; + } + + parent = h->data; + r->out.result = reg_open_key(parent, r->in.key.name, &key); + if(W_ERROR_IS_OK(r->out.result)) { + r->out.result = reg_key_del(key); + } + return NT_STATUS_OK; } @@ -160,6 +175,14 @@ static NTSTATUS winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CT static NTSTATUS winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_EnumKey *r) { + struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY); + REG_KEY *key; + if(!h) { + return NT_STATUS_INVALID_HANDLE; + } + + key = h->data; + return NT_STATUS_NOT_IMPLEMENTED; } @@ -221,11 +244,22 @@ static NTSTATUS winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *m struct winreg_OpenKey *r) { struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, HTYPE_REGKEY); + REG_KEY *k, *subkey; if(!h) { return NT_STATUS_INVALID_HANDLE; } + + k = h->data; + + + r->out.result = reg_open_key(k, r->in.keyname.name, &subkey); + if(W_ERROR_IS_OK(r->out.result)) { + struct dcesrv_handle *newh = dcesrv_handle_new(dce_call->conn, HTYPE_REGKEY); + h->data = subkey; + r->out.handle = &h->wire_handle; + } - return NT_STATUS_NOT_IMPLEMENTED; + return NT_STATUS_OK; } @@ -339,26 +373,6 @@ static NTSTATUS winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX } -/* - winreg_OpenHKCC -*/ -static NTSTATUS winreg_OpenHKCC(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKCC *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - winreg_OpenHKDD -*/ -static NTSTATUS winreg_OpenHKDD(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKDD *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - /* winreg_QueryMultipleValues */ @@ -389,26 +403,6 @@ static NTSTATUS winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX } -/* - winreg_OpenHKPT -*/ -static NTSTATUS winreg_OpenHKPT(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKPT *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - -/* - winreg_OpenHKPN -*/ -static NTSTATUS winreg_OpenHKPN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct winreg_OpenHKPN *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - - /* winreg_QueryMultipleValues2 */ diff --git a/source4/torture/rpc/winreg.c b/source4/torture/rpc/winreg.c index 72fdc96c11..68466f0084 100644 --- a/source4/torture/rpc/winreg.c +++ b/source4/torture/rpc/winreg.c @@ -54,27 +54,24 @@ static BOOL test_GetVersion(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } static BOOL test_CreateKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle, const char *name, const char *class) + struct policy_handle *handle, char *name, const char *class) { struct winreg_CreateKey r; struct policy_handle newhandle; NTSTATUS status; struct sec_desc_buf sec_desc; + uint32 sec_info = 0; printf("\ntesting CreateKey\n"); r.in.handle = handle; r.out.handle = &newhandle; init_winreg_String(&r.in.key, name); - init_winreg_String(&r.in.class, class); + init_winreg_String(&r.in.class, class); r.in.reserved = 0x0; - r.in.reserved2 = 0x0; r.in.access_mask = 0x02000000; - r.out.reserved = 0x0; - r.in.sec_info = 0x0; - sec_desc.size = 0; - sec_desc.sd = NULL; - r.in.sec_desc = &sec_desc; + r.in.sec_info = &sec_info; + r.in.sec_desc = NULL; status = dcerpc_winreg_CreateKey(p, mem_ctx, &r); @@ -148,6 +145,11 @@ static BOOL test_OpenKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, status = dcerpc_winreg_OpenKey(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("OpenKey failed - %s\n", nt_errstr(status)); + return False; + } + if (!W_ERROR_IS_OK(r.out.result)) { printf("OpenKey failed - %s\n", win_errstr(r.out.result)); return False; @@ -195,6 +197,11 @@ static BOOL test_QueryInfoKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, status = dcerpc_winreg_QueryInfoKey(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("QueryInfoKey failed - %s\n", nt_errstr(status)); + return False; + } + if (!W_ERROR_IS_OK(r.out.result)) { printf("QueryInfoKey failed - %s\n", win_errstr(r.out.result)); return False; @@ -371,6 +378,53 @@ static BOOL test_OpenHKCR(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return ret; } +static BOOL test_InitiateSystemShutdown(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + const char *msg, uint32 timeout) +{ + struct winreg_InitiateSystemShutdown r; + NTSTATUS status; + + init_winreg_String(&r.in.message, msg); + r.in.flags = 0; + r.in.timeout = timeout; + + status = dcerpc_winreg_InitiateSystemShutdown(p, mem_ctx, &r); + + if (!NT_STATUS_IS_OK(status)) { + printf("InitiateSystemShutdown failed - %s\n", nt_errstr(status)); + return False; + } + + if (!W_ERROR_IS_OK(r.out.result)) { + printf("InitiateSystemShutdown failed - %s\n", win_errstr(r.out.result)); + return False; + } + + return True; +} + +static BOOL test_AbortSystemShutdown(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) +{ + struct winreg_AbortSystemShutdown r; + NTSTATUS status; + + r.in.server = 0x0; + + status = dcerpc_winreg_AbortSystemShutdown(p, mem_ctx, &r); + + if (!NT_STATUS_IS_OK(status)) { + printf("AbortSystemShutdown failed - %s\n", nt_errstr(status)); + return False; + } + + if (!W_ERROR_IS_OK(r.out.result)) { + printf("AbortSystemShutdown failed - %s\n", win_errstr(r.out.result)); + return False; + } + + return True; +} + static BOOL test_OpenHKCU(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle) { @@ -433,17 +487,7 @@ static BOOL test_Open(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, void *fn) if (!open_fn(p, mem_ctx, &handle)) return False; - if (!test_GetVersion(p, mem_ctx, &handle)) { - printf("GetVersion failed\n"); - ret = False; - } - - if (!test_FlushKey(p, mem_ctx, &handle)) { - printf("FlushKey failed\n"); - ret = False; - } - - if (!test_CreateKey(p, mem_ctx, &handle, "spottyfoot", "foo")) { + if (!test_CreateKey(p, mem_ctx, &handle, "spottyfoot", NULL)) { printf("CreateKey failed\n"); ret = False; } @@ -463,6 +507,16 @@ static BOOL test_Open(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, void *fn) ret = False; } + if (!test_GetVersion(p, mem_ctx, &handle)) { + printf("GetVersion failed\n"); + ret = False; + } + + if (!test_FlushKey(p, mem_ctx, &handle)) { + printf("FlushKey failed\n"); + ret = False; + } + /* The HKCR hive has a very large fanout */ @@ -482,7 +536,7 @@ static BOOL test_Open(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, void *fn) BOOL torture_rpc_winreg(int dummy) { NTSTATUS status; - struct dcerpc_pipe *p; + struct dcerpc_pipe *p; TALLOC_CTX *mem_ctx; BOOL ret = True; winreg_open_fn *open_fns[] = { test_OpenHKLM, test_OpenHKU, @@ -500,6 +554,9 @@ BOOL torture_rpc_winreg(int dummy) return False; } + if(!test_InitiateSystemShutdown(p, mem_ctx, "spottyfood", 30)) + ret = False; + for (i = 0; i < ARRAY_SIZE(open_fns); i++) { if (!test_Open(p, mem_ctx, open_fns[i])) ret = False; -- cgit