r20: Add the registry library. Still needs a lot of work,
authorJelmer Vernooij <jelmer@samba.org>
Sun, 4 Apr 2004 16:24:08 +0000 (16:24 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:50:33 +0000 (12:50 -0500)
see source/lib/registry/TODO for details.
(This used to be commit 7cab3a00d7b4b1d95a3bfa6b28f318b4aaa5d493)

30 files changed:
source4/Makefile.in
source4/aclocal.m4
source4/configure.in
source4/include/includes.h
source4/include/registry.h [new file with mode: 0644]
source4/lib/registry/TODO [new file with mode: 0644]
source4/lib/registry/common/reg_display.c [new file with mode: 0644]
source4/lib/registry/common/reg_interface.c [new file with mode: 0644]
source4/lib/registry/common/reg_objects.c [new file with mode: 0644]
source4/lib/registry/common/reg_util.c [new file with mode: 0644]
source4/lib/registry/common/registry.h [new file with mode: 0644]
source4/lib/registry/config.m4 [new file with mode: 0644]
source4/lib/registry/reg_backend_dir/reg_backend_dir.c [new file with mode: 0644]
source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c [new file with mode: 0644]
source4/lib/registry/reg_backend_ldb/reg_backend_ldb.c [new file with mode: 0644]
source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c [new file with mode: 0644]
source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c [new file with mode: 0644]
source4/lib/registry/reg_backend_wine/reg_backend_wine.c [new file with mode: 0644]
source4/lib/registry/tools/regdiff.c [new file with mode: 0644]
source4/lib/registry/tools/regpatch.c [new file with mode: 0644]
source4/lib/registry/tools/regshell.c [new file with mode: 0644]
source4/lib/registry/tools/regtree.c [new file with mode: 0644]
source4/lib/registry/winregistry.pc.in [new file with mode: 0644]
source4/registry/reg_cachehook.c [deleted file]
source4/registry/reg_db.c [deleted file]
source4/registry/reg_frontend.c [deleted file]
source4/registry/reg_objects.c [deleted file]
source4/rpc_server/config.m4
source4/rpc_server/winreg/rpc_winreg.c [new file with mode: 0644]
source4/script/mkproto.pl

index 31e752165df5d344981173133bfed24aae325d0e..8f9bad0da5c09ca07fbb0c323b67d582e426b2b1 100644 (file)
@@ -138,6 +138,9 @@ NTVFS_LIBS = @NTVFS_LIBS@
 DCERPC_OBJS = @DCERPC_OBJS@
 DCERPC_LIBS = @DCERPC_LIBS@
 
+REG_OBJS = @REG_OBJS@
+REG_LIBS = @REG_LIBS@
+
 TORTURE_RAW_OBJS = @TORTURE_RAW_OBJS@
 
 TORTURE_RPC_OBJS = @TORTURE_RPC_OBJS@
@@ -187,9 +190,14 @@ NDRDUMP_OBJS = utils/ndrdump.o utils/rewrite.o \
                $(LIBSMB_OBJS) $(CONFIG_OBJS) $(LIBBASIC_OBJS)
 NDRDUMP_LIBS = $(LIBSMB_LIBS) $(CONFIG_LIBS) $(LIBBASIC_LIBS)
 
+REGTREE_OBJ = $(REG_OBJS) lib/registry/tools/regtree.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)
+
 PROTO_OBJ =    $(SERVER_OBJS) $(PROCESS_MODEL_OBJS) $(CLIENT_OBJS) $(TORTURE_OBJS) \
                $(DCERPC_OBJS) $(SMB_OBJS) $(AUTH_OBJS) $(PASSDB_OBJS) $(NTVFS_OBJS) \
-               $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBCMDLINE_OBJS) $(LIBSMB_OBJS)
+               $(LIBBASIC_OBJS) $(CONFIG_OBJS) $(LIBCMDLINE_OBJS) $(LIBSMB_OBJS) $(REG_OBJS)
 
 
 ######################################################################
@@ -333,6 +341,23 @@ bin/locktest@EXEEXT@: $(LOCKTEST_OBJS) bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(LOCKTEST_OBJS) $(LDFLAGS) $(LOCKTEST_LIBS)
 
+
+bin/regshell@EXEEXT@: $(REGSHELL_OBJ) bin/.dummy
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(REGSHELL_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS) $(LIBCMDLINE_LIBS)
+
+bin/regtree@EXEEXT@: $(REGTREE_OBJ) bin/.dummy
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(REGTREE_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS)
+
+bin/regpatch@EXEEXT@: $(REGPATCH_OBJ) bin/.dummy
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(REGPATCH_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS)
+
+bin/regdiff@EXEEXT@: $(REGDIFF_OBJ) bin/.dummy
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(REGDIFF_OBJ) $(LDFLAGS) $(LIBS) $(REG_LIBS)
 install: installbin installtorture installdat 
 
 # DESTDIR is used here to prevent packagers wasting their time
index de23fd19798a2e837c961bc2a7dc53e8bf2ed734..55630c9a3980733a67224af89750b7a1275eb4a5 100644 (file)
@@ -712,3 +712,59 @@ dnl AC_DISABLE_STATIC - set the default static flag to --disable-static
 AC_DEFUN([AC_DISABLE_STATIC],
 [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
 AC_ENABLE_STATIC(no)])
+
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN(PKG_CHECK_MODULES, [
+  succeeded=no
+
+  if test -z "$PKG_CONFIG"; then
+    AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+  fi
+
+  if test "$PKG_CONFIG" = "no" ; then
+     echo "*** The pkg-config script could not be found. Make sure it is"
+     echo "*** in your path, or set the PKG_CONFIG environment variable"
+     echo "*** to the full path to pkg-config."
+     echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+  else
+     PKG_CONFIG_MIN_VERSION=0.9.0
+     if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+        AC_MSG_CHECKING(for $2)
+
+        if $PKG_CONFIG --exists "$2" ; then
+            AC_MSG_RESULT(yes)
+            succeeded=yes
+
+            AC_MSG_CHECKING($1_CFLAGS)
+            $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+            AC_MSG_RESULT($$1_CFLAGS)
+
+            AC_MSG_CHECKING($1_LIBS)
+            $1_LIBS=`$PKG_CONFIG --libs "$2"`
+            AC_MSG_RESULT($$1_LIBS)
+        else
+            $1_CFLAGS=""
+            $1_LIBS=""
+            ## If we have a custom action on failure, don't print errors, but 
+            ## do set a variable so people can do so.
+            $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+            ifelse([$4], ,echo $$1_PKG_ERRORS,)
+        fi
+
+        AC_SUBST($1_CFLAGS)
+        AC_SUBST($1_LIBS)
+     else
+        echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+        echo "*** See http://www.freedesktop.org/software/pkgconfig"
+     fi
+  fi
+
+  if test $succeeded = yes; then
+     ifelse([$3], , :, [$3])
+  else
+     ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+  fi
+])
index a7fe7d9cdaa72d78fc4b80882833cf27c1c42796..a35400588b668dfcaa189a994fa47e52da910708 100644 (file)
@@ -209,6 +209,7 @@ sinclude(auth/config.m4)
 sinclude(passdb/config.m4)
 sinclude(ntvfs/config.m4)
 sinclude(rpc_server/config.m4)
+sinclude(lib/registry/config.m4)
 sinclude(torture/config.m4)
 
 AC_DEFINE_UNQUOTED(STRING_STATIC_MODULES, "$string_static_modules", [String list of builtin modules])
index 224142532313da47e8a4aee09ce49a3ceda7ea51..3ea7d9549fb24dde3eb633711242a2043f3f42cf 100644 (file)
@@ -731,6 +731,7 @@ extern int errno;
 #include "context.h"
 #include "ntvfs/ntvfs.h"
 #include "cli_context.h"
+#include "registry.h"
 
 
 /* used in net.c */
diff --git a/source4/include/registry.h b/source4/include/registry.h
new file mode 100644 (file)
index 0000000..210bcd1
--- /dev/null
@@ -0,0 +1,60 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Gerald Carter                        2002.
+   Copyright (C) Jelmer Vernooij                                         2003-2004.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _REGISTRY_H /* _REGISTRY_H */
+#define _REGISTRY_H 
+
+#define HKEY_CLASSES_ROOT      0x80000000
+#define HKEY_CURRENT_USER      0x80000001
+#define HKEY_LOCAL_MACHINE     0x80000002
+#define HKEY_USERS             0x80000003
+
+/* Registry data types */
+
+#define        REG_DELETE                                                                      -1
+#define        REG_NONE                                                                        0
+#define        REG_SZ                                                                          1
+#define        REG_EXPAND_SZ                                                           2
+#define        REG_BINARY                                                                      3
+#define        REG_DWORD                                                                       4
+#define        REG_DWORD_LE                                                            4 /* DWORD, little endian*/
+#define        REG_DWORD_BE                                                            5 /* DWORD, big endian */
+#define        REG_LINK                                                                        6
+#define        REG_MULTI_SZ                                                            7
+#define        REG_RESOURCE_LIST                                                       8
+#define        REG_FULL_RESOURCE_DESCRIPTOR                            9
+#define        REG_RESOURCE_REQUIREMENTS_LIST                          10
+
+typedef struct reg_handle_s REG_HANDLE;
+typedef struct reg_key_s REG_KEY;
+typedef struct reg_val_s REG_VAL;
+typedef struct reg_ops_s REG_OPS;
+
+#if 0
+//FIXME
+typedef struct ace_struct_s {
+  unsigned char type, flags;
+  unsigned int perms;   /* Perhaps a better def is in order */
+  DOM_SID *trustee;
+} ACE;
+#endif
+
+#endif /* _REGISTRY_H */
diff --git a/source4/lib/registry/TODO b/source4/lib/registry/TODO
new file mode 100644 (file)
index 0000000..26fb8d2
--- /dev/null
@@ -0,0 +1,27 @@
+- support subtrees
+- ../../, /bla/blie support in regshell
+- use memory pools?
+- get rid of all the nasty memory leaks..
+- security stuff
+- finish 'regpatch'
+- clean up code
+- rpc_server
+
+reg_backend_dir:
+ - value support
+reg_backend_nt4:
+ - write support
+
+reg_backend_rpc:
+ - value enum support
+ - write support
+reg_backend_ldb:
+ - implement
+
+reg_backend_wine.c:
+ - implement
+
+regpatch.c: 
+ - test/finish
diff --git a/source4/lib/registry/common/reg_display.c b/source4/lib/registry/common/reg_display.c
new file mode 100644 (file)
index 0000000..e12f4ba
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Gerald Carter                     2001
+   Copyright (C) Tim Potter                        2000
+   Copyright (C) Jelmer Vernooij                                  2004
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+void display_reg_value(REG_VAL *value)
+{
+       pstring text;
+
+       switch(reg_val_type(value)) {
+       case REG_DWORD:
+               printf("%s: REG_DWORD: 0x%08x\n", reg_val_name(value), 
+                      *((uint32 *) reg_val_data_blk(value)));
+               break;
+       case REG_SZ:
+               rpcstr_pull(text, reg_val_data_blk(value), sizeof(text), reg_val_size(value),
+                           STR_TERMINATE);
+               printf("%s: REG_SZ: %s\n", reg_val_name(value), text);
+               break;
+       case REG_BINARY:
+               printf("%s: REG_BINARY: unknown length value not displayed\n",
+                      reg_val_name(value));
+               break;
+       case REG_MULTI_SZ: {
+               uint16 *curstr = (uint16 *) reg_val_data_blk(value);
+               uint8 *start = reg_val_data_blk(value);
+               printf("%s: REG_MULTI_SZ:\n", reg_val_name(value));
+               while ((*curstr != 0) && 
+                      ((uint8 *) curstr < start + reg_val_size(value))) {
+                       rpcstr_pull(text, curstr, sizeof(text), -1, 
+                                   STR_TERMINATE);
+                       printf("  %s\n", text);
+                       curstr += strlen(text) + 1;
+               }
+       }
+       break;
+       default:
+               printf("%s: unknown type %d\n", reg_val_name(value), reg_val_type(value));
+       }
+       
+}
diff --git a/source4/lib/registry/common/reg_interface.c b/source4/lib/registry/common/reg_interface.c
new file mode 100644 (file)
index 0000000..dc49dab
--- /dev/null
@@ -0,0 +1,423 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Transparent registry backend handling
+   Copyright (C) Jelmer Vernooij                       2003-2004.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/* List of available backends */
+static struct reg_init_function_entry *backends = NULL;
+
+static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
+
+/* Register new backend */
+NTSTATUS registry_register(void *_function)  
+{
+       REG_OPS *functions = _function;
+       struct reg_init_function_entry *entry = backends;
+
+       if (!functions || !functions->name) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       DEBUG(5,("Attempting to register registry backend %s\n", functions->name));
+
+       /* Check for duplicates */
+       if (reg_find_backend_entry(functions->name)) {
+               DEBUG(0,("There already is a registry backend registered with the name %s!\n", functions->name));
+               return NT_STATUS_OBJECT_NAME_COLLISION;
+       }
+
+       entry = malloc(sizeof(struct reg_init_function_entry));
+       entry->functions = functions;
+
+       DLIST_ADD(backends, entry);
+       DEBUG(5,("Successfully added registry backend '%s'\n", functions->name));
+       return NT_STATUS_OK;
+}
+
+
+/* Find a backend in the list of available backends */
+static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
+{
+       struct reg_init_function_entry *entry = backends;
+
+       while(entry) {
+               if (strcmp(entry->functions->name, name)==0) return entry;
+               entry = entry->next;
+       }
+
+       return NULL;
+}
+
+/* Open a registry file/host/etc */
+REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_load)
+{
+       struct reg_init_function_entry *entry;
+       static BOOL reg_first_init = True;
+       REG_HANDLE *ret;
+
+       if(reg_first_init) {
+               if (!NT_STATUS_IS_OK(register_subsystem("registry", registry_register))) {
+                       return False;
+               }
+
+               static_init_reg;
+               reg_first_init = False;
+       }
+
+       entry = reg_find_backend_entry(backend);
+       
+       if (!entry) {
+               DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
+               return NULL;
+       }
+
+       ret = malloc(sizeof(REG_HANDLE));
+       ZERO_STRUCTP(ret);      
+       ret->location = location?strdup(location):NULL;
+       ret->functions = entry->functions;
+       ret->backend_data = NULL;
+
+       if(!entry->functions->open_registry) {
+               return ret;
+       }
+       
+       if(entry->functions->open_registry(ret, location, try_full_load))
+               return ret;
+
+       SAFE_FREE(ret);
+       return NULL;
+}
+
+/* Open a key */
+REG_KEY *reg_open_key(REG_KEY *parent, const char *name)
+{
+       char *fullname;
+       REG_KEY *ret = NULL;
+
+       if(!parent) {
+               DEBUG(0, ("Invalid parent key specified"));
+               return NULL;
+       }
+
+       if(!parent->handle->functions->open_key && 
+          (parent->handle->functions->get_subkey_by_name || 
+          parent->handle->functions->get_subkey_by_index)) {
+               char *orig = strdup(name), 
+                        *curbegin = orig, 
+                        *curend = strchr(orig, '\\');
+               REG_KEY *curkey = parent;
+
+               while(curbegin && *curbegin) {
+                       if(curend)*curend = '\0';
+                       curkey = reg_key_get_subkey_by_name(curkey, curbegin);
+                       if(!curkey) return NULL;
+                       if(!curend) break;
+                       curbegin = curend + 1;
+                       curend = strchr(curbegin, '\\');
+               }
+               
+               return curkey;
+       }
+
+       asprintf(&fullname, "%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;
+       }
+
+       ret = parent->handle->functions->open_key(parent->handle, fullname);
+
+       if(ret) {
+               ret->handle = parent->handle;
+               ret->path = fullname;
+       } else
+               SAFE_FREE(fullname);
+
+       return ret;
+}
+
+REG_VAL *reg_key_get_value_by_index(REG_KEY *key, int idx)
+{
+       REG_VAL *ret;
+
+       if(!key) return NULL;
+
+       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]);
+               } else {
+                       return NULL;
+               }
+       } else {
+               ret = key->handle->functions->get_value_by_index(key, idx);
+       }
+       
+       if(ret) {
+               ret->parent = key;
+               ret->handle = key->handle;
+       }
+
+       return ret;
+}
+
+int reg_key_num_subkeys(REG_KEY *key)
+{
+       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;
+       }
+
+       return key->handle->functions->num_subkeys(key);
+}
+
+int reg_key_num_values(REG_KEY *key)
+{
+       
+       if(!key) return 0;
+       
+       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;
+               }
+               
+               if(!key->cache_values) 
+                       key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
+
+               return key->cache_values_count;
+       }
+
+       
+       return key->handle->functions->num_values(key);
+}
+
+REG_KEY *reg_key_get_subkey_by_index(REG_KEY *key, int idx)
+{
+       REG_KEY *ret = NULL;
+
+       if(!key) return NULL;
+
+       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]);
+               } else {
+                       /* No such key ! */
+                       return NULL;
+               }
+       } else {
+               ret = key->handle->functions->get_subkey_by_index(key, idx);
+       }
+
+       if(ret && !ret->path) {
+               asprintf(&ret->path, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
+               ret->handle = key->handle;
+       }
+
+       return ret;
+}
+
+REG_KEY *reg_key_get_subkey_by_name(REG_KEY *key, const char *name)
+{
+       int i, max;
+       REG_KEY *ret = NULL;
+
+       if(!key) return NULL;
+
+       if(key->handle->functions->get_subkey_by_name) {
+               ret = key->handle->functions->get_subkey_by_name(key,name);
+       } 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;
+                               break;
+                       }
+                       reg_key_free(v);
+               }
+       }
+
+       if(ret && !ret->path) {
+               asprintf(&ret->path, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
+               ret->handle = key->handle;
+       }
+               
+       return ret; 
+}
+
+REG_VAL *reg_key_get_value_by_name(REG_KEY *key, const char *name)
+{
+       int i, max;
+       REG_VAL *ret = NULL;
+
+       if(!key) return NULL;
+
+       if(key->handle->functions->get_value_by_name) {
+               ret = key->handle->functions->get_value_by_name(key,name);
+       } 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;
+                               break;
+                       }
+                       reg_val_free(v);
+               }
+       }
+       
+       if(ret) {
+               ret->parent = key;
+               ret->handle = key->handle;
+       }
+       
+       return ret;
+}
+
+BOOL reg_key_del(REG_KEY *key)
+{
+       if(key->handle->functions->del_key)
+               return key->handle->functions->del_key(key);
+
+       return False;
+}
+
+BOOL reg_sync(REG_HANDLE *h, const char *location)
+{
+       if(!h->functions->sync)
+               return True;
+
+       return h->functions->sync(h, location);
+}
+
+BOOL reg_key_del_recursive(REG_KEY *key)
+{
+       BOOL succeed = True;
+       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;
+       }
+
+       /* 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;
+       }
+
+       if(succeed)reg_key_del(key);
+
+       return succeed;
+}
+
+BOOL reg_val_del(REG_VAL *val)
+{
+       if (!val->handle->functions->del_value) {
+               DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name));
+               return False;
+       }
+       
+       return val->handle->functions->del_value(val);
+}
+
+BOOL reg_key_add_name(REG_KEY *parent, const char *name)
+{
+       if (!parent->handle->functions->add_key) {
+               DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name));
+               return False;
+       }
+
+       return parent->handle->functions->add_key(parent, name);
+}
+
+BOOL reg_val_update(REG_VAL *val, int type, void *data, int len)
+{
+       /* A 'real' update function has preference */
+       if (val->handle->functions->update_value) 
+               return val->handle->functions->update_value(val, type, data, len);
+
+       /* Otherwise, just remove and add again */
+       if (val->handle->functions->add_value && 
+               val->handle->functions->del_value) {
+               REG_VAL *new;
+               if(!val->handle->functions->del_value(val)) 
+                       return False;
+               
+               new = val->handle->functions->add_value(val->parent, val->name, type, data, len);
+               memcpy(val, new, sizeof(REG_VAL));
+               return True;
+       }
+               
+       DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name));
+       return False;
+}
+
+void reg_free(REG_HANDLE *h)
+{
+       if(!h->functions->close_registry) return;
+
+       h->functions->close_registry(h);
+}
+
+REG_KEY *reg_get_root(REG_HANDLE *h) 
+{
+       REG_KEY *ret = NULL;
+       if(h->functions->open_root_key) {
+               ret = h->functions->open_root_key(h);
+       } else if(h->functions->open_key) {
+               ret = h->functions->open_key(h, "\\");
+       } else {
+               DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name));
+       }
+
+       if(ret) {
+               ret->handle = h;
+               ret->path = strdup("\\");
+       }
+
+       return ret;
+}
+
+REG_VAL *reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen)
+{
+       REG_VAL *ret;
+       if(!key->handle->functions->add_value)
+               return NULL;
+
+       ret = key->handle->functions->add_value(key, name, type, value, vallen);
+       ret->parent = key;
+       ret->handle = key->handle;
+       return ret;
+}
diff --git a/source4/lib/registry/common/reg_objects.c b/source4/lib/registry/common/reg_objects.c
new file mode 100644 (file)
index 0000000..911dc15
--- /dev/null
@@ -0,0 +1,202 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  RPC Pipe client / server routines
+ *  Copyright (C) Gerald Carter                     2002.
+ *  Copyright (C) Jelmer Vernooij                                      2003-2004.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Implementation of registry frontend view functions. */
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+/***********************************************************************
+ allocate memory for and duplicate a REG_VAL.
+ This is malloc'd memory so the caller should free it when done
+ **********************************************************************/
+
+REG_VAL* reg_val_dup( REG_VAL *val )
+{
+       REG_VAL         *copy = NULL;
+       
+       if ( !val ) 
+               return NULL;
+       
+       if ( !(copy = malloc( sizeof(REG_VAL) )) ) {
+               DEBUG(0,("dup_registry_value: malloc() failed!\n"));
+               return NULL;
+       }
+       
+       /* copy all the non-pointer initial data */
+       
+       memcpy( copy, val, sizeof(REG_VAL) );
+       if ( val->data_blk ) 
+       {
+               if ( !(copy->data_blk = memdup( val->data_blk, val->data_len )) ) {
+                       DEBUG(0,("dup_registry_value: memdup() failed for [%d] bytes!\n",
+                               val->data_len));
+                       SAFE_FREE( copy );
+               }
+       }
+       
+       return copy;    
+}
+
+/**********************************************************************
+ free the memory allocated to a REG_VAL 
+ *********************************************************************/
+void reg_val_free( REG_VAL *val )
+{
+       if ( !val )
+               return;
+
+       if(val->handle->functions->free_val_backend_data)
+               val->handle->functions->free_val_backend_data(val);
+               
+       SAFE_FREE( val->data_blk );
+       SAFE_FREE( val );
+
+       return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint8* reg_val_data_blk( REG_VAL *val )
+{
+       return val->data_blk;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+int reg_val_size( REG_VAL *val )
+{
+       return val->data_len;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+char *reg_val_name( REG_VAL *val )
+{
+       return val->name;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint32 reg_val_type( REG_VAL *val )
+{
+       return val->data_type;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+char *reg_key_name( REG_KEY *key )
+{
+       return key->name;
+}
+
+REG_KEY *reg_key_dup(REG_KEY *key)
+{
+       key->ref++;
+       return key;
+}
+
+void reg_key_free(REG_KEY *key)
+{
+       if(!key)
+               return;
+       
+       key->ref--;
+       if(key->ref) return;
+       
+       if(key->handle->functions->free_key_backend_data)
+               key->handle->functions->free_key_backend_data(key);
+
+       if(key->cache_values) {
+               int i;
+               for(i = 0; i < key->cache_values_count; i++) {
+                       reg_val_free(key->cache_values[i]);
+               }
+               SAFE_FREE(key->cache_values);
+       }
+
+       if(key->cache_subkeys) {
+               int i;
+               for(i = 0; i < key->cache_subkeys_count; i++) {
+                       reg_key_free(key->cache_subkeys[i]);
+               }
+               SAFE_FREE(key->cache_subkeys);
+       }
+
+       SAFE_FREE(key->path);
+       SAFE_FREE(key->name);
+       SAFE_FREE(key);
+}
+
+char *reg_val_get_path(REG_VAL *v)
+{
+       /* FIXME */
+       return NULL;
+}
+
+char *reg_key_get_path(REG_KEY *k)
+{
+       SMB_REG_ASSERT(k);
+       return k->path;
+}
+
+/* For use by the backends _ONLY_ */
+REG_KEY *reg_key_new_abs(const char *path, REG_HANDLE *h, void *data)
+{
+       REG_KEY *r = malloc(sizeof(REG_KEY));
+       ZERO_STRUCTP(r);
+       r->handle = h;
+       r->path = strdup(path);
+       r->name = strdup(strrchr(path, '\\')?strrchr(path,'\\')+1:path);
+       r->backend_data = data;
+       r->ref = 1;
+       return r;
+}
+
+REG_KEY *reg_key_new_rel(const char *name, REG_KEY *k, void *data)
+{
+       REG_KEY *r = malloc(sizeof(REG_KEY));
+       ZERO_STRUCTP(r);
+       r->handle = k->handle;
+       r->name = strdup(name);
+       r->backend_data = data;
+       r->ref = 1;
+       return r;
+}
+
+REG_VAL *reg_val_new(REG_KEY *parent, void *data)
+{
+       REG_VAL *r = malloc(sizeof(REG_VAL));
+       ZERO_STRUCTP(r);
+       r->handle = parent->handle;
+       r->backend_data = data;
+       r->ref = 1;
+       return r;
+}
diff --git a/source4/lib/registry/common/reg_util.c b/source4/lib/registry/common/reg_util.c
new file mode 100644 (file)
index 0000000..2941c38
--- /dev/null
@@ -0,0 +1,164 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Transparent registry backend handling
+   Copyright (C) Jelmer Vernooij                       2003-2004.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/* Return string description of registry value type */
+const char *str_regtype(int type)
+{
+       switch(type) {
+       case REG_SZ: return "STRING";
+       case REG_DWORD: return "DWORD";
+       case REG_BINARY: return "BINARY";
+       }
+       return "Unknown";
+}
+
+char *reg_val_data_string(REG_VAL *v)
+{ 
+  char *asciip;
+  char *ret = NULL;
+  int i;
+
+  if(reg_val_size(v) == 0) return strdup("");
+
+  switch (reg_val_type(v)) {
+  case REG_SZ:
+         /* FIXME: Convert to ascii */
+         return strdup(reg_val_data_blk(v));
+
+  case REG_EXPAND_SZ:
+         return strdup(reg_val_data_blk(v));
+
+  case REG_BINARY:
+         ret = malloc(reg_val_size(v) * 3 + 2);
+         asciip = ret;
+         for (i=0; i<reg_val_size(v); i++) { 
+                 int str_rem = reg_val_size(v) * 3 - (asciip - ret);
+                 asciip += snprintf(asciip, str_rem, "%02x", *(unsigned char *)(reg_val_data_blk(v)+i));
+                 if (i < reg_val_size(v) && str_rem > 0)
+                         *asciip = ' '; asciip++;      
+         }
+         *asciip = '\0';
+         return ret;
+         break;
+
+  case REG_DWORD:
+         if (*(int *)reg_val_data_blk(v) == 0)
+                 ret = strdup("0");
+         else
+                 asprintf(&ret, "0x%x", *(int *)reg_val_data_blk(v));
+         break;
+
+  case REG_MULTI_SZ:
+       /* FIXME */
+    break;
+
+  default:
+    return 0;
+    break;
+  } 
+
+  return ret;
+}
+
+const char *reg_val_description(REG_VAL *val) 
+{
+       char *ret, *ds = reg_val_data_string(val);
+       asprintf(&ret, "%s = %s : %s", reg_val_name(val)?reg_val_name(val):"<No Name>", str_regtype(reg_val_type(val)), ds);
+       free(ds);
+       return ret;
+}
+
+BOOL reg_val_set_string(REG_VAL *val, char *str)
+{
+       /* FIXME */
+       return False;
+}
+
+REG_VAL *reg_key_get_subkey_val(REG_KEY *key, const char *subname, const char *valname)
+{
+       REG_KEY *k = reg_key_get_subkey_by_name(key, subname);
+       if(!k) return NULL;
+       
+       return reg_key_get_value_by_name(k, valname);
+}
+
+BOOL 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_VAL *v;
+       if(!k) return False;
+
+       v = reg_key_get_value_by_name(k, valname);
+       if(!v) return False;
+       
+       return reg_val_update(v, type, data, real_len);
+}
+
+/***********************************************************************
+ Utility function for splitting the base path of a registry path off
+ by setting base and new_path to the apprapriate offsets withing the
+ path.
+ WARNING!!  Does modify the original string!
+ ***********************************************************************/
+
+BOOL reg_split_path( char *path, char **base, char **new_path )
+{
+       char *p;
+       
+       *new_path = *base = NULL;
+       
+       if ( !path)
+               return False;
+       
+       *base = path;
+       
+       p = strchr( path, '\\' );
+       
+       if ( p ) {
+               *p = '\0';
+               *new_path = p+1;
+       }
+       
+       return True;
+}
+
+char *reg_path_win2unix(char *path) 
+{
+       int i;
+       for(i = 0; path[i]; i++) {
+               if(path[i] == '\\') path[i] = '/';
+       }
+       return path;
+}
+
+char *reg_path_unix2win(char *path) 
+{
+       int i;
+       for(i = 0; path[i]; i++) {
+               if(path[i] == '/') path[i] = '\\';
+       }
+       return path;
+}
diff --git a/source4/lib/registry/common/registry.h b/source4/lib/registry/common/registry.h
new file mode 100644 (file)
index 0000000..4b29006
--- /dev/null
@@ -0,0 +1,121 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   This file contains the _internal_ structs for the registry 
+   subsystem. Backends and the subsystem itself are the only
+   files that need to include this file.
+   Copyright (C) Gerald Carter                        2002.
+   Copyright (C) Jelmer Vernooij                                         2003-2004.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _REGISTRY_REGISTRY_H /* _REGISTRY_REGISTRY_H */
+#define _REGISTRY_REGISTRY_H 
+
+#define REGISTRY_INTERFACE_VERSION 1
+
+/* structure to store the registry handles */
+struct reg_key_s {
+  char *name;         /* Name of the key                    */
+  char *path;            /* Full path to the key */
+  smb_ucs2_t *class_name; /* Name of key class */
+  NTTIME last_mod; /* Time last modified                 */
+  SEC_DESC *security;
+  REG_HANDLE *handle;
+  void *backend_data;
+  REG_VAL **cache_values; 
+  int cache_values_count;
+  REG_KEY **cache_subkeys; 
+  int cache_subkeys_count;
+  int ref;
+};
+
+struct reg_val_s {
+  char *name;
+  int has_name;
+  int data_type;
+  int data_len;
+  void *data_blk;    /* Might want a separate block */
+  REG_HANDLE *handle;
+  REG_KEY *parent;
+  void *backend_data;
+  int ref;
+};
+
+/* 
+ * Container for function pointers to enumeration routines
+ * for virtual registry view 
+ */ 
+struct reg_ops_s {
+       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 *);
+
+       /* 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);
+
+       /* 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 ***);
+
+       /* Key management */
+       BOOL (*add_key)(REG_KEY *, const char *name);
+       BOOL (*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 *);
+       
+       /* 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); 
+
+       void (*free_key_backend_data) (REG_KEY *);
+       void (*free_val_backend_data) (REG_VAL *);
+};
+
+typedef struct reg_sub_tree_s {
+       char *path;
+       REG_HANDLE *handle;
+       struct reg_sub_tree_s *prev, *next;
+} REG_SUBTREE;
+
+struct reg_handle_s {
+       REG_OPS *functions;
+       REG_SUBTREE *subtrees;
+       char *location;
+       void *backend_data;
+};
+
+struct reg_init_function_entry {
+       /* Function to create a member of the pdb_methods list */
+       REG_OPS *functions;
+       struct reg_init_function_entry *prev, *next;
+};
+
+/* Used internally */
+#define SMB_REG_ASSERT(a) { if(!(a)) { DEBUG(0,("%s failed! (%s:%d)", #a, __FILE__, __LINE__)); }}
+
+#endif /* _REGISTRY_H */
diff --git a/source4/lib/registry/config.m4 b/source4/lib/registry/config.m4
new file mode 100644 (file)
index 0000000..277fd30
--- /dev/null
@@ -0,0 +1,16 @@
+# Registry backends
+                                                                                                                              
+if test t$BLDSHARED = ttrue; then
+    LIBWINREG_SHARED=bin/libwinregistry.$SHLIBEXT
+fi
+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])])
+
+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_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_OUTPUT(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
new file mode 100644 (file)
index 0000000..baed39b
--- /dev/null
@@ -0,0 +1,154 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Jelmer Vernooij                                         2004.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+static DIR *reg_dir_dir(REG_HANDLE *h, const char *base, const char *name)
+{
+       char *path = NULL;
+       DIR *d;
+       asprintf(&path, "%s/%s/%s", h->location, base, name);
+       path = reg_path_win2unix(path);
+       
+       d = opendir(path);
+       if(!d) {
+               printf("Unable to open '%s'\n", path);
+               return NULL;
+       }
+       SAFE_FREE(path);
+       return d;
+}
+
+static BOOL reg_dir_add_key(REG_KEY *parent, const char *name)
+{
+       char *path;
+       int ret;
+       asprintf(&path, "%s/%s/%s", parent->handle->location, reg_key_get_path(parent), name);
+       path = reg_path_win2unix(path);
+       ret = mkdir(path, 0700);
+       free(path);
+       return (ret == 0);
+}
+
+static BOOL reg_dir_del_key(REG_KEY *k)
+{
+       char *path;
+       int ret;
+       asprintf(&path, "%s/%s", k->handle->location, reg_key_get_path(k));
+       path = reg_path_win2unix(path);
+       ret = rmdir(path);
+       free(path);
+       return (ret == 0);
+}
+
+static REG_KEY *reg_dir_open_key(REG_HANDLE *h, const char *name)
+{
+       DIR *d;
+       char *fullpath;
+       if(!name) {
+               DEBUG(0, ("NULL pointer passed as directory name!"));
+               return NULL;
+       }
+       fullpath = reg_path_win2unix(strdup(name));
+       d = reg_dir_dir(h, "", fullpath);
+       free(fullpath);
+       
+       if(d) return reg_key_new_abs(name, h, d);
+       return NULL;
+}
+
+static BOOL reg_dir_fetch_subkeys(REG_KEY *k, int *count, REG_KEY ***r)
+{
+       DIR *d = (DIR *)k->backend_data;
+       struct dirent *e;
+       int max = 200;
+       REG_KEY **ar;
+       if(!d) return False;
+       rewinddir(d);
+       (*count) = 0;
+       ar = malloc(sizeof(REG_KEY *) * max);
+       
+       while((e = readdir(d))) {
+               if(e->d_type == DT_DIR && 
+                  strcmp(e->d_name, ".") &&
+                  strcmp(e->d_name, "..")) {
+                       char *fullpath = reg_path_win2unix(strdup(k->path));
+                       ar[(*count)] = reg_key_new_rel(e->d_name, k, reg_dir_dir(k->handle, fullpath, e->d_name));
+                       free(fullpath);
+                       if(ar[(*count)])(*count)++;
+
+                       if((*count) == max) {
+                               max+=200;
+                               ar = realloc(ar, sizeof(REG_KEY *) * max);
+                       }
+               }
+       }
+       
+       *r = ar;
+       return True;
+}
+
+static BOOL reg_dir_open(REG_HANDLE *h, const char *loc, BOOL try) {
+       if(!loc) return False;
+       return True;
+}
+
+static void dir_free(REG_KEY *k) 
+{
+       closedir((DIR *)k->backend_data);
+}
+
+static REG_VAL *reg_dir_add_value(REG_KEY *p, const char *name, int type, void *data, int len)
+{
+       REG_VAL *ret = reg_val_new(p, NULL);
+       char *fullpath;
+       FILE *fd;
+       ret->name = name?strdup(name):NULL;
+       fullpath = reg_path_win2unix(strdup(reg_val_get_path(ret)));
+       
+       fd = fopen(fullpath, "w+");
+       
+       /* FIXME */
+       return NULL;
+}
+
+static BOOL reg_dir_del_value(REG_VAL *v)
+{
+       char *fullpath = reg_path_win2unix(strdup(reg_val_get_path(v)));
+       return False;
+}
+
+static REG_OPS reg_backend_dir = {
+       .name = "dir",
+       .open_registry = reg_dir_open,
+       .open_key = reg_dir_open_key,
+       .fetch_subkeys = reg_dir_fetch_subkeys,
+       .add_key = reg_dir_add_key,
+       .del_key = reg_dir_del_key,
+       .add_value = reg_dir_add_value,
+       .del_value = reg_dir_del_value,
+       .free_key_backend_data = dir_free
+};
+
+NTSTATUS reg_dir_init(void)
+{
+       return register_backend("registry", &reg_backend_dir);
+}
diff --git a/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c b/source4/lib/registry/reg_backend_gconf/reg_backend_gconf.c
new file mode 100644 (file)
index 0000000..14da2f5
--- /dev/null
@@ -0,0 +1,189 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Jelmer Vernooij                                         2004.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+#include <gconf/gconf-client.h>
+
+static BOOL reg_open_gconf(REG_HANDLE *h, const char *location, BOOL try_complete_load) 
+{
+       h->backend_data = (void *)gconf_client_get_default();
+       return True;
+}
+
+static BOOL reg_close_gconf(REG_HANDLE *h) 
+{
+       return True;
+}
+
+static REG_KEY *gconf_open_key (REG_HANDLE *h, const char *name) 
+{
+       char *fullpath = reg_path_win2unix(strdup(name));
+
+       /* Check if key exists */
+       if(!gconf_client_dir_exists((GConfClient *)h->backend_data, fullpath, NULL)) {
+               free(fullpath);
+               return NULL;
+       }
+       free(fullpath);
+
+       return reg_key_new_abs(name, h, NULL);
+}
+
+static BOOL gconf_fetch_values(REG_KEY *p, int *count, REG_VAL ***vals)
+{
+       GSList *entries;
+       GSList *cur;
+       REG_VAL **ar = malloc(sizeof(REG_VAL *));
+       char *fullpath = strdup(reg_key_get_path(p));
+       fullpath = reg_path_win2unix(fullpath);
+       cur = entries = gconf_client_all_entries((GConfClient*)p->handle->backend_data, fullpath, NULL);
+       free(fullpath);
+
+       (*count) = 0;
+       while(cur) {
+               GConfEntry *entry = cur->data;
+               GConfValue *value = gconf_entry_get_value(entry);
+               REG_VAL *newval = reg_val_new(p, NULL);
+               newval->name = strdup(strrchr(gconf_entry_get_key(entry), '/')+1);
+               if(value) {
+                       switch(value->type) {
+                       case GCONF_VALUE_INVALID: 
+                               newval->data_type = REG_NONE;
+                               break;
+
+                       case GCONF_VALUE_STRING:
+                               newval->data_type = REG_SZ;
+                               newval->data_blk = strdup(gconf_value_get_string(value));
+                               newval->data_len = strlen(newval->data_blk);
+                               break;
+
+                       case GCONF_VALUE_INT:
+                               newval->data_type = REG_DWORD;
+                               newval->data_blk = malloc(sizeof(long));
+                               *((long *)newval->data_blk) = gconf_value_get_int(value);
+                               newval->data_len = sizeof(long);
+                               break;
+
+                       case GCONF_VALUE_FLOAT:
+                               newval->data_blk = malloc(sizeof(double));
+                               newval->data_type = REG_BINARY;
+                               *((double *)newval->data_blk) = gconf_value_get_float(value);
+                               newval->data_len = sizeof(double);
+                               break;
+
+                       case GCONF_VALUE_BOOL:
+                               newval->data_blk = malloc(sizeof(BOOL));
+                               newval->data_type = REG_BINARY;
+                               *((BOOL *)newval->data_blk) = gconf_value_get_bool(value);
+                               newval->data_len = sizeof(BOOL);
+                               break;
+
+                       default:
+                               newval->data_type = REG_NONE;
+                               DEBUG(0, ("Not implemented..\n"));
+                               break;
+                       }
+               } else newval->data_type = REG_NONE; 
+
+               ar[(*count)] = newval;
+               ar = realloc(ar, sizeof(REG_VAL *) * ((*count)+2));
+               (*count)++;
+               g_free(cur->data);
+               cur = cur->next;
+       }
+
+       g_slist_free(entries);
+       *vals = ar;
+       return True;
+}
+
+static BOOL gconf_fetch_subkeys(REG_KEY *p, int *count, REG_KEY ***subs) 
+{
+       GSList *dirs;
+       GSList *cur;
+       REG_KEY **ar = malloc(sizeof(REG_KEY *));
+       char *fullpath = strdup(reg_key_get_path(p));
+       fullpath = reg_path_win2unix(fullpath);
+       cur = dirs = gconf_client_all_dirs((GConfClient*)p->handle->backend_data, fullpath,NULL);
+       free(fullpath);
+
+       (*count) = 0;
+       while(cur) {
+               ar[(*count)] = reg_key_new_abs(reg_path_unix2win((char *)cur->data), p->handle, NULL);
+               ar = realloc(ar, sizeof(REG_KEY *) * ((*count)+2));
+               (*count)++;
+               g_free(cur->data);
+               cur = cur->next;
+       }
+
+       g_slist_free(dirs);
+       *subs = ar;
+       return True;
+}
+
+static BOOL gconf_update_value(REG_VAL *val, int type, void *data, int len)
+{
+       GError *error = NULL;
+       char *keypath = reg_path_win2unix(strdup(reg_key_get_path(val->parent)));
+       char *valpath;
+       if(val->name)asprintf(&valpath, "%s/%s", keypath, val->name);
+       else valpath = strdup(keypath);
+       free(keypath);
+       
+       switch(type) {
+       case REG_SZ:
+       case REG_EXPAND_SZ:
+               gconf_client_set_string((GConfClient *)val->handle->backend_data, valpath, data, &error);
+               free(valpath);
+               return (error == NULL);
+
+       case REG_DWORD:
+               gconf_client_set_int((GConfClient *)val->handle->backend_data, valpath, 
+ *((int *)data), &error);
+               free(valpath);
+               return (error == NULL);
+       default:
+               DEBUG(0, ("Unsupported type: %d\n", type));
+               free(valpath);
+               return False;
+       }
+       return False;
+}
+
+static REG_OPS reg_backend_gconf = {
+       .name = "gconf",
+       .open_registry = reg_open_gconf,
+       .close_registry = reg_close_gconf,
+       .open_key = gconf_open_key,
+       .fetch_subkeys = gconf_fetch_subkeys,
+       .fetch_values = gconf_fetch_values,
+       .update_value = gconf_update_value,
+       
+       /* Note: 
+        * since GConf uses schemas for what keys and values are allowed, there 
+        * is no way of 'emulating' add_key and del_key here.
+        */
+};
+
+NTSTATUS reg_gconf_init(void)
+{
+       return register_backend("registry", &reg_backend_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
new file mode 100644 (file)
index 0000000..75d5a95
--- /dev/null
@@ -0,0 +1,61 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Jelmer Vernooij                                         2004.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+/* 
+ * 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)
+{
+       struct ldb_context *c;
+       c = ldb_connect(location, 0, NULL);
+
+       if(!c) return False;
+
+       handle->backend_data = c;
+       
+       return True;
+}
+
+static BOOL ldb_close_registry(REG_HANDLE *h) 
+{
+       ldb_close(h);
+       return True;
+}
+
+static REG_KEY *ldb_open_key(REG_HANDLE *h, const char *name)
+{
+       /* FIXME */
+}
+
+static REG_OPS reg_backend_ldb = {
+       .name = "ldb",
+       .open_registry = ldb_open_registry,
+       .close_registry = ldb_close_registry,
+       .open_key = ldb_open_key,
+};
+
+NTSTATUS reg_ldb_init(void)
+{
+       return register_backend("registry", &reg_backend_ldb);
+}
diff --git a/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c b/source4/lib/registry/reg_backend_nt4/reg_backend_nt4.c
new file mode 100644 (file)
index 0000000..ef2565b
--- /dev/null
@@ -0,0 +1,1745 @@
+/*
+   Samba Unix/Linux SMB client utility libeditreg.c 
+   Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
+   Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+/*************************************************************************
+                                                       
+ A utility to edit a Windows NT/2K etc registry file.
+                                     
+ Many of the ideas in here come from other people and software. 
+ I first looked in Wine in misc/registry.c and was also influenced by
+ http://www.wednesday.demon.co.uk/dosreg.html
+
+ Which seems to contain comments from someone else. I reproduce them here
+ incase the site above disappears. It actually comes from 
+ http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt. 
+
+ The goal here is to read the registry into memory, manipulate it, and then
+ write it out if it was changed by any actions of the user.
+
+The windows NT registry has 2 different blocks, where one can occur many
+times...
+
+the "regf"-Block
+================
+"regf" is obviously the abbreviation for "Registry file". "regf" is the
+signature of the header-block which is always 4kb in size, although only
+the first 64 bytes seem to be used and a checksum is calculated over
+the first 0x200 bytes only!
+
+Offset            Size      Contents
+0x00000000      D-Word      ID: ASCII-"regf" = 0x66676572
+0x00000004      D-Word      ???? //see struct REG_HANDLE
+0x00000008      D-Word      ???? Always the same value as at 0x00000004
+0x0000000C      Q-Word      last modify date in WinNT date-format
+0x00000014      D-Word      1
+0x00000018      D-Word      3
+0x0000001C      D-Word      0
+0x00000020      D-Word      1
+0x00000024      D-Word      Offset of 1st key record
+0x00000028      D-Word      Size of the data-blocks (Filesize-4kb)
+0x0000002C      D-Word      1
+0x000001FC      D-Word      Sum of all D-Words from 0x00000000 to
+0x000001FB  //XOR of all words. Nigel
+
+I have analyzed more registry files (from multiple machines running
+NT 4.0 german version) and could not find an explanation for the values
+marked with ???? the rest of the first 4kb page is not important...
+
+the "hbin"-Block
+================
+I don't know what "hbin" stands for, but this block is always a multiple
+of 4kb in size.
+
+Inside these hbin-blocks the different records are placed. The memory-
+management looks like a C-compiler heap management to me...
+
+hbin-Header
+===========
+Offset      Size      Contents
+0x0000      D-Word      ID: ASCII-"hbin" = 0x6E696268
+0x0004      D-Word      Offset from the 1st hbin-Block
+0x0008      D-Word      Offset to the next hbin-Block
+0x001C      D-Word      Block-size
+
+The values in 0x0008 and 0x001C should be the same, so I don't know
+if they are correct or swapped...
+
+From offset 0x0020 inside a hbin-block data is stored with the following
+format:
+
+Offset      Size      Contents
+0x0000      D-Word      Data-block size    //this size must be a
+multiple of 8. Nigel
+0x0004      ????      Data
+If the size field is negative (bit 31 set), the corresponding block
+is free and has a size of -blocksize!
+
+That does not seem to be true. All block lengths seem to be negative! 
+(Richard Sharpe) 
+
+The data is stored as one record per block. Block size is a multiple
+of 4 and the last block reaches the next hbin-block, leaving no room.
+
+(That also seems incorrect, in that the block size if a multiple of 8.
+That is, the block, including the 4 byte header, is always a multiple of
+8 bytes. Richard Sharpe.)
+
+Records in the hbin-blocks
+==========================
+
+nk-Record
+
+      The nk-record can be treated as a combination of tree-record and
+      key-record of the win 95 registry.
+
+lf-Record
+
+      The lf-record is the counterpart to the RGKN-record (the
+      hash-function)
+
+vk-Record
+
+      The vk-record consists information to a single value (value key).
+
+sk-Record
+
+      sk (? Security Key ?) is the ACL of the registry.
+
+Value-Lists
+
+      The value-lists contain information about which values are inside a
+      sub-key and don't have a header.
+
+Datas
+
+      The datas of the registry are (like the value-list) stored without a
+      header.
+
+All offset-values are relative to the first hbin-block and point to the
+block-size field of the record-entry. to get the file offset, you have to add
+the header size (4kb) and the size field (4 bytes)...
+
+the nk-Record
+=============
+Offset      Size      Contents
+0x0000      Word      ID: ASCII-"nk" = 0x6B6E
+0x0002      Word      for the root-key: 0x2C, otherwise 0x20  //key symbolic links 0x10. Nigel
+0x0004      Q-Word      write-date/time in windows nt notation
+0x0010      D-Word      Offset of Owner/Parent key
+0x0014      D-Word      number of sub-Keys
+0x001C      D-Word      Offset of the sub-key lf-Records
+0x0024      D-Word      number of values
+0x0028      D-Word      Offset of the Value-List
+0x002C      D-Word      Offset of the sk-Record
+
+0x0030      D-Word      Offset of the Class-Name //see NK structure for the use of these fields. Nigel
+0x0044      D-Word      Unused (data-trash)  //some kind of run time index. Does not appear to be important. Nigel
+0x0048      Word      name-length
+0x004A      Word      class-name length
+0x004C      ????      key-name
+
+the Value-List
+==============
+Offset      Size      Contents
+0x0000      D-Word      Offset 1st Value
+0x0004      D-Word      Offset 2nd Value
+0x????      D-Word      Offset nth Value
+
+To determine the number of values, you have to look at the owner-nk-record!
+
+Der vk-Record
+=============
+Offset      Size      Contents
+0x0000      Word      ID: ASCII-"vk" = 0x6B76
+0x0002      Word      name length
+0x0004      D-Word      length of the data   //if top bit is set when offset contains data. Nigel
+0x0008      D-Word      Offset of Data
+0x000C      D-Word      Type of value
+0x0010      Word      Flag
+0x0012      Word      Unused (data-trash)
+0x0014      ????      Name
+
+If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default)
+
+If the data-size is lower 5, the data-offset value is used to store the data itself!
+
+The data-types
+==============
+Wert      Beteutung
+0x0001      RegSZ:             character string (in UNICODE!)
+0x0002      ExpandSZ:   string with "%var%" expanding (UNICODE!)
+0x0003      RegBin:           raw-binary value
+0x0004      RegDWord:   Dword
+0x0007      RegMultiSZ:      multiple strings, seperated with 0
+                  (UNICODE!)
+
+The "lf"-record
+===============
+Offset      Size      Contents
+0x0000      Word      ID: ASCII-"lf" = 0x666C
+0x0002      Word      number of keys
+0x0004      ????      Hash-Records
+
+Hash-Record
+===========
+Offset      Size      Contents
+0x0000      D-Word      Offset of corresponding "nk"-Record
+0x0004      D-Word      ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv!
+
+Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the 
+key-name you have to change the hash-value too!
+
+//These hashrecords must be sorted low to high within the lf record. Nigel.
+
+The "sk"-block
+==============
+(due to the complexity of the SAM-info, not clear jet)
+(This is just a self-relative security descriptor in the data. R Sharpe.) 
+
+
+Offset      Size      Contents
+0x0000      Word      ID: ASCII-"sk" = 0x6B73
+0x0002      Word      Unused
+0x0004      D-Word      Offset of previous "sk"-Record
+0x0008      D-Word      Offset of next "sk"-Record
+0x000C      D-Word      usage-counter
+0x0010      D-Word      Size of "sk"-record in bytes
+????                                             //standard self
+relative security desciptor. Nigel
+????  ????      Security and auditing settings...
+????
+
+The usage counter counts the number of references to this
+"sk"-record. You can use one "sk"-record for the entire registry!
+
+Windows nt date/time format
+===========================
+The time-format is a 64-bit integer which is incremented every
+0,0000001 seconds by 1 (I don't know how accurate it realy is!)
+It starts with 0 at the 1st of january 1601 0:00! All values are
+stored in GMT time! The time-zone is important to get the real
+time!
+
+Common values for win95 and win-nt
+==================================
+Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF).
+If a value has no name (length=0, flag(bit 0)=0), it is treated as the
+"Default" entry...
+If a value has no data (length=0), it is displayed as empty.
+
+simplyfied win-3.?? registry:
+=============================
+
++-----------+
+| next rec. |---+                      +----->+------------+
+| first sub |   |                      |      | Usage cnt. |
+| name      |   |  +-->+------------+  |      | length     |
+| value     |   |  |   | next rec.  |  |      | text       |------->+-------+
++-----------+   |  |   | name rec.  |--+      +------------+        | xxxxx |
+   +------------+  |   | value rec. |-------->+------------+        +-------+
+   v               |   +------------+         | Usage cnt. |
++-----------+      |                          | length     |
+| next rec. |      |                          | text       |------->+-------+
+| first sub |------+                          +------------+        | xxxxx |
+| name      |                                                       +-------+
+| value     |
++-----------+    
+
+Greatly simplyfied structure of the nt-registry:
+================================================
+   
++---------------------------------------------------------------+
+|                                                               |
+v                                                               |
++---------+     +---------->+-----------+  +----->+---------+   |
+| "nk"    |     |           | lf-rec.   |  |      | nk-rec. |   |
+| ID      |     |           | # of keys |  |      | parent  |---+
+| Date    |     |           | 1st key   |--+      | ....    |
+| parent  |     |           +-----------+         +---------+
+| suk-keys|-----+
+| values  |--------------------->+----------+
+| SK-rec. |---------------+      | 1. value |--> +----------+
+| class   |--+            |      +----------+    | vk-rec.  |
++---------+  |            |                      | ....     |
+             v            |                      | data     |--> +-------+
+      +------------+      |                      +----------+    | xxxxx |
+      | Class name |      |                                      +-------+
+      +------------+      |
+                          v
+          +---------+    +---------+
+   +----->| next sk |--->| Next sk |--+
+   |  +---| prev sk |<---| prev sk |  |
+   |  |   | ....    |    | ...     |  |
+   |  |   +---------+    +---------+  |
+   |  |                    ^          |
+   |  |                    |          |
+   |  +--------------------+          |
+   +----------------------------------+
+
+---------------------------------------------------------------------------
+
+Hope this helps....  (Although it was "fun" for me to uncover this things,
+                  it took me several sleepless nights ;)
+
+            B.D.
+
+*************************************************************************/
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+#define REG_KEY_LIST_SIZE 10
+/*FIXME*/
+
+/*
+ * Structures for dealing with the on-disk format of the registry
+ */
+
+const char *def_owner_sid_str = NULL;
+
+/* 
+ * These definitions are for the in-memory registry structure.
+ * It is a tree structure that mimics what you see with tools like regedit
+ */
+
+
+/*
+ * Definition of a Key. It has a name, classname, date/time last modified,
+ * sub-keys, values, and a security descriptor
+ */
+
+#define REG_ROOT_KEY 1
+#define REG_SUB_KEY  2
+#define REG_SYM_LINK 3
+
+/* 
+ * All of the structures below actually have a four-byte length before them
+ * which always seems to be negative. The following macro retrieves that
+ * size as an integer
+ */
+
+#define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1))
+
+typedef unsigned int DWORD;
+typedef unsigned short WORD;
+
+typedef struct sk_struct SK_HDR;
+/*
+ * This structure keeps track of the output format of the registry
+ */
+#define REG_OUTBLK_HDR 1
+#define REG_OUTBLK_HBIN 2
+
+typedef struct regf_block {
+       DWORD REGF_ID;     /* regf */
+       DWORD uk1;
+       DWORD uk2;
+       DWORD tim1, tim2;
+       DWORD uk3;             /* 1 */
+       DWORD uk4;             /* 3 */
+       DWORD uk5;             /* 0 */
+       DWORD uk6;             /* 1 */
+       DWORD first_key;       /* offset */
+       unsigned int dblk_size;
+    DWORD uk7[116];        /* 1 */
+    DWORD chksum;
+} REGF_HDR;
+
+typedef struct hbin_sub_struct {
+       DWORD dblocksize;
+       char data[1];
+} HBIN_SUB_HDR;
+
+typedef struct hbin_struct {
+       DWORD HBIN_ID; /* hbin */
+       DWORD off_from_first;
+       DWORD off_to_next;
+       DWORD uk1;
+       DWORD uk2;
+       DWORD uk3;
+       DWORD uk4;
+       DWORD blk_size;
+       HBIN_SUB_HDR hbin_sub_hdr;
+} HBIN_HDR;
+
+typedef struct nk_struct {
+       WORD NK_ID;
+       WORD type;
+       DWORD t1, t2;
+       DWORD uk1;
+       DWORD own_off;
+       DWORD subk_num;
+       DWORD uk2;
+       DWORD lf_off;
+       DWORD uk3;
+       DWORD val_cnt;
+       DWORD val_off;
+       DWORD sk_off;
+       DWORD clsnam_off;
+       DWORD unk4[4];
+       DWORD unk5;
+       WORD nam_len;
+       WORD clsnam_len;
+       char key_nam[1];  /* Actual length determined by nam_len */
+} NK_HDR;
+
+struct sk_struct {
+       WORD SK_ID;
+       WORD uk1;
+       DWORD prev_off;
+       DWORD next_off;
+       DWORD ref_cnt;
+       DWORD rec_size;
+       char sec_desc[1];
+};
+
+typedef struct key_sec_desc_s {
+       struct key_sec_desc_s *prev, *next;
+       int ref_cnt;
+       int state;
+       int offset;
+       SK_HDR *sk_hdr;     /* This means we must keep the registry in memory */
+       SEC_DESC *sec_desc;
+} KEY_SEC_DESC; 
+
+/* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */
+typedef struct sk_map_s {
+  int sk_off;
+  KEY_SEC_DESC *key_sec_desc;
+} SK_MAP;
+
+typedef struct vk_struct {
+  WORD VK_ID;
+  WORD nam_len;
+  DWORD dat_len;    /* If top-bit set, offset contains the data */
+  DWORD dat_off;
+  DWORD dat_type;
+  WORD flag;        /* =1, has name, else no name (=Default). */
+  WORD unk1;
+  char dat_name[1]; /* Name starts here ... */
+} VK_HDR;
+
+typedef DWORD VL_TYPE[1];  /* Value list is an array of vk rec offsets */
+                                                                                
+typedef struct hash_struct {
+  DWORD nk_off;
+  char hash[4];
+} HASH_REC;
+
+
+typedef struct lf_struct {
+  WORD LF_ID;
+  WORD key_count;
+  struct hash_struct hr[1];  /* Array of hash records, depending on key_count */} LF_HDR;
+
+
+
+/*
+ * This structure keeps track of the output format of the registry
+ */
+#define REG_OUTBLK_HDR 1
+#define REG_OUTBLK_HBIN 2
+
+typedef struct hbin_blk_s {
+  int type, size;
+  struct hbin_blk_s *next;
+  char *data;                /* The data block                */
+  unsigned int file_offset;  /* Offset in file                */
+  unsigned int free_space;   /* Amount of free space in block */
+  unsigned int fsp_off;      /* Start of free space in block  */
+  int complete, stored;
+} HBIN_BLK;
+
+typedef struct regf_struct_s {
+       int reg_type;
+       int fd;
+       struct stat sbuf;
+       char *base;
+       int modified;
+       NTTIME last_mod_time;
+       NK_HDR *first_key;
+       int sk_count, sk_map_size;
+       SK_MAP *sk_map;
+       const char *owner_sid_str;
+       SEC_DESC *def_sec_desc;
+       /*
+        * These next pointers point to the blocks used to contain the 
+        * keys when we are preparing to write them to a file
+        */
+       HBIN_BLK *blk_head, *blk_tail, *free_space;
+       TALLOC_CTX *mem_ctx;
+} REGF;
+
+DWORD str_to_dword(const char *a) {
+       int i;
+       unsigned long ret = 0;
+       for(i = strlen(a)-1; i >= 0; i--) {
+               ret = ret * 0x100 + a[i];
+       }
+       return ret;
+}
+
+#if 0
+
+/*
+ * Create an ACE
+ */
+static BOOL nt_create_ace(SEC_ACE *ace, int type, int flags, uint32 perms, const char *sid)
+{
+  DOM_SID s;
+  SEC_ACCESS access;
+  access.mask = perms;
+  if(!string_to_sid(&s, sid))return False;
+  init_sec_ace(ace, &s, type, access, flags);
+  return True;
+}
+
+/*
+ * Create a default ACL
+ */
+static SEC_ACL *nt_create_default_acl(REG_HANDLE *regf)
+{
+  SEC_ACE aces[8];
+
+  if(!nt_create_ace(&aces[0], 0x00, 0x0, 0xF003F, regf->owner_sid_str)) return NULL;
+  if(!nt_create_ace(&aces[1], 0x00, 0x0, 0xF003F, "S-1-5-18")) return NULL;
+  if(!nt_create_ace(&aces[2], 0x00, 0x0, 0xF003F, "S-1-5-32-544")) return NULL;
+  if(!nt_create_ace(&aces[3], 0x00, 0x0, 0x20019, "S-1-5-12")) return NULL;
+  if(!nt_create_ace(&aces[4], 0x00, 0x0B, GENERIC_RIGHT_ALL_ACCESS, regf->owner_sid_str)) return NULL;
+  if(!nt_create_ace(&aces[5], 0x00, 0x0B, 0x10000000, "S-1-5-18")) return NULL;
+  if(!nt_create_ace(&aces[6], 0x00, 0x0B, 0x10000000, "S-1-5-32-544")) return NULL;
+  if(!nt_create_ace(&aces[7], 0x00, 0x0B, 0x80000000, "S-1-5-12")) return NULL;
+
+  return make_sec_acl(regf->mem_ctx, 2, 8, aces);
+}
+
+/*
+ * Create a default security descriptor. We pull in things from env
+ * if need be 
+ */
+static SEC_DESC *nt_create_def_sec_desc(REG_HANDLE *regf)
+{
+  SEC_DESC *tmp;
+
+  tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC));
+
+  tmp->revision = 1;
+  tmp->type = SEC_DESC_SELF_RELATIVE | SEC_DESC_DACL_PRESENT;
+  if (!string_to_sid(tmp->owner_sid, "S-1-5-32-544")) goto error;
+  if (!string_to_sid(tmp->grp_sid, "S-1-5-18")) goto error;
+  tmp->sacl = NULL;
+  tmp->dacl = nt_create_default_acl(regf);
+
+  return tmp;
+
+ error:
+  if (tmp) nt_delete_sec_desc(tmp);
+  return NULL;
+}
+
+/*
+ * We will implement inheritence that is based on what the parent's SEC_DESC
+ * says, but the Owner and Group SIDs can be overwridden from the command line
+ * and additional ACEs can be applied from the command line etc.
+ */
+static KEY_SEC_DESC *nt_inherit_security(REG_KEY *key)
+{
+
+  if (!key) return NULL;
+  return key->security;
+}
+
+/*
+ * Create an initial security descriptor and init other structures, if needed
+ * We assume that the initial security stuff is empty ...
+ */
+static KEY_SEC_DESC *nt_create_init_sec(REG_HANDLE *h)
+{
+       REGF *regf = h->backend_data;
+       KEY_SEC_DESC *tsec = NULL;
+
+       tsec = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
+
+       tsec->ref_cnt = 1;
+       tsec->state = SEC_DESC_NBK;
+       tsec->offset = 0;
+
+       tsec->sec_desc = regf->def_sec_desc;
+
+       return tsec;
+}
+#endif
+
+/*
+ * Get the starting record for NT Registry file 
+ */
+
+/* 
+ * Where we keep all the regf stuff for one registry.
+ * This is the structure that we use to tie the in memory tree etc 
+ * together. By keeping separate structs, we can operate on different
+ * registries at the same time.
+ * Currently, the SK_MAP is an array of mapping structure.
+ * Since we only need this on input and output, we fill in the structure
+ * as we go on input. On output, we know how many SK items we have, so
+ * we can allocate the structure as we need to.
+ * If you add stuff here that is dynamically allocated, add the 
+ * appropriate free statements below.
+ */
+
+#define REG_HANDLE_REGTYPE_NONE 0
+#define REG_HANDLE_REGTYPE_NT   1
+#define REG_HANDLE_REGTYPE_W9X  2
+
+#define TTTONTTIME(r, t1, t2) (r)->last_mod_time.low = (t1); \
+                              (r)->last_mod_time.high = (t2);
+
+#define REGF_HDR_BLKSIZ 0x1000 
+
+#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4) 
+#define LOCN(base, f) ((base) + OFF(f))
+
+/* Get the header of the registry. Return a pointer to the structure 
+ * If the mmap'd area has not been allocated, then mmap the input file
+ */
+static REGF_HDR *nt_get_regf_hdr(REG_HANDLE *h)
+{
+       REGF *regf = h->backend_data;
+       SMB_REG_ASSERT(regf);
+
+       if (!regf->base) { /* Try to mmap etc the file */
+
+               if ((regf->fd = open(h->location, O_RDONLY, 0000)) <0) {
+                       return NULL; /* What about errors? */
+               }
+
+               if (fstat(regf->fd, &regf->sbuf) < 0) {
+                       return NULL;
+               }
+
+               regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0);
+
+               if ((int)regf->base == 1) {
+                       DEBUG(0,("Could not mmap file: %s, %s\n", h->location,
+                                        strerror(errno)));
+                       return NULL;
+               }
+       }
+
+       /* 
+        * At this point, regf->base != NULL, and we should be able to read the 
+        * header 
+        */
+
+       SMB_REG_ASSERT(regf->base != NULL);
+
+       return (REGF_HDR *)regf->base;
+}
+
+/*
+ * Validate a regf header
+ * For now, do nothing, but we should check the checksum
+ */
+static int valid_regf_hdr(REGF_HDR *regf_hdr)
+{
+       if (!regf_hdr) return 0;
+
+       return 1;
+}
+
+#if 0
+
+/*
+ * Process an SK header ...
+ * Every time we see a new one, add it to the map. Otherwise, just look it up.
+ * We will do a simple linear search for the moment, since many KEYs have the 
+ * same security descriptor. 
+ * We allocate the map in increments of 10 entries.
+ */
+
+/*
+ * Create a new entry in the map, and increase the size of the map if needed
+ */
+static SK_MAP *alloc_sk_map_entry(REG_HANDLE *h, KEY_SEC_DESC *tmp, int sk_off)
+{
+       REGF *regf = h->backend_data;
+       if (!regf->sk_map) { /* Allocate a block of 10 */
+               regf->sk_map = (SK_MAP *)malloc(sizeof(SK_MAP) * 10);
+               regf->sk_map_size = 10;
+               regf->sk_count = 1;
+               (regf->sk_map)[0].sk_off = sk_off;
+               (regf->sk_map)[0].key_sec_desc = tmp;
+       }
+       else { /* Simply allocate a new slot, unless we have to expand the list */ 
+               int ndx = regf->sk_count;
+               if (regf->sk_count >= regf->sk_map_size) {
+                       regf->sk_map = (SK_MAP *)realloc(regf->sk_map, 
+                                                                                        (regf->sk_map_size + 10)*sizeof(SK_MAP));
+                       if (!regf->sk_map) {
+                               free(tmp);
+                               return NULL;
+                       }
+                       /*
+                        * ndx already points at the first entry of the new block
+                        */
+                       regf->sk_map_size += 10;
+               }
+               (regf->sk_map)[ndx].sk_off = sk_off;
+               (regf->sk_map)[ndx].key_sec_desc = tmp;
+               regf->sk_count++;
+       }
+       return regf->sk_map;
+}
+
+/*
+ * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not
+ * found
+ */
+KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off)
+{
+       int i;
+
+       if (!sk_map) return NULL;
+
+       for (i = 0; i < count; i++) {
+
+               if (sk_map[i].sk_off == sk_off)
+                       return sk_map[i].key_sec_desc;
+
+       }
+
+       return NULL;
+
+}
+
+/*
+ * Allocate a KEY_SEC_DESC if we can't find one in the map
+ */
+static KEY_SEC_DESC *lookup_create_sec_key(REG_HANDLE *h, SK_MAP *sk_map, int sk_off)
+{
+       REGF *regf = h->backend_data;
+       KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off);
+
+       if (tmp) {
+               return tmp;
+       }
+       else { /* Allocate a new one */
+               tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
+               memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */
+               tmp->state = SEC_DESC_RES;
+               if (!alloc_sk_map_entry(h, tmp, sk_off)) {
+                       return NULL;
+               }
+               return tmp;
+       }
+}
+
+static SEC_DESC *process_sec_desc(REG_HANDLE *regf, SEC_DESC *sec_desc)
+{
+       SEC_DESC *tmp = NULL;
+
+       tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC));
+
+       tmp->revision = SVAL(&sec_desc->revision,0);
+       tmp->type = SVAL(&sec_desc->type,0);
+       DEBUG(2, ("SEC_DESC Rev: %0X, Type: %0X\n", tmp->revision, tmp->type));
+       DEBUGADD(2, ("SEC_DESC Owner Off: %0X\n", IVAL(&sec_desc->off_owner_sid,0)));
+       DEBUGADD(2, ("SEC_DESC Group Off: %0X\n", IVAL(&sec_desc->off_grp_sid,0)));
+       DEBUGADD(2, ("SEC_DESC DACL Off: %0X\n", IVAL(&sec_desc->off_dacl,0)));
+       tmp->owner_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_owner_sid,0)));
+       if (!tmp->owner_sid) {
+               free(tmp);
+               return NULL;
+       }
+       tmp->grp_sid = sid_dup_talloc(regf->mem_ctx, (DOM_SID *)((char *)sec_desc + IVAL(&sec_desc->off_grp_sid,0)));
+       if (!tmp->grp_sid) {
+               free(tmp);
+               return NULL;
+       }
+
+       /* Now pick up the SACL and DACL */
+
+       DEBUG(0, ("%d, %d\n", IVAL(&sec_desc->off_sacl,0), IVAL(&sec_desc->off_dacl,0)));
+
+       if (sec_desc->off_sacl)
+               tmp->sacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_sacl,0)));
+       else
+               tmp->sacl = NULL;
+
+       if (sec_desc->off_dacl)
+               tmp->dacl = dup_sec_acl(regf->mem_ctx, (SEC_ACL *)((char *)sec_desc + IVAL(&sec_desc->off_dacl,0)));
+       else
+               tmp->dacl = NULL;
+
+       return tmp;
+}
+
+static KEY_SEC_DESC *process_sk(REG_HANDLE *regf, SK_HDR *sk_hdr, int sk_off, int size)
+{
+       KEY_SEC_DESC *tmp = NULL;
+       int sk_next_off, sk_prev_off, sk_size;
+       SEC_DESC *sec_desc;
+
+       if (!sk_hdr) return NULL;
+
+       if (SVAL(&sk_hdr->SK_ID,0) != str_to_dword("sk")) {
+               DEBUG(0, ("Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr,
+                                 regf->regfile_name));
+               return NULL;
+       }
+
+       if (-size < (sk_size = IVAL(&sk_hdr->rec_size,0))) {
+               DEBUG(0, ("Incorrect SK record size: %d vs %d. %s\n",
+                                 -size, sk_size, regf->regfile_name));
+               return NULL;
+       }
+
+       /* 
+        * Now, we need to look up the SK Record in the map, and return it
+        * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can
+        * use that
+        */
+
+       if (regf->sk_map &&
+               ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL)
+               && (tmp->state == SEC_DESC_OCU)) {
+               tmp->ref_cnt++;
+               return tmp;
+       }
+
+       /* Here, we have an item in the map that has been reserved, or tmp==NULL. */
+
+       SMB_REG_ASSERT(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON));
+
+       /*
+        * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the
+        * new KEY_SEC_DESC to the mapping structure, since the offset supplied is 
+        * the actual offset of structure. The same offset will be used by
+        * all future references to this structure
+        * We could put all this unpleasantness in a function.
+        */
+
+       if (!tmp) {
+               tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
+               memset(tmp, 0, sizeof(KEY_SEC_DESC));
+
+               /*
+                * Allocate an entry in the SK_MAP ...
+                * We don't need to free tmp, because that is done for us if the
+                * sm_map entry can't be expanded when we need more space in the map.
+                */
+
+               if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
+                       return NULL;
+               }
+       }
+
+       tmp->ref_cnt++;
+       tmp->state = SEC_DESC_OCU;
+
+       /*
+        * Now, process the actual sec desc and plug the values in
+        */
+
+       sec_desc = (SEC_DESC *)&sk_hdr->sec_desc[0];
+       tmp->sec_desc = process_sec_desc(regf, sec_desc);
+
+       /*
+        * Now forward and back links. Here we allocate an entry in the sk_map
+        * if it does not exist, and mark it reserved
+        */
+
+       sk_prev_off = IVAL(&sk_hdr->prev_off,0);
+       tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off);
+       SMB_REG_ASSERT(tmp->prev != NULL);
+       sk_next_off = IVAL(&sk_hdr->next_off,0);
+       tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off);
+       SMB_REG_ASSERT(tmp->next != NULL);
+
+       return tmp;
+}
+#endif
+
+/*
+ * Process a VK header and return a value
+ */
+static REG_VAL *vk_to_val(REG_KEY *parent, VK_HDR *vk_hdr, int size)
+{
+       char val_name[1024];
+       REGF *regf = parent->handle->backend_data;
+       int nam_len, dat_len, flag, dat_type, dat_off, vk_id;
+       const char *val_type;
+       REG_VAL *tmp = NULL; 
+
+       if (!vk_hdr) return NULL;
+
+       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;
+       }
+
+       nam_len = SVAL(&vk_hdr->nam_len,0);
+       val_name[nam_len] = '\0';
+       flag = SVAL(&vk_hdr->flag,0);
+       dat_type = IVAL(&vk_hdr->dat_type,0);
+       dat_len = IVAL(&vk_hdr->dat_len,0);  /* If top bit, offset contains data */
+       dat_off = IVAL(&vk_hdr->dat_off,0);
+
+       tmp = reg_val_new(parent, NULL);
+       tmp->has_name = flag;
+       tmp->data_type = dat_type;
+
+       if (flag & 0x01) {
+               strncpy(val_name, vk_hdr->dat_name, nam_len);
+               tmp->name = strdup(val_name);
+       }
+       else
+               strncpy(val_name, "<No Name>", 10);
+
+       /*
+        * Allocate space and copy the data as a BLOB
+        */
+
+       if (dat_len&0x7FFFFFFF) {
+
+               char *dtmp = (char *)malloc(dat_len&0x7FFFFFFF);
+
+               tmp->data_blk = dtmp;
+
+               if ((dat_len&0x80000000) == 0) { /* The data is pointed to by the offset */
+                       char *dat_ptr = LOCN(regf->base, dat_off);
+                       memcpy(dtmp, dat_ptr, dat_len);
+               }
+               else { /* The data is in the offset or type */
+                       /*
+                        * FIXME.
+                        * Some registry files seem to have weird fields. If top bit is set,
+                        * but len is 0, the type seems to be the value ...
+                        * Not sure how to handle this last type for the moment ...
+                        */
+                       dat_len = dat_len & 0x7FFFFFFF;
+                       memcpy(dtmp, &dat_off, dat_len);
+               }
+
+               tmp->data_len = dat_len;
+       }
+
+       return tmp;
+}
+
+static BOOL vl_verify(VL_TYPE vl, int count, int size)
+{
+       if(!vl) return False;
+       if (-size < (count+1)*sizeof(int)){
+               DEBUG(0, ("Error in VL header format. Size less than space required. %d\n", -size));
+               return False;
+       }
+       return True;
+}
+
+static BOOL 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 True;
+}
+
+static int lf_num_entries(REG_HANDLE *h, LF_HDR *lf_hdr, int size)
+{
+       int count;
+
+       if(!lf_verify(h, lf_hdr, size)) return 0;
+
+       SMB_REG_ASSERT(size < 0);
+
+       count = SVAL(&lf_hdr->key_count,0);
+       DEBUG(2, ("Key Count: %u\n", count));
+       if (count <= 0) return 0;
+
+       return count;
+}
+
+
+static REG_KEY *nk_to_key(REG_HANDLE *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent);
+
+
+
+/*
+ * 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)
+{
+       REGF *regf = parent->handle->backend_data;
+       int count, nk_off;
+       NK_HDR *nk_hdr;
+
+       if (!lf_hdr) return NULL;
+
+       if(!lf_verify(parent->handle, lf_hdr, size)) return NULL;
+
+       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;
+
+       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);
+}
+
+static REG_KEY *nk_to_key(REG_HANDLE *h, NK_HDR *nk_hdr, int size, REG_KEY *parent)
+{
+       REGF *regf = h->backend_data;
+       REG_KEY *tmp = NULL, *own;
+       int name_len, clsname_len, sk_off, own_off;
+       unsigned int nk_id;
+       SK_HDR *sk_hdr;
+       int type;
+       char key_name[1024], cls_name[1024];
+
+       if (!nk_hdr) return NULL;
+
+       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;
+       }
+
+       SMB_REG_ASSERT(size < 0);
+
+       name_len = SVAL(&nk_hdr->nam_len,0);
+       clsname_len = SVAL(&nk_hdr->clsnam_len,0);
+
+       /*
+        * The value of -size should be ge 
+        * (sizeof(NK_HDR) - 1 + name_len)
+        * The -1 accounts for the fact that we included the first byte of 
+        * the name in the structure. clsname_len is the length of the thing 
+        * pointed to by clsnam_off
+        */
+
+       if (-size < (sizeof(NK_HDR) - 1 + name_len)) {
+               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;*/
+       }
+
+       DEBUG(2, ("NK HDR: Name len: %d, class name len: %d\n", name_len, clsname_len));
+
+       /* Fish out the key name and process the LF list */
+
+       SMB_REG_ASSERT(name_len < sizeof(key_name));
+
+       strncpy(key_name, nk_hdr->key_nam, name_len);
+       key_name[name_len] = '\0';
+
+       type = (SVAL(&nk_hdr->type,0)==0x2C?REG_ROOT_KEY:REG_SUB_KEY);
+       if(type == REG_ROOT_KEY && parent) {
+               DEBUG(0,("Root key encountered below root level!\n"));
+               return NULL;
+       }
+
+       if(type == REG_ROOT_KEY) tmp = reg_key_new_abs(key_name, h, nk_hdr);
+       else tmp = reg_key_new_rel(key_name, parent, nk_hdr);
+
+       DEBUG(2, ("Key name: %s\n", key_name));
+
+       /*
+        * Fish out the class name, it is in UNICODE, while the key name is 
+        * ASCII :-)
+        */
+
+       if (clsname_len) { /* Just print in Ascii for now */
+               smb_ucs2_t *clsnamep;
+               int clsnam_off;
+
+               clsnam_off = IVAL(&nk_hdr->clsnam_off,0);
+               clsnamep = (smb_ucs2_t *)LOCN(regf->base, clsnam_off);
+               DEBUG(2, ("Class Name Offset: %0X\n", clsnam_off));
+
+               tmp->class_name = talloc_strdup_w(regf->mem_ctx, clsnamep);
+
+               DEBUGADD(2,("  Class Name: %s\n", cls_name));
+
+       }
+
+       /*
+        * Process the owner offset ...
+        */
+
+       own_off = IVAL(&nk_hdr->own_off,0);
+       own = (REG_KEY *)LOCN(regf->base, own_off);
+       DEBUG(2, ("Owner Offset: %0X\n", own_off));
+
+       DEBUGADD(2, ("  Owner locn: %0X, Our locn: %0X\n", 
+                                (unsigned int)own, (unsigned int)nk_hdr));
+
+       /* 
+        * We should verify that the owner field is correct ...
+        * for now, we don't worry ...
+        */
+
+       /* 
+        * Also handle the SK header ...
+        */
+
+       sk_off = IVAL(&nk_hdr->sk_off,0);
+       sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off);
+       DEBUG(2, ("SK Offset: %0X\n", sk_off));
+
+       if (sk_off != -1) {
+
+#if 0
+               tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr));
+#endif
+
+       } 
+
+       return tmp;
+}
+
+/*
+ * Allocate a new hbin block, set up the header for the block etc 
+ */
+static HBIN_BLK *nt_create_hbin_blk(REG_HANDLE *h, int size)
+{
+       REGF *regf = h->backend_data;
+       HBIN_BLK *tmp;
+       HBIN_HDR *hdr;
+
+       if (!regf || !size) return NULL;
+
+       /* Round size up to multiple of REGF_HDR_BLKSIZ */
+
+       size = (size + (REGF_HDR_BLKSIZ - 1)) & ~(REGF_HDR_BLKSIZ - 1);
+
+       tmp = (HBIN_BLK *)malloc(sizeof(HBIN_BLK));
+       memset(tmp, 0, sizeof(HBIN_BLK));
+
+       tmp->data = malloc(size);
+
+       memset(tmp->data, 0, size);  /* Make it pristine */
+
+       tmp->size = size;
+       /*FIXMEtmp->file_offset = regf->blk_tail->file_offset + regf->blk_tail->size;*/
+
+       tmp->free_space = size - (sizeof(HBIN_HDR) - sizeof(HBIN_SUB_HDR));
+       tmp->fsp_off = size - tmp->free_space;
+
+       /* 
+        * Now, build the header in the data block 
+        */
+       hdr = (HBIN_HDR *)tmp->data;
+       hdr->HBIN_ID = str_to_dword("hbin");
+       hdr->off_from_first = tmp->file_offset - REGF_HDR_BLKSIZ;
+       hdr->off_to_next = tmp->size;
+       hdr->blk_size = tmp->size;
+
+       /*
+        * Now link it in
+        */
+
+       regf->blk_tail->next = tmp;
+       regf->blk_tail = tmp;
+       if (!regf->free_space) regf->free_space = tmp;
+
+       return tmp;
+}
+
+/*
+ * Allocate a unit of space ... and return a pointer as function param
+ * and the block's offset as a side effect
+ */
+static void *nt_alloc_regf_space(REG_HANDLE *h, int size, unsigned int *off)
+{
+       REGF *regf = h->backend_data;
+       int tmp = 0;
+       void *ret = NULL;
+       HBIN_BLK *blk;
+
+       if (!regf || !size || !off) return NULL;
+
+       SMB_REG_ASSERT(regf->blk_head != NULL);
+
+       /*
+        * round up size to include header and then to 8-byte boundary
+        */
+       size = (size + 4 + 7) & ~7;
+
+       /*
+        * Check if there is space, if none, grab a block
+        */
+       if (!regf->free_space) {
+               if (!nt_create_hbin_blk(h, REGF_HDR_BLKSIZ))
+                       return NULL;
+       }
+
+       /*
+        * Now, chain down the list of blocks looking for free space
+        */
+
+       for (blk = regf->free_space; blk != NULL; blk = blk->next) {
+               if (blk->free_space <= size) {
+                       tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
+                       ret = blk->data + blk->fsp_off;
+                       blk->free_space -= size;
+                       blk->fsp_off += size;
+
+                       /* Insert the header */
+                       ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
+
+                       /*
+                        * Fix up the free space ptr
+                        * If it is NULL, we fix it up next time
+                        */
+
+                       if (!blk->free_space) 
+                               regf->free_space = blk->next;
+
+                       *off = tmp;
+                       return (((char *)ret)+4);/* The pointer needs to be to the data struct */
+               }
+       }
+
+       /*
+        * If we got here, we need to add another block, which might be 
+        * larger than one block -- deal with that later
+        */
+       if (nt_create_hbin_blk(h, REGF_HDR_BLKSIZ)) {
+               blk = regf->free_space;
+               tmp = blk->file_offset + blk->fsp_off - REGF_HDR_BLKSIZ;
+               ret = blk->data + blk->fsp_off;
+               blk->free_space -= size;
+               blk->fsp_off += size;
+
+               /* Insert the header */
+               ((HBIN_SUB_HDR *)ret)->dblocksize = -size;
+
+               /*
+                * Fix up the free space ptr
+                * If it is NULL, we fix it up next time
+                */
+
+               if (!blk->free_space) 
+                       regf->free_space = blk->next;
+
+               *off = tmp;
+               return (((char *)ret) + 4);/* The pointer needs to be to the data struct */
+       }
+
+       return NULL;
+}
+
+/*
+ * Store a SID at the location provided
+ */
+static int nt_store_SID(REG_HANDLE *regf, DOM_SID *sid, unsigned char *locn)
+{
+       int i;
+       unsigned char *p = locn;
+
+       if (!regf || !sid || !locn) return 0;
+
+       *p = sid->sid_rev_num; p++;
+       *p = sid->num_auths; p++;
+
+       for (i=0; i < 6; i++) {
+               *p = sid->id_auth[i]; p++;
+       }
+
+       for (i=0; i < sid->num_auths; i++) {
+               SIVAL(p, 0, sid->sub_auths[i]); p+=4;
+       }
+
+       return p - locn;
+
+}
+
+static int nt_store_ace(REG_HANDLE *regf, SEC_ACE *ace, unsigned char *locn)
+{
+       int size = 0;
+       SEC_ACE *reg_ace = (SEC_ACE *)locn;
+       unsigned char *p;
+
+       if (!regf || !ace || !locn) return 0;
+
+       reg_ace->type = ace->type;
+       reg_ace->flags = ace->flags;
+
+       /* Deal with the length when we have stored the SID */
+
+       p = (unsigned char *)&reg_ace->info.mask;
+
+       SIVAL(p, 0, ace->info.mask); p += 4;
+
+       size = nt_store_SID(regf, &ace->trustee, p);
+
+       size += 8; /* Size of the fixed header */
+
+       p = (unsigned char *)&reg_ace->size;
+
+       SSVAL(p, 0, size);
+
+       return size;
+}
+
+/*
+ * Store an ACL at the location provided
+ */
+static int nt_store_acl(REG_HANDLE *regf, SEC_ACL *acl, unsigned char *locn) {
+       int size = 0, i;
+       unsigned char *p = locn, *s;
+
+       if (!regf || !acl || !locn) return 0;
+
+       /*
+        * Now store the header and then the ACEs ...
+        */
+
+       SSVAL(p, 0, acl->revision);
+
+       p += 2; s = p; /* Save this for the size field */
+
+       p += 2;
+
+       SIVAL(p, 0, acl->num_aces);
+
+       p += 4;
+
+       for (i = 0; i < acl->num_aces; i++) {
+               size = nt_store_ace(regf, &acl->ace[i], p);
+               p += size;
+       }
+
+       size = s - locn;
+       SSVAL(s, 0, size);
+       return size;
+}
+
+/*
+ * Flatten and store the Sec Desc 
+ * Windows lays out the DACL first, but since there is no SACL, it might be
+ * that first, then the owner, then the group SID. So, we do it that way
+ * too.
+ */
+static unsigned int nt_store_sec_desc(REG_HANDLE *regf, SEC_DESC *sd, char *locn)
+{
+       SEC_DESC *rsd = (SEC_DESC *)locn;
+       unsigned int size = 0, off = 0;
+
+       if (!regf || !sd || !locn) return 0;
+
+       /* 
+        * Now, fill in the first two fields, then lay out the various fields
+        * as needed
+        */
+
+       rsd->revision = SEC_DESC_REVISION;
+       rsd->type = SEC_DESC_DACL_PRESENT | SEC_DESC_SELF_RELATIVE;  
+
+       off = 4 * sizeof(DWORD) + 4;
+
+       if (sd->sacl){
+               size = nt_store_acl(regf, sd->sacl, (char *)(locn + off));
+               rsd->off_sacl = off;
+       }
+       else
+               rsd->off_sacl = 0;
+
+       off += size;
+
+       if (sd->dacl) {
+               rsd->off_dacl = off;
+               size = nt_store_acl(regf, sd->dacl, (char *)(locn + off));
+       }
+       else {
+               rsd->off_dacl = 0;
+       }
+
+       off += size;
+
+       /* Now the owner and group SIDs */
+
+       if (sd->owner_sid) {
+               rsd->off_owner_sid = off;
+               size = nt_store_SID(regf, sd->owner_sid, (char *)(locn + off));
+       }
+       else {
+               rsd->off_owner_sid = 0;
+       }
+
+       off += size;
+
+       if (sd->grp_sid) {
+               rsd->off_grp_sid = off;
+               size = nt_store_SID(regf, sd->grp_sid, (char *)(locn + off));
+       }
+       else {
+               rsd->off_grp_sid = 0;
+       }
+
+       off += size;
+
+       return size;
+}
+
+/*
+ * Store the security information
+ *
+ * If it has already been stored, just get its offset from record
+ * otherwise, store it and record its offset
+ */
+static unsigned int nt_store_security(REG_HANDLE *regf, KEY_SEC_DESC *sec)
+{
+       int size = 0;
+       unsigned int sk_off;
+       SK_HDR *sk_hdr;
+
+       if (sec->offset) return sec->offset;
+
+       /*
+        * OK, we don't have this one in the file yet. We must compute the 
+        * size taken by the security descriptor as a self-relative SD, which
+        * means making one pass over each structure and figuring it out
+        */
+
+//FIXME        size = sec_desc_size(sec->sec_desc);
+
+       /* Allocate that much space */
+
+       sk_hdr = nt_alloc_regf_space(regf, size, &sk_off);
+       sec->sk_hdr = sk_hdr;
+
+       if (!sk_hdr) return 0;
+
+       /* Now, lay out the sec_desc in the space provided */
+
+       sk_hdr->SK_ID = str_to_dword("sk");
+
+       /* 
+        * We can't deal with the next and prev offset in the SK_HDRs until the
+        * whole tree has been stored, then we can go and deal with them
+        */
+
+       sk_hdr->ref_cnt = sec->ref_cnt;
+       sk_hdr->rec_size = size;       /* Is this correct */
+
+       /* Now, lay out the sec_desc */
+
+       if (!nt_store_sec_desc(regf, sec->sec_desc, (char *)&sk_hdr->sec_desc))
+               return 0;
+
+       return sk_off;
+
+}
+
+#if 0
+
+/*
+ * Store a KEY in the file ...
+ *
+ * We store this depth first, and defer storing the lf struct until
+ * all the sub-keys have been stored.
+ * 
+ * We store the NK hdr, any SK header, class name, and VK structure, then
+ * recurse down the LF structures ... 
+ * 
+ * We return the offset of the NK struct
+ * FIXME, FIXME, FIXME: Convert to using SIVAL and SSVAL ...
+ */
+static int nt_store_reg_key(REG_HANDLE *regf, REG_KEY *key)
+{
+       NK_HDR *nk_hdr; 
+       unsigned int nk_off, sk_off, size;
+
+       if (!regf || !key) return 0;
+
+       size = sizeof(NK_HDR) + strlen(key->name) - 1;
+       nk_hdr = nt_alloc_regf_space(regf, size, &nk_off);
+       if (!nk_hdr) goto error;
+
+       key->offset = nk_off;  /* We will need this later */
+
+       /*
+        * Now fill in each field etc ...
+        */
+
+       nk_hdr->NK_ID = str_to_dword("nk"); 
+       if (key->type == REG_ROOT_KEY)
+               nk_hdr->type = 0x2C;
+       else
+               nk_hdr->type = 0x20;
+
+       /* FIXME: Fill in the time of last update */
+
+       if (key->type != REG_ROOT_KEY)
+               nk_hdr->own_off = key->owner->offset;
+
+       if (key->sub_keys)
+               nk_hdr->subk_num = key->sub_keys->key_count;
+
+       /*
+        * Now, process the Sec Desc and then store its offset
+        */
+
+       sk_off = nt_store_security(regf, key->security);
+       nk_hdr->sk_off = sk_off;
+
+       /*
+        * Then, store the val list and store its offset
+        */
+       if (key->values) {
+               nk_hdr->val_cnt = key->values->val_count;
+               nk_hdr->val_off = nt_store_val_list(regf, key->values);
+       }
+       else {
+               nk_hdr->val_off = -1;
+               nk_hdr->val_cnt = 0;
+       }
+
+       /*
+        * Finally, store the subkeys, and their offsets
+        */
+
+error:
+       return 0;
+}
+#endif
+
+/*
+ * Store the registry header ...
+ * We actually create the registry header block and link it to the chain
+ * of output blocks.
+ */
+static REGF_HDR *nt_get_reg_header(REG_HANDLE *h) {
+       REGF *regf = h->backend_data;
+       HBIN_BLK *tmp = NULL;
+
+       tmp = (HBIN_BLK *)malloc(sizeof(HBIN_BLK));
+
+       memset(tmp, 0, sizeof(HBIN_BLK));
+       tmp->type = REG_OUTBLK_HDR;
+       tmp->size = REGF_HDR_BLKSIZ;
+       tmp->data = malloc(REGF_HDR_BLKSIZ);
+       if (!tmp->data) goto error;
+
+       memset(tmp->data, 0, REGF_HDR_BLKSIZ);  /* Make it pristine, unlike Windows */
+       regf->blk_head = regf->blk_tail = tmp;
+
+       return (REGF_HDR *)tmp->data;
+
+error:
+       if (tmp) free(tmp);
+       return NULL;
+}
+
+static BOOL nt_close_registry (REG_HANDLE *h) 
+{
+       REGF *regf = h->backend_data;
+       if (regf->base) munmap(regf->base, regf->sbuf.st_size);
+       regf->base = NULL;
+       close(regf->fd);    /* Ignore the error :-) */
+
+       free(regf->sk_map);
+       regf->sk_count = regf->sk_map_size = 0;
+
+       free(regf);
+       return False;
+}
+
+static BOOL nt_open_registry (REG_HANDLE *h, const char *location, BOOL try_load) 
+{
+       REGF *regf = (REGF *)malloc(sizeof(REGF));
+       REGF_HDR *regf_hdr;
+       unsigned int regf_id, hbin_id;
+       HBIN_HDR *hbin_hdr;
+
+       memset(regf, 0, sizeof(REGF));
+       regf->mem_ctx = talloc_init("regf");
+       regf->owner_sid_str = def_owner_sid_str;
+       h->backend_data = regf;
+
+       DEBUG(5, ("Attempting to load registry file\n"));
+
+       /* Get the header */
+
+       if ((regf_hdr = nt_get_regf_hdr(h)) == NULL) {
+               DEBUG(0, ("Unable to get header\n"));
+               return False;
+       }
+
+       /* Now process that header and start to read the rest in */
+
+       if ((regf_id = IVAL(&regf_hdr->REGF_ID,0)) != str_to_dword("regf")) {
+               DEBUG(0, ("Unrecognized NT registry header id: %0X, %s\n",
+                                 regf_id, h->location));
+               return False;
+       }
+
+       /*
+        * Validate the header ...
+        */
+       if (!valid_regf_hdr(regf_hdr)) {
+               DEBUG(0, ("Registry file header does not validate: %s\n",
+                                 h->location));
+               return False;
+       }
+
+       /* Update the last mod date, and then go get the first NK record and on */
+
+       TTTONTTIME(regf, IVAL(&regf_hdr->tim1,0), IVAL(&regf_hdr->tim2,0));
+
+       /* 
+        * The hbin hdr seems to be just uninteresting garbage. Check that
+        * it is there, but that is all.
+        */
+
+       hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ);
+
+       if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID,0)) != str_to_dword("hbin")) {
+               DEBUG(0, ("Unrecognized registry hbin hdr ID: %0X, %s\n", 
+                                 hbin_id, h->location));
+               return False;
+       } 
+
+       /*
+        * Get a pointer to the first key from the hreg_hdr
+        */
+
+       DEBUG(2, ("First Key: %0X\n",
+                         IVAL(&regf_hdr->first_key, 0)));
+
+       regf->first_key = (NK_HDR *)LOCN(regf->base, IVAL(&regf_hdr->first_key,0));
+       DEBUGADD(2, ("First Key Offset: %0X\n", 
+                                IVAL(&regf_hdr->first_key, 0)));
+
+       DEBUGADD(2, ("Data Block Size: %d\n",
+                                IVAL(&regf_hdr->dblk_size, 0)));
+
+       DEBUGADD(2, ("Offset to next hbin block: %0X\n",
+                                IVAL(&hbin_hdr->off_to_next, 0)));
+
+       DEBUGADD(2, ("HBIN block size: %0X\n",
+                                IVAL(&hbin_hdr->blk_size, 0)));
+
+       /*
+        * Unmap the registry file, as we might want to read in another
+        * tree etc.
+        */
+
+       h->backend_data = regf;
+
+       return True;
+}
+
+static REG_KEY *nt_get_root_key(REG_HANDLE *h) 
+{ 
+       return nk_to_key(h, ((REGF *)h->backend_data)->first_key, BLK_SIZE(((REGF *)h->backend_data)->first_key), NULL);
+}
+
+static int nt_num_subkeys(REG_KEY *k) 
+{
+       REGF *regf = k->handle->backend_data;
+       LF_HDR *lf_hdr;
+       int lf_off;
+       NK_HDR *nk_hdr = k->backend_data;
+       lf_off = IVAL(&nk_hdr->lf_off,0);
+       DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
+       if(lf_off == -1) return 0;
+       lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
+
+       return lf_num_entries(k->handle, lf_hdr, BLK_SIZE(lf_hdr));
+}
+
+static int nt_num_values(REG_KEY *k)
+{
+       NK_HDR *nk_hdr = k->backend_data;
+       return IVAL(&nk_hdr->val_cnt,0);
+}
+
+static REG_VAL *nt_value_by_index(REG_KEY *k, int n)
+{
+       VL_TYPE *vl;
+       int val_off, vk_off;
+       VK_HDR *vk_hdr;
+       REGF *regf = k->handle->backend_data;
+       NK_HDR *nk_hdr = k->backend_data;
+       val_off = IVAL(&nk_hdr->val_off,0);
+       vl = (VL_TYPE *)LOCN(regf->base, val_off);
+       DEBUG(2, ("Val List Offset: %0X\n", val_off));
+
+       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));
+}
+
+static REG_KEY *nt_key_by_index(REG_KEY *k, int n)
+{
+       REGF *regf = k->handle->backend_data;
+       int lf_off;
+       NK_HDR *nk_hdr = k->backend_data;
+       LF_HDR *lf_hdr;
+       lf_off = IVAL(&nk_hdr->lf_off,0);
+       DEBUG(2, ("SubKey list offset: %0X\n", lf_off));
+
+       /*
+        * No more subkeys if lf_off == -1
+        */
+
+       if (lf_off != -1) {
+               lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
+               return lf_get_entry(k, lf_hdr, BLK_SIZE(lf_hdr), n);
+       }
+
+       return NULL;
+}
+
+static REG_OPS reg_backend_nt4 = {
+       .name = "nt4",
+       .open_registry = nt_open_registry,
+       .close_registry = nt_close_registry,
+       .open_root_key = nt_get_root_key,
+       .num_subkeys = nt_num_subkeys,
+       .num_values = nt_num_values,
+       .get_subkey_by_index = nt_key_by_index,
+       .get_value_by_index = nt_value_by_index,
+
+       /* TODO: 
+       .add_key
+       .add_value
+       .del_key
+       .del_value
+       .update_value
+       */
+};
+
+NTSTATUS reg_nt4_init(void)
+{
+       return register_backend("registry", &reg_backend_nt4);
+}
diff --git a/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c b/source4/lib/registry/reg_backend_rpc/reg_backend_rpc.c
new file mode 100644 (file)
index 0000000..7e8ad9b
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+   Samba Unix/Linux SMB implementation
+   RPC backend for the registry library
+   Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+static void init_winreg_String(struct winreg_String *name, const char *s)
+{
+    name->name = s;
+    if (s) {
+        name->name_len = 2 * (strlen_m(s) + 1);
+        name->name_size = name->name_len;
+    } else {
+        name->name_len = 0;
+        name->name_size = 0;
+    }
+}
+
+
+#define openhive(u) static struct policy_handle *open_ ## u(struct dcerpc_pipe *p, REG_HANDLE *h) \
+{ \
+       NTSTATUS status; \
+       struct winreg_Open ## u r; \
+       struct winreg_OpenUnknown unknown; \
+       struct policy_handle *hnd = malloc(sizeof(struct policy_handle)); \
+       TALLOC_CTX *mem_ctx = talloc_init("openhive"); \
+       \
+       unknown.unknown0 = 0x84e0; \
+       unknown.unknown1 = 0x0000; \
+       r.in.unknown = &unknown; \
+       r.in.access_required = SEC_RIGHTS_MAXIMUM_ALLOWED; \
+       r.out.handle = hnd;\
+       \
+       if (!NT_STATUS_IS_OK(dcerpc_winreg_Open ## u(p, mem_ctx, &r))) {\
+               printf("Error executing open\n");\
+               return NULL;\
+       }\
+\
+       talloc_destroy(mem_ctx);\
+\
+       return hnd;\
+}
+
+openhive(HKLM)
+openhive(HKCU)
+openhive(HKPD)
+openhive(HKU)
+openhive(HKCR)
+
+struct rpc_data {
+       struct dcerpc_pipe *pipe;
+       struct policy_handle *hives[10];
+};
+
+struct {
+       char *name;
+       struct policy_handle *(*open) (struct dcerpc_pipe *p, REG_HANDLE *h);
+} known_hives[] = {
+{ "HKEY_LOCAL_MACHINE", open_HKLM },
+{ "HKEY_CURRENT_USER", open_HKCU },
+{ "HKEY_CLASSES_ROOT", open_HKCR },
+{ "HKEY_PERFORMANCE_DATA", open_HKPD },
+{ "HKEY_USERS", open_HKU },
+{ NULL, NULL }
+};
+
+static BOOL rpc_open_registry(REG_HANDLE *h, const char *location, BOOL try_full)
+{
+       BOOL res = True;
+       struct rpc_data *mydata = malloc(sizeof(struct rpc_data));
+       char *binding = strdup(location);
+       NTSTATUS status;
+       
+       ZERO_STRUCTP(mydata);
+       
+       status = dcerpc_pipe_connect(&mydata->pipe, binding, 
+                    DCERPC_WINREG_UUID,
+                    DCERPC_WINREG_VERSION,
+                     lp_workgroup(),
+                     "jelwin", "dds");
+
+       if(!NT_STATUS_IS_OK(status)) return False;
+
+       h->backend_data = mydata;
+       
+       return True;
+}
+
+static REG_KEY *rpc_open_root(REG_HANDLE *h)
+{
+       /* There's not really a 'root' key here */
+       return reg_key_new_abs("\\", h, h->backend_data);
+}
+
+static BOOL rpc_close_registry(REG_HANDLE *h)
+{
+       dcerpc_pipe_close(((struct rpc_data *)h->backend_data)->pipe);
+       free(h->backend_data);
+       return True;
+}
+
+static struct policy_handle *rpc_get_key_handle(REG_HANDLE *h, const char *path)
+{
+       char *hivename;
+       int i = 0;
+       struct rpc_data *mydata = h->backend_data;
+       struct policy_handle *hive = NULL;
+       char *end = strchr(path+1, '\\');
+    NTSTATUS status;
+    struct winreg_OpenKey r;
+       struct policy_handle *key_handle = malloc(sizeof(struct policy_handle));
+       TALLOC_CTX *mem_ctx;
+       if(end) hivename = strndup(path+1, end-path-1);
+       else hivename = strdup(path+1);
+
+       for(i = 0; known_hives[i].name; i++) {
+               if(!strcmp(hivename, known_hives[i].name)) {
+               if(!mydata->hives[i]) mydata->hives[i] = known_hives[i].open(mydata->pipe, h);
+                       hive = mydata->hives[i];
+               }
+       }
+       
+       if(!hive) {
+               DEBUG(0, ("No such hive: %s\n", hivename));
+               return NULL;
+       }
+
+       DEBUG(2, ("Opening %s, hive: %s\n", path, hivename));
+
+       if(!end || !(*end) || !(*(end+1))) return hive;
+
+       memset(&r, 0, sizeof(struct winreg_OpenKey));
+    r.in.handle = hive;
+    init_winreg_String(&r.in.keyname, end+1);
+    r.in.unknown = 0x00000000;
+    r.in.access_mask = 0x02000000;
+    r.out.handle = key_handle;
+                        
+       mem_ctx = talloc_init("openkey");
+    status = dcerpc_winreg_OpenKey(mydata->pipe, mem_ctx, &r);
+       talloc_destroy(mem_ctx);
+                                                                                                                               
+    if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
+        return NULL;
+    }
+
+       return key_handle;
+}
+
+static REG_KEY *rpc_open_key(REG_HANDLE *h, const char *name)
+{
+       return reg_key_new_abs(name, h, rpc_get_key_handle(h, name));
+}
+
+static BOOL rpc_fetch_subkeys(REG_KEY *parent, int *count, REG_KEY ***subkeys) 
+{
+       struct winreg_EnumKey r;
+       struct winreg_EnumKeyNameRequest keyname;
+       struct winreg_String classname;
+       struct winreg_Time tm;
+       struct rpc_data *mydata = parent->handle->backend_data;
+       int i;
+       REG_KEY **ar = malloc(sizeof(REG_KEY *));
+       NTSTATUS status = NT_STATUS_OK;
+       TALLOC_CTX *mem_ctx;
+
+       /* List the hives */
+       if(parent->backend_data == parent->handle->backend_data) { 
+               REG_KEY **ar = malloc(sizeof(REG_KEY *));
+               for(i = 0; known_hives[i].name; i++) {
+                       ar[i] = reg_key_new_rel(known_hives[i].name, parent, NULL);
+                       (*count)++;
+                       ar = realloc(ar, sizeof(REG_KEY *) * ((*count)+1));
+               }
+
+               *subkeys = ar;
+
+               return True;
+       }
+
+       if(!parent->backend_data) parent->backend_data = rpc_get_key_handle(parent->handle, reg_key_get_path(parent));
+
+       if(!parent->backend_data) return False;
+
+       mem_ctx = talloc_init("enumkey");
+       (*count) = 0;
+       r.in.handle = parent->backend_data;
+       keyname.unknown = 0x0000020a;
+       init_winreg_String(&keyname.key_name, NULL);
+       init_winreg_String(&classname, NULL);
+       r.in.in_name = &keyname;
+       r.in.class = &classname;
+       tm.low = tm.high = 0x7fffffff;
+       r.in.last_changed_time = &tm;
+       r.out.result.v = 0;
+
+       for(i = 0; NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result); i++) {
+               r.in.enum_index = i;
+               r.in.unknown = r.out.unknown = 0x0414;
+               r.in.key_name_len = r.out.key_name_len = 0;
+               status = dcerpc_winreg_EnumKey(mydata->pipe, mem_ctx, &r);
+               if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
+                       ar[(*count)] = reg_key_new_rel(r.out.out_name->name, parent, NULL);
+                       (*count)++;
+                       ar = realloc(ar, ((*count)+1) * sizeof(REG_KEY *));
+               }
+       }
+
+       *subkeys = ar;
+       return True;
+}
+
+static BOOL rpc_fetch_values(REG_KEY *parent, int *count, REG_VAL ***values) 
+{
+       struct winreg_EnumValue r;
+       struct winreg_EnumValueName name;
+       struct winreg_Uint8buf value;
+       struct winreg_Uint16buf buf;
+       struct rpc_data *mydata = parent->handle->backend_data;
+       TALLOC_CTX *mem_ctx;
+       uint32 type, requested_len, returned_len;
+       NTSTATUS status = NT_STATUS_OK;
+       REG_VAL **ar = malloc(sizeof(REG_VAL *));
+
+       (*count) = 0;
+
+       if(!parent->backend_data) parent->backend_data = rpc_get_key_handle(parent->handle, reg_key_get_path(parent));
+
+       if(!parent->backend_data) return False;
+
+       r.in.handle = parent->backend_data;
+       r.in.enum_index = 0;
+
+       buf.max_len = 0x7fff;
+       buf.offset = 0;
+       buf.len = 0;
+       buf.buffer = NULL;
+
+       name.len = 0;
+       name.max_len = buf.max_len *2;
+       name.buf = &buf;
+
+       r.in.name = r.out.name = &name;
+
+       type = 0;
+       r.in.type = r.out.type = &type;
+       value.max_len = 0x7fff;
+       value.offset = 0;
+       value.len = 0;
+       value.buffer = NULL;
+
+       r.in.value = r.out.value = &value;
+
+       requested_len = value.max_len;
+       r.in.requested_len = &requested_len;
+       returned_len = 0;
+       r.in.returned_len = &returned_len;
+       r.out.result.v = 0;
+
+       mem_ctx = talloc_init("fetchvalues");
+       while(1) {
+               status = dcerpc_winreg_EnumValue(mydata->pipe, mem_ctx, &r);
+               if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
+                       r.in.enum_index++;
+                       ar[(*count)] = reg_val_new(parent, NULL);
+                       ar[(*count)]->name = strdup((char *)name.buf);
+                       ar[(*count)]->data_type = *r.out.type;
+                       ar[(*count)]->data_len = value.len;
+                       ar[(*count)]->data_blk = malloc(value.len);
+                       memcpy(ar[(*count)]->data_blk, value.buffer, value.len);
+                       (*count)++;
+                       ar = realloc(ar, ((*count)+1) * sizeof(REG_VAL *));
+               } else break;
+       } 
+       
+       talloc_destroy(mem_ctx);
+
+       return True;
+}
+
+static REG_OPS reg_backend_rpc = {
+       .name = "rpc",
+       .open_registry = rpc_open_registry,
+       .close_registry = rpc_close_registry,
+       .open_root_key = rpc_open_root,
+       .open_key = rpc_open_key,
+       .fetch_subkeys = rpc_fetch_subkeys,
+       .fetch_values = rpc_fetch_values,
+};
+
+NTSTATUS reg_rpc_init(void)
+{
+       return register_backend("registry", &reg_backend_rpc);
+}
diff --git a/source4/lib/registry/reg_backend_wine/reg_backend_wine.c b/source4/lib/registry/reg_backend_wine/reg_backend_wine.c
new file mode 100644 (file)
index 0000000..6c8d788
--- /dev/null
@@ -0,0 +1,32 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Jelmer Vernooij                                         2004.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/common/registry.h"
+
+static REG_OPS reg_backend_wine = {
+       .name = "wine",
+};
+
+NTSTATUS reg_wine_init(void)
+{
+       register_backend("registry", &reg_backend_wine);
+       return NT_STATUS_OK;
+}
diff --git a/source4/lib/registry/tools/regdiff.c b/source4/lib/registry/tools/regdiff.c
new file mode 100644 (file)
index 0000000..070516b
--- /dev/null
@@ -0,0 +1,148 @@
+/* 
+   Unix SMB/CIFS implementation.
+   simple registry frontend
+   
+   Copyright (C) Jelmer Vernooij 2004
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+void writediff(REG_KEY *oldkey, REG_KEY *newkey, FILE *out)
+{
+       int i, numvals1, numvals2, numkeys2;
+
+       numkeys2 = reg_key_num_subkeys(newkey);
+       for(i = 0; i < numkeys2; i++) {
+               REG_KEY *t1 = reg_key_get_subkey_by_index(newkey, i);
+               REG_KEY *t2 = reg_key_get_subkey_by_name(oldkey, reg_key_name(t1));
+               if(!t2) {
+                       fprintf(out, "[%s]\n", reg_key_get_path(t1));
+               }
+               writediff(t2, t1, out);
+       }
+
+       numvals2 = reg_key_num_values(newkey);
+       for(i = 0; i < numvals2; i++) {
+               REG_VAL *t1 = reg_key_get_value_by_index(newkey, i);
+               REG_VAL *t2 = reg_key_get_value_by_name(oldkey, reg_val_name(t1));
+               if(!t2 || reg_val_size(t2) != reg_val_size(t1) || memcmp(reg_val_data_blk(t1), reg_val_data_blk(t2), reg_val_size(t1))) {
+                       fprintf(out, "\"%s\"=%s:%s\n", reg_val_name(t1), str_regtype(reg_val_type(t1)), reg_val_data_string(t1));
+               }
+       }
+
+       numvals1 = reg_key_num_values(oldkey);
+       for(i = 0; i < numvals1; i++) {
+               REG_VAL *t1 = reg_key_get_value_by_index(oldkey, i);
+               if(!reg_key_get_value_by_name(newkey, reg_val_name(t1))) {
+                       fprintf(out, "\"%s\"=-\n", reg_val_name(t1));
+               }
+       }
+}
+
+int main (int argc, char **argv)
+{
+       uint32  setparms, checkparms;
+       int opt;
+       poptContext pc;
+       REG_KEY *root;
+       const char *backend1 = NULL, *backend2 = NULL;
+       const char *location2;
+       char *outputfile = NULL;
+       FILE *fd = stdout;
+       REG_HANDLE *h2;
+       REG_KEY *root1 = NULL, *root2;
+       int from_null = 0;
+       int fullpath = 0, no_values = 0;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               {"backend", 'b', POPT_ARG_STRING, NULL, 'b', "backend to use", NULL},
+               {"output", 'o', POPT_ARG_STRING, &outputfile, 'o', "output file to use", NULL },
+               {"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL" },
+               POPT_TABLEEND
+       };
+
+       pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+       
+       while((opt = poptGetNextOpt(pc)) != -1) {
+               switch(opt)     {
+                       case 'b':
+                               if(!backend1 && !from_null) backend1 = poptGetOptArg(pc);
+                               else if(!backend2) backend2 = poptGetOptArg(pc);
+                               break;
+               }
+       }
+       setup_logging(argv[0], True);
+
+       if(!from_null) {
+               REG_HANDLE *h1;
+               const char *location1;
+               location1 = poptGetArg(pc);
+               if(!location1) {
+                       poptPrintUsage(pc, stderr, 0);
+                       return 1;
+               }
+
+               if(!backend1) backend1 = "dir";
+
+               h1 = reg_open(backend1, location1, True);
+               if(!h1) {
+                       fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location1, backend1);
+                       return 1;
+               }
+
+               root1 = reg_get_root(h1);
+       }
+
+       location2 = poptGetArg(pc);
+       if(!location2) {
+               poptPrintUsage(pc, stderr, 0);
+               return 2;
+       }
+
+       if(!backend2) backend2 = "dir";
+       
+       h2 = reg_open(backend2, location2, True);
+       if(!h2) {
+               fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location2, backend2);
+               return 1;
+       }
+       
+       root2 = reg_get_root(h2);
+       if(!root2) {
+               fprintf(stderr, "Can't open root key for '%s:%s'\n", backend2, location2);
+               return 1;
+       }
+
+       poptFreeContext(pc);
+
+       if(outputfile) {
+               fd = fopen(outputfile, "w+");
+               if(!fd) {
+                       fprintf(stderr, "Unable to open '%s'\n", outputfile);
+                       return 1;
+               }
+       }
+
+       fprintf(fd, "REGEDIT4\n\n");
+       fprintf(fd, "; Generated using regdiff\n");
+
+       writediff(root1, root2, fd); 
+
+       fclose(fd);
+       
+       return 0;
+}
diff --git a/source4/lib/registry/tools/regpatch.c b/source4/lib/registry/tools/regpatch.c
new file mode 100644 (file)
index 0000000..f76da7e
--- /dev/null
@@ -0,0 +1,808 @@
+/* 
+   Unix SMB/CIFS implementation.
+   simple registry frontend
+   
+   Copyright (C) 2002, Richard Sharpe, rsharpe@richardsharpe.com
+   Copyright (C) 2004, Jelmer Vernooij, jelmer@samba.org
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * Routines to parse a REGEDIT4 file
+ * 
+ * The file consists of:
+ * 
+ * REGEDIT4
+ * \[[-]key-path\]\n
+ * <value-spec>*
+ *
+ * Format:
+ * [cmd:]name=type:value
+ *
+ * cmd = a|d|c|add|delete|change|as|ds|cs
+ *
+ * There can be more than one key-path and value-spec.
+ *
+ * Since we want to support more than one type of file format, we
+ * construct a command-file structure that keeps info about the command file
+ */
+
+#define FMT_UNREC -1
+#define FMT_REGEDIT4 0
+#define FMT_EDITREG1_1 1
+
+#define FMT_STRING_REGEDIT4 "REGEDIT4"
+#define FMT_STRING_EDITREG1_0 "EDITREG1.0"
+
+#define CMD_NONE     0
+#define CMD_ADD_KEY  1
+#define CMD_DEL_KEY  2
+
+#define CMD_KEY 1
+#define CMD_VAL 2
+
+#include <include/includes.h>
+
+typedef struct val_spec_list {
+  struct val_spec_list *next;
+  char *name;
+  int type;
+  char *val;    /* Kept as a char string, really? */
+} VAL_SPEC_LIST;
+
+typedef struct command_s {
+  int cmd;
+  char *key;
+  int val_count;
+  VAL_SPEC_LIST *val_spec_list, *val_spec_last;
+} CMD;
+
+typedef struct cmd_line {
+  int len, line_len;
+  char *line;
+} CMD_LINE;
+
+static void free_val_spec_list(VAL_SPEC_LIST *vl)
+{
+  if (!vl) return;
+  if (vl->name) free(vl->name);
+  if (vl->val) free(vl->val);
+  free(vl);
+
+}
+
+/* 
+ * Some routines to handle lines of info in the command files
+ */
+static void skip_to_eol(int fd)
+{
+  int rc;
+  char ch = 0;
+
+  while ((rc = read(fd, &ch, 1)) == 1) {
+    if (ch == 0x0A) return;
+  }
+  if (rc < 0) {
+    DEBUG(0, ("Could not read file descriptor: %d, %s\n",
+           fd, strerror(errno)));
+    exit(1);
+  }
+}
+
+static void free_cmd(CMD *cmd)
+{
+  if (!cmd) return;
+
+  while (cmd->val_spec_list) {
+    VAL_SPEC_LIST *tmp;
+
+    tmp = cmd->val_spec_list;
+    cmd->val_spec_list = tmp->next;
+    free(tmp);
+  }
+
+  free(cmd);
+
+}
+
+static void free_cmd_line(CMD_LINE *cmd_line)
+{
+  if (cmd_line) {
+    if (cmd_line->line) free(cmd_line->line);
+    free(cmd_line);
+  }
+}
+
+static void print_line(struct cmd_line *cl)
+{
+  char *pl;
+
+  if (!cl) return;
+
+  pl = smb_xmalloc(cl->line_len + 1);
+
+  strncpy(pl, cl->line, cl->line_len);
+  pl[cl->line_len] = 0;
+
+  fprintf(stdout, "%s\n", pl);
+  free(pl);
+}
+
+#define INIT_ALLOC 10 
+
+/*
+ * Read a line from the input file.
+ * NULL returned when EOF and no chars read
+ * Otherwise we return a cmd_line *
+ * Exit if other errors
+ */
+static struct cmd_line *get_cmd_line(int fd)
+{
+  struct cmd_line *cl = (CMD_LINE *)smb_xmalloc(sizeof(CMD_LINE));
+  int i = 0, rc;
+  unsigned char ch;
+
+  cl->len = INIT_ALLOC;
+
+  /*
+   * Allocate some space for the line. We extend later if needed.
+   */
+
+  cl->line = (char *)smb_xmalloc(INIT_ALLOC);
+
+  /*
+   * Now read in the chars to EOL. Don't store the EOL in the 
+   * line. What about CR?
+   */
+
+  while ((rc = read(fd, &ch, 1)) == 1 && ch != '\n') {
+    if (ch == '\r') continue; /* skip CR */
+    if (i == cl->len) {
+      /*
+       * Allocate some more memory
+       */
+      if ((cl->line = realloc(cl->line, cl->len + INIT_ALLOC)) == NULL) {
+       DEBUG(0, ("Unable to realloc space for line: %s\n",
+               strerror(errno)));
+       exit(1);
+      }
+      cl->len += INIT_ALLOC;
+    }
+    cl->line[i] = ch;
+    i++;
+  }
+
+  /* read 0 and we were at loc'n 0, return NULL */
+  if (rc == 0 && i == 0) {
+    free_cmd_line(cl);
+    return NULL;
+  }
+
+  cl->line_len = i;
+
+  return cl;
+
+}
+
+/*
+ * parse_value: parse out a value. We pull it apart as:
+ *
+ * <value> ::= <value-name>=<type>:<value-string>
+ *
+ * <value-name> ::= char-string-without-spaces | '"' char-string '"'
+ *
+ * If it parsed OK, return the <value-name> as a string, and the
+ * value type and value-string in parameters.
+ *
+ * The value name can be empty. There can only be one empty name in 
+ * a list of values. A value of - removes the value entirely.  
+ */
+
+static char *parse_name(char *nstr)
+{
+  int len = 0, start = 0;
+  if (!nstr) return NULL;
+
+  len = strlen(nstr);
+
+  while (len && nstr[len - 1] == ' ') len--;
+
+  nstr[len] = 0; /* Trim any spaces ... if there were none, doesn't matter */
+
+  /*
+   * Beginning and end should be '"' or neither should be so
+   */
+  if ((nstr[0] == '"' && nstr[len - 1] != '"') ||
+      (nstr[0] != '"' && nstr[len - 1] == '"'))
+    return NULL;
+
+  if (nstr[0] == '"') {
+    start = 1;
+    len -= 2;
+  }
+
+  return strndup(&nstr[start], len);
+}
+
+static int parse_value_type(char *tstr)
+{
+  int len = strlen(tstr);
+  
+  while (len && tstr[len - 1] == ' ') len--;
+  tstr[len] = 0;
+
+  if (strcmp(tstr, "REG_DWORD") == 0)
+    return REG_DWORD;
+  else if (strcmp(tstr, "dword") == 0)
+    return REG_DWORD;
+  else if (strcmp(tstr, "REG_EXPAND_SZ") == 0)
+    return REG_EXPAND_SZ;
+  else if (strcmp(tstr, "REG_BIN") == 0)
+    return REG_BINARY;
+  else if (strcmp(tstr, "REG_SZ") == 0)
+    return REG_SZ;
+  else if (strcmp(tstr, "REG_MULTI_SZ") == 0)
+    return REG_MULTI_SZ;
+  else if (strcmp(tstr, "-") == 0)
+    return REG_DELETE;
+
+  return 0;
+}
+
+static char *parse_val_str(char *vstr)
+{
+  
+  return strndup(vstr, strlen(vstr));
+
+}
+
+static char *parse_value(struct cmd_line *cl, int *vtype, char **val)
+{
+  char *p1 = NULL, *p2 = NULL, *nstr = NULL, *tstr = NULL, *vstr = NULL;
+  
+  if (!cl || !vtype || !val) return NULL;
+  if (!cl->line_len) return NULL;
+
+  p1 = strndup(cl->line, cl->line_len);
+  /* FIXME: Better return codes etc ... */
+  if (!p1) return NULL;
+  p2 = strchr(p1, '=');
+  if (!p2) return NULL;
+
+  *p2 = 0; p2++; /* Split into two strings at p2 */
+
+  /* Now, parse the name ... */
+
+  nstr = parse_name(p1);
+  if (!nstr) goto error;
+
+  /* Now, split the remainder and parse on type and val ... */
+
+  tstr = p2;
+  while (*tstr == ' ') tstr++; /* Skip leading white space */
+  p2 = strchr(p2, ':');
+
+  if (p2) {
+    *p2 = 0; p2++; /* split on the : */
+  }
+
+  *vtype = parse_value_type(tstr);
+
+  if (!vtype) goto error;
+
+  if (!p2 || !*p2) return nstr;
+
+  /* Now, parse the value string. It should return a newly malloc'd string */
+  
+  while (*p2 == ' ') p2++; /* Skip leading space */
+  vstr = parse_val_str(p2);
+
+  if (!vstr) goto error;
+
+  *val = vstr;
+
+  return nstr;
+
+ error:
+  if (p1) free(p1);
+  if (nstr) free(nstr);
+  if (vstr) free(vstr);
+  return NULL;
+}
+
+/*
+ * Parse out a key. Look for a correctly formatted key [...] 
+ * and whether it is a delete or add? A delete is signalled 
+ * by a - in front of the key.
+ * Assumes that there are no leading and trailing spaces
+ */
+
+static char *parse_key(struct cmd_line *cl, int *cmd)
+{
+  int start = 1;
+  char *tmp;
+
+  if (cl->line[0] != '[' ||
+      cl->line[cl->line_len - 1] != ']') return NULL;
+  if (cl->line_len == 2) return NULL;
+  *cmd = CMD_ADD_KEY;
+  if (cl->line[1] == '-') {
+    if (cl->line_len == 3) return NULL;
+    start = 2;
+    *cmd = CMD_DEL_KEY;
+  }
+  tmp = smb_xmalloc(cl->line_len - 1 - start + 1);
+  strncpy(tmp, &cl->line[start], cl->line_len - 1 - start);
+  tmp[cl->line_len - 1 - start] = 0;
+  return tmp;
+}
+
+/*
+ * Parse a line to determine if we have a key or a value
+ * We only check for key or val ...
+ */
+
+static int parse_line(struct cmd_line *cl)
+{
+
+  if (!cl || cl->len == 0) return 0;
+
+  if (cl->line[0] == '[')  /* No further checking for now */
+    return CMD_KEY;
+  else 
+    return CMD_VAL;
+}
+
+/*
+ * We seek to offset 0, read in the required number of bytes, 
+ * and compare to the correct value.
+ * We then seek back to the original location
+ */
+static int regedit4_file_type(int fd)
+{
+  int cur_ofs = 0;
+  char desc[9];
+
+  cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
+  if (cur_ofs < 0) {
+    DEBUG(0, ("Unable to get current offset: %s\n", strerror(errno)));
+    exit(1);  /* FIXME */
+  }
+
+  if (cur_ofs) {
+    lseek(fd, 0, SEEK_SET);
+  }
+
+  if (read(fd, desc, 8) < 8) {
+    DEBUG(0, ("Unable to read command file format\n")); 
+    exit(2);  /* FIXME */
+  }
+
+  desc[8] = 0;
+
+  if (strcmp(desc, FMT_STRING_REGEDIT4) == 0) {
+    if (cur_ofs) {
+      lseek(fd, cur_ofs, SEEK_SET);
+    }
+    else {
+      skip_to_eol(fd);
+    }
+    return FMT_REGEDIT4;
+  }
+
+  return FMT_UNREC;
+}
+
+/*
+ * Run though the data in the line and strip anything after a comment
+ * char.
+ */
+static void strip_comment(struct cmd_line *cl)
+{
+  int i;
+
+  if (!cl) return;
+
+  for (i = 0; i < cl->line_len; i++) {
+    if (cl->line[i] == ';') {
+      cl->line_len = i;
+      return;
+    }
+  }
+}
+
+/* 
+ * trim leading space
+ */
+
+static void trim_leading_spaces(struct cmd_line *cl)
+{
+  int i;
+
+  if (!cl) return;
+
+  for (i = 0; i < cl->line_len; i++) {
+    if (cl->line[i] != ' '){
+      if (i) memcpy(cl->line, &cl->line[i], cl->line_len - i);
+      return;
+    }
+  }
+}
+
+/* 
+ * trim trailing spaces
+ */
+static void trim_trailing_spaces(struct cmd_line *cl)
+{
+  int i;
+
+  if (!cl) return;
+
+  for (i = cl->line_len; i == 0; i--) {
+    if (cl->line[i-1] != ' ' &&
+       cl->line[i-1] != '\t') {
+      cl->line_len = i;
+    }
+  }
+}
+
+/* 
+ * Get a command ... This consists of possibly multiple lines:
+ * [key]
+ * values*
+ * possibly Empty line
+ *
+ * value ::= <value-name>=<value-type>':'<value-string>
+ * <value-name> is some path, possibly enclosed in quotes ...
+ * We alctually look for the next key to terminate a previous key
+ * if <value-type> == '-', then it is a delete type.
+ */
+static CMD *regedit4_get_cmd(int fd)
+{
+  struct command_s *cmd = NULL;
+  struct cmd_line *cl = NULL;
+  struct val_spec_list *vl = NULL;
+
+  cmd = (struct command_s *)smb_xmalloc(sizeof(struct command_s));
+
+  cmd->cmd = CMD_NONE;
+  cmd->key = NULL;
+  cmd->val_count = 0;
+  cmd->val_spec_list = cmd->val_spec_last = NULL;
+  while ((cl = get_cmd_line(fd))) {
+
+    /*
+     * If it is an empty command line, and we already have a key
+     * then exit from here ... FIXME: Clean up the parser
+     */
+
+    if (cl->line_len == 0 && cmd->key) {
+      free_cmd_line(cl);
+      break;
+    } 
+
+    strip_comment(cl);     /* remove anything beyond a comment char */
+    trim_trailing_spaces(cl);
+    trim_leading_spaces(cl);
+
+    if (cl->line_len == 0) {    /* An empty line */
+      free_cmd_line(cl);
+    }
+    else {                 /* Else, non-empty ... */
+      /* 
+       * Parse out the bits ... 
+       */
+      switch (parse_line(cl)) {
+      case CMD_KEY:
+       if ((cmd->key = parse_key(cl, &cmd->cmd)) == NULL) {
+         DEBUG(0, ("Error parsing key from line: "));
+         print_line(cl);
+         DEBUG(0, ("\n"));
+       }
+       break;
+
+      case CMD_VAL:
+       /*
+        * We need to add the value stuff to the list
+        * There could be a \ on the end which we need to 
+        * handle at some time
+        */
+       vl = (struct val_spec_list *)smb_xmalloc(sizeof(struct val_spec_list));
+       vl->next = NULL;
+       vl->val = NULL;
+       vl->name = parse_value(cl, &vl->type, &vl->val);
+       if (!vl->name) goto error;
+       if (cmd->val_spec_list == NULL) {
+         cmd->val_spec_list = cmd->val_spec_last = vl;
+       }
+       else {
+         cmd->val_spec_last->next = vl;
+         cmd->val_spec_last = vl;
+       }
+       cmd->val_count++;
+       break;
+
+      default:
+       DEBUG(0, ("Unrecognized line in command file: \n"));
+       print_line(cl);
+       break;
+      }
+    }
+
+  }
+  if (!cmd->cmd) goto error; /* End of file ... */
+
+  return cmd;
+
+ error:
+  if (vl) free(vl);
+  if (cmd) free_cmd(cmd);
+  return NULL;
+}
+
+static int regedit4_exec_cmd(CMD *cmd)
+{
+
+  return 0;
+}
+
+static int editreg_1_0_file_type(int fd)
+{
+  int cur_ofs = 0;
+  char desc[11];
+
+  cur_ofs = lseek(fd, 0, SEEK_CUR); /* Get current offset */
+  if (cur_ofs < 0) {
+    DEBUG(0, ("Unable to get current offset: %s\n", strerror(errno)));
+    exit(1);  /* FIXME */
+  }
+
+  if (cur_ofs) {
+    lseek(fd, 0, SEEK_SET);
+  }
+
+  if (read(fd, desc, 10) < 10) {
+    DEBUG(0, ("Unable to read command file format\n")); 
+    exit(2);  /* FIXME */
+  }
+
+  desc[10] = 0;
+
+  if (strcmp(desc, FMT_STRING_EDITREG1_0) == 0) {
+    lseek(fd, cur_ofs, SEEK_SET);
+    return FMT_REGEDIT4;
+  }
+
+  return FMT_UNREC;
+}
+
+static CMD *editreg_1_0_get_cmd(int fd)
+{
+  return NULL;
+}
+
+static int editreg_1_0_exec_cmd(CMD *cmd)
+{
+
+  return -1;
+}
+
+typedef struct command_ops_s {
+  int type;
+  int (*file_type)(int fd);
+  CMD *(*get_cmd)(int fd);
+  int (*exec_cmd)(CMD *cmd);
+} CMD_OPS;
+
+CMD_OPS default_cmd_ops[] = {
+  {0, regedit4_file_type, regedit4_get_cmd, regedit4_exec_cmd},
+  {1, editreg_1_0_file_type, editreg_1_0_get_cmd, editreg_1_0_exec_cmd},
+  {-1,  NULL, NULL, NULL}
+}; 
+
+typedef struct command_file_s {
+  char *name;
+  int type, fd;
+  CMD_OPS cmd_ops;
+} CMD_FILE;
+
+/*
+ * Create a new command file structure
+ */
+
+static CMD_FILE *cmd_file_create(char *file)
+{
+  CMD_FILE *tmp;
+  struct stat sbuf;
+  int i = 0;
+
+  /*
+   * Let's check if the file exists ...
+   * No use creating the cmd_file structure if the file does not exist
+   */
+
+  if (stat(file, &sbuf) < 0) { /* Not able to access file */
+
+    return NULL;
+  }
+
+  tmp = (CMD_FILE *)smb_xmalloc(sizeof(CMD_FILE)); 
+
+  /*
+   * Let's fill in some of the fields;
+   */
+
+  tmp->name = strdup(file);
+
+  if ((tmp->fd = open(file, O_RDONLY, 666)) < 0) {
+    free(tmp);
+    return NULL;
+  }
+
+  /*
+   * Now, try to find the format by indexing through the table
+   */
+  while (default_cmd_ops[i].type != -1) {
+    if ((tmp->type = default_cmd_ops[i].file_type(tmp->fd)) >= 0) {
+      tmp->cmd_ops = default_cmd_ops[i];
+      return tmp;
+    }
+    i++;
+  }
+
+  /* 
+   * If we got here, return NULL, as we could not figure out the type
+   * of command file.
+   *
+   * What about errors? 
+   */
+
+  free(tmp);
+  return NULL;
+}
+
+/*
+ * Extract commands from the command file, and execute them.
+ * We pass a table of command callbacks for that 
+ */
+
+//FIXME
+
+/*
+ * Main code from here on ...
+ */
+
+/*
+ * key print function here ...
+ */
+
+/*
+ * Sec Desc print functions 
+ */
+
+char *str_type(unsigned char type);
+
+int nt_apply_reg_command_file(REG_HANDLE *regf, const char *cmd_file_name)
+{
+       CMD *cmd;
+       int modified = 0;
+       CMD_FILE *cmd_file = NULL;
+       cmd_file = cmd_file_create(cmd_file_name);
+
+       while ((cmd = cmd_file->cmd_ops.get_cmd(cmd_file->fd)) != NULL) {
+
+               /*
+                * Now, apply the requests to the tree ...
+                */
+               switch (cmd->cmd) {
+               case CMD_ADD_KEY: {
+                                                         REG_KEY *tmp = NULL;
+                                                         tmp = reg_open_key(reg_get_root(regf), cmd->key);
+                                                         /* If we found it, apply the other bits, else create such a key */
+                                                         if (!tmp) {
+                                                                 if(reg_key_add_name(reg_get_root(regf), cmd->key)) {
+                                                                         tmp = reg_open_key(reg_get_root(regf), cmd->key);
+                                                                 }
+                                                                 modified = 1;
+                                                         }
+
+                                                         while (cmd->val_count) {
+                                                                 VAL_SPEC_LIST *val = cmd->val_spec_list;
+                                                                 REG_VAL *reg_val = NULL;
+
+                                                                 if (val->type == REG_DELETE) {
+                                                                         reg_val = reg_key_get_value_by_name( tmp, val->name);
+                                                                         reg_val_del(reg_val);
+                                                                         modified = 1;
+                                                                 }
+                                                                 else {
+                                                                         /* FIXME 
+                                                                         reg_val = nt_add_reg_value(tmp, val->name, val->type,
+                                                                                                                                val->val); */
+                                                                         modified = 1;
+                                                                 }
+
+                                                                 cmd->val_spec_list = val->next;
+                                                                 free_val_spec_list(val);
+                                                                 cmd->val_count--;
+                                                         }
+
+                                                         break;
+                                                 }
+
+               case CMD_DEL_KEY:
+                                                 /* 
+                                                  * Any value does not matter ...
+                                                  * Find the key if it exists, and delete it ...
+                                                  */
+
+                                                 reg_key_del_recursive(reg_open_key(reg_get_root(regf), cmd->key));
+                                                 modified = 1;
+                                                 break;
+               }
+       }
+       free_cmd(cmd);
+
+       return modified;
+}
+
+int main (int argc, char **argv)
+{
+       uint32  setparms, checkparms;
+       int opt;
+       poptContext pc;
+       REG_KEY *root;
+       const char *location;
+       const char *patch;
+       char *backend = "dir";
+       REG_HANDLE *h;
+       int fullpath = 0, no_values = 0;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               {"backend", 'b', POPT_ARG_STRING, &backend, 'b', "backend to use", NULL},
+               POPT_TABLEEND
+       };
+
+       pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+       
+       while((opt = poptGetNextOpt(pc)) != -1) {
+       }
+
+       setup_logging(argv[0], True);
+
+       location = poptGetArg(pc);
+       if(!location) {
+               poptPrintUsage(pc, stderr, 0);
+               return 1;
+       }
+
+       h = reg_open(backend, location, True);
+       if(!h) {
+               fprintf(stderr, "Unable to open '%s' with backend '%s'\n", location, backend);
+               return 1;
+       }
+
+       poptFreeContext(pc);
+
+       patch = poptGetArg(pc);
+       if(!patch) patch = "/dev/stdin";
+
+       nt_apply_reg_command_file(h, patch);
+       
+       return 0;
+}
diff --git a/source4/lib/registry/tools/regshell.c b/source4/lib/registry/tools/regshell.c
new file mode 100644 (file)
index 0000000..9074d1c
--- /dev/null
@@ -0,0 +1,243 @@
+/* 
+   Unix SMB/CIFS implementation.
+   simple registry frontend
+   
+   Copyright (C) Jelmer Vernooij 2004
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* 
+ * ck/cd - change key
+ * ls - list values/keys
+ * rmval/rm - remove value
+ * rmkey/rmdir - remove key
+ * mkkey/mkdir - make key
+ * help
+ * exit
+ */
+
+static REG_KEY *cmd_set(REG_KEY *cur, int argc, char **argv)
+{
+       /* FIXME */
+       return NULL;
+}
+
+static REG_KEY *cmd_ck(REG_KEY *cur, int argc, char **argv)
+{ 
+       REG_KEY *new;
+       if(argc < 2) {
+               new = cur;
+       } else {
+               new = reg_open_key(cur, argv[1]);
+       }
+       
+       if(!new) new = cur;
+
+       printf("Current path is: %s\n", reg_key_get_path(new));
+       
+       return new;
+}
+
+static REG_KEY *cmd_ls(REG_KEY *cur, int argc, char **argv)
+{
+       int i, num;
+       num = reg_key_num_subkeys(cur);
+       for(i = 0; i < num; i++) {
+               REG_KEY *sub = reg_key_get_subkey_by_index(cur, i);
+               printf("K %s\n", reg_key_name(sub));
+       }
+
+       num = reg_key_num_values(cur);
+       for(i = 0; i < num; i++) {
+               REG_VAL *sub = reg_key_get_value_by_index(cur, i);
+               printf("V %s %s %s\n", reg_val_name(sub), str_regtype(reg_val_type(sub)), reg_val_data_string(sub));
+       }
+       
+       return NULL; 
+}
+static REG_KEY *cmd_mkkey(REG_KEY *cur, int argc, char **argv)
+{ 
+       if(argc < 2) {
+               fprintf(stderr, "Usage: mkkey <keyname>\n");
+               return NULL;
+       }
+       
+       if(!reg_key_add_name(cur, argv[1])) {
+               fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
+               return NULL;
+       }
+
+       fprintf(stderr, "Successfully added new subkey '%s' to '%s'\n", argv[1], reg_key_get_path(cur));
+       
+       return NULL; 
+}
+
+static REG_KEY *cmd_rmkey(REG_KEY *cur, int argc, char **argv)
+{ 
+       REG_KEY *key;
+       if(argc < 2) {
+               fprintf(stderr, "Usage: rmkey <name>\n");
+               return NULL;
+       }
+
+       key = reg_open_key(cur, argv[1]);
+       if(!key) {
+               fprintf(stderr, "No such subkey '%s'\n", argv[1]);
+               return NULL;
+       }
+
+       if(!reg_key_del(key)) {
+               fprintf(stderr, "Error deleting '%s'\n", argv[1]);
+       } else {
+               fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
+       }
+       
+       return NULL; 
+}
+
+static REG_KEY *cmd_rmval(REG_KEY *cur, int argc, char **argv)
+{ 
+       REG_VAL *val;
+       if(argc < 2) {
+               fprintf(stderr, "Usage: rmval <valuename>\n");
+               return NULL;
+       }
+
+       val = reg_key_get_value_by_name(cur, argv[1]);
+       if(!val) {
+               fprintf(stderr, "No such value '%s'\n", argv[1]);
+               return NULL;
+       }
+
+       if(!reg_val_del(val)) {
+               fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
+       } else {
+               fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
+       }
+
+       return NULL; 
+}
+
+static REG_KEY *cmd_exit(REG_KEY *cur, int argc, char **argv)
+{
+       exit(0);
+       return NULL; 
+}
+
+static REG_KEY *cmd_help(REG_KEY *, int, char **);
+
+struct {
+       const char *name;
+       const char *alias;
+       const char *help;
+       REG_KEY *(*handle)(REG_KEY *, int argc, char **argv);
+} regshell_cmds[] = {
+       {"ck", "cd", "Change current key", cmd_ck },
+       {"list", "ls", "List values/keys in current key", cmd_ls },
+       {"mkkey", "mkdir", "Make new key", cmd_mkkey },
+       {"rmval", "rm", "Remove value", cmd_rmval },
+       {"rmkey", "rmdir", "Remove key", cmd_rmkey },
+       {"set", "update", "Update value", cmd_set },
+       {"help", "?", "Help", cmd_help },
+       {"exit", "quit", "Exit", cmd_exit },
+       {NULL }
+};
+
+static REG_KEY *cmd_help(REG_KEY *cur, int argc, char **argv)
+{
+       int i;
+       printf("Available commands:\n");
+       for(i = 0; regshell_cmds[i].name; i++) {
+               printf("%s - %s\n", regshell_cmds[i].name, regshell_cmds[i].help);
+       }
+       return NULL;
+} 
+
+REG_KEY *process_cmd(REG_KEY *k, char *line)
+{
+       int argc;
+       char **argv = NULL;
+       int ret, i;
+
+       if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
+               fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
+               return k;
+       }
+
+       for(i = 0; regshell_cmds[i].name; i++) {
+               if(!strcmp(regshell_cmds[i].name, argv[0]) || 
+                  (regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
+                       return regshell_cmds[i].handle(k, argc, argv);
+               }
+       }
+
+       fprintf(stderr, "No such command '%s'\n", argv[0]);
+       
+       return k;
+}
+
+int main (int argc, char **argv)
+{
+       uint32  setparms, checkparms;
+       int opt;
+       char *backend = "dir";
+       REG_KEY *curkey = NULL;;
+       poptContext pc;
+       REG_HANDLE *h;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+               POPT_TABLEEND
+       };
+       
+       pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+       
+       while((opt = poptGetNextOpt(pc)) != -1) {
+       }
+
+       h = reg_open(backend, poptPeekArg(pc), True);
+       if(!h) {
+               fprintf(stderr, "Unable to open '%s' with backend '%s'\n", poptGetArg(pc), backend);
+               return 1;
+       }
+       poptFreeContext(pc);
+
+    setup_logging("regtree", True);
+
+       curkey = reg_get_root(h);
+
+       if(!curkey) return 1;
+
+       while(True) {
+               char *line, *prompt;
+               
+               asprintf(&prompt, "%s> ", reg_key_get_path(curkey));
+               
+               line = smb_readline(prompt, NULL, NULL);
+
+               if(!line)
+                       break;
+
+               if(line[0] != '\n') {
+                       REG_KEY *new = process_cmd(curkey, line);
+                       if(new)curkey = new;
+               }
+       }
+
+       return 0;
+}
diff --git a/source4/lib/registry/tools/regtree.c b/source4/lib/registry/tools/regtree.c
new file mode 100644 (file)
index 0000000..80cbccf
--- /dev/null
@@ -0,0 +1,91 @@
+/* 
+   Unix SMB/CIFS implementation.
+   simple registry frontend
+   
+   Copyright (C) Jelmer Vernooij 2004
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+void print_tree(int l, REG_KEY *p, int fullpath, int novals)
+{
+       int num_subkeys, i, num_values;
+
+       for(i = 0; i < l; i++) putchar(' ');
+       if(fullpath) printf("%s\n", reg_key_get_path(p));
+       else printf("%s\n", reg_key_name(p));
+
+       num_subkeys = reg_key_num_subkeys(p);
+       for(i = 0; i < num_subkeys; i++) {
+               REG_KEY *subkey = reg_key_get_subkey_by_index(p, i);
+               print_tree(l+1, subkey, fullpath, novals);
+               reg_key_free(subkey);
+       }
+
+       if(!novals) {
+               num_values = reg_key_num_values(p);
+               for(i = 0; i < num_values; i++) {
+                       int j;
+                       char *desc;
+                       REG_VAL *value = reg_key_get_value_by_index(p, i);
+                       for(j = 0; j < l+1; j++) putchar(' ');
+                       desc = reg_val_description(value);
+                       printf("%s\n", desc);
+                       free(desc);
+                       reg_val_free(value);
+               }
+       }
+}
+
+int main (int argc, char **argv)
+{
+       uint32  setparms, checkparms;
+       int opt;
+       char *backend = "dir";
+       poptContext pc;
+       REG_KEY *root;
+       REG_HANDLE *h;
+       int fullpath = 0, no_values = 0;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+               {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
+               {"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL},
+               POPT_TABLEEND
+       };
+
+       pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+       
+       while((opt = poptGetNextOpt(pc)) != -1) {
+       }
+
+       setup_logging("regtree", True);
+
+       h = reg_open(backend, poptPeekArg(pc), True);
+       if(!h) {
+               fprintf(stderr, "Unable to open '%s' with backend '%s'\n", poptGetArg(pc), backend);
+               return 1;
+       }
+       poptFreeContext(pc);
+
+       root = reg_get_root(h);
+       if(!root) return 1;
+
+       print_tree(0, root, fullpath, no_values);
+       
+       return 0;
+}
diff --git a/source4/lib/registry/winregistry.pc.in b/source4/lib/registry/winregistry.pc.in
new file mode 100644 (file)
index 0000000..ad134da
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: winregistry
+Description: Windows registry library
+Version: @PACKAGE_VERSION@
+Libs: @LIBS@ @REG_LIBS@ -L${prefix}/lib -lwinregistry
+Cflags: -I${includedir} @CFLAGS@ @CFLAGS@
diff --git a/source4/registry/reg_cachehook.c b/source4/registry/reg_cachehook.c
deleted file mode 100644 (file)
index 547eed3..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* 
- *  Unix SMB/CIFS implementation.
- *  RPC Pipe client / server routines
- *  Copyright (C) Gerald Carter                     2002.
- *
- *  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.
- */
-
-/* Implementation of registry hook cache tree */
-
-#include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-static SORTED_TREE *cache_tree;
-extern REGISTRY_OPS regdb_ops;         /* these are the default */
-static REGISTRY_HOOK default_hook = { KEY_TREE_ROOT, &regdb_ops };
-
-/**********************************************************************
- Initialize the cache tree
- *********************************************************************/
-
-BOOL reghook_cache_init( void )
-{
-       cache_tree = sorted_tree_init( &default_hook, NULL, NULL );
-
-       return ( cache_tree == NULL );
-}
-
-/**********************************************************************
- Add a new REGISTRY_HOOK to the cache.  Note that the keyname
- is not in the exact format that a SORTED_TREE expects.
- *********************************************************************/
-
-BOOL reghook_cache_add( REGISTRY_HOOK *hook )
-{
-       pstring key;
-       
-       if ( !hook )
-               return False;
-               
-       pstrcpy( key, "\\");
-       pstrcat( key, hook->keyname );  
-       
-       pstring_sub( key, "\\", "/" );
-
-       DEBUG(10,("reghook_cache_add: Adding key [%s]\n", key));
-               
-       return sorted_tree_add( cache_tree, key, hook );
-}
-
-/**********************************************************************
- Initialize the cache tree
- *********************************************************************/
-
-REGISTRY_HOOK* reghook_cache_find( char *keyname )
-{
-       char *key;
-       int len;
-       REGISTRY_HOOK *hook;
-       
-       if ( !keyname )
-               return NULL;
-       
-       /* prepend the string with a '\' character */
-       
-       len = strlen( keyname );
-       if ( !(key = malloc( len + 2 )) ) {
-               DEBUG(0,("reghook_cache_find: malloc failed for string [%s] !?!?!\n",
-                       keyname));
-               return NULL;
-       }
-
-       *key = '\\';
-       strncpy( key+1, keyname, len+1);
-       
-       /* swap to a form understood by the SORTED_TREE */
-
-       string_sub( key, "\\", "/", 0 );
-               
-       DEBUG(10,("reghook_cache_find: Searching for keyname [%s]\n", key));
-       
-       hook = sorted_tree_find( cache_tree, key ) ;
-       
-       SAFE_FREE( key );
-       
-       return hook;
-}
-
-/**********************************************************************
- Initialize the cache tree
- *********************************************************************/
-
-void reghook_dump_cache( int debuglevel )
-{
-       DEBUG(debuglevel,("reghook_dump_cache: Starting cache dump now...\n"));
-       
-       sorted_tree_print_keys( cache_tree, debuglevel );
-}
diff --git a/source4/registry/reg_db.c b/source4/registry/reg_db.c
deleted file mode 100644 (file)
index b0917c8..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/* 
- *  Unix SMB/CIFS implementation.
- *  RPC Pipe client / server routines
- *  Copyright (C) Gerald Carter                     2002.
- *
- *  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.
- */
-
-/* Implementation of internal registry database functions. */
-
-#include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-static TDB_CONTEXT *tdb_reg;
-
-
-/***********************************************************************
- Open the registry data in the tdb
- ***********************************************************************/
-static BOOL init_registry_data( void )
-{
-       pstring         keyname;
-       REGSUBKEY_CTR   subkeys;
-
-       ZERO_STRUCTP( &subkeys );
-
-       /* HKEY_LOCAL_MACHINE */
-       
-       regsubkey_ctr_init( &subkeys );
-       pstrcpy( keyname, KEY_HKLM );
-       regsubkey_ctr_addkey( &subkeys, "SYSTEM" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       regsubkey_ctr_destroy( &subkeys );
-               
-       regsubkey_ctr_init( &subkeys );
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM" );
-       regsubkey_ctr_addkey( &subkeys, "CurrentControlSet" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       regsubkey_ctr_destroy( &subkeys );
-               
-       regsubkey_ctr_init( &subkeys );
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM/CurrentControlSet" );
-       regsubkey_ctr_addkey( &subkeys, "Control" );
-       regsubkey_ctr_addkey( &subkeys, "Services" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       regsubkey_ctr_destroy( &subkeys );
-
-       regsubkey_ctr_init( &subkeys );
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control" );
-       regsubkey_ctr_addkey( &subkeys, "Print" );
-       regsubkey_ctr_addkey( &subkeys, "ProductOptions" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       regsubkey_ctr_destroy( &subkeys );
-
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/ProductOptions" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-
-       regsubkey_ctr_init( &subkeys );
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services" );
-       regsubkey_ctr_addkey( &subkeys, "Netlogon" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       regsubkey_ctr_destroy( &subkeys );
-               
-       regsubkey_ctr_init( &subkeys );
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon" );
-       regsubkey_ctr_addkey( &subkeys, "Parameters" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       regsubkey_ctr_destroy( &subkeys );
-               
-       pstrcpy( keyname, KEY_HKLM );
-       pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon/Parameters" );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ))
-               return False;
-       
-       /* HKEY_USER */
-               
-       pstrcpy( keyname, KEY_HKU );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ) )
-               return False;
-               
-       /* HKEY_CLASSES_ROOT*/
-               
-       pstrcpy( keyname, KEY_HKCR );
-       if ( !regdb_store_reg_keys( keyname, &subkeys ) )
-               return False;
-               
-       return True;
-}
-
-/***********************************************************************
- Open the registry database
- ***********************************************************************/
-BOOL init_registry_db( void )
-{
-       static pid_t local_pid;
-
-       if (tdb_reg && local_pid == sys_getpid())
-               return True;
-
-       /* 
-        * try to open first without creating so we can determine
-        * if we need to init the data in the registry
-        */
-       
-       tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
-       if ( !tdb_reg ) 
-       {
-               tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
-               if ( !tdb_reg ) {
-                       DEBUG(0,("init_registry: Failed to open registry %s (%s)\n",
-                               lock_path("registry.tdb"), strerror(errno) ));
-                       return False;
-               }
-               
-               DEBUG(10,("init_registry: Successfully created registry tdb\n"));
-               
-               /* create the registry here */
-               if ( !init_registry_data() ) {
-                       DEBUG(0,("init_registry: Failed to initiailize data in registry!\n"));
-                       return False;
-               }
-       }
-
-       local_pid = sys_getpid();
-               
-       return True;
-}
-
-
-
-/***********************************************************************
- Add subkey strings to the registry tdb under a defined key
- fmt is the same format as tdb_pack except this function only supports
- fstrings
-
- The full path to the registry key is used as database after the 
- \'s are converted to /'s.  Key string is also normalized to UPPER
- case.
- ***********************************************************************/
-BOOL regdb_store_reg_keys( char *keyname, REGSUBKEY_CTR *ctr )
-{
-       TDB_DATA kbuf, dbuf;
-       char *buffer, *tmpbuf;
-       int i = 0;
-       uint32 len, buflen;
-       BOOL ret = True;
-       uint32 num_subkeys = regsubkey_ctr_numkeys( ctr );
-       
-       if ( !keyname )
-               return False;
-       
-       strupper_m( keyname  );
-       
-       /* allocate some initial memory */
-               
-       buffer = malloc(sizeof(pstring));
-       buflen = sizeof(pstring);
-       len = 0;
-       
-       /* store the number of subkeys */
-       
-       len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys );
-       
-       /* pack all the strings */
-       
-       for (i=0; i<num_subkeys; i++) {
-               len += tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
-               if ( len > buflen ) {
-                       /* allocate some extra space */
-                       if ((tmpbuf = Realloc( buffer, len*2 )) == NULL) {
-                               DEBUG(0,("regdb_store_reg_keys: Failed to realloc memory of size [%d]\n", len*2));
-                               ret = False;
-                               goto done;
-                       }
-                       buffer = tmpbuf;
-                       buflen = len*2;
-                                       
-                       len = tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
-               }               
-       }
-       
-       /* finally write out the data */
-       
-       kbuf.dptr = keyname;
-       kbuf.dsize = strlen(keyname)+1;
-       dbuf.dptr = buffer;
-       dbuf.dsize = len;
-       if ( tdb_store( tdb_reg, kbuf, dbuf, TDB_REPLACE ) == -1) {
-               ret = False;
-               goto done;
-       }
-
-done:          
-       SAFE_FREE( buffer );
-       
-       return ret;
-}
-
-/***********************************************************************
- Retrieve an array of strings containing subkeys.  Memory should be 
- released by the caller.  The subkeys are stored in a catenated string
- of null terminated character strings
- ***********************************************************************/
-
-int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr )
-{
-       pstring path;
-       uint32 num_items;
-       TDB_DATA dbuf;
-       char *buf;
-       uint32 buflen, len;
-       int i;
-       fstring subkeyname;
-
-       DEBUG(10,("regdb_fetch_reg_keys: Enter key => [%s]\n", key ? key : "NULL"));
-       
-       pstrcpy( path, key );
-       
-       /* convert to key format */
-       pstring_sub( path, "\\", "/" ); 
-       strupper_m( path );
-       
-       dbuf = tdb_fetch_by_string( tdb_reg, path );
-       
-       buf = dbuf.dptr;
-       buflen = dbuf.dsize;
-       
-       if ( !buf ) {
-               DEBUG(5,("regdb_fetch_reg_keys: tdb lookup failed to locate key [%s]\n", key));
-               return -1;
-       }
-       
-       len = tdb_unpack( buf, buflen, "d", &num_items);
-       
-       for (i=0; i<num_items; i++) {
-               len += tdb_unpack( buf+len, buflen-len, "f", subkeyname );
-               regsubkey_ctr_addkey( ctr, subkeyname );
-       }
-
-       SAFE_FREE( dbuf.dptr );
-       
-       DEBUG(10,("regdb_fetch_reg_keys: Exit [%d] items\n", num_items));
-       
-       return num_items;
-}
-
-
-/***********************************************************************
- Retrieve an array of strings containing subkeys.  Memory should be 
- released by the caller.  The subkeys are stored in a catenated string
- of null terminated character strings
- ***********************************************************************/
-
-int regdb_fetch_reg_values( char* key, REGVAL_CTR *val )
-{
-       return 0;
-}
-
-/***********************************************************************
- Stub function since we do not currently support storing registry 
- values in the registry.tdb
- ***********************************************************************/
-
-BOOL regdb_store_reg_values( char *key, REGVAL_CTR *val )
-{
-       return False;
-}
-
-
-/* 
- * Table of function pointers for default access
- */
-REGISTRY_OPS regdb_ops = {
-       regdb_fetch_reg_keys,
-       regdb_fetch_reg_values,
-       regdb_store_reg_keys,
-       regdb_store_reg_values
-};
-
-
diff --git a/source4/registry/reg_frontend.c b/source4/registry/reg_frontend.c
deleted file mode 100644 (file)
index a9dfb52..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/* 
- *  Unix SMB/CIFS implementation.
- *  RPC Pipe client / server routines
- *  Copyright (C) Gerald Carter                     2002.
- *
- *  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.
- */
-
-/* Implementation of registry frontend view functions. */
-
-#include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-extern REGISTRY_OPS printing_ops;
-extern REGISTRY_OPS regdb_ops;         /* these are the default */
-
-/* array of REGISTRY_HOOK's which are read into a tree for easy access */
-
-
-REGISTRY_HOOK reg_hooks[] = {
-  { KEY_PRINTING,   &printing_ops },
-  { NULL, NULL }
-};
-
-
-/***********************************************************************
- Open the registry database and initialize the REGISTRY_HOOK cache
- ***********************************************************************/
-BOOL init_registry( void )
-{
-       int i;
-       
-       if ( !init_registry_db() ) {
-               DEBUG(0,("init_registry: failed to initialize the registry tdb!\n"));
-               return False;
-       }
-               
-       /* build the cache tree of registry hooks */
-       
-       reghook_cache_init();
-       
-       for ( i=0; reg_hooks[i].keyname; i++ ) {
-               if ( !reghook_cache_add(&reg_hooks[i]) )
-                       return False;
-       }
-
-       if ( DEBUGLEVEL >= 20 )
-               reghook_dump_cache(20);
-
-       return True;
-}
-
-
-
-
-/***********************************************************************
- High level wrapper function for storing registry subkeys
- ***********************************************************************/
-BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
-{
-       if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys_fn )
-               return key->hook->ops->store_subkeys_fn( key->name, subkeys );
-       else
-               return False;
-
-}
-
-/***********************************************************************
- High level wrapper function for storing registry values
- ***********************************************************************/
-BOOL store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
-{
-       if ( key->hook && key->hook->ops && key->hook->ops->store_values_fn )
-               return key->hook->ops->store_values_fn( key->name, val );
-       else
-               return False;
-}
-
-
-/***********************************************************************
- High level wrapper function for enumerating registry subkeys
- Initialize the TALLOC_CTX if necessary
- ***********************************************************************/
-
-int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
-{
-       int result = -1;
-       
-       if ( key->hook && key->hook->ops && key->hook->ops->subkey_fn )
-               result = key->hook->ops->subkey_fn( key->name, subkey_ctr );
-
-       return result;
-}
-
-/***********************************************************************
- retreive a specific subkey specified by index.  Caller is 
- responsible for freeing memory
- ***********************************************************************/
-
-BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index )
-{
-       static REGSUBKEY_CTR ctr;
-       static pstring save_path;
-       static BOOL ctr_init = False;
-       char *s;
-       
-       *subkey = NULL;
-       
-       /* simple caching for performance; very basic heuristic */
-       
-       if ( !ctr_init ) {
-               DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name));
-               ZERO_STRUCTP( &ctr );   
-               regsubkey_ctr_init( &ctr );
-               
-               pstrcpy( save_path, key->name );
-               
-               if ( fetch_reg_keys( key, &ctr) == -1 )
-                       return False;
-                       
-               ctr_init = True;
-       }
-       /* clear the cache when key_index == 0 or the path has changed */
-       else if ( !key_index || StrCaseCmp( save_path, key->name) ) {
-
-               DEBUG(8,("fetch_reg_keys_specific: Updating cache of subkeys for [%s]\n", key->name));
-               
-               regsubkey_ctr_destroy( &ctr );  
-               regsubkey_ctr_init( &ctr );
-               
-               pstrcpy( save_path, key->name );
-               
-               if ( fetch_reg_keys( key, &ctr) == -1 )
-                       return False;
-       }
-       
-       if ( !(s = regsubkey_ctr_specific_key( &ctr, key_index )) )
-               return False;
-
-       *subkey = strdup( s );
-
-       return True;
-}
-
-
-/***********************************************************************
- High level wrapper function for enumerating registry values
- Initialize the TALLOC_CTX if necessary
- ***********************************************************************/
-
-int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
-{
-       int result = -1;
-       
-       if ( key->hook && key->hook->ops && key->hook->ops->value_fn )
-               result = key->hook->ops->value_fn( key->name, val );
-
-       return result;
-}
-
-
-/***********************************************************************
- retreive a specific subkey specified by index.  Caller is 
- responsible for freeing memory
- ***********************************************************************/
-
-BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 val_index )
-{
-       static REGVAL_CTR       ctr;
-       static pstring          save_path;
-       static BOOL             ctr_init = False;
-       REGISTRY_VALUE          *v;
-       
-       *val = NULL;
-       
-       /* simple caching for performance; very basic heuristic */
-       
-       if ( !ctr_init ) {
-               DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name));
-
-               ZERO_STRUCTP( &ctr );   
-               regval_ctr_init( &ctr );
-               
-               pstrcpy( save_path, key->name );
-               
-               if ( fetch_reg_values( key, &ctr) == -1 )
-                       return False;
-                       
-               ctr_init = True;
-       }
-       /* clear the cache when val_index == 0 or the path has changed */
-       else if ( !val_index || StrCaseCmp(save_path, key->name) ) {
-
-               DEBUG(8,("fetch_reg_values_specific: Updating cache of values for [%s]\n", key->name));         
-               
-               regval_ctr_destroy( &ctr );     
-               regval_ctr_init( &ctr );
-               
-               pstrcpy( save_path, key->name );
-               
-               if ( fetch_reg_values( key, &ctr) == -1 )
-                       return False;
-       }
-       
-       if ( !(v = regval_ctr_specific_value( &ctr, val_index )) )
-               return False;
-
-       *val = dup_registry_value( v );
-
-       return True;
-}
-
-/***********************************************************************
- Utility function for splitting the base path of a registry path off
- by setting base and new_path to the apprapriate offsets withing the
- path.
- WARNING!!  Does modify the original string!
- ***********************************************************************/
-
-BOOL reg_split_path( char *path, char **base, char **new_path )
-{
-       char *p;
-       
-       *new_path = *base = NULL;
-       
-       if ( !path)
-               return False;
-       
-       *base = path;
-       
-       p = strchr( path, '\\' );
-       
-       if ( p ) {
-               *p = '\0';
-               *new_path = p+1;
-       }
-       
-       return True;
-}
-
-
-
diff --git a/source4/registry/reg_objects.c b/source4/registry/reg_objects.c
deleted file mode 100644 (file)
index 9cfeb7f..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/* 
- *  Unix SMB/CIFS implementation.
- *  RPC Pipe client / server routines
- *  Copyright (C) Gerald Carter                     2002.
- *
- *  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.
- */
-
-/* Implementation of registry frontend view functions. */
-
-#include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-
-/***********************************************************************
- Init the talloc context held by a REGSUBKEY_CTR structure
- **********************************************************************/
-
-void regsubkey_ctr_init( REGSUBKEY_CTR *ctr )
-{
-       if ( !ctr->ctx )
-               ctr->ctx = talloc_init("regsubkey_ctr_init for ctr %p", ctr);
-}
-
-/***********************************************************************
- Add a new key to the array
- **********************************************************************/
-
-int regsubkey_ctr_addkey( REGSUBKEY_CTR *ctr, const char *keyname )
-{
-       uint32 len;
-       char **pp;
-       
-       if ( keyname )
-       {
-               len = strlen( keyname );
-
-               /* allocate a space for the char* in the array */
-               
-               if (  ctr->subkeys == 0 )
-                       ctr->subkeys = talloc( ctr->ctx, sizeof(char*) );
-               else {
-                       pp = talloc_realloc( ctr->ctx, ctr->subkeys, sizeof(char*)*(ctr->num_subkeys+1) );
-                       if ( pp )
-                               ctr->subkeys = pp;
-               }
-
-               /* allocate the string and save it in the array */
-               
-               ctr->subkeys[ctr->num_subkeys] = talloc( ctr->ctx, len+1 );
-               strncpy( ctr->subkeys[ctr->num_subkeys], keyname, len+1 );
-               ctr->num_subkeys++;
-       }
-       
-       return ctr->num_subkeys;
-}
-/***********************************************************************
- How many keys does the container hold ?
- **********************************************************************/
-
-int regsubkey_ctr_numkeys( REGSUBKEY_CTR *ctr )
-{
-       return ctr->num_subkeys;
-}
-
-/***********************************************************************
- Retreive a specific key string
- **********************************************************************/
-
-char* regsubkey_ctr_specific_key( REGSUBKEY_CTR *ctr, uint32 key_index )
-{
-       if ( ! (key_index < ctr->num_subkeys) )
-               return NULL;
-               
-       return ctr->subkeys[key_index];
-}
-
-/***********************************************************************
- free memory held by a REGSUBKEY_CTR structure
- **********************************************************************/
-
-void regsubkey_ctr_destroy( REGSUBKEY_CTR *ctr )
-{
-       if ( ctr ) {
-               talloc_destroy( ctr->ctx );     
-               ZERO_STRUCTP( ctr );
-       }
-}
-
-
-/*
- * Utility functions for REGVAL_CTR
- */
-
-/***********************************************************************
- Init the talloc context held by a REGSUBKEY_CTR structure
- **********************************************************************/
-
-void regval_ctr_init( REGVAL_CTR *ctr )
-{
-       if ( !ctr->ctx )
-               ctr->ctx = talloc_init("regval_ctr_init for ctr %p", ctr);
-}
-
-/***********************************************************************
- How many keys does the container hold ?
- **********************************************************************/
-
-int regval_ctr_numvals( REGVAL_CTR *ctr )
-{
-       return ctr->num_values;
-}
-
-/***********************************************************************
- allocate memory for and duplicate a REGISTRY_VALUE.
- This is malloc'd memory so the caller should free it when done
- **********************************************************************/
-
-REGISTRY_VALUE* dup_registry_value( REGISTRY_VALUE *val )
-{
-       REGISTRY_VALUE  *copy = NULL;
-       
-       if ( !val )
-               return NULL;
-       
-       if ( !(copy = malloc( sizeof(REGISTRY_VALUE) )) ) {
-               DEBUG(0,("dup_registry_value: malloc() failed!\n"));
-               return NULL;
-       }
-       
-       /* copy all the non-pointer initial data */
-       
-       memcpy( copy, val, sizeof(REGISTRY_VALUE) );
-       if ( val->data_p ) 
-       {
-               if ( !(copy->data_p = memdup( val->data_p, val->size )) ) {
-                       DEBUG(0,("dup_registry_value: memdup() failed for [%d] bytes!\n",
-                               val->size));
-                       SAFE_FREE( copy );
-               }
-       }
-       
-       return copy;    
-}
-
-/**********************************************************************
- free the memory allocated to a REGISTRY_VALUE 
- *********************************************************************/
-void free_registry_value( REGISTRY_VALUE *val )
-{
-       if ( !val )
-               return;
-               
-       SAFE_FREE( val->data_p );
-       SAFE_FREE( val );
-       
-       return;
-}
-
-/**********************************************************************
- *********************************************************************/
-
-uint8* regval_data_p( REGISTRY_VALUE *val )
-{
-       return val->data_p;
-}
-
-/**********************************************************************
- *********************************************************************/
-
-int regval_size( REGISTRY_VALUE *val )
-{
-       return val->size;
-}
-
-/**********************************************************************
- *********************************************************************/
-
-char* regval_name( REGISTRY_VALUE *val )
-{
-       return val->valuename;
-}
-
-/**********************************************************************
- *********************************************************************/
-
-uint32 regval_type( REGISTRY_VALUE *val )
-{
-       return val->type;
-}
-
-/***********************************************************************
- Retreive a pointer to a specific value.  Caller shoud dup the structure
- since this memory may go away with a regval_ctr_destroy()
- **********************************************************************/
-
-REGISTRY_VALUE* regval_ctr_specific_value( REGVAL_CTR *ctr, uint32 idx )
-{
-       if ( !(idx < ctr->num_values) )
-               return NULL;
-               
-       return ctr->values[idx];
-}
-
-/***********************************************************************
- Retrive the TALLOC_CTX associated with a REGISTRY_VALUE 
- **********************************************************************/
-
-TALLOC_CTX* regval_ctr_getctx( REGVAL_CTR *val )
-{
-       if ( !val )
-               return NULL;
-
-       return val->ctx;
-}
-
-/***********************************************************************
- Add a new registry value to the array
- **********************************************************************/
-
-int regval_ctr_addvalue( REGVAL_CTR *ctr, const char *name, uint16 type, 
-                         const char *data_p, size_t size )
-{
-       REGISTRY_VALUE **ppreg;
-       
-       if ( name )
-       {
-               /* allocate a slot in the array of pointers */
-               
-               if (  ctr->num_values == 0 )
-                       ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
-               else {
-                       ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
-                       if ( ppreg )
-                               ctr->values = ppreg;
-               }
-
-               /* allocate a new value and store the pointer in the arrya */
-               
-               ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
-
-               /* init the value */
-       
-               fstrcpy( ctr->values[ctr->num_values]->valuename, name );
-               ctr->values[ctr->num_values]->type = type;
-               ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, data_p, size );
-               ctr->values[ctr->num_values]->size = size;
-               ctr->num_values++;
-       }
-
-       return ctr->num_values;
-}
-
-/***********************************************************************
- Add a new registry value to the array
- **********************************************************************/
-
-int regval_ctr_copyvalue( REGVAL_CTR *ctr, REGISTRY_VALUE *val )
-{
-       REGISTRY_VALUE **ppreg;
-       
-       if ( val )
-       {
-               /* allocate a slot in the array of pointers */
-               
-               if (  ctr->num_values == 0 )
-                       ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
-               else {
-                       ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
-                       if ( ppreg )
-                               ctr->values = ppreg;
-               }
-
-               /* allocate a new value and store the pointer in the arrya */
-               
-               ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
-
-               /* init the value */
-       
-               fstrcpy( ctr->values[ctr->num_values]->valuename, val->valuename );
-               ctr->values[ctr->num_values]->type = val->type;
-               ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, val->data_p, val->size );
-               ctr->values[ctr->num_values]->size = val->size;
-               ctr->num_values++;
-       }
-
-       return ctr->num_values;
-}
-
-/***********************************************************************
- Delete a single value from the registry container.
- No need to free memory since it is talloc'd.
- **********************************************************************/
-
-int regval_ctr_delvalue( REGVAL_CTR *ctr, const char *name )
-{
-       int     i;
-       
-       /* search for the value */
-       if (!(ctr->num_values))
-               return 0;
-       
-       for ( i=0; i<ctr->num_values; i++ ) {
-               if ( strcmp( ctr->values[i]->valuename, name ) == 0)
-                       break;
-       }
-       
-       /* just return if we don't find it */
-       
-       if ( i == ctr->num_values )
-               return ctr->num_values;
-       
-       /* just shift everything down one */
-       
-       for ( /* use previous i */; i<(ctr->num_values-1); i++ )
-               memcpy( ctr->values[i], ctr->values[i+1], sizeof(REGISTRY_VALUE) );
-               
-       /* paranoia */
-       
-       ZERO_STRUCTP( ctr->values[i] );
-       
-       ctr->num_values--;
-       
-       return ctr->num_values;
-}
-
-/***********************************************************************
- Delete a single value from the registry container.
- No need to free memory since it is talloc'd.
- **********************************************************************/
-
-REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, const char *name )
-{
-       int     i;
-       
-       /* search for the value */
-       
-       for ( i=0; i<ctr->num_values; i++ ) {
-               if ( strequal( ctr->values[i]->valuename, name ) )
-                       return ctr->values[i];
-       }
-       
-       return NULL;
-}
-
-/***********************************************************************
- free memory held by a REGVAL_CTR structure
- **********************************************************************/
-
-void regval_ctr_destroy( REGVAL_CTR *ctr )
-{
-       if ( ctr ) {
-               talloc_destroy( ctr->ctx );
-               ZERO_STRUCTP( ctr );
-       }
-}
-
-
index 8de6d273b96397950b64db8f67040094f2f12471..388208c09d273ee4b17f295b6d2cbf3487627c86 100644 (file)
@@ -3,6 +3,7 @@ dnl # DCERPC Server subsystem
 SMB_MODULE(dcerpc_rpcecho,DCERPC,STATIC,[rpc_server/echo/rpc_echo.o])
 SMB_MODULE(dcerpc_epmapper,DCERPC,STATIC,[rpc_server/epmapper/rpc_epmapper.o])
 SMB_MODULE(dcerpc_remote,DCERPC,STATIC,[rpc_server/remote/dcesrv_remote.o])
+SMB_MODULE(dcerpc_winreg,DCERPC,STATIC,[rpc_server/winreg/rpc_winreg.o \$(REG_OBJS)],[],[\$(REG_LIBS)])
 
 SMB_SUBSYSTEM(DCERPC,rpc_server/dcerpc_server.o,
                [rpc_server/dcerpc_tcp.o rpc_server/dcesrv_auth.o rpc_server/handles.o],
diff --git a/source4/rpc_server/winreg/rpc_winreg.c b/source4/rpc_server/winreg/rpc_winreg.c
new file mode 100644 (file)
index 0000000..2dc6dcd
--- /dev/null
@@ -0,0 +1,389 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   endpoint server for the winreg pipe
+
+   Copyright (C) Jelmer Vernooij 2004
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+REG_HANDLE *get_registry_handle() {
+       return reg_open("nt4", "/home/aurelia/jelmer/NTUSER.dat", False);
+}
+
+/* 
+  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;
+}
+
+
+/* 
+  winreg_OpenHKCU 
+*/
+static NTSTATUS winreg_OpenHKCU(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_OpenHKCU *r)
+{
+       REG_KEY *hkcu = reg_open_key(get_registry_handle(), "\\HKEY_CURRENT_USER");
+
+       if(!hkcu) {
+               r->out.result = WERR_NO_MORE_ITEMS;
+               return NT_STATUS_OK;
+       }
+
+       r->out.result = WERR_OK;
+       
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  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;
+}
+
+
+/* 
+  winreg_DeleteKey 
+*/
+static NTSTATUS winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_DeleteKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_DeleteValue 
+*/
+static NTSTATUS winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_DeleteValue *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_EnumKey 
+*/
+static NTSTATUS winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_EnumKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_EnumValue 
+*/
+static NTSTATUS winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_EnumValue *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_FlushKey 
+*/
+static NTSTATUS winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_FlushKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_GetKeySecurity 
+*/
+static NTSTATUS winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_GetKeySecurity *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_LoadKey 
+*/
+static NTSTATUS winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_LoadKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_NotifyChangeKeyValue 
+*/
+static NTSTATUS winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_NotifyChangeKeyValue *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_OpenKey 
+*/
+static NTSTATUS winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_OpenKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_QueryInfoKey 
+*/
+static NTSTATUS winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_QueryInfoKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_QueryValue 
+*/
+static NTSTATUS winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_QueryValue *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_ReplaceKey 
+*/
+static NTSTATUS winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_ReplaceKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_RestoreKey 
+*/
+static NTSTATUS winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_RestoreKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_SaveKey 
+*/
+static NTSTATUS winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_SaveKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_SetKeySecurity 
+*/
+static NTSTATUS winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_SetKeySecurity *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_SetValue 
+*/
+static NTSTATUS winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_SetValue *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_UnLoadKey 
+*/
+static NTSTATUS winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_UnLoadKey *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_InitiateSystemShutdown 
+*/
+static NTSTATUS winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_InitiateSystemShutdown *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_AbortSystemShutdown 
+*/
+static NTSTATUS winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_AbortSystemShutdown *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_GetVersion 
+*/
+static NTSTATUS winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_GetVersion *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  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 
+*/
+static NTSTATUS winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_QueryMultipleValues *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_InitiateSystemShutdownEx 
+*/
+static NTSTATUS winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_InitiateSystemShutdownEx *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  winreg_SaveKeyEx 
+*/
+static NTSTATUS winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_SaveKeyEx *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* 
+  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 
+*/
+static NTSTATUS winreg_QueryMultipleValues2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct winreg_QueryMultipleValues2 *r)
+{
+       return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_winreg_s.c"
index dac64045ce170f0fc458542e4c1cb4a3e9506601..02291fbb5b0a75d907834bf57ccc640aeafceda7 100644 (file)
@@ -69,7 +69,7 @@ sub process_file($)
                next unless ( $line =~ /
                              ^void|^BOOL|^int|^struct|^char|^const|^\w+_[tT]\s|^uint|^unsigned|^long|
                              ^NTSTATUS|^ADS_STATUS|^enum\s.*\(|^DATA_BLOB|^WERROR|^XFILE|^FILE|^DIR|
-                             ^double|^TDB_CONTEXT|^TDB_DATA|^TALLOC_CTX|^NTTIME|^FN_
+                             ^double|^TDB_CONTEXT|^TDB_DATA|^TALLOC_CTX|^NTTIME|^FN_|^REG_KEY|^REG_HANDLE|^REG_VAL
                              /xo);
 
                if ($line =~ /^FN_/) {